[gtk/wip/matthiasc/popup5: 11/75] Reimplement GtkPopover
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/matthiasc/popup5: 11/75] Reimplement GtkPopover
- Date: Mon, 29 Apr 2019 19:42:51 +0000 (UTC)
commit 56baf05b7025e6020b5591e5c66dedd268f5d14a
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Apr 29 03:25:37 2019 +0000
Reimplement GtkPopover
gtk/gtkmain.c | 21 +
gtk/gtkpopover.c | 2443 +++++++++++--------------------------------
gtk/gtkpopover.h | 94 +-
gtk/gtkpopoverprivate.h | 2 -
gtk/gtkwidget.c | 10 +-
gtk/gtkwindow.c | 2 +
gtk/inspector/object-tree.c | 2 +
tests/meson.build | 1 -
tests/testpopup.c | 62 --
9 files changed, 675 insertions(+), 1962 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index da2aa2c85e..98adee3a3a 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1330,6 +1330,27 @@ rewrite_event_for_grabs (GdkEvent *event)
event_widget = gtk_get_event_widget (event);
grab_widget = gtk_native_get_for_surface (grab_surface);
+ switch ((guint) event->any.type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_END:
+ case GDK_TOUCH_CANCEL:
+ case GDK_TOUCHPAD_SWIPE:
+ case GDK_TOUCHPAD_PINCH:
+ if (grab_surface != event->any.surface &&
+ GTK_IS_POPOVER (grab_widget))
+ {
+ gtk_widget_hide (grab_widget);
+ return NULL;
+ }
+ break;
+ default:;
+ }
+
if (grab_widget &&
gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
return rewrite_event_for_surface (event, grab_surface);
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 70632e8eac..cccba821d4 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -1,5 +1,8 @@
/* GTK - The GIMP Toolkit
- * Copyright © 2013 Carlos Garnacho <carlosg gnome org>
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Authors:
+ * - Matthias Clasen <mclasen redhat com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,7 +25,8 @@
*
* GtkPopover is a bubble-like context window, primarily meant to
* provide context-dependent information or options. Popovers are
- * attached to a widget, passed at construction time on gtk_popover_new(),
+ * attached to a widget, passed at construction time on gtk_popover_new
+(),
* or updated afterwards through gtk_popover_set_relative_to(), by
* default they will point to the whole widget area, although this
* behavior can be changed through gtk_popover_set_pointing_to().
@@ -104,246 +108,265 @@
#include "config.h"
#include "gtkpopoverprivate.h"
-
-#include "gtkadjustment.h"
-#include "gtkbox.h"
-#include "gtkbutton.h"
-#include "gtkcontainerprivate.h"
+#include "gtknative.h"
+#include "gtkwidgetprivate.h"
+#include "gtkeventcontrollerkey.h"
#include "gtkcssnodeprivate.h"
-#include "gtkentry.h"
+#include "gtkbindings.h"
+#include "gtkenums.h"
+#include "gtktypebuiltins.h"
+#include "gtkmnemonichash.h"
#include "gtkgizmoprivate.h"
#include "gtkintl.h"
-#include "gtklabel.h"
-#include "gtkmain.h"
-#include "gtkmenusectionbox.h"
-#include "gtkmenutracker.h"
-#include "gtkmodelbutton.h"
#include "gtkprivate.h"
-#include "gtkprogresstrackerprivate.h"
-#include "gtkrender.h"
-#include "gtkroundedboxprivate.h"
-#include "gtkscrollable.h"
-#include "gtksettingsprivate.h"
-#include "gtksizegroup.h"
-#include "gtksnapshot.h"
+#include "gtkmain.h"
#include "gtkstack.h"
-#include "gtkstylecontextprivate.h"
-#include "gtktypebuiltins.h"
-#include "gtkwidgetprivate.h"
-#include "gtkwindowprivate.h"
-#include "gtkgesturemultipress.h"
-#include "gtkeventcontrollerkey.h"
+#include "gtkmenusectionbox.h"
+#include "gdk/gdkeventsprivate.h"
+#include "gtkpointerfocusprivate.h"
+#include "gtkcssnodeprivate.h"
+
+static GListStore *popover_list = NULL;
-#include "a11y/gtkpopoveraccessible.h"
+typedef struct {
+ GskRenderer *renderer;
+ GdkSurface *surface;
+ GtkWidget *default_widget;
-#include "gsk/gskroundedrectprivate.h"
+ GdkSurfaceState state;
+ GtkWidget *relative_to;
+ GdkRectangle pointing_to;
+ gboolean has_pointing_to;
+ guint surface_transform_changed_cb;
+ GtkPositionType position;
+ gboolean modal;
+ gboolean has_grab;
-#ifdef GDK_WINDOWING_WAYLAND
-#include "wayland/gdkwayland.h"
-#endif
+ GtkWidget *contents_widget;
+} GtkPopoverPrivate;
-#define TAIL_GAP_WIDTH 24
-#define TAIL_HEIGHT 12
-#define TRANSITION_DIFF 20
-#define TRANSITION_DURATION 150 * 1000
+enum {
+ CLOSE,
+ CLOSED,
+ LAST_SIGNAL
+};
-#define POS_IS_VERTICAL(p) ((p) == GTK_POS_TOP || (p) == GTK_POS_BOTTOM)
+static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_RELATIVE_TO = 1,
PROP_POINTING_TO,
PROP_POSITION,
PROP_MODAL,
- PROP_CONSTRAIN_TO,
PROP_DEFAULT_WIDGET,
NUM_PROPERTIES
};
-enum {
- CLOSED,
- N_SIGNALS
-};
-
-enum {
- STATE_SHOWING,
- STATE_SHOWN,
- STATE_HIDING,
- STATE_HIDDEN
-};
-
-typedef struct _GtkPopoverPrivate GtkPopoverPrivate;
-struct _GtkPopoverPrivate
-{
- GtkWidget *widget;
- GtkWidget *contents_widget;
- GtkCssNode *arrow_node;
- GtkWindow *window;
- GtkWidget *prev_focus_widget;
- GtkWidget *default_widget;
- GtkWidget *prev_default;
- GtkScrollable *parent_scrollable;
- GtkAdjustment *vadj;
- GtkAdjustment *hadj;
- GdkRectangle pointing_to;
- GtkPopoverConstraint constraint;
- GtkProgressTracker tracker;
- guint prev_focus_unmap_id;
- guint hierarchy_changed_id;
- guint size_allocate_id;
- guint unmap_id;
- guint scrollable_notify_id;
- guint grab_notify_id;
- guint state_changed_id;
- guint has_pointing_to : 1;
- guint preferred_position : 2;
- guint final_position : 2;
- guint current_position : 2;
- guint modal : 1;
- guint button_pressed : 1;
- guint grab_notify_blocked : 1;
- guint state : 2;
- guint visible : 1;
- guint first_frame_skipped : 1;
- gint transition_diff;
- guint tick_id;
-
- gint tip_x;
- gint tip_y;
-};
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
-static GParamSpec *properties[NUM_PROPERTIES];
-static GQuark quark_widget_popovers = 0;
-static guint signals[N_SIGNALS] = { 0 };
+static void gtk_popover_native_interface_init (GtkNativeInterface *iface);
-static void gtk_popover_update_relative_to (GtkPopover *popover,
- GtkWidget *relative_to);
-static void gtk_popover_set_state (GtkPopover *popover,
- guint state);
-static void gtk_popover_apply_modality (GtkPopover *popover,
- gboolean modal);
+G_DEFINE_TYPE_WITH_CODE (GtkPopover, gtk_popover, GTK_TYPE_BIN,
+ G_ADD_PRIVATE (GtkPopover)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE,
+ gtk_popover_native_interface_init))
-static void gtk_popover_set_scrollable_full (GtkPopover *popover,
- GtkScrollable *scrollable);
-G_DEFINE_TYPE_WITH_PRIVATE (GtkPopover, gtk_popover, GTK_TYPE_BIN)
+static GskRenderer *
+gtk_popover_native_get_renderer (GtkNative *native)
+{
+ GtkPopover *popover = GTK_POPOVER (native);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ return priv->renderer;
+}
static void
-measure_contents (GtkGizmo *gizmo,
- GtkOrientation orientation,
- int for_size,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
+gtk_popover_native_get_surface_transform (GtkNative *native,
+ int *x,
+ int *y)
{
- GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
- GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
+ GtkStyleContext *context;
+ GtkBorder margin, border, padding;
- if (child)
- gtk_widget_measure (child, orientation, for_size,
- minimum, natural,
- minimum_baseline, natural_baseline);
+ context = gtk_widget_get_style_context (GTK_WIDGET (native));
+ gtk_style_context_get_margin (context, &margin);
+ gtk_style_context_get_border (context, &border);
+ gtk_style_context_get_padding (context, &padding);
+
+ *x = margin.left + border.left + padding.left;
+ *y = margin.top + border.top + padding.top;
}
static void
-allocate_contents (GtkGizmo *gizmo,
- int width,
- int height,
- int baseline)
+move_to_rect (GtkPopover *popover)
{
- GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
- GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GdkRectangle rect;
+ GdkGravity parent_anchor;
+ GdkGravity surface_anchor;
+ GdkAnchorHints anchor_hints;
- if (child)
- gtk_widget_size_allocate (child,
- &(GtkAllocation) {
- 0, 0,
- width, height
- }, -1);
+ gtk_widget_get_surface_allocation (priv->relative_to, &rect);
+ if (priv->has_pointing_to)
+ {
+ rect.x += priv->pointing_to.x;
+ rect.y += priv->pointing_to.y;
+ rect.width = priv->pointing_to.width;
+ rect.height = priv->pointing_to.height;
+ }
+
+ switch (priv->position)
+ {
+ case GTK_POS_LEFT:
+ parent_anchor = GDK_GRAVITY_WEST;
+ surface_anchor = GDK_GRAVITY_EAST;
+ anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
+ break;
+
+ case GTK_POS_RIGHT:
+ parent_anchor = GDK_GRAVITY_EAST;
+ surface_anchor = GDK_GRAVITY_WEST;
+ anchor_hints = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_SLIDE_Y;
+ break;
+
+ case GTK_POS_TOP:
+ parent_anchor = GDK_GRAVITY_NORTH;
+ surface_anchor = GDK_GRAVITY_SOUTH;
+ anchor_hints = GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X;
+ break;
+
+ case GTK_POS_BOTTOM:
+ parent_anchor = GDK_GRAVITY_SOUTH;
+ surface_anchor = GDK_GRAVITY_NORTH;
+ anchor_hints = GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ gdk_surface_move_to_rect (priv->surface,
+ &rect,
+ parent_anchor,
+ surface_anchor,
+ anchor_hints,
+ 0, 0);
}
static void
-node_style_changed_cb (GtkCssNode *node,
- GtkCssStyleChange *change,
- GtkWidget *widget)
+gtk_popover_move_resize (GtkPopover *popover)
{
- if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE))
- gtk_widget_queue_resize (widget);
- else
- gtk_widget_queue_draw (widget);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GtkRequisition req;
+
+ gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &req);
+ gdk_surface_resize (priv->surface, req.width, req.height);
+ move_to_rect (popover);
}
-static gboolean
-key_controller_key_pressed (GtkEventControllerKey *key,
- guint keyval,
- guint keycode,
- GdkModifierType modifiers,
- GtkPopover *popover)
+static void
+gtk_popover_native_check_resize (GtkNative *native)
{
+ GtkPopover *popover = GTK_POPOVER (native);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWidget *toplevel, *focus;
+ GtkWidget *widget = GTK_WIDGET (popover);
- if (keyval == GDK_KEY_Escape)
+ if (!_gtk_widget_get_alloc_needed (widget))
+ gtk_widget_ensure_allocate (widget);
+ else if (gtk_widget_get_visible (widget))
{
- gtk_popover_popdown (popover);
- return TRUE;
+ gtk_popover_move_resize (popover);
+ gtk_widget_allocate (GTK_WIDGET (popover),
+ gdk_surface_get_width (priv->surface),
+ gdk_surface_get_height (priv->surface),
+ -1, NULL);
}
+}
- if (priv->modal)
- {
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (popover));
- if (GTK_IS_WINDOW (toplevel))
- {
- focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
+static void
+gtk_popover_focus_in (GtkWidget *widget)
+{
+}
- if (focus && gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
- {
- if (gtk_event_controller_key_forward (key, focus))
- return TRUE;
- }
+static void
+gtk_popover_focus_out (GtkWidget *widget)
+{
+}
- /* Piggyback on the toplevel to have it handle key navigation */
- return gtk_event_controller_key_forward (key, toplevel);
- }
- }
+static void
+ensure_state_flag_backdrop (GtkWidget *widget)
+{
+ GtkPopover *popover = GTK_POPOVER (widget);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- return FALSE;
+ if ((priv->state & GDK_SURFACE_STATE_FOCUSED) != 0)
+ gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_BACKDROP);
+ else
+ gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_BACKDROP, FALSE);
}
static void
-gesture_pressed (GtkGestureMultiPress *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- GtkPopover *popover)
+surface_state_changed (GtkWidget *widget)
{
+ GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GdkSurfaceState new_surface_state;
+ GdkSurfaceState changed_mask;
+
+ new_surface_state = gdk_surface_get_state (_gtk_widget_get_surface (widget));
+ changed_mask = new_surface_state ^ priv->state;
+ priv->state = new_surface_state;
- priv->button_pressed = TRUE;
+ if (changed_mask & GDK_SURFACE_STATE_FOCUSED)
+ ensure_state_flag_backdrop (widget);
+
+ if (changed_mask & GDK_SURFACE_STATE_WITHDRAWN)
+ {
+ if (priv->state & GDK_SURFACE_STATE_WITHDRAWN)
+ gtk_widget_hide (widget);
+ }
}
static void
-gesture_released (GtkGestureMultiPress *gesture,
- gint n_press,
- gdouble x,
- gdouble y,
- GtkPopover *popover)
+surface_size_changed (GtkWindow *window,
+ guint width,
+ guint height)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- graphene_rect_t child_bounds;
- GtkWidget *child;
+}
- if (!priv->button_pressed)
- return;
+static void
+measure_contents (GtkGizmo *gizmo,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
+ GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
- child = gtk_bin_get_child (GTK_BIN (popover));
- if (!child ||
- !gtk_widget_compute_bounds (child, GTK_WIDGET (popover), &child_bounds) ||
- !graphene_rect_contains_point (&child_bounds,
- &(graphene_point_t){x, y}))
- gtk_popover_popdown (popover);
+ if (child)
+ gtk_widget_measure (child, orientation, for_size,
+ minimum, natural,
+ minimum_baseline, natural_baseline);
+}
+
+static void
+allocate_contents (GtkGizmo *gizmo,
+ int width,
+ int height,
+ int baseline)
+{
+ GtkPopover *popover = GTK_POPOVER (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
+ GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
+
+ if (child)
+ gtk_widget_size_allocate (child,
+ &(GtkAllocation) { 0, 0, width, height
+ }, -1);
}
static void
@@ -355,9 +378,13 @@ activate_default_cb (GSimpleAction *action,
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GtkWidget *focus_widget;
- focus_widget = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (priv->widget)));
+ focus_widget = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (priv->relative_to)));
+ if (!gtk_widget_is_ancestor (focus_widget, GTK_WIDGET (popover)))
+ focus_widget = NULL;
+
if (priv->default_widget && gtk_widget_is_sensitive (priv->default_widget) &&
- (!focus_widget || !gtk_widget_get_receives_default (focus_widget)))
+ (!focus_widget || !gtk_widget_get_receives_default (focus_widget)
+))
gtk_widget_activate (priv->default_widget);
else if (focus_widget && gtk_widget_is_sensitive (focus_widget))
gtk_widget_activate (focus_widget);
@@ -384,1019 +411,240 @@ static void
gtk_popover_init (GtkPopover *popover)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWidget *widget;
- GtkStyleContext *context;
GtkEventController *controller;
+ GtkStyleContext *context;
- widget = GTK_WIDGET (popover);
- gtk_widget_set_has_surface (widget, TRUE);
+ gtk_widget_set_has_surface (GTK_WIDGET (popover), TRUE);
+
+ priv->position = GTK_POS_TOP;
priv->modal = TRUE;
- priv->tick_id = 0;
- priv->state = STATE_HIDDEN;
- priv->visible = FALSE;
- priv->preferred_position = GTK_POS_TOP;
- priv->constraint = GTK_POPOVER_CONSTRAINT_WINDOW;
-
- priv->arrow_node = gtk_css_node_new ();
- gtk_css_node_set_name (priv->arrow_node, I_("arrow"));
- gtk_css_node_set_parent (priv->arrow_node, gtk_widget_get_css_node (widget));
- gtk_css_node_set_state (priv->arrow_node,
- gtk_css_node_get_state (gtk_widget_get_css_node (widget)));
- g_signal_connect_object (priv->arrow_node, "style-changed",
- G_CALLBACK (node_style_changed_cb), popover, 0);
- g_object_unref (priv->arrow_node);
-
- priv->contents_widget = gtk_gizmo_new ("contents", measure_contents, allocate_contents, NULL, NULL);
-
- gtk_widget_set_parent (priv->contents_widget, widget);
-
- context = gtk_widget_get_style_context (priv->contents_widget);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
controller = gtk_event_controller_key_new ();
- g_signal_connect (controller, "key-pressed",
- G_CALLBACK (key_controller_key_pressed), popover);
- gtk_widget_add_controller (widget, controller);
-
- controller = GTK_EVENT_CONTROLLER (gtk_gesture_multi_press_new ());
- g_signal_connect (controller, "pressed",
- G_CALLBACK (gesture_pressed), popover);
- g_signal_connect (controller, "released",
- G_CALLBACK (gesture_released), popover);
- gtk_widget_add_controller (widget, controller);
+ g_signal_connect_swapped (controller, "focus-in", G_CALLBACK (gtk_popover_focus_in), popover);
+ g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (gtk_popover_focus_out), popover);
+ gtk_widget_add_controller (GTK_WIDGET (popover), controller);
+
+ priv->contents_widget = gtk_gizmo_new ("contents",
+ measure_contents,
+ allocate_contents,
+ NULL,
+ NULL);
+ gtk_widget_set_parent (priv->contents_widget, GTK_WIDGET (popover));
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (popover));
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
add_actions (popover);
}
static void
-gtk_popover_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+gtk_popover_realize (GtkWidget *widget)
{
- switch (prop_id)
- {
- case PROP_RELATIVE_TO:
- gtk_popover_set_relative_to (GTK_POPOVER (object),
- g_value_get_object (value));
- break;
- case PROP_POINTING_TO:
- gtk_popover_set_pointing_to (GTK_POPOVER (object),
- g_value_get_boxed (value));
- break;
- case PROP_POSITION:
- gtk_popover_set_position (GTK_POPOVER (object),
- g_value_get_enum (value));
- break;
- case PROP_MODAL:
- gtk_popover_set_modal (GTK_POPOVER (object),
- g_value_get_boolean (value));
- break;
- case PROP_CONSTRAIN_TO:
- gtk_popover_set_constrain_to (GTK_POPOVER (object),
- g_value_get_enum (value));
- break;
- case PROP_DEFAULT_WIDGET:
- gtk_popover_set_default_widget (GTK_POPOVER (object),
- g_value_get_object (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
+ GtkPopover *popover = GTK_POPOVER (widget);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GdkRectangle parent_rect;
+ GdkDisplay *display;
+
+ gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
+
+ display = gtk_widget_get_display (priv->relative_to);
+
+ priv->surface = gdk_surface_new_popup_full (display, gtk_widget_get_surface (priv->relative_to));
+
+ gtk_widget_set_surface (widget, priv->surface);
+ g_signal_connect_swapped (priv->surface, "notify::state", G_CALLBACK (surface_state_changed), widget);
+ g_signal_connect_swapped (priv->surface, "size-changed", G_CALLBACK (surface_size_changed), widget);
+
+ gtk_widget_register_surface (widget, priv->surface);
+
+ GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
+
+ priv->renderer = gsk_renderer_new_for_surface (priv->surface);
}
static void
-gtk_popover_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+gtk_popover_unrealize (GtkWidget *widget)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (object));
+ GtkPopover *popover = GTK_POPOVER (widget);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- switch (prop_id)
- {
- case PROP_RELATIVE_TO:
- g_value_set_object (value, priv->widget);
- break;
- case PROP_POINTING_TO:
- g_value_set_boxed (value, &priv->pointing_to);
- break;
- case PROP_POSITION:
- g_value_set_enum (value, priv->preferred_position);
- break;
- case PROP_MODAL:
- g_value_set_boolean (value, priv->modal);
- break;
- case PROP_CONSTRAIN_TO:
- g_value_set_enum (value, priv->constraint);
- break;
- case PROP_DEFAULT_WIDGET:
- g_value_set_object (value, priv->default_widget);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
+ GTK_WIDGET_CLASS (gtk_popover_parent_class)->unrealize (widget);
+
+ gsk_renderer_unrealize (priv->renderer);
+ g_clear_object (&priv->renderer);
+
+ g_signal_handlers_disconnect_by_func (priv->surface, surface_state_changed, widget);
+ g_signal_handlers_disconnect_by_func (priv->surface, surface_size_changed, widget);
+
+ g_clear_object (&priv->surface);
}
-static gboolean
-transitions_enabled (GtkPopover *popover)
+static void
+gtk_popover_move_focus (GtkWidget *widget,
+ GtkDirectionType dir)
{
- return gtk_settings_get_enable_animations (gtk_widget_get_settings (GTK_WIDGET (popover)));
+ gtk_widget_child_focus (widget, dir);
+
+ if (!gtk_widget_get_focus_child (widget))
+ gtk_root_set_focus (GTK_ROOT (widget), NULL);
}
static void
-gtk_popover_hide_internal (GtkPopover *popover)
+gtk_popover_show (GtkWidget *widget)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWidget *widget = GTK_WIDGET (popover);
+ _gtk_widget_set_visible_flag (widget, TRUE);
+ gtk_css_node_validate (gtk_widget_get_css_node (widget));
+ gtk_widget_realize (widget);
+ gtk_popover_native_check_resize (GTK_NATIVE (widget));
+ gtk_widget_map (widget);
- if (!priv->visible)
- return;
+ if (!gtk_widget_get_focus_child (widget))
+ gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD);
+}
- priv->visible = FALSE;
+static void
+gtk_popover_hide (GtkWidget *widget)
+{
+ _gtk_widget_set_visible_flag (widget, FALSE);
+ gtk_widget_unmap (widget);
g_signal_emit (widget, signals[CLOSED], 0);
-
- if (priv->modal)
- gtk_popover_apply_modality (popover, FALSE);
-
- if (gtk_widget_get_realized (widget))
- {
- cairo_region_t *region = cairo_region_create ();
- gdk_surface_input_shape_combine_region (gtk_widget_get_surface (widget),
- region, 0, 0);
- cairo_region_destroy (region);
- }
}
static void
-gtk_popover_finalize (GObject *object)
+grab_prepare_func (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer data)
{
- GtkPopover *popover = GTK_POPOVER (object);
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->widget)
- gtk_popover_update_relative_to (popover, NULL);
-
- G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
+ gdk_surface_show (surface);
}
static void
-popover_unset_prev_focus (GtkPopover *popover)
+unset_surface_transform_changed_cb (gpointer data)
{
+ GtkPopover *popover = data;
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- if (!priv->prev_focus_widget)
- return;
+ priv->surface_transform_changed_cb = 0;
+}
- if (priv->prev_focus_unmap_id)
- {
- g_signal_handler_disconnect (priv->prev_focus_widget,
- priv->prev_focus_unmap_id);
- priv->prev_focus_unmap_id = 0;
- }
+static gboolean
+surface_transform_changed_cb (GtkWidget *widget,
+ const graphene_matrix_t *transform,
+ gpointer user_data)
+{
+ move_to_rect (GTK_POPOVER (user_data));
- g_clear_object (&priv->prev_focus_widget);
+ return G_SOURCE_CONTINUE;
}
static void
-gtk_popover_dispose (GObject *object)
+gtk_popover_map (GtkWidget *widget)
{
- GtkPopover *popover = GTK_POPOVER (object);
+ GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GtkWidget *child;
+ GdkRectangle parent_rect;
+ GdkDisplay *display;
if (priv->modal)
- gtk_popover_apply_modality (popover, FALSE);
-
- if (priv->window)
{
- g_signal_handlers_disconnect_by_data (priv->window, popover);
- _gtk_window_remove_popover (priv->window, GTK_WIDGET (object));
+ display = gtk_widget_get_display (priv->relative_to);
+ gdk_seat_grab (gdk_display_get_default_seat (display),
+ priv->surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL, grab_prepare_func, NULL);
+ priv->has_grab = TRUE;
}
- priv->window = NULL;
-
- if (priv->widget)
- gtk_popover_update_relative_to (popover, NULL);
-
- popover_unset_prev_focus (popover);
+ gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
+ move_to_rect (popover);
- g_clear_object (&priv->default_widget);
-
- if (priv->contents_widget)
- {
- GtkWidget *child = gtk_bin_get_child (GTK_BIN (popover));
-
- if (child)
- {
- /* Parent is content_widget! */
- gtk_widget_unparent (child);
- _gtk_bin_set_child (GTK_BIN (popover), NULL);
- }
+ priv->surface_transform_changed_cb =
+ gtk_widget_add_surface_transform_changed_callback (priv->relative_to,
+ surface_transform_changed_cb,
+ popover,
+ unset_surface_transform_changed_cb);
- gtk_widget_unparent (priv->contents_widget);
- priv->contents_widget = NULL;
- }
+ GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
- G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL && gtk_widget_get_visible (child))
+ gtk_widget_map (child);
}
static void
-gtk_popover_realize (GtkWidget *widget)
-{
- GtkAllocation allocation;
- GdkSurface *surface;
-
- gtk_widget_get_surface_allocation (widget, &allocation);
-
- surface = gdk_surface_new_child (gtk_widget_get_surface (gtk_widget_get_parent (widget)), &allocation);
-
- gtk_widget_set_surface (widget, surface);
- gtk_widget_register_surface (widget, surface);
-
- GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
-}
-
-static void
-window_active_changed (GtkWindow *window,
- GParamSpec *pspec,
- GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (!priv->modal ||
- !gtk_widget_is_drawable (GTK_WIDGET (popover)))
- return;
-
- if (gtk_window_is_active (window))
- {
- /* Regain the grab when the window is focused */
- GtkWidget *focus;
-
- gtk_grab_add (GTK_WIDGET (popover));
-
- focus = gtk_window_get_focus (window);
-
- if (focus == NULL || !gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
- gtk_widget_grab_focus (GTK_WIDGET (popover));
-
- if (priv->grab_notify_blocked)
- g_signal_handler_unblock (priv->widget, priv->grab_notify_id);
-
- priv->grab_notify_blocked = FALSE;
- }
- else
- {
- /* Temporarily remove the grab when unfocused */
- g_signal_handler_block (priv->widget, priv->grab_notify_id);
- gtk_grab_remove (GTK_WIDGET (popover));
-
- priv->grab_notify_blocked = TRUE;
- }
-}
-
-static void
-window_set_focus (GtkWindow *window,
- GParamSpec *pspec,
- GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWidget *widget = gtk_root_get_focus (GTK_ROOT (window));
-
- if (!priv->modal || !widget || !gtk_widget_is_drawable (GTK_WIDGET (popover)))
- return;
-
- widget = gtk_widget_get_ancestor (widget, GTK_TYPE_POPOVER);
- while (widget != NULL)
- {
- if (widget == GTK_WIDGET (popover))
- return;
-
- widget = gtk_popover_get_relative_to (GTK_POPOVER (widget));
- if (widget == NULL)
- break;
- widget = gtk_widget_get_ancestor (widget, GTK_TYPE_POPOVER);
- }
-
- popover_unset_prev_focus (popover);
- gtk_widget_hide (GTK_WIDGET (popover));
-}
-
-static void
-prev_focus_unmap_cb (GtkWidget *widget,
- GtkPopover *popover)
-{
- popover_unset_prev_focus (popover);
-}
-
-static void
-gtk_popover_apply_modality (GtkPopover *popover,
- gboolean modal)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (!priv->window)
- return;
-
- if (modal)
- {
- GtkWidget *prev_focus;
-
- prev_focus = gtk_window_get_focus (priv->window);
- priv->prev_focus_widget = prev_focus;
- if (priv->prev_focus_widget)
- {
- priv->prev_focus_unmap_id =
- g_signal_connect (prev_focus, "unmap",
- G_CALLBACK (prev_focus_unmap_cb), popover);
- g_object_ref (prev_focus);
- }
- gtk_grab_add (GTK_WIDGET (popover));
- gtk_window_set_focus (priv->window, NULL);
- gtk_widget_grab_focus (GTK_WIDGET (popover));
-
- g_signal_connect (priv->window, "notify::is-active",
- G_CALLBACK (window_active_changed), popover);
- g_signal_connect (priv->window, "notify::focus-widget",
- G_CALLBACK (window_set_focus), popover);
- }
- else
- {
- g_signal_handlers_disconnect_by_data (priv->window, popover);
- if (priv->prev_focus_widget == GTK_WIDGET (priv->window))
- priv->prev_focus_unmap_id = 0;
- gtk_grab_remove (GTK_WIDGET (popover));
-
- /* Let prev_focus_widget regain focus */
- if (priv->prev_focus_widget &&
- gtk_widget_is_drawable (priv->prev_focus_widget))
- {
- if (GTK_IS_ENTRY (priv->prev_focus_widget))
- gtk_entry_grab_focus_without_selecting (GTK_ENTRY (priv->prev_focus_widget));
- else
- gtk_widget_grab_focus (priv->prev_focus_widget);
- }
- else if (priv->window)
- gtk_widget_grab_focus (GTK_WIDGET (priv->window));
-
- popover_unset_prev_focus (popover);
- }
-}
-
-static gboolean
-show_animate_cb (GtkWidget *widget,
- GdkFrameClock *frame_clock,
- gpointer user_data)
+gtk_popover_unmap (GtkWidget *widget)
{
GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- gdouble t;
-
- if (priv->first_frame_skipped)
- gtk_progress_tracker_advance_frame (&priv->tracker,
- gdk_frame_clock_get_frame_time (frame_clock));
- else
- priv->first_frame_skipped = TRUE;
-
- t = gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE);
-
- if (priv->state == STATE_SHOWING)
- {
- priv->transition_diff = TRANSITION_DIFF - (TRANSITION_DIFF * t);
- gtk_widget_set_opacity (widget, t);
- }
- else if (priv->state == STATE_HIDING)
- {
- priv->transition_diff = -TRANSITION_DIFF * t;
- gtk_widget_set_opacity (widget, 1.0 - t);
- }
-
- gtk_popover_update_position (popover);
- gtk_widget_queue_allocate (GTK_WIDGET (priv->window));
-
- if (gtk_progress_tracker_get_state (&priv->tracker) == GTK_PROGRESS_STATE_AFTER)
- {
- if (priv->state == STATE_SHOWING)
- {
- gtk_popover_set_state (popover, STATE_SHOWN);
-
- if (!priv->visible)
- gtk_popover_set_state (popover, STATE_HIDING);
- }
- else
- {
- gtk_widget_hide (widget);
- }
-
- priv->tick_id = 0;
- return G_SOURCE_REMOVE;
- }
- else
- return G_SOURCE_CONTINUE;
-}
-
-static void
-gtk_popover_stop_transition (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->tick_id != 0)
- {
- gtk_widget_remove_tick_callback (GTK_WIDGET (popover), priv->tick_id);
- priv->tick_id = 0;
- }
-}
-
-static void
-gtk_popover_start_transition (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->tick_id != 0)
- return;
-
- priv->first_frame_skipped = FALSE;
- gtk_progress_tracker_start (&priv->tracker, TRANSITION_DURATION, 0, 1.0);
- priv->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (popover),
- show_animate_cb,
- popover, NULL);
-}
-
-static void
-gtk_popover_set_state (GtkPopover *popover,
- guint state)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (!transitions_enabled (popover) ||
- !gtk_widget_get_realized (GTK_WIDGET (popover)))
- {
- if (state == STATE_SHOWING)
- state = STATE_SHOWN;
- else if (state == STATE_HIDING)
- state = STATE_HIDDEN;
- }
-
- priv->state = state;
-
- if (state == STATE_SHOWING || state == STATE_HIDING)
- gtk_popover_start_transition (popover);
- else
- {
- gtk_popover_stop_transition (popover);
-
- gtk_widget_set_visible (GTK_WIDGET (popover), state == STATE_SHOWN);
- }
-}
-
-static void
-gtk_popover_map (GtkWidget *widget)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-
- priv->prev_default = gtk_window_get_default_widget (priv->window);
- if (priv->prev_default)
- g_object_ref (priv->prev_default);
-
- GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
-
- gdk_surface_show (gtk_widget_get_surface (widget));
- gtk_popover_update_position (GTK_POPOVER (widget));
-
- gtk_window_set_default_widget (priv->window, priv->default_widget);
-}
-
-static void
-gtk_popover_unmap (GtkWidget *widget)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
+ GtkWidget *child;
- priv->button_pressed = FALSE;
+ gtk_widget_remove_surface_transform_changed_callback (priv->relative_to,
+ priv->surface_transform_changed_cb);
+ priv->surface_transform_changed_cb = 0;
- gdk_surface_hide (gtk_widget_get_surface (widget));
GTK_WIDGET_CLASS (gtk_popover_parent_class)->unmap (widget);
- if (gtk_window_get_default_widget (priv->window) == priv->default_widget)
- gtk_window_set_default_widget (priv->window, priv->prev_default);
- g_clear_object (&priv->prev_default);
-}
-
-static GtkPositionType
-get_effective_position (GtkPopover *popover,
- GtkPositionType pos)
-{
- if (_gtk_widget_get_direction (GTK_WIDGET (popover)) == GTK_TEXT_DIR_RTL)
- {
- if (pos == GTK_POS_LEFT)
- pos = GTK_POS_RIGHT;
- else if (pos == GTK_POS_RIGHT)
- pos = GTK_POS_LEFT;
- }
-
- return pos;
-}
-
-static void
-get_margin (GtkWidget *widget,
- GtkBorder *border)
-{
- GtkStyleContext *context;
-
- context = gtk_widget_get_style_context (widget);
- gtk_style_context_get_margin (context,
- border);
-}
-
-static void
-gtk_popover_get_gap_coords (GtkPopover *popover,
- gint *initial_x_out,
- gint *initial_y_out,
- gint *tip_x_out,
- gint *tip_y_out,
- gint *final_x_out,
- gint *final_y_out)
-{
- GtkWidget *widget = GTK_WIDGET (popover);
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GdkRectangle rect = { 0 };
- gint base, tip, tip_pos;
- gint initial_x, initial_y;
- gint tip_x, tip_y;
- gint final_x, final_y;
- GtkPositionType pos;
- gint border_radius;
- GtkStyleContext *context;
- GtkBorder border;
- int popover_width, popover_height;
-
- gtk_popover_get_pointing_to (popover, &rect);
- popover_width = gtk_widget_get_width (widget);
- popover_height = gtk_widget_get_height (widget);
-
-#ifdef GDK_WINDOWING_WAYLAND
- if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
- {
- gint win_x, win_y;
-
- gtk_widget_translate_coordinates (priv->widget, GTK_WIDGET (priv->window),
- rect.x, rect.y, &rect.x, &rect.y);
- gdk_surface_get_origin (gtk_widget_get_surface (GTK_WIDGET (popover)),
- &win_x, &win_y);
- rect.x -= win_x;
- rect.y -= win_y;
- }
- else
-#endif
- gtk_widget_translate_coordinates (priv->widget, widget,
- rect.x, rect.y, &rect.x, &rect.y);
-
- context = gtk_widget_get_style_context (priv->contents_widget);
- gtk_style_context_get_border (context, &border);
-
- pos = get_effective_position (popover, priv->final_position);
-
- gtk_style_context_get_border (context, &border);
- gtk_style_context_get (context,
- GTK_STYLE_PROPERTY_BORDER_RADIUS, &border_radius,
- NULL);
-
- if (pos == GTK_POS_BOTTOM || pos == GTK_POS_RIGHT)
+ gdk_surface_hide (priv->surface);
+ if (priv->has_grab)
{
- tip = 0;
- base = tip + TAIL_HEIGHT + border.top;
- }
- else if (pos == GTK_POS_TOP)
- {
- base = popover_height - border.bottom - TAIL_HEIGHT;
- tip = base + TAIL_HEIGHT;
- }
- else if (pos == GTK_POS_LEFT)
- {
- base = popover_width - border.right - TAIL_HEIGHT;
- tip = base + TAIL_HEIGHT;
- }
- else
- g_assert_not_reached ();
-
- if (POS_IS_VERTICAL (pos))
- {
- tip_pos = rect.x + (rect.width / 2);
- initial_x = CLAMP (tip_pos - TAIL_GAP_WIDTH / 2,
- border_radius,
- popover_width - TAIL_GAP_WIDTH - border_radius);
- initial_y = base;
-
- tip_x = CLAMP (tip_pos, 0, popover_width);
- tip_y = tip;
-
- final_x = CLAMP (tip_pos + TAIL_GAP_WIDTH / 2,
- border_radius + TAIL_GAP_WIDTH,
- popover_width - border_radius);
- final_y = base;
- }
- else
- {
- tip_pos = rect.y + (rect.height / 2);
-
- initial_x = base;
- initial_y = CLAMP (tip_pos - TAIL_GAP_WIDTH / 2,
- border_radius,
- popover_height - TAIL_GAP_WIDTH - border_radius);
-
- tip_x = tip;
- tip_y = CLAMP (tip_pos, 0, popover_height);
-
- final_x = base;
- final_y = CLAMP (tip_pos + TAIL_GAP_WIDTH / 2,
- border_radius + TAIL_GAP_WIDTH,
- popover_height - border_radius);
- }
-
- *initial_x_out = initial_x;
- *initial_y_out = initial_y;
-
- *tip_x_out = tip_x;
- *tip_y_out = tip_y;
-
- *final_x_out = final_x;
- *final_y_out = final_y;
-}
-
-static void
-gtk_popover_get_rect_for_size (GtkPopover *popover,
- int popover_width,
- int popover_height,
- GdkRectangle *rect)
-{
- GtkWidget *widget = GTK_WIDGET (popover);
- int x, y, w, h;
- GtkBorder margin;
-
- get_margin (widget, &margin);
-
- x = 0;
- y = 0;
- w = popover_width;
- h = popover_height;
-
- x += MAX (TAIL_HEIGHT, margin.left);
- y += MAX (TAIL_HEIGHT, margin.top);
- w -= x + MAX (TAIL_HEIGHT, margin.right);
- h -= y + MAX (TAIL_HEIGHT, margin.bottom);
-
- rect->x = x;
- rect->y = y;
- rect->width = w;
- rect->height = h;
-}
-
-static void
-gtk_popover_get_rect_coords (GtkPopover *popover,
- int *x_out,
- int *y_out,
- int *w_out,
- int *h_out)
-{
- GtkWidget *widget = GTK_WIDGET (popover);
- GdkRectangle rect;
- GtkAllocation allocation;
-
- gtk_widget_get_allocation (widget, &allocation);
- gtk_popover_get_rect_for_size (popover, allocation.width, allocation.height, &rect);
-
- *x_out = rect.x;
- *y_out = rect.y;
- *w_out = rect.width;
- *h_out = rect.height;
-}
-
-static void
-gtk_popover_apply_tail_path (GtkPopover *popover,
- cairo_t *cr)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- gint initial_x, initial_y;
- gint tip_x, tip_y;
- gint final_x, final_y;
- GtkStyleContext *context;
- GtkBorder border;
-
- if (!priv->widget)
- return;
-
- context = gtk_widget_get_style_context (priv->contents_widget);
- gtk_style_context_get_border (context, &border);
-
- cairo_set_line_width (cr, 1);
- gtk_popover_get_gap_coords (popover,
- &initial_x, &initial_y,
- &tip_x, &tip_y,
- &final_x, &final_y);
-
- cairo_move_to (cr, initial_x, initial_y);
- cairo_line_to (cr, tip_x, tip_y);
- cairo_line_to (cr, final_x, final_y);
-}
-
-static void
-gtk_popover_fill_border_path (GtkPopover *popover,
- cairo_t *cr)
-{
- GtkWidget *widget = GTK_WIDGET (popover);
- GtkAllocation allocation;
- GtkStyleContext *context;
- int x, y, w, h;
- GskRoundedRect box;
-
- context = gtk_widget_get_style_context (widget);
- gtk_widget_get_allocation (widget, &allocation);
-
- cairo_set_source_rgba (cr, 0, 0, 0, 1);
-
- gtk_popover_apply_tail_path (popover, cr);
- cairo_close_path (cr);
- cairo_fill (cr);
-
- gtk_popover_get_rect_coords (popover, &x, &y, &w, &h);
-
- gtk_rounded_boxes_init_for_style (&box,
- NULL, NULL,
- gtk_style_context_lookup_style (context),
- x, y, w, h);
- gsk_rounded_rect_path (&box, cr);
- cairo_fill (cr);
-}
-
-static void
-gtk_popover_update_shape (GtkPopover *popover)
-{
- GtkWidget *widget = GTK_WIDGET (popover);
- cairo_surface_t *cairo_surface;
- cairo_region_t *region;
- GdkSurface *surface;
- cairo_t *cr;
-
-#ifdef GDK_WINDOWING_WAYLAND
- if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
- return;
-#endif
-
- surface = gtk_widget_get_surface (widget);
- cairo_surface =
- gdk_surface_create_similar_surface (surface,
- CAIRO_CONTENT_COLOR_ALPHA,
- gdk_surface_get_width (surface),
- gdk_surface_get_height (surface));
-
- cr = cairo_create (cairo_surface);
- gtk_popover_fill_border_path (popover, cr);
- cairo_destroy (cr);
-
- region = gdk_cairo_region_create_from_surface (cairo_surface);
- cairo_surface_destroy (cairo_surface);
-
- gtk_widget_input_shape_combine_region (widget, region);
- cairo_region_destroy (region);
-
- gdk_surface_set_child_input_shapes (gtk_widget_get_surface (widget));
-}
-
-static void
-_gtk_popover_update_child_visible (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWidget *widget = GTK_WIDGET (popover);
- GdkRectangle rect;
- GtkAllocation allocation;
- GtkWidget *parent;
-
- if (!priv->parent_scrollable)
- {
- gtk_widget_set_child_visible (widget, TRUE);
- return;
- }
-
- parent = gtk_widget_get_parent (GTK_WIDGET (priv->parent_scrollable));
- gtk_popover_get_pointing_to (popover, &rect);
-
- gtk_widget_translate_coordinates (priv->widget, parent,
- rect.x, rect.y, &rect.x, &rect.y);
-
- gtk_widget_get_allocation (GTK_WIDGET (parent), &allocation);
-
- if (rect.x + rect.width < 0 || rect.x > allocation.width ||
- rect.y + rect.height < 0 || rect.y > allocation.height)
- gtk_widget_set_child_visible (widget, FALSE);
- else
- gtk_widget_set_child_visible (widget, TRUE);
-}
-
-static GtkPositionType
-opposite_position (GtkPositionType pos)
-{
- switch (pos)
- {
- default:
- case GTK_POS_LEFT: return GTK_POS_RIGHT;
- case GTK_POS_RIGHT: return GTK_POS_LEFT;
- case GTK_POS_TOP: return GTK_POS_BOTTOM;
- case GTK_POS_BOTTOM: return GTK_POS_TOP;
- }
-}
-
-void
-gtk_popover_update_position (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWidget *widget = GTK_WIDGET (popover);
- GtkAllocation window_alloc;
- GtkBorder window_shadow;
- GdkRectangle rect = { 0 };
- GtkRequisition req;
- GtkPositionType pos;
- gint overshoot[4];
- gint i, j;
- gint best;
-
- if (!priv->window || !gtk_widget_get_mapped (widget))
- return;
-
- gtk_widget_get_preferred_size (widget, NULL, &req);
- gtk_widget_get_allocation (GTK_WIDGET (priv->window), &window_alloc);
- _gtk_window_get_shadow_width (priv->window, &window_shadow);
- priv->final_position = priv->preferred_position;
-
- gtk_popover_get_pointing_to (popover, &rect);
- gtk_widget_translate_coordinates (priv->widget, GTK_WIDGET (priv->window),
- rect.x, rect.y, &rect.x, &rect.y);
-
- pos = get_effective_position (popover, priv->preferred_position);
-
- overshoot[GTK_POS_TOP] = req.height - rect.y + window_shadow.top;
- overshoot[GTK_POS_BOTTOM] = rect.y + rect.height + req.height - window_alloc.height
- + window_shadow.bottom;
- overshoot[GTK_POS_LEFT] = req.width - rect.x + window_shadow.left;
- overshoot[GTK_POS_RIGHT] = rect.x + rect.width + req.width - window_alloc.width
- + window_shadow.right;
-
-#ifdef GDK_WINDOWING_WAYLAND
- if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)) &&
- priv->constraint == GTK_POPOVER_CONSTRAINT_NONE)
- {
- priv->final_position = priv->preferred_position;
- }
- else
-#endif
- if (overshoot[pos] <= 0)
- {
- priv->final_position = priv->preferred_position;
- }
- else if (overshoot[opposite_position (pos)] <= 0)
- {
- priv->final_position = opposite_position (priv->preferred_position);
- }
- else
- {
- best = G_MAXINT;
- pos = 0;
- for (i = 0; i < 4; i++)
- {
- j = get_effective_position (popover, i);
- if (overshoot[j] < best)
- {
- pos = i;
- best = overshoot[j];
- }
- }
- priv->final_position = pos;
- }
-
- switch (priv->final_position)
- {
- case GTK_POS_TOP:
- rect.y += priv->transition_diff;
- break;
- case GTK_POS_BOTTOM:
- rect.y -= priv->transition_diff;
- break;
- case GTK_POS_LEFT:
- rect.x += priv->transition_diff;
- break;
- case GTK_POS_RIGHT:
- rect.x -= priv->transition_diff;
- break;
- default:
- break;
- }
-
- _gtk_window_set_popover_position (priv->window, widget,
- priv->final_position, &rect);
+ GdkDisplay *display;
- if (priv->final_position != priv->current_position)
- {
- if (gtk_widget_is_drawable (widget))
- gtk_popover_update_shape (popover);
-
- priv->current_position = priv->final_position;
+ display = gtk_widget_get_display (priv->relative_to);
+ gdk_seat_ungrab (gdk_display_get_default_seat (display));
+ priv->has_grab = FALSE;
}
- _gtk_popover_update_child_visible (popover);
-}
-
-GtkWidget *
-gtk_popover_get_contents_widget (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- return priv->contents_widget;
-}
-
-static void
-gtk_popover_snapshot (GtkWidget *widget,
- GtkSnapshot *snapshot)
-{
- GtkPopover *popover = GTK_POPOVER (widget);
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkStyleContext *context;
- GtkBorder border;
- cairo_t *cr;
-
- /* Draw the child first so we can draw the arrow (partially) over it */
- gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
-
- cr = gtk_snapshot_append_cairo (snapshot,
- &GRAPHENE_RECT_INIT (
- 0, 0,
- gtk_widget_get_width (widget),
- gtk_widget_get_height (widget)
- ));
-
- /* Clip to the arrow shape */
- cairo_save (cr);
-
- gtk_popover_apply_tail_path (popover, cr);
-
- cairo_clip (cr);
-
- context = gtk_widget_get_style_context (widget);
- gtk_style_context_save_to_node (context, priv->arrow_node);
- gtk_style_context_get_border (context, &border);
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL)
+ gtk_widget_unmap (child);
+}
- /* Render the arrow background */
- gtk_render_background (context, cr,
- 0, 0,
- gtk_widget_get_width (widget),
- gtk_widget_get_height (widget));
+static void
+gtk_popover_dispose (GObject *object)
+{
+ GtkPopover *popover = GTK_POPOVER (object);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ guint i;
+ GtkWidget *child;
- /* Render the border of the arrow tip */
- if (border.bottom > 0)
+ for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (popover_list)); i++)
{
- GdkRGBA *border_color;
+ gpointer item = g_list_model_get_item (G_LIST_MODEL (popover_list), i);
+ if (item == object)
+ {
+ g_list_store_remove (popover_list, i);
+ break;
+ }
+ else
+ g_object_unref (item);
+ }
- gtk_style_context_get (context, "border-color", &border_color, NULL);
- gtk_popover_apply_tail_path (popover, cr);
- gdk_cairo_set_source_rgba (cr, border_color);
+ child = gtk_bin_get_child (GTK_BIN (popover));
- cairo_set_line_width (cr, border.bottom + 1);
- cairo_stroke (cr);
- gdk_rgba_free (border_color);
+ if (child)
+ {
+ gtk_widget_unparent (child);
+ _gtk_bin_set_child (GTK_BIN (popover), NULL);
}
- cairo_restore (cr);
- /* We're done */
- cairo_destroy (cr);
+ g_clear_pointer (&priv->contents_widget, gtk_widget_unparent);
- gtk_style_context_restore (context);
+ G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);
}
-static gint
-get_border_radius (GtkWidget *widget)
+static void
+gtk_popover_finalize (GObject *object)
{
- GtkStyleContext *context;
- gint border_radius;
-
- context = gtk_widget_get_style_context (widget);
- gtk_style_context_get (context,
- GTK_STYLE_PROPERTY_BORDER_RADIUS, &border_radius,
- NULL);
- return border_radius;
+ G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
}
-static gint
-get_minimal_size (GtkPopover *popover,
- GtkOrientation orientation)
+static void
+gtk_popover_constructed (GObject *object)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkPositionType pos;
- gint minimal_size;
-
- minimal_size = 2 * get_border_radius (GTK_WIDGET (popover));
- pos = get_effective_position (popover, priv->preferred_position);
-
- if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
- (orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
- minimal_size += TAIL_GAP_WIDTH;
-
- return minimal_size;
+ g_list_store_append (popover_list, object);
+ g_object_unref (object);
}
static void
@@ -1410,22 +658,11 @@ gtk_popover_measure (GtkWidget *widget,
{
GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- int minimal_size;
-
- *minimum = 0;
- *natural = 0;
-
- if (for_size >= 0)
- for_size -= TAIL_HEIGHT;
- gtk_widget_measure (priv->contents_widget, orientation, for_size, minimum, natural, NULL, NULL);
-
- minimal_size = get_minimal_size (popover, orientation);
- *minimum = MAX (*minimum, minimal_size);
- *natural = MAX (*natural, minimal_size);
-
- *minimum += TAIL_HEIGHT;
- *natural += TAIL_HEIGHT;
+ gtk_widget_measure (priv->contents_widget,
+ orientation, for_size,
+ minimum, natural,
+ minimum_baseline, natural_baseline);
}
static void
@@ -1436,133 +673,102 @@ gtk_popover_size_allocate (GtkWidget *widget,
{
GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkAllocation child_alloc = (GtkAllocation) {0, 0, width, height};
-
- /* Note that we in measure() we add TAIL_HEIGHT in both directions, regardless
- * of the popovers position. This is to ensure that we get enough space
- * even priv->current_position changes between measure and size-allocate.
- */
- child_alloc.height -= TAIL_HEIGHT;
- child_alloc.width -= TAIL_HEIGHT;
-
- switch (priv->current_position)
- {
- case GTK_POS_TOP:
- child_alloc.x += TAIL_HEIGHT / 2;
- break;
- case GTK_POS_BOTTOM:
- child_alloc.x += TAIL_HEIGHT / 2;
- child_alloc.y += TAIL_HEIGHT;
- break;
- case GTK_POS_LEFT:
- child_alloc.y += TAIL_HEIGHT / 2;
- break;
- case GTK_POS_RIGHT:
- child_alloc.x += TAIL_HEIGHT;
- child_alloc.y += TAIL_HEIGHT / 2;
- break;
- default:
- break;
- }
- gtk_widget_size_allocate (priv->contents_widget, &child_alloc, -1);
+ if (priv->surface)
+ gtk_popover_move_resize (popover);
- if (gtk_widget_get_realized (widget))
- {
- GtkAllocation a;
- gtk_widget_get_surface_allocation (widget, &a);
- gdk_surface_move_resize (gtk_widget_get_surface (widget),
- a.x, a.y, a.width, a.height);
- gtk_popover_update_shape (popover);
- }
+ gtk_widget_size_allocate (priv->contents_widget,
+ &(GtkAllocation) { 0, 0, width, height },
+ baseline);
}
static void
-gtk_popover_grab_focus (GtkWidget *widget)
+gtk_popover_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
- GtkWidget *child;
-
- if (!priv->visible)
- return;
-
- /* Focus the first natural child */
- child = gtk_bin_get_child (GTK_BIN (widget));
+ GtkPopover *popover = GTK_POPOVER (widget);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- if (child)
- gtk_widget_child_focus (child, GTK_DIR_TAB_FORWARD);
+ gtk_widget_snapshot_child (widget, priv->contents_widget, snapshot);
}
-static gboolean
-gtk_popover_focus (GtkWidget *widget,
- GtkDirectionType direction)
+static void
+gtk_popover_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GtkPopover *popover = GTK_POPOVER (widget);
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (!priv->visible)
- return FALSE;
+ GtkPopover *popover = GTK_POPOVER (object);
- if (!GTK_WIDGET_CLASS (gtk_popover_parent_class)->focus (widget, direction))
+ switch (prop_id)
{
- GtkWidget *focus;
+ case PROP_RELATIVE_TO:
+ gtk_popover_set_relative_to (popover, g_value_get_object (value));
+ break;
+
+ case PROP_POINTING_TO:
+ gtk_popover_set_pointing_to (popover, g_value_get_boxed (value));
+ break;
- focus = gtk_window_get_focus (priv->window);
- focus = gtk_widget_get_parent (focus);
+ case PROP_POSITION:
+ gtk_popover_set_position (popover, g_value_get_enum (value));
+ break;
- /* Unset focus child through children, so it is next stepped from
- * scratch.
- */
- while (focus && focus != widget)
- {
- gtk_widget_set_focus_child (focus, NULL);
- focus = gtk_widget_get_parent (focus);
- }
+ case PROP_MODAL:
+ gtk_popover_set_modal (popover, g_value_get_boolean (value));
+ break;
- return gtk_widget_child_focus (gtk_bin_get_child (GTK_BIN (widget)),
- direction);
- }
+ case PROP_DEFAULT_WIDGET:
+ gtk_popover_set_default_widget (popover, g_value_get_object (value));
+ break;
- return TRUE;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
-gtk_popover_show (GtkWidget *widget)
+gtk_popover_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
+ GtkPopover *popover = GTK_POPOVER (object);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- if (priv->window)
- _gtk_window_raise_popover (priv->window, widget);
+ switch (prop_id)
+ {
+ case PROP_RELATIVE_TO:
+ g_value_set_object (value, priv->relative_to);
+ break;
- priv->visible = TRUE;
+ case PROP_POINTING_TO:
+ g_value_set_boxed (value, &priv->pointing_to);
+ break;
- GTK_WIDGET_CLASS (gtk_popover_parent_class)->show (widget);
+ case PROP_POSITION:
+ g_value_set_enum (value, priv->position);
+ break;
- if (priv->modal)
- gtk_popover_apply_modality (GTK_POPOVER (widget), TRUE);
+ case PROP_MODAL:
+ g_value_set_boolean (value, priv->modal);
+ break;
- priv->state = STATE_SHOWN;
+ case PROP_DEFAULT_WIDGET:
+ g_value_set_object (value, priv->default_widget);
+ break;
- if (gtk_widget_get_realized (widget))
- gdk_surface_input_shape_combine_region (gtk_widget_get_surface (widget),
- NULL, 0, 0);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
-gtk_popover_hide (GtkWidget *widget)
+gtk_popover_close (GtkPopover *popover)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (GTK_POPOVER (widget));
-
- gtk_popover_hide_internal (GTK_POPOVER (widget));
-
- gtk_popover_stop_transition (GTK_POPOVER (widget));
- priv->state = STATE_HIDDEN;
- priv->transition_diff = 0;
- gtk_progress_tracker_finish (&priv->tracker);
- gtk_widget_set_opacity (widget, 1.0);
-
-
- GTK_WIDGET_CLASS (gtk_popover_parent_class)->hide (widget);
+ gtk_widget_hide (GTK_WIDGET (popover));
}
static void
@@ -1573,10 +779,9 @@ gtk_popover_add (GtkContainer *container,
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
_gtk_bin_set_child (GTK_BIN (popover), child);
-
gtk_widget_set_parent (child, priv->contents_widget);
}
-
+
static void
gtk_popover_remove (GtkContainer *container,
GtkWidget *child)
@@ -1587,20 +792,6 @@ gtk_popover_remove (GtkContainer *container,
gtk_widget_unparent (child);
}
-static void
-gtk_popover_state_flags_changed (GtkWidget *widget,
- GtkStateFlags previous_state)
-{
- GtkPopover *popover = GTK_POPOVER (widget);
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkStateFlags state;
-
- state = gtk_widget_get_state_flags (widget);
- gtk_css_node_set_state (priv->arrow_node, state);
-
- GTK_WIDGET_CLASS (gtk_popover_parent_class)->state_flags_changed (widget, previous_state);
-}
-
static void
gtk_popover_class_init (GtkPopoverClass *klass)
{
@@ -1608,31 +799,31 @@ gtk_popover_class_init (GtkPopoverClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+ if (popover_list == NULL)
+ popover_list = g_list_store_new (GTK_TYPE_WIDGET);
+
+ object_class->constructed = gtk_popover_constructed;
+ object_class->dispose = gtk_popover_dispose;
+ object_class->finalize = gtk_popover_finalize;
object_class->set_property = gtk_popover_set_property;
object_class->get_property = gtk_popover_get_property;
- object_class->finalize = gtk_popover_finalize;
- object_class->dispose = gtk_popover_dispose;
widget_class->realize = gtk_popover_realize;
+ widget_class->unrealize = gtk_popover_unrealize;
widget_class->map = gtk_popover_map;
widget_class->unmap = gtk_popover_unmap;
+ widget_class->show = gtk_popover_show;
+ widget_class->hide = gtk_popover_hide;
widget_class->measure = gtk_popover_measure;
widget_class->size_allocate = gtk_popover_size_allocate;
widget_class->snapshot = gtk_popover_snapshot;
- widget_class->grab_focus = gtk_popover_grab_focus;
- widget_class->focus = gtk_popover_focus;
- widget_class->show = gtk_popover_show;
- widget_class->hide = gtk_popover_hide;
- widget_class->state_flags_changed = gtk_popover_state_flags_changed;
+ widget_class->move_focus = gtk_popover_move_focus;
container_class->add = gtk_popover_add;
container_class->remove = gtk_popover_remove;
- /**
- * GtkPopover:relative-to:
- *
- * Sets the attached widget.
- */
+ klass->close = gtk_popover_close;
+
properties[PROP_RELATIVE_TO] =
g_param_spec_object ("relative-to",
P_("Relative to"),
@@ -1640,11 +831,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE);
- /**
- * GtkPopover:pointing-to:
- *
- * Marks a specific rectangle to be pointed.
- */
properties[PROP_POINTING_TO] =
g_param_spec_boxed ("pointing-to",
P_("Pointing to"),
@@ -1652,452 +838,118 @@ gtk_popover_class_init (GtkPopoverClass *klass)
GDK_TYPE_RECTANGLE,
GTK_PARAM_READWRITE);
- /**
- * GtkPopover:position
- *
- * Sets the preferred position of the popover.
- */
properties[PROP_POSITION] =
g_param_spec_enum ("position",
P_("Position"),
P_("Position to place the bubble window"),
GTK_TYPE_POSITION_TYPE, GTK_POS_TOP,
- GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
-
- /**
- * GtkPopover:modal
- *
- * Sets whether the popover is modal (so other elements in the window do not
- * receive input while the popover is visible).
- */
- properties[PROP_MODAL] =
- g_param_spec_boolean ("modal",
- P_("Modal"),
- P_("Whether the popover is modal"),
- TRUE,
- GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
-
- /**
- * GtkPopover:constrain-to:
- *
- * Sets a constraint for the popover position.
- */
- properties[PROP_CONSTRAIN_TO] =
- g_param_spec_enum ("constrain-to",
- P_("Constraint"),
- P_("Constraint for the popover position"),
- GTK_TYPE_POPOVER_CONSTRAINT, GTK_POPOVER_CONSTRAINT_WINDOW,
- GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
-
- properties[PROP_DEFAULT_WIDGET] =
- g_param_spec_object ("default-widget",
- P_("Default widget"),
- P_("The default widget"),
- GTK_TYPE_WIDGET,
- GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
-
- g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
-
- /**
- * GtkPopover::closed:
- *
- * This signal is emitted when the popover is dismissed either through
- * API or user interaction.
- */
- signals[CLOSED] =
- g_signal_new (I_("closed"),
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkPopoverClass, closed),
- NULL, NULL, NULL,
- G_TYPE_NONE, 0);
-
- quark_widget_popovers = g_quark_from_static_string ("gtk-quark-widget-popovers");
- gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_POPOVER_ACCESSIBLE);
- gtk_widget_class_set_css_name (widget_class, I_("popover"));
-}
-
-static void
-gtk_popover_update_scrollable (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkScrollable *scrollable;
-
- scrollable = GTK_SCROLLABLE (gtk_widget_get_ancestor (priv->widget,
- GTK_TYPE_SCROLLABLE));
- gtk_popover_set_scrollable_full (popover, scrollable);
-}
-
-static void
-_gtk_popover_parent_hierarchy_changed (GtkWidget *widget,
- GParamSpec *pspec,
- GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- GtkWindow *new_window;
-
- new_window = GTK_WINDOW (gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW));
-
- if (priv->window == new_window)
- return;
-
- g_object_ref (popover);
-
- if (gtk_widget_has_grab (GTK_WIDGET (popover)))
- gtk_popover_apply_modality (popover, FALSE);
-
- if (priv->window)
- _gtk_window_remove_popover (priv->window, GTK_WIDGET (popover));
-
- if (priv->parent_scrollable)
- gtk_popover_set_scrollable_full (popover, NULL);
-
- priv->window = new_window;
-
- if (new_window)
- {
- _gtk_window_add_popover (new_window, GTK_WIDGET (popover), priv->widget, TRUE);
- gtk_popover_update_scrollable (popover);
- gtk_popover_update_position (popover);
- }
-
- if (gtk_widget_is_visible (GTK_WIDGET (popover)))
- gtk_widget_queue_resize (GTK_WIDGET (popover));
-
- g_object_unref (popover);
-}
-
-static void
-_popover_propagate_state (GtkPopover *popover,
- GtkStateFlags state,
- GtkStateFlags old_state,
- GtkStateFlags flag)
-{
- if ((state & flag) != (old_state & flag))
- {
- if ((state & flag) == flag)
- gtk_widget_set_state_flags (GTK_WIDGET (popover), flag, FALSE);
- else
- gtk_widget_unset_state_flags (GTK_WIDGET (popover), flag);
- }
-}
-
-static void
-_gtk_popover_parent_state_changed (GtkWidget *widget,
- GtkStateFlags old_state,
- GtkPopover *popover)
-{
- guint state;
-
- state = gtk_widget_get_state_flags (widget);
- _popover_propagate_state (popover, state, old_state,
- GTK_STATE_FLAG_INSENSITIVE);
- _popover_propagate_state (popover, state, old_state,
- GTK_STATE_FLAG_BACKDROP);
-}
-
-static void
-_gtk_popover_parent_grab_notify (GtkWidget *widget,
- gboolean was_shadowed,
- GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->modal &&
- gtk_widget_is_visible (GTK_WIDGET (popover)) &&
- !gtk_widget_has_grab (GTK_WIDGET (popover)))
- {
- GtkWidget *grab_widget;
-
- grab_widget = gtk_grab_get_current ();
-
- if (!grab_widget || !GTK_IS_POPOVER (grab_widget))
- gtk_popover_popdown (popover);
- }
-}
-
-static void
-_gtk_popover_parent_unmap (GtkWidget *widget,
- GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->state == STATE_SHOWING)
- priv->visible = FALSE;
- else if (priv->state == STATE_SHOWN)
- gtk_popover_set_state (popover, STATE_HIDING);
-}
-
-static void
-gtk_popover_parent_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline,
- GtkPopover *popover)
-{
- gtk_popover_update_position (popover);
-}
-
-static void
-_unmanage_popover (GObject *object)
-{
- gtk_popover_update_relative_to (GTK_POPOVER (object), NULL);
- g_object_unref (object);
-}
-
-static void
-widget_manage_popover (GtkWidget *widget,
- GtkPopover *popover)
-{
- GHashTable *popovers;
-
- popovers = g_object_get_qdata (G_OBJECT (widget), quark_widget_popovers);
-
- if (G_UNLIKELY (!popovers))
- {
- popovers = g_hash_table_new_full (NULL, NULL,
- (GDestroyNotify) _unmanage_popover, NULL);
- g_object_set_qdata_full (G_OBJECT (widget),
- quark_widget_popovers, popovers,
- (GDestroyNotify) g_hash_table_unref);
- }
-
- g_hash_table_add (popovers, g_object_ref_sink (popover));
-}
-
-static void
-widget_unmanage_popover (GtkWidget *widget,
- GtkPopover *popover)
-{
- GHashTable *popovers;
-
- popovers = g_object_get_qdata (G_OBJECT (widget), quark_widget_popovers);
-
- if (G_UNLIKELY (!popovers))
- return;
-
- g_hash_table_remove (popovers, popover);
-}
-
-static void
-adjustment_changed_cb (GtkAdjustment *adjustment,
- GtkPopover *popover)
-{
- gtk_popover_update_position (popover);
-}
-
-static void
-_gtk_popover_set_scrollable (GtkPopover *popover,
- GtkScrollable *scrollable)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->parent_scrollable)
- {
- if (priv->vadj)
- {
- g_signal_handlers_disconnect_by_data (priv->vadj, popover);
- g_object_unref (priv->vadj);
- priv->vadj = NULL;
- }
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
- if (priv->hadj)
- {
- g_signal_handlers_disconnect_by_data (priv->hadj, popover);
- g_object_unref (priv->hadj);
- priv->hadj = NULL;
- }
+ properties[PROP_MODAL] =
+ g_param_spec_boolean ("modal",
+ P_("Modal"),
+ P_("Whether the popover is modal"),
+ TRUE,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
- g_object_unref (priv->parent_scrollable);
- }
+ properties[PROP_DEFAULT_WIDGET] =
+ g_param_spec_object ("default-widget",
+ P_("Default widget"),
+ P_("The default widget"),
+ GTK_TYPE_WIDGET,
+ GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
- priv->parent_scrollable = scrollable;
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
- if (scrollable)
- {
- g_object_ref (scrollable);
- priv->vadj = gtk_scrollable_get_vadjustment (scrollable);
- priv->hadj = gtk_scrollable_get_hadjustment (scrollable);
+ signals[CLOSE] =
+ g_signal_new (I_("close"),
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkPopoverClass, close),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
- if (priv->vadj)
- {
- g_object_ref (priv->vadj);
- g_signal_connect (priv->vadj, "changed",
- G_CALLBACK (adjustment_changed_cb), popover);
- g_signal_connect (priv->vadj, "value-changed",
- G_CALLBACK (adjustment_changed_cb), popover);
- }
+ signals[CLOSED] =
+ g_signal_new (I_("closed"),
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkPopoverClass, closed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
- if (priv->hadj)
- {
- g_object_ref (priv->hadj);
- g_signal_connect (priv->hadj, "changed",
- G_CALLBACK (adjustment_changed_cb), popover);
- g_signal_connect (priv->hadj, "value-changed",
- G_CALLBACK (adjustment_changed_cb), popover);
- }
- }
+ gtk_widget_class_set_css_name (widget_class, "popover");
}
-static void
-scrollable_notify_cb (GObject *object,
- GParamSpec *pspec,
- GtkPopover *popover)
+GtkWidget *
+gtk_popover_new (GtkWidget *relative_to)
{
- if (pspec->value_type == GTK_TYPE_ADJUSTMENT)
- _gtk_popover_set_scrollable (popover, GTK_SCROLLABLE (object));
+ return GTK_WIDGET (g_object_new (GTK_TYPE_POPOVER,
+ "relative-to", relative_to,
+ NULL));
}
static void
-gtk_popover_set_scrollable_full (GtkPopover *popover,
- GtkScrollable *scrollable)
+size_changed (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline,
+ GtkPopover *popover)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- if (priv->scrollable_notify_id != 0 &&
- g_signal_handler_is_connected (priv->parent_scrollable, priv->scrollable_notify_id))
- {
- g_signal_handler_disconnect (priv->parent_scrollable, priv->scrollable_notify_id);
- priv->scrollable_notify_id = 0;
- }
+ if (priv->surface)
+ gtk_popover_move_resize (popover);
+}
- _gtk_popover_set_scrollable (popover, scrollable);
+GListModel *
+gtk_popover_get_popovers (void)
+{
+ if (popover_list == NULL)
+ popover_list = g_list_store_new (GTK_TYPE_WIDGET);
- if (scrollable)
- {
- priv->scrollable_notify_id =
- g_signal_connect (priv->parent_scrollable, "notify",
- G_CALLBACK (scrollable_notify_cb), popover);
- }
+ return G_LIST_MODEL (popover_list);
}
-static void
-gtk_popover_update_relative_to (GtkPopover *popover,
- GtkWidget *relative_to)
+void
+gtk_popover_set_default_widget (GtkPopover *popover,
+ GtkWidget *widget)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- if (priv->widget == relative_to)
- return;
-
- g_object_ref (popover);
-
- if (priv->window)
- {
- _gtk_window_remove_popover (priv->window, GTK_WIDGET (popover));
- priv->window = NULL;
- }
-
- popover_unset_prev_focus (popover);
-
- if (priv->widget)
- {
- if (g_signal_handler_is_connected (priv->widget, priv->hierarchy_changed_id))
- g_signal_handler_disconnect (priv->widget, priv->hierarchy_changed_id);
- if (g_signal_handler_is_connected (priv->widget, priv->size_allocate_id))
- g_signal_handler_disconnect (priv->widget, priv->size_allocate_id);
- if (g_signal_handler_is_connected (priv->widget, priv->unmap_id))
- g_signal_handler_disconnect (priv->widget, priv->unmap_id);
- if (g_signal_handler_is_connected (priv->widget, priv->state_changed_id))
- g_signal_handler_disconnect (priv->widget, priv->state_changed_id);
- if (g_signal_handler_is_connected (priv->widget, priv->grab_notify_id))
- g_signal_handler_disconnect (priv->widget, priv->grab_notify_id);
-
- widget_unmanage_popover (priv->widget, popover);
- }
-
- if (priv->parent_scrollable)
- gtk_popover_set_scrollable_full (popover, NULL);
+ g_return_if_fail (GTK_IS_POPOVER (popover));
- priv->widget = relative_to;
- g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_RELATIVE_TO]);
+ if (priv->default_widget == widget)
+ return;
- if (priv->widget)
+ if (priv->default_widget)
{
- priv->window =
- GTK_WINDOW (gtk_widget_get_ancestor (priv->widget, GTK_TYPE_WINDOW));
-
- priv->hierarchy_changed_id =
- g_signal_connect (priv->widget, "notify::root",
- G_CALLBACK (_gtk_popover_parent_hierarchy_changed),
- popover);
- priv->size_allocate_id =
- g_signal_connect (priv->widget, "size-allocate",
- G_CALLBACK (gtk_popover_parent_size_allocate),
- popover);
- priv->unmap_id =
- g_signal_connect (priv->widget, "unmap",
- G_CALLBACK (_gtk_popover_parent_unmap),
- popover);
- priv->state_changed_id =
- g_signal_connect (priv->widget, "state-flags-changed",
- G_CALLBACK (_gtk_popover_parent_state_changed),
- popover);
- priv->grab_notify_id =
- g_signal_connect (priv->widget, "grab-notify",
- G_CALLBACK (_gtk_popover_parent_grab_notify),
- popover);
-
- /* Give ownership of the popover to widget */
- widget_manage_popover (priv->widget, popover);
+ _gtk_widget_set_has_default (priv->default_widget, FALSE);
+ gtk_widget_queue_draw (priv->default_widget);
+ g_object_notify (G_OBJECT (priv->default_widget), "has-default");
}
- if (priv->window)
- _gtk_window_add_popover (priv->window, GTK_WIDGET (popover), priv->widget, TRUE);
-
- if (priv->widget)
- gtk_popover_update_scrollable (popover);
-
- _gtk_widget_update_parent_muxer (GTK_WIDGET (popover));
- g_object_unref (popover);
-}
-
-static void
-gtk_popover_update_pointing_to (GtkPopover *popover,
- const GdkRectangle *pointing_to)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ g_set_object (&priv->default_widget, widget);
- if (pointing_to)
+ if (priv->default_widget)
{
- priv->pointing_to = *pointing_to;
- priv->has_pointing_to = TRUE;
+ _gtk_widget_set_has_default (priv->default_widget, TRUE);
+ gtk_widget_queue_draw (priv->default_widget);
+ g_object_notify (G_OBJECT (priv->default_widget), "has-default");
}
- else
- priv->has_pointing_to = FALSE;
- g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POINTING_TO]);
+ g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_DEFAULT_WIDGET]);
}
static void
-gtk_popover_update_preferred_position (GtkPopover *popover,
- GtkPositionType position)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- if (priv->preferred_position == position)
- return;
-
- priv->preferred_position = position;
- g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
-}
-
-/**
- * gtk_popover_new:
- * @relative_to: (allow-none): #GtkWidget the popover is related to
- *
- * Creates a new popover to point to @relative_to
- *
- * Returns: a new #GtkPopover
- **/
-GtkWidget *
-gtk_popover_new (GtkWidget *relative_to)
+gtk_popover_native_interface_init (GtkNativeInterface *iface)
{
- g_return_val_if_fail (relative_to == NULL || GTK_IS_WIDGET (relative_to), NULL);
-
- return g_object_new (GTK_TYPE_POPOVER,
- "relative-to", relative_to,
- NULL);
+ iface->get_renderer = gtk_popover_native_get_renderer;
+ iface->get_surface_transform = gtk_popover_native_get_surface_transform;
+ iface->check_resize = gtk_popover_native_check_resize;
}
/**
@@ -2108,7 +960,8 @@ gtk_popover_new (GtkWidget *relative_to)
* Sets a new widget to be attached to @popover. If @popover is
* visible, the position will be updated.
*
- * Note: the ownership of popovers is always given to their @relative_to
+ * Note: the ownership of popovers is always given to their @relative_t
+o
* widget, so if @relative_to is set to %NULL on an attached @popover, it
* will be detached from its previous widget, and consequently destroyed
* unless extra references are kept.
@@ -2117,13 +970,31 @@ void
gtk_popover_set_relative_to (GtkPopover *popover,
GtkWidget *relative_to)
{
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
g_return_if_fail (GTK_IS_POPOVER (popover));
- g_return_if_fail (relative_to == NULL || GTK_IS_WIDGET (relative_to));
- gtk_popover_update_relative_to (popover, relative_to);
+ g_object_ref (popover);
+
+ if (priv->relative_to)
+ {
+ g_signal_handlers_disconnect_by_func (priv->relative_to, size_changed, popover);
+ gtk_widget_unparent (GTK_WIDGET (popover));
+ }
+
+ priv->relative_to = relative_to;
+
+ if (priv->relative_to)
+ {
+ g_signal_connect (priv->relative_to, "size-allocate", G_CALLBACK (size_changed), popover);
+ gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (popover)),
+ gtk_widget_get_css_node (relative_to));
+ gtk_widget_set_parent (GTK_WIDGET (popover), relative_to);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_RELATIVE_TO]);
- if (relative_to)
- gtk_popover_update_position (popover);
+ g_object_unref (popover);
}
/**
@@ -2141,7 +1012,7 @@ gtk_popover_get_relative_to (GtkPopover *popover)
g_return_val_if_fail (GTK_IS_POPOVER (popover), NULL);
- return priv->widget;
+ return priv->relative_to;
}
/**
@@ -2157,11 +1028,19 @@ void
gtk_popover_set_pointing_to (GtkPopover *popover,
const GdkRectangle *rect)
{
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
g_return_if_fail (GTK_IS_POPOVER (popover));
- g_return_if_fail (rect != NULL);
- gtk_popover_update_pointing_to (popover, rect);
- gtk_popover_update_position (popover);
+ if (rect)
+ {
+ priv->pointing_to = *rect;
+ priv->has_pointing_to = TRUE;
+ }
+ else
+ priv->has_pointing_to = FALSE;
+
+ g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POINTING_TO]);
}
/**
@@ -2187,18 +1066,6 @@ gtk_popover_get_pointing_to (GtkPopover *popover,
if (priv->has_pointing_to)
*rect = priv->pointing_to;
- else if (priv->widget)
- {
- graphene_rect_t r;
-
- if (!gtk_widget_compute_bounds (priv->widget, priv->widget, &r))
- return FALSE;
-
- rect->x = floorf (r.origin.x);
- rect->y = floorf (r.origin.y);
- rect->width = ceilf (r.size.width);
- rect->height = ceilf (r.size.height);
- }
return priv->has_pointing_to;
}
@@ -2219,11 +1086,16 @@ void
gtk_popover_set_position (GtkPopover *popover,
GtkPositionType position)
{
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
g_return_if_fail (GTK_IS_POPOVER (popover));
- g_return_if_fail (position >= GTK_POS_LEFT && position <= GTK_POS_BOTTOM);
- gtk_popover_update_preferred_position (popover, position);
- gtk_popover_update_position (popover);
+ if (priv->position == position)
+ return;
+
+ priv->position = position;
+
+ g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
}
/**
@@ -2241,7 +1113,7 @@ gtk_popover_get_position (GtkPopover *popover)
g_return_val_if_fail (GTK_IS_POPOVER (popover), GTK_POS_TOP);
- return priv->preferred_position;
+ return priv->position;
}
/**
@@ -2269,9 +1141,6 @@ gtk_popover_set_modal (GtkPopover *popover,
priv->modal = modal;
- if (gtk_widget_is_visible (GTK_WIDGET (popover)))
- gtk_popover_apply_modality (popover, priv->modal);
-
g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_MODAL]);
}
@@ -2294,6 +1163,38 @@ gtk_popover_get_modal (GtkPopover *popover)
return priv->modal;
}
+/**
+ * gtk_popover_popup:
+ * @popover: a #GtkPopover
+ *
+ * Pops @popover up. This is different than a gtk_widget_show() call
+ * in that it shows the popover with a transition. If you want to show
+ * the popover without a transition, use gtk_widget_show().
+ */
+void
+gtk_popover_popup (GtkPopover *popover)
+{
+ g_return_if_fail (GTK_IS_POPOVER (popover));
+
+ gtk_widget_show (GTK_WIDGET (popover));
+}
+
+/**
+ * gtk_popover_popdown:
+ * @popover: a #GtkPopover
+ *
+ * Pops @popover down.This is different than a gtk_widget_hide() call
+ * in that it shows the popover with a transition. If you want to hide
+ * the popover without a transition, use gtk_widget_hide().
+ */
+void
+gtk_popover_popdown (GtkPopover *popover)
+{
+ g_return_if_fail (GTK_IS_POPOVER (popover));
+
+ gtk_widget_hide (GTK_WIDGET (popover));
+}
+
static void
back_to_main (GtkWidget *popover)
{
@@ -2340,7 +1241,6 @@ gtk_popover_bind_model (GtkPopover *popover,
GMenuModel *model,
const gchar *action_namespace)
{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GtkWidget *child;
GtkWidget *stack;
GtkStyleContext *style_context;
@@ -2352,7 +1252,7 @@ gtk_popover_bind_model (GtkPopover *popover,
if (child)
gtk_widget_destroy (child);
- style_context = gtk_widget_get_style_context (priv->contents_widget);
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (popover));
if (model)
{
@@ -2412,156 +1312,11 @@ gtk_popover_new_from_model (GtkWidget *relative_to,
return popover;
}
-/**
- * gtk_popover_set_default_widget:
- * @popover: a #GtkPopover
- * @widget: (allow-none): the new default widget, or %NULL
- *
- * Sets the widget that should be set as default widget while
- * the popover is shown (see gtk_window_set_default()). #GtkPopover
- * remembers the previous default widget and reestablishes it
- * when the popover is dismissed.
- */
-void
-gtk_popover_set_default_widget (GtkPopover *popover,
- GtkWidget *widget)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- g_return_if_fail (GTK_IS_POPOVER (popover));
-
- if (priv->default_widget == widget)
- return;
-
- if (priv->default_widget)
- g_object_unref (priv->default_widget);
-
- priv->default_widget = widget;
-
- if (priv->default_widget)
- g_object_ref (priv->default_widget);
-
- if (gtk_widget_get_mapped (GTK_WIDGET (popover)))
- gtk_window_set_default_widget (priv->window, priv->default_widget);
-
- g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_DEFAULT_WIDGET]);
-}
-/**
- * gtk_popover_get_default_widget:
- * @popover: a #GtkPopover
- *
- * Gets the widget that should be set as the default while
- * the popover is shown.
- *
- * Returns: (nullable) (transfer none): the default widget,
- * or %NULL if there is none
- */
GtkWidget *
-gtk_popover_get_default_widget (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- g_return_val_if_fail (GTK_IS_POPOVER (popover), NULL);
-
- return priv->default_widget;
-}
-
-/**
- * gtk_popover_set_constrain_to:
- * @popover: a #GtkPopover
- * @constraint: the new constraint
- *
- * Sets a constraint for positioning this popover.
- *
- * Note that not all platforms support placing popovers freely,
- * and may already impose constraints.
- */
-void
-gtk_popover_set_constrain_to (GtkPopover *popover,
- GtkPopoverConstraint constraint)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- g_return_if_fail (GTK_IS_POPOVER (popover));
-
- if (priv->constraint == constraint)
- return;
-
- priv->constraint = constraint;
- gtk_popover_update_position (popover);
-
- g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_CONSTRAIN_TO]);
-}
-
-/**
- * gtk_popover_get_constrain_to:
- * @popover: a #GtkPopover
- *
- * Returns the constraint for placing this popover.
- * See gtk_popover_set_constrain_to().
- *
- * Returns: the constraint for placing this popover.
- */
-GtkPopoverConstraint
-gtk_popover_get_constrain_to (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- g_return_val_if_fail (GTK_IS_POPOVER (popover), GTK_POPOVER_CONSTRAINT_WINDOW);
-
- return priv->constraint;
-}
-
-/**
- * gtk_popover_popup:
- * @popover: a #GtkPopover
- *
- * Pops @popover up. This is different than a gtk_widget_show() call
- * in that it shows the popover with a transition. If you want to show
- * the popover without a transition, use gtk_widget_show().
- */
-void
-gtk_popover_popup (GtkPopover *popover)
-{
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
-
- g_return_if_fail (GTK_IS_POPOVER (popover));
-
- if (priv->state == STATE_SHOWING ||
- priv->state == STATE_SHOWN)
- return;
-
- gtk_widget_show (GTK_WIDGET (popover));
-
- if (transitions_enabled (popover))
- gtk_popover_set_state (popover, STATE_SHOWING);
-}
-
-/**
- * gtk_popover_popdown:
- * @popover: a #GtkPopover
- *
- * Pops @popover down.This is different than a gtk_widget_hide() call
- * in that it shows the popover with a transition. If you want to hide
- * the popover without a transition, use gtk_widget_hide().
- */
-void
-gtk_popover_popdown (GtkPopover *popover)
+gtk_popover_get_contents_widget (GtkPopover *popover)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- g_return_if_fail (GTK_IS_POPOVER (popover));
-
- if (priv->state == STATE_HIDING ||
- priv->state == STATE_HIDDEN)
- return;
-
-
- if (!transitions_enabled (popover))
- gtk_widget_hide (GTK_WIDGET (popover));
- else
- gtk_popover_set_state (popover, STATE_HIDING);
-
- gtk_popover_hide_internal (popover);
+ return priv->contents_widget;
}
diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h
index 11acc02645..e9456bd7cb 100644
--- a/gtk/gtkpopover.h
+++ b/gtk/gtkpopover.h
@@ -1,5 +1,8 @@
/* GTK - The GIMP Toolkit
- * Copyright © 2013 Carlos Garnacho <carlosg gnome org>
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Authors:
+ * - Matthias Clasen <mclasen redhat com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,95 +25,88 @@
#error "Only <gtk/gtk.h> can be included directly."
#endif
-#include <gtk/gtkwindow.h>
+#include <gtk/gtkbin.h>
G_BEGIN_DECLS
-#define GTK_TYPE_POPOVER (gtk_popover_get_type ())
-#define GTK_POPOVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_POPOVER, GtkPopover))
-#define GTK_POPOVER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_POPOVER, GtkPopoverClass))
-#define GTK_IS_POPOVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_POPOVER))
-#define GTK_IS_POPOVER_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_POPOVER))
-#define GTK_POPOVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_POPOVER, GtkPopoverClass))
+#define GTK_TYPE_POPOVER (gtk_popover_get_type ())
+#define GTK_POPOVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_POPOVER, GtkPopover))
+#define GTK_POPOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_POPOVER,
GtkPopoverClass))
+#define GTK_IS_POPOVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_POPOVER))
+#define GTK_IS_POPOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_POPOVER))
+#define GTK_POPOVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_POPOVER,
GtkPopoverClass))
-typedef struct _GtkPopover GtkPopover;
-typedef struct _GtkPopoverClass GtkPopoverClass;
+typedef struct _GtkPopover GtkPopover;
+typedef struct _GtkPopoverClass GtkPopoverClass;
struct _GtkPopover
{
- GtkBin parent_instance;
+ GtkBin parent;
};
struct _GtkPopoverClass
{
GtkBinClass parent_class;
- void (* closed) (GtkPopover *popover);
+ /* keybinding signals */
+
+ void (* close) (GtkPopover *popover);
- /*< private >*/
+ /* signals */
- /* Padding for future expansion */
- gpointer reserved[10];
+ void (* closed) (GtkPopover *popover);
};
GDK_AVAILABLE_IN_ALL
-GType gtk_popover_get_type (void) G_GNUC_CONST;
+GType gtk_popover_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_popover_new (GtkWidget *relative_to);
+GtkWidget * gtk_popover_new (GtkWidget *relative_to);
GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_popover_new_from_model (GtkWidget *relative_to,
- GMenuModel *model);
+GtkWidget * gtk_popover_new_from_model (GtkWidget *relative_to,
+ GMenuModel *model);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_set_relative_to (GtkPopover *popover,
- GtkWidget *relative_to);
-GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_popover_get_relative_to (GtkPopover *popover);
+void gtk_popover_bind_model (GtkPopover *popover,
+ GMenuModel *model,
+ const gchar *action_namespace);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_set_pointing_to (GtkPopover *popover,
- const GdkRectangle *rect);
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_popover_get_pointing_to (GtkPopover *popover,
- GdkRectangle *rect);
-GDK_AVAILABLE_IN_ALL
-void gtk_popover_set_position (GtkPopover *popover,
- GtkPositionType position);
+void gtk_popover_set_relative_to (GtkPopover *popover,
+ GtkWidget *relative_to);
GDK_AVAILABLE_IN_ALL
-GtkPositionType gtk_popover_get_position (GtkPopover *popover);
+GtkWidget * gtk_popover_get_relative_to (GtkPopover *popover);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_set_modal (GtkPopover *popover,
- gboolean modal);
+void gtk_popover_set_pointing_to (GtkPopover *popover,
+ const GdkRectangle *rect);
GDK_AVAILABLE_IN_ALL
-gboolean gtk_popover_get_modal (GtkPopover *popover);
-
+gboolean gtk_popover_get_pointing_to (GtkPopover *popover,
+ GdkRectangle *rect);
+GDK_AVAILABLE_IN_ALL
+void gtk_popover_set_position (GtkPopover *popover,
+ GtkPositionType position);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_bind_model (GtkPopover *popover,
- GMenuModel *model,
- const gchar *action_namespace);
+GtkPositionType gtk_popover_get_position (GtkPopover *popover);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_set_default_widget (GtkPopover *popover,
- GtkWidget *widget);
+void gtk_popover_set_modal (GtkPopover *popover,
+ gboolean modal);
GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_popover_get_default_widget (GtkPopover *popover);
+gboolean gtk_popover_get_modal (GtkPopover *popover);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_set_constrain_to (GtkPopover *popover,
- GtkPopoverConstraint constraint);
-
+void gtk_popover_popup (GtkPopover *popover);
GDK_AVAILABLE_IN_ALL
-GtkPopoverConstraint gtk_popover_get_constrain_to (GtkPopover *popover);
+void gtk_popover_popdown (GtkPopover *popover);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_popup (GtkPopover *popover);
+void gtk_popover_set_default_widget (GtkPopover *popover,
+ GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
-void gtk_popover_popdown (GtkPopover *popover);
-
+GListModel * gtk_popover_get_popovers (void);
G_END_DECLS
diff --git a/gtk/gtkpopoverprivate.h b/gtk/gtkpopoverprivate.h
index fe24a5d775..db5fa6e57a 100644
--- a/gtk/gtkpopoverprivate.h
+++ b/gtk/gtkpopoverprivate.h
@@ -22,8 +22,6 @@
G_BEGIN_DECLS
-void gtk_popover_update_position (GtkPopover *popover);
-
GtkWidget *gtk_popover_get_contents_widget (GtkPopover *popover);
G_END_DECLS
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 4a6796f9af..290e0d2a5f 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -7414,10 +7414,12 @@ gtk_widget_get_scale_factor (GtkWidget *widget)
* just returning 1:
*/
display = _gtk_widget_get_display (widget);
- monitor = gdk_display_get_monitor (display, 0);
-
- if (monitor)
- return gdk_monitor_get_scale_factor (monitor);
+ if (display)
+ {
+ monitor = gdk_display_get_monitor (display, 0);
+ if (monitor)
+ return gdk_monitor_get_scale_factor (monitor);
+ }
return 1;
}
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index fa08ad83e4..902a8cc4f4 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -5878,8 +5878,10 @@ popover_size_allocate (GtkWindowPopover *popover,
if (!gtk_widget_get_mapped (popover->widget))
return;
+#if 0
if (GTK_IS_POPOVER (popover->widget))
gtk_popover_update_position (GTK_POPOVER (popover->widget));
+#endif
popover_get_rect (popover, window, &rect);
gtk_widget_size_allocate (popover->widget, &rect, -1);
diff --git a/gtk/inspector/object-tree.c b/gtk/inspector/object-tree.c
index f2caf34708..f977096d69 100644
--- a/gtk/inspector/object-tree.c
+++ b/gtk/inspector/object-tree.c
@@ -41,6 +41,7 @@
#include "gtklabel.h"
#include "gtklistbox.h"
#include "gtkmenuitem.h"
+#include "gtkpopover.h"
#include "gtksettings.h"
#include "gtksizegroup.h"
#include "gtktextview.h"
@@ -1144,6 +1145,7 @@ create_root_model (void)
g_object_unref);
gtk_filter_list_model_set_model (filter, gtk_window_get_toplevels ());
g_list_store_append (list, filter);
+ g_list_store_append (list, gtk_popover_get_popovers ());
g_object_unref (filter);
flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
diff --git a/tests/meson.build b/tests/meson.build
index f70401b2d4..677fbb74e6 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -114,7 +114,6 @@ gtk_tests = [
['testpopover'],
['gdkgears', ['gtkgears.c']],
['listmodel'],
- ['testpopup'],
['testgaction'],
['testwidgetfocus'],
['testwidgettransforms'],
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]