[gtk+/wip/attente/popup-at: 1/4] gtkmenu: add gtk_menu_popup_at_* ()
- From: William Hua <williamhua src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/attente/popup-at: 1/4] gtkmenu: add gtk_menu_popup_at_* ()
- Date: Tue, 28 Jun 2016 03:47:30 +0000 (UTC)
commit 0370262696e670d25c566d4d12658c4918855334
Author: William Hua <william hua canonical com>
Date: Tue Jun 14 15:42:13 2016 -0400
gtkmenu: add gtk_menu_popup_at_* ()
Adds the following functions:
gtk_menu_popup_at_rect ()
gtk_menu_popup_at_widget ()
gtk_menu_popup_at_pointer ()
docs/reference/gtk/gtk3-sections.txt | 3 +
gtk/gtkmenu.c | 468 ++++++++++++++++++++++++++++-----
gtk/gtkmenu.h | 16 ++
gtk/gtkmenuprivate.h | 18 ++
4 files changed, 434 insertions(+), 71 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 0c072c6..853cb66 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -2241,6 +2241,9 @@ gtk_menu_new_from_model
gtk_menu_set_screen
gtk_menu_reorder_child
gtk_menu_attach
+gtk_menu_popup_at_rect
+gtk_menu_popup_at_widget
+gtk_menu_popup_at_pointer
gtk_menu_popup_for_device
gtk_menu_popup
gtk_menu_set_accel_group
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 8531cf7..44fff75 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -195,7 +195,11 @@ enum {
PROP_TEAROFF_STATE,
PROP_TEAROFF_TITLE,
PROP_MONITOR,
- PROP_RESERVE_TOGGLE_SIZE
+ PROP_RESERVE_TOGGLE_SIZE,
+ PROP_ANCHOR_HINTS,
+ PROP_RECT_ANCHOR_DX,
+ PROP_RECT_ANCHOR_DY,
+ PROP_MENU_TYPE_HINT
};
enum {
@@ -693,6 +697,62 @@ gtk_menu_class_init (GtkMenuClass *class)
TRUE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
+ g_object_class_install_property (gobject_class,
+ PROP_ANCHOR_HINTS,
+ g_param_spec_flags ("anchor-hints",
+ P_("Anchor hints"),
+ P_("Positioning hints for when the menu might fall
off-screen"),
+ GDK_TYPE_ANCHOR_HINTS,
+ GDK_ANCHOR_FLIP |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (gobject_class,
+ PROP_RECT_ANCHOR_DX,
+ g_param_spec_int ("rect-anchor-dx",
+ P_("Rect anchor dx"),
+ P_("Rect anchor horizontal offset"),
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (gobject_class,
+ PROP_RECT_ANCHOR_DY,
+ g_param_spec_int ("rect-anchor-dy",
+ P_("Rect anchor dy"),
+ P_("Rect anchor vertical offset"),
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property (gobject_class,
+ PROP_MENU_TYPE_HINT,
+ g_param_spec_enum ("menu-type-hint",
+ P_("Menu type hint"),
+ P_("Menu window type hint"),
+ GDK_TYPE_WINDOW_TYPE_HINT,
+ GDK_WINDOW_TYPE_HINT_POPUP_MENU,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
/**
* GtkMenu:horizontal-padding:
*
@@ -964,6 +1024,18 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
case PROP_RESERVE_TOGGLE_SIZE:
gtk_menu_set_reserve_toggle_size (menu, g_value_get_boolean (value));
break;
+ case PROP_ANCHOR_HINTS:
+ menu->priv->anchor_hints = g_value_get_flags (value);
+ break;
+ case PROP_RECT_ANCHOR_DX:
+ menu->priv->rect_anchor_dx = g_value_get_int (value);
+ break;
+ case PROP_RECT_ANCHOR_DY:
+ menu->priv->rect_anchor_dy = g_value_get_int (value);
+ break;
+ case PROP_MENU_TYPE_HINT:
+ menu->priv->menu_type_hint = g_value_get_enum (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1008,6 +1080,18 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
case PROP_RESERVE_TOGGLE_SIZE:
g_value_set_boolean (value, gtk_menu_get_reserve_toggle_size (menu));
break;
+ case PROP_ANCHOR_HINTS:
+ g_value_set_flags (value, menu->priv->anchor_hints);
+ break;
+ case PROP_RECT_ANCHOR_DX:
+ g_value_set_int (value, menu->priv->rect_anchor_dx);
+ break;
+ case PROP_RECT_ANCHOR_DY:
+ g_value_set_int (value, menu->priv->rect_anchor_dy);
+ break;
+ case PROP_MENU_TYPE_HINT:
+ g_value_set_enum (value, menu->priv->menu_type_hint);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1549,53 +1633,16 @@ associate_menu_grab_transfer_window (GtkMenu *menu)
g_object_set_data (G_OBJECT (toplevel_window), I_("gdk-attached-grab-window"), transfer_window);
}
-/**
- * gtk_menu_popup_for_device:
- * @menu: a #GtkMenu
- * @device: (allow-none): a #GdkDevice
- * @parent_menu_shell: (allow-none): the menu shell containing the triggering
- * menu item, or %NULL
- * @parent_menu_item: (allow-none): the menu item whose activation triggered
- * the popup, or %NULL
- * @func: (allow-none): a user supplied function used to position the menu,
- * or %NULL
- * @data: (allow-none): user supplied data to be passed to @func
- * @destroy: (allow-none): destroy notify for @data
- * @button: the mouse button which was pressed to initiate the event
- * @activate_time: the time at which the activation event occurred
- *
- * Displays a menu and makes it available for selection.
- *
- * Applications can use this function to display context-sensitive menus,
- * and will typically supply %NULL for the @parent_menu_shell,
- * @parent_menu_item, @func, @data and @destroy parameters. The default
- * menu positioning function will position the menu at the current position
- * of @device (or its corresponding pointer).
- *
- * The @button parameter should be the mouse button pressed to initiate
- * the menu popup. If the menu popup was initiated by something other than
- * a mouse button press, such as a mouse button release or a keypress,
- * @button should be 0.
- *
- * The @activate_time parameter is used to conflict-resolve initiation of
- * concurrent requests for mouse/keyboard grab requests. To function
- * properly, this needs to be the time stamp of the user event (such as
- * a mouse click or key press) that caused the initiation of the popup.
- * Only if no such event is available, gtk_get_current_event_time() can
- * be used instead.
- *
- * Since: 3.0
- */
-void
-gtk_menu_popup_for_device (GtkMenu *menu,
- GdkDevice *device,
- GtkWidget *parent_menu_shell,
- GtkWidget *parent_menu_item,
- GtkMenuPositionFunc func,
- gpointer data,
- GDestroyNotify destroy,
- guint button,
- guint32 activate_time)
+static void
+gtk_menu_popup_internal (GtkMenu *menu,
+ GdkDevice *device,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ GDestroyNotify destroy,
+ guint button,
+ guint32 activate_time)
{
GtkMenuPrivate *priv = menu->priv;
GtkWidget *widget;
@@ -1802,6 +1849,73 @@ gtk_menu_popup_for_device (GtkMenu *menu,
}
/**
+ * gtk_menu_popup_for_device:
+ * @menu: a #GtkMenu
+ * @device: (allow-none): a #GdkDevice
+ * @parent_menu_shell: (allow-none): the menu shell containing the triggering
+ * menu item, or %NULL
+ * @parent_menu_item: (allow-none): the menu item whose activation triggered
+ * the popup, or %NULL
+ * @func: (allow-none): a user supplied function used to position the menu,
+ * or %NULL
+ * @data: (allow-none): user supplied data to be passed to @func
+ * @destroy: (allow-none): destroy notify for @data
+ * @button: the mouse button which was pressed to initiate the event
+ * @activate_time: the time at which the activation event occurred
+ *
+ * Displays a menu and makes it available for selection.
+ *
+ * Applications can use this function to display context-sensitive menus,
+ * and will typically supply %NULL for the @parent_menu_shell,
+ * @parent_menu_item, @func, @data and @destroy parameters. The default
+ * menu positioning function will position the menu at the current position
+ * of @device (or its corresponding pointer).
+ *
+ * The @button parameter should be the mouse button pressed to initiate
+ * the menu popup. If the menu popup was initiated by something other than
+ * a mouse button press, such as a mouse button release or a keypress,
+ * @button should be 0.
+ *
+ * The @activate_time parameter is used to conflict-resolve initiation of
+ * concurrent requests for mouse/keyboard grab requests. To function
+ * properly, this needs to be the time stamp of the user event (such as
+ * a mouse click or key press) that caused the initiation of the popup.
+ * Only if no such event is available, gtk_get_current_event_time() can
+ * be used instead.
+ *
+ * Since: 3.0
+ */
+void
+gtk_menu_popup_for_device (GtkMenu *menu,
+ GdkDevice *device,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ GDestroyNotify destroy,
+ guint button,
+ guint32 activate_time)
+{
+ GtkMenuPrivate *priv;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ priv = menu->priv;
+ priv->transient_for = NULL;
+ priv->widget = NULL;
+
+ gtk_menu_popup_internal (menu,
+ device,
+ parent_menu_shell,
+ parent_menu_item,
+ func,
+ data,
+ destroy,
+ button,
+ activate_time);
+}
+
+/**
* gtk_menu_popup:
* @menu: a #GtkMenu
* @parent_menu_shell: (allow-none): the menu shell containing the
@@ -1853,6 +1967,241 @@ gtk_menu_popup (GtkMenu *menu,
button, activate_time);
}
+static GdkDevice *
+get_device_for_event (const GdkEvent *event)
+{
+ GdkDevice *device = NULL;
+ GdkSeat *seat = NULL;
+ GdkScreen *screen = NULL;
+ GdkDisplay *display = NULL;
+
+ device = gdk_event_get_device (event);
+
+ if (device)
+ return device;
+
+ seat = gdk_event_get_seat (event);
+
+ if (!seat)
+ {
+ screen = gdk_event_get_screen (event);
+
+ if (screen)
+ display = gdk_screen_get_display (screen);
+
+ if (!display)
+ display = gdk_display_get_default ();
+
+ if (display)
+ seat = gdk_display_get_default_seat (display);
+ }
+
+ return seat ? gdk_seat_get_pointer (seat) : NULL;
+}
+
+void
+gtk_menu_popup_at_rect (GtkMenu *menu,
+ GdkWindow *transient_for,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity menu_anchor,
+ const GdkEvent *trigger_event)
+{
+ GtkMenuPrivate *priv;
+ GdkEvent *current_event = NULL;
+ GdkDevice *device = NULL;
+ guint button = 0;
+ guint32 activate_time = GDK_CURRENT_TIME;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+ g_return_if_fail (GDK_IS_WINDOW (transient_for));
+ g_return_if_fail (rect);
+
+ priv = menu->priv;
+ priv->transient_for = transient_for;
+ priv->rect = *rect;
+ priv->widget = NULL;
+ priv->rect_anchor = rect_anchor;
+ priv->menu_anchor = menu_anchor;
+
+ if (!trigger_event)
+ {
+ current_event = gtk_get_current_event ();
+ trigger_event = current_event;
+ }
+
+ if (trigger_event)
+ {
+ device = get_device_for_event (trigger_event);
+ gdk_event_get_button (trigger_event, &button);
+ activate_time = gdk_event_get_time (trigger_event);
+ }
+ else
+ g_warning ("no trigger event for menu popup");
+
+ gtk_menu_popup_internal (menu,
+ device,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ button,
+ activate_time);
+
+ if (current_event)
+ gdk_event_free (current_event);
+}
+
+void
+gtk_menu_popup_at_widget (GtkMenu *menu,
+ GtkWidget *widget,
+ GdkGravity widget_anchor,
+ GdkGravity menu_anchor,
+ const GdkEvent *trigger_event)
+{
+ GtkMenuPrivate *priv;
+ GdkEvent *current_event = NULL;
+ GdkDevice *device = NULL;
+ guint button = 0;
+ guint32 activate_time = GDK_CURRENT_TIME;
+ GtkWidget *parent_menu_shell = NULL;
+ GtkWidget *parent_menu_item = NULL;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ priv = menu->priv;
+ priv->transient_for = NULL;
+ priv->widget = widget;
+ priv->rect_anchor = widget_anchor;
+ priv->menu_anchor = menu_anchor;
+
+ if (!trigger_event)
+ {
+ current_event = gtk_get_current_event ();
+ trigger_event = current_event;
+ }
+
+ if (trigger_event)
+ {
+ device = get_device_for_event (trigger_event);
+ gdk_event_get_button (trigger_event, &button);
+ activate_time = gdk_event_get_time (trigger_event);
+ }
+ else
+ g_warning ("no trigger event for menu popup");
+
+ if (GTK_IS_MENU_ITEM (priv->widget))
+ {
+ parent_menu_item = priv->widget;
+
+ if (GTK_IS_MENU_SHELL (gtk_widget_get_parent (parent_menu_item)))
+ parent_menu_shell = gtk_widget_get_parent (parent_menu_item);
+ }
+
+ gtk_menu_popup_internal (menu,
+ device,
+ parent_menu_shell,
+ parent_menu_item,
+ NULL,
+ NULL,
+ NULL,
+ button,
+ activate_time);
+
+ if (current_event)
+ gdk_event_free (current_event);
+}
+
+void
+gtk_menu_popup_at_pointer (GtkMenu *menu,
+ const GdkEvent *trigger_event)
+{
+ GdkEvent *current_event = NULL;
+ GdkWindow *transient_for = NULL;
+ GdkDevice *device = NULL;
+ GdkRectangle rect = { 0, 0, 1, 1 };
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ if (!trigger_event)
+ {
+ current_event = gtk_get_current_event ();
+ trigger_event = current_event;
+ }
+
+ if (trigger_event)
+ {
+ transient_for = gdk_event_get_window (trigger_event);
+
+ if (transient_for)
+ {
+ device = get_device_for_event (trigger_event);
+
+ if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+ device = gdk_device_get_associated_device (device);
+
+ if (device)
+ gdk_window_get_device_position (transient_for, device, &rect.x, &rect.y, NULL);
+ }
+ }
+ else
+ g_warning ("no trigger event for menu popup");
+
+ gtk_menu_popup_at_rect (menu,
+ transient_for,
+ &rect,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ trigger_event);
+
+ if (current_event)
+ gdk_event_free (current_event);
+}
+
+static void
+get_arrows_border (GtkMenu *menu,
+ GtkBorder *border)
+{
+ GtkMenuPrivate *priv = menu->priv;
+ gint top_arrow_height, bottom_arrow_height;
+
+ gtk_css_gadget_get_preferred_size (priv->top_arrow_gadget,
+ GTK_ORIENTATION_VERTICAL,
+ -1,
+ &top_arrow_height, NULL,
+ NULL, NULL);
+ gtk_css_gadget_get_preferred_size (priv->bottom_arrow_gadget,
+ GTK_ORIENTATION_VERTICAL,
+ -1,
+ &bottom_arrow_height, NULL,
+ NULL, NULL);
+
+ border->top = priv->upper_arrow_visible ? top_arrow_height : 0;
+ border->bottom = priv->lower_arrow_visible ? bottom_arrow_height : 0;
+ border->left = border->right = 0;
+}
+
+void
+gtk_menu_update_scroll_offset (GtkMenu *menu,
+ const GdkRectangle *flipped_rect,
+ const GdkRectangle *slid_rect,
+ gboolean flipped_x,
+ gboolean flipped_y,
+ gpointer user_data)
+{
+ GtkBorder arrows_border;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+ g_return_if_fail (flipped_rect);
+ g_return_if_fail (slid_rect);
+
+ get_arrows_border (menu, &arrows_border);
+ menu->priv->scroll_offset = arrows_border.top + (slid_rect->y - flipped_rect->y);
+ gtk_menu_scroll_to (menu, menu->priv->scroll_offset);
+}
+
/**
* gtk_menu_popdown:
* @menu: a #GtkMenu
@@ -2518,29 +2867,6 @@ gtk_menu_reorder_child (GtkMenu *menu,
}
static void
-get_arrows_border (GtkMenu *menu,
- GtkBorder *border)
-{
- GtkMenuPrivate *priv = menu->priv;
- gint top_arrow_height, bottom_arrow_height;
-
- gtk_css_gadget_get_preferred_size (priv->top_arrow_gadget,
- GTK_ORIENTATION_VERTICAL,
- -1,
- &top_arrow_height, NULL,
- NULL, NULL);
- gtk_css_gadget_get_preferred_size (priv->bottom_arrow_gadget,
- GTK_ORIENTATION_VERTICAL,
- -1,
- &bottom_arrow_height, NULL,
- NULL, NULL);
-
- border->top = priv->upper_arrow_visible ? top_arrow_height : 0;
- border->bottom = priv->lower_arrow_visible ? bottom_arrow_height : 0;
- border->left = border->right = 0;
-}
-
-static void
get_menu_padding (GtkWidget *widget,
GtkBorder *padding)
{
diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h
index 5b8cb14..c9f6157 100644
--- a/gtk/gtkmenu.h
+++ b/gtk/gtkmenu.h
@@ -152,6 +152,22 @@ void gtk_menu_popup_for_device (GtkMenu *menu,
GDestroyNotify destroy,
guint button,
guint32 activate_time);
+GDK_AVAILABLE_IN_3_22
+void gtk_menu_popup_at_rect (GtkMenu *menu,
+ GdkWindow *transient_for,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity menu_anchor,
+ const GdkEvent *trigger_event);
+GDK_AVAILABLE_IN_3_22
+void gtk_menu_popup_at_widget (GtkMenu *menu,
+ GtkWidget *widget,
+ GdkGravity widget_anchor,
+ GdkGravity menu_anchor,
+ const GdkEvent *trigger_event);
+GDK_AVAILABLE_IN_3_22
+void gtk_menu_popup_at_pointer (GtkMenu *menu,
+ const GdkEvent *trigger_event);
/* Position the menu according to its position function. Called
* from gtkmenuitem.c when a menu-item changes its allocation
diff --git a/gtk/gtkmenuprivate.h b/gtk/gtkmenuprivate.h
index cb6ec25..87126b2 100644
--- a/gtk/gtkmenuprivate.h
+++ b/gtk/gtkmenuprivate.h
@@ -53,6 +53,16 @@ struct _GtkMenuPrivate
gint position_x;
gint position_y;
+ GdkWindow *transient_for;
+ GdkRectangle rect;
+ GtkWidget *widget;
+ GdkGravity rect_anchor;
+ GdkGravity menu_anchor;
+ GdkAnchorHints anchor_hints;
+ gint rect_anchor_dx;
+ gint rect_anchor_dy;
+ GdkWindowTypeHint menu_type_hint;
+
guint toggle_size;
guint accel_size;
@@ -130,6 +140,14 @@ struct _GtkMenuPrivate
gint initial_drag_offset;
};
+G_GNUC_INTERNAL
+void gtk_menu_update_scroll_offset (GtkMenu *menu,
+ const GdkRectangle *flipped_rect,
+ const GdkRectangle *slid_rect,
+ gboolean flipped_x,
+ gboolean flipped_y,
+ gpointer user_data);
+
G_END_DECLS
#endif /* __GTK_MENU_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]