[gtk/wip/matthiasc/popup2: 65/90] popup: Recreate most popover api
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/matthiasc/popup2: 65/90] popup: Recreate most popover api
- Date: Sat, 23 Mar 2019 13:41:34 +0000 (UTC)
commit dc08d6f491ca75de451a7755781b1a9135f539ec
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Mar 20 22:55:23 2019 -0400
popup: Recreate most popover api
gtk/gtkpopup.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
gtk/gtkpopup.h | 24 +++++
2 files changed, 315 insertions(+), 39 deletions(-)
---
diff --git a/gtk/gtkpopup.c b/gtk/gtkpopup.c
index 608c9b41e9..5b1e631504 100644
--- a/gtk/gtkpopup.c
+++ b/gtk/gtkpopup.c
@@ -30,6 +30,7 @@
#include "gtktypebuiltins.h"
#include "gtkmnemonichash.h"
#include "gtkintl.h"
+#include "gtkprivate.h"
#include "gtkmain.h"
#include "gdk/gdkeventsprivate.h"
#include "gtkpointerfocusprivate.h"
@@ -40,24 +41,41 @@ typedef struct {
GdkDisplay *display;
GskRenderer *renderer;
GdkSurface *surface;
- GdkSurfaceState state;
- GtkWidget *relative_to;
GtkWidget *focus_widget;
gboolean active;
GtkWidget *default_widget;
GtkMnemonicHash *mnemonic_hash;
GList *foci;
+
+ GdkSurfaceState state;
+ GtkWidget *relative_to;
+ GdkRectangle pointing_to;
+ gboolean has_pointing_to;
+ GtkPositionType position;
+ gboolean modal;
+ gboolean has_grab;
} GtkPopupPrivate;
enum {
ACTIVATE_FOCUS,
ACTIVATE_DEFAULT,
CLOSE,
+ CLOSED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
+enum {
+ PROP_RELATIVE_TO = 1,
+ PROP_POINTING_TO,
+ PROP_POSITION,
+ PROP_MODAL,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL };
+
static void gtk_popup_root_interface_init (GtkRootInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkPopup, gtk_popup, GTK_TYPE_BIN,
@@ -102,21 +120,70 @@ gtk_popup_root_get_surface_transform (GtkRoot *root,
}
static void
-gtk_popup_move_resize (GtkPopup *popup)
+move_to_rect (GtkPopup *popup)
{
GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
GdkRectangle rect;
+ GdkGravity parent_anchor;
+ GdkGravity surface_anchor;
+ GdkAnchorHints anchor_hints;
+
+ 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;
+ break;
+
+ case GTK_POS_RIGHT:
+ parent_anchor = GDK_GRAVITY_EAST;
+ surface_anchor = GDK_GRAVITY_WEST;
+ anchor_hints = GDK_ANCHOR_FLIP_X;
+ break;
+
+ case GTK_POS_TOP:
+ parent_anchor = GDK_GRAVITY_NORTH;
+ surface_anchor = GDK_GRAVITY_SOUTH;
+ anchor_hints = GDK_ANCHOR_FLIP_Y;
+ break;
+
+ case GTK_POS_BOTTOM:
+ parent_anchor = GDK_GRAVITY_SOUTH;
+ surface_anchor = GDK_GRAVITY_NORTH;
+ anchor_hints = GDK_ANCHOR_FLIP_Y;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ gdk_surface_move_to_rect (priv->surface,
+ &rect,
+ parent_anchor,
+ surface_anchor,
+ anchor_hints,
+ 0, 0);
+}
+
+static void
+gtk_popup_move_resize (GtkPopup *popup)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
GtkRequisition req;
gtk_widget_get_preferred_size (GTK_WIDGET (popup), NULL, &req);
gdk_surface_resize (priv->surface, req.width, req.height);
- gtk_widget_get_surface_allocation (priv->relative_to, &rect);
- gdk_surface_move_to_rect (priv->surface,
- &rect,
- GDK_GRAVITY_SOUTH,
- GDK_GRAVITY_NORTH,
- GDK_ANCHOR_FLIP_Y,
- 0, 10);
+ move_to_rect (popup);
}
static void
@@ -196,10 +263,14 @@ surface_size_changed (GtkWindow *window,
static void
gtk_popup_init (GtkPopup *popup)
{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
GtkEventController *controller;
gtk_widget_set_has_surface (GTK_WIDGET (popup), TRUE);
+ priv->position = GTK_POS_TOP;
+ priv->modal = TRUE;
+
controller = gtk_event_controller_key_new ();
g_signal_connect_swapped (controller, "focus-in", G_CALLBACK (gtk_popup_focus_in), popup);
g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (gtk_popup_focus_out), popup);
@@ -273,6 +344,7 @@ gtk_popup_hide (GtkWidget *widget)
{
_gtk_widget_set_visible_flag (widget, FALSE);
gtk_widget_unmap (widget);
+ g_signal_emit (widget, signals[CLOSED], 0);
}
static void
@@ -291,19 +363,18 @@ gtk_popup_map (GtkWidget *widget)
GtkWidget *child;
GdkRectangle parent_rect;
- gdk_seat_grab (gdk_display_get_default_seat (priv->display),
- priv->surface,
- GDK_SEAT_CAPABILITY_ALL,
- TRUE,
- NULL, NULL, grab_prepare_func, NULL);
+ if (priv->modal)
+ {
+ gdk_seat_grab (gdk_display_get_default_seat (priv->display),
+ priv->surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL, grab_prepare_func, NULL);
+ priv->has_grab = TRUE;
+ }
gtk_widget_get_surface_allocation (priv->relative_to, &parent_rect);
- gdk_surface_move_to_rect (priv->surface,
- &parent_rect,
- GDK_GRAVITY_SOUTH,
- GDK_GRAVITY_NORTH,
- GDK_ANCHOR_FLIP_Y,
- 0, 10);
+ move_to_rect (popup);
GTK_WIDGET_CLASS (gtk_popup_parent_class)->map (widget);
@@ -322,7 +393,11 @@ gtk_popup_unmap (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_popup_parent_class)->unmap (widget);
gdk_surface_hide (priv->surface);
- gdk_seat_ungrab (gdk_display_get_default_seat (priv->display));
+ if (priv->has_grab)
+ {
+ gdk_seat_ungrab (gdk_display_get_default_seat (priv->display));
+ priv->has_grab = FALSE;
+ }
child = gtk_bin_get_child (GTK_BIN (widget));
if (child != NULL)
@@ -412,12 +487,30 @@ gtk_popup_set_property (GObject *object,
switch (prop_id)
{
- case 1 + GTK_ROOT_PROP_FOCUS_WIDGET:
+ case PROP_RELATIVE_TO:
+ gtk_popup_set_relative_to (popup, g_value_get_object (value));
+ break;
+
+ case PROP_POINTING_TO:
+ gtk_popup_set_pointing_to (popup, g_value_get_boxed (value));
+ break;
+
+ case PROP_POSITION:
+ gtk_popup_set_position (popup, g_value_get_enum (value));
+ break;
+
+ case PROP_MODAL:
+ gtk_popup_set_modal (popup, g_value_get_boolean (value));
+ break;
+
+ case NUM_PROPERTIES + GTK_ROOT_PROP_FOCUS_WIDGET:
gtk_popup_set_focus (popup, g_value_get_object (value));
break;
- case 1 + GTK_ROOT_PROP_DEFAULT_WIDGET:
+
+ case NUM_PROPERTIES + GTK_ROOT_PROP_DEFAULT_WIDGET:
gtk_popup_set_default (popup, g_value_get_object (value));
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -435,12 +528,30 @@ gtk_popup_get_property (GObject *object,
switch (prop_id)
{
- case 1 + GTK_ROOT_PROP_FOCUS_WIDGET:
+ case PROP_RELATIVE_TO:
+ g_value_set_object (value, priv->relative_to);
+ break;
+
+ case PROP_POINTING_TO:
+ g_value_set_boxed (value, &priv->pointing_to);
+ break;
+
+ case PROP_POSITION:
+ g_value_set_enum (value, priv->position);
+ break;
+
+ case PROP_MODAL:
+ g_value_set_boolean (value, priv->modal);
+ break;
+
+ case NUM_PROPERTIES + GTK_ROOT_PROP_FOCUS_WIDGET:
g_value_set_object (value, priv->focus_widget);
break;
- case 1 + GTK_ROOT_PROP_DEFAULT_WIDGET:
+
+ case NUM_PROPERTIES + GTK_ROOT_PROP_DEFAULT_WIDGET:
g_value_set_object (value, priv->default_widget);
break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -508,7 +619,36 @@ gtk_popup_class_init (GtkPopupClass *klass)
klass->activate_focus = gtk_popup_activate_focus;
klass->close = gtk_popup_close;
- gtk_root_install_properties (object_class, 1);
+ properties[PROP_RELATIVE_TO] =
+ g_param_spec_object ("relative-to",
+ P_("Relative to"),
+ P_("Widget the bubble window points to"),
+ GTK_TYPE_WIDGET,
+ GTK_PARAM_READWRITE);
+
+ properties[PROP_POINTING_TO] =
+ g_param_spec_boxed ("pointing-to",
+ P_("Pointing to"),
+ P_("Rectangle the bubble window points to"),
+ GDK_TYPE_RECTANGLE,
+ GTK_PARAM_READWRITE);
+
+ 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);
+
+ 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_class_install_properties (object_class, NUM_PROPERTIES, properties);
+ gtk_root_install_properties (object_class, NUM_PROPERTIES);
signals[ACTIVATE_FOCUS] =
g_signal_new (I_("activate-focus"),
@@ -540,6 +680,16 @@ gtk_popup_class_init (GtkPopupClass *klass)
G_TYPE_NONE,
0);
+ signals[CLOSED] =
+ g_signal_new (I_("closed"),
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkPopupClass, closed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
+
binding_set = gtk_binding_set_by_class (klass);
add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
@@ -577,18 +727,6 @@ size_changed (GtkWidget *widget,
gtk_popup_move_resize (popup);
}
-void
-gtk_popup_set_relative_to (GtkPopup *popup,
- GtkWidget *relative_to)
-{
- GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
-
- priv->relative_to = relative_to;
- g_signal_connect (priv->relative_to, "size-allocate", G_CALLBACK (size_changed), popup);
- priv->display = gtk_widget_get_display (relative_to);
- gtk_widget_set_parent (GTK_WIDGET (popup), relative_to);
-}
-
static void
gtk_popup_set_focus (GtkPopup *popup,
GtkWidget *focus)
@@ -1046,3 +1184,117 @@ gtk_popup_root_interface_init (GtkRootInterface *iface)
iface->maybe_update_cursor = gtk_popup_root_maybe_update_cursor;
}
+void
+gtk_popup_set_relative_to (GtkPopup *popup,
+ GtkWidget *relative_to)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_if_fail (GTK_IS_POPUP (popup));
+
+ priv->relative_to = relative_to;
+ g_signal_connect (priv->relative_to, "size-allocate", G_CALLBACK (size_changed), popup);
+ priv->display = gtk_widget_get_display (relative_to);
+ gtk_widget_set_parent (GTK_WIDGET (popup), relative_to);
+
+ g_object_notify_by_pspec (G_OBJECT (popup), properties[PROP_RELATIVE_TO]);
+}
+
+GtkWidget *
+gtk_popup_get_relative_to (GtkPopup *popup)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_val_if_fail (GTK_IS_POPUP (popup), NULL);
+
+ return priv->relative_to;
+}
+
+void
+gtk_popup_set_pointing_to (GtkPopup *popup,
+ const GdkRectangle *rect)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_if_fail (GTK_IS_POPUP (popup));
+
+ if (rect)
+ {
+ priv->pointing_to = *rect;
+ priv->has_pointing_to = TRUE;
+ }
+ else
+ priv->has_pointing_to = FALSE;
+
+ g_object_notify_by_pspec (G_OBJECT (popup), properties[PROP_POINTING_TO]);
+}
+
+gboolean
+gtk_popup_get_pointing_to (GtkPopup *popup,
+ GdkRectangle *rect)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_val_if_fail (GTK_IS_POPUP (popup), FALSE);
+ g_return_val_if_fail (rect != NULL, FALSE);
+
+ if (priv->has_pointing_to)
+ *rect = priv->pointing_to;
+
+ return priv->has_pointing_to;
+}
+
+void
+gtk_popup_set_position (GtkPopup *popup,
+ GtkPositionType position)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_if_fail (GTK_IS_POPUP (popup));
+
+ if (priv->position == position)
+ return;
+
+ priv->position = position;
+
+ g_object_notify_by_pspec (G_OBJECT (popup), properties[PROP_POSITION]);
+}
+
+GtkPositionType
+gtk_popup_get_position (GtkPopup *popup)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_val_if_fail (GTK_IS_POPUP (popup), GTK_POS_TOP);
+
+ return priv->position;
+}
+
+void
+gtk_popup_set_modal (GtkPopup *popup,
+ gboolean modal)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_if_fail (GTK_IS_POPUP (popup));
+
+ modal = modal != FALSE;
+
+ if (priv->modal == modal)
+ return;
+
+ priv->modal = modal;
+
+ g_object_notify_by_pspec (G_OBJECT (popup), properties[PROP_MODAL]);
+}
+
+gboolean
+gtk_popup_get_modal (GtkPopup *popup)
+{
+ GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+
+ g_return_val_if_fail (GTK_IS_POPUP (popup), FALSE);
+
+ return priv->modal;
+}
+
diff --git a/gtk/gtkpopup.h b/gtk/gtkpopup.h
index f3755d4296..d822d3dd8e 100644
--- a/gtk/gtkpopup.h
+++ b/gtk/gtkpopup.h
@@ -53,6 +53,10 @@ struct _GtkPopupClass
void (* activate_focus) (GtkPopup *popup);
void (* activate_default) (GtkPopup *popup);
void (* close) (GtkPopup *popup);
+
+ /* signals */
+
+ void (* closed) (GtkPopup *popup);
};
GDK_AVAILABLE_IN_ALL
@@ -64,6 +68,26 @@ GtkWidget * gtk_popup_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_popup_set_relative_to (GtkPopup *popup,
GtkWidget *relative_to);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_popup_get_relative_to (GtkPopup *popup);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_popup_set_pointing_to (GtkPopup *popup,
+ const GdkRectangle *rect);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_popup_get_pointing_to (GtkPopup *popup,
+ GdkRectangle *rect);
+GDK_AVAILABLE_IN_ALL
+void gtk_popup_set_position (GtkPopup *popup,
+ GtkPositionType position);
+GDK_AVAILABLE_IN_ALL
+GtkPositionType gtk_popup_get_position (GtkPopup *popup);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_popup_set_modal (GtkPopup *popup,
+ gboolean modal);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_popup_get_modal (GtkPopup *popup);
GDK_AVAILABLE_IN_ALL
GListModel * gtk_popup_get_popups (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]