summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Hua <william.hua@canonical.com>2016-07-12 14:08:36 -0400
committerWilliam Hua <william.hua@canonical.com>2016-07-19 09:38:54 -0400
commit8701e34f749cf196c9726c01c03f35ce4eb39836 (patch)
tree1608d0bcc69917633b1640dfa7a3651158868880
parent05b9bc5cff5f2bd625412ddac2184af8c026895b (diff)
downloadgtk+-8701e34f749cf196c9726c01c03f35ce4eb39836.tar.gz
port to new gtk_menu_popup_at_* () functions
https://bugzilla.gnome.org/show_bug.cgi?id=756579
-rw-r--r--demos/gtk-demo/clipboard.c2
-rw-r--r--demos/gtk-demo/main.c2
-rw-r--r--demos/gtk-demo/search_entry.c3
-rw-r--r--gtk/deprecated/gtkcolorsel.c53
-rw-r--r--gtk/gtkappchooserwidget.c3
-rw-r--r--gtk/gtkcombobox.c285
-rw-r--r--gtk/gtkentry.c88
-rw-r--r--gtk/gtklabel.c65
-rw-r--r--gtk/gtklinkbutton.c73
-rw-r--r--gtk/gtkmenubutton.c294
-rw-r--r--gtk/gtkmenuitem.c358
-rw-r--r--gtk/gtkmenuitemprivate.h1
-rw-r--r--gtk/gtkmountoperation.c39
-rw-r--r--gtk/gtknotebook.c83
-rw-r--r--gtk/gtkplacesview.c26
-rw-r--r--gtk/gtkrecentchooserdefault.c57
-rw-r--r--gtk/gtktextview.c147
-rw-r--r--gtk/gtktoolbar.c95
-rw-r--r--gtk/gtkwindow.c21
19 files changed, 553 insertions, 1142 deletions
diff --git a/demos/gtk-demo/clipboard.c b/demos/gtk-demo/clipboard.c
index f04a203bb0..8bb44e9ed9 100644
--- a/demos/gtk-demo/clipboard.c
+++ b/demos/gtk-demo/clipboard.c
@@ -193,7 +193,7 @@ button_press (GtkWidget *widget,
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, button->time);
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) button);
return TRUE;
}
diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c
index a6adc6a52f..923030f02b 100644
--- a/demos/gtk-demo/main.c
+++ b/demos/gtk-demo/main.c
@@ -966,7 +966,7 @@ end_cb (GtkMenuItem *item, GtkWidget *scrollbar)
static gboolean
scrollbar_popup (GtkWidget *scrollbar, GtkWidget *menu)
{
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
return TRUE;
}
diff --git a/demos/gtk-demo/search_entry.c b/demos/gtk-demo/search_entry.c
index 8573aa1e89..63df73cb00 100644
--- a/demos/gtk-demo/search_entry.c
+++ b/demos/gtk-demo/search_entry.c
@@ -157,8 +157,7 @@ icon_press_cb (GtkEntry *entry,
gpointer data)
{
if (position == GTK_ENTRY_ICON_PRIMARY)
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
- event->button, event->time);
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
}
static void
diff --git a/gtk/deprecated/gtkcolorsel.c b/gtk/deprecated/gtkcolorsel.c
index f43edf2254..27be9c19db 100644
--- a/gtk/deprecated/gtkcolorsel.c
+++ b/gtk/deprecated/gtkcolorsel.c
@@ -1423,40 +1423,6 @@ palette_set_color (GtkWidget *drawing_area,
}
static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkAllocation allocation;
- GtkWidget *widget;
- GtkRequisition req;
- gint root_x, root_y;
- GdkScreen *screen;
-
- widget = GTK_WIDGET (user_data);
-
- g_return_if_fail (gtk_widget_get_realized (widget));
-
- gdk_window_get_origin (gtk_widget_get_window (widget),
- &root_x, &root_y);
-
- gtk_widget_get_preferred_size (GTK_WIDGET (menu),
- &req, NULL);
- gtk_widget_get_allocation (widget, &allocation);
-
- /* Put corner of menu centered on color cell */
- *x = root_x + allocation.width / 2;
- *y = root_y + allocation.height / 2;
-
- /* Ensure sanity */
- screen = gtk_widget_get_screen (widget);
- *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
- *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
-}
-
-static void
save_color_selected (GtkWidget *menuitem,
gpointer data)
{
@@ -1477,7 +1443,7 @@ save_color_selected (GtkWidget *menuitem,
static void
do_popup (GtkColorSelection *colorsel,
GtkWidget *drawing_area,
- guint32 timestamp)
+ const GdkEvent *trigger_event)
{
GtkWidget *menu;
GtkWidget *mi;
@@ -1499,9 +1465,14 @@ do_popup (GtkColorSelection *colorsel,
gtk_widget_show_all (mi);
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
- popup_position_func, drawing_area,
- 3, timestamp);
+ if (trigger_event && gdk_event_triggers_context_menu (trigger_event))
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), trigger_event);
+ else
+ gtk_menu_popup_at_widget (GTK_MENU (menu),
+ drawing_area,
+ GDK_GRAVITY_CENTER,
+ GDK_GRAVITY_NORTH_WEST,
+ trigger_event);
}
@@ -1540,7 +1511,7 @@ palette_press (GtkWidget *drawing_area,
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
{
- do_popup (colorsel, drawing_area, event->time);
+ do_popup (colorsel, drawing_area, (GdkEvent *) event);
return TRUE;
}
@@ -1638,9 +1609,7 @@ static gboolean
palette_popup (GtkWidget *widget,
gpointer data)
{
- GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
-
- do_popup (colorsel, widget, GDK_CURRENT_TIME);
+ do_popup (data, widget, NULL);
return TRUE;
}
diff --git a/gtk/gtkappchooserwidget.c b/gtk/gtkappchooserwidget.c
index 2aeb2b9449..fd9e6b9e8c 100644
--- a/gtk/gtkappchooserwidget.c
+++ b/gtk/gtkappchooserwidget.c
@@ -257,8 +257,7 @@ widget_button_press_event_cb (GtkWidget *widget,
if (n_children > 0)
/* actually popup the menu */
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
- event->button, event->time);
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
g_list_free (children);
}
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index d0e2dd3aba..2e0976e629 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -306,21 +306,6 @@ static void gtk_combo_box_menu_hide (GtkWidget *menu,
static void gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
GtkWidget *popup);
-static void gtk_combo_box_menu_position_below (GtkMenu *menu,
- gint *x,
- gint *y,
- gint *push_in,
- gpointer user_data);
-static void gtk_combo_box_menu_position_over (GtkMenu *menu,
- gint *x,
- gint *y,
- gint *push_in,
- gpointer user_data);
-static void gtk_combo_box_menu_position (GtkMenu *menu,
- gint *x,
- gint *y,
- gint *push_in,
- gpointer user_data);
static void gtk_combo_box_unset_model (GtkComboBox *combo_box);
@@ -1922,187 +1907,6 @@ gtk_combo_box_set_popup_widget (GtkComboBox *combo_box,
}
static void
-gtk_combo_box_menu_position_below (GtkMenu *menu,
- gint *x,
- gint *y,
- gint *push_in,
- gpointer user_data)
-{
- GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
- GtkComboBoxPrivate *priv = combo_box->priv;
- GtkAllocation child_allocation, border_allocation, content_allocation;
- gint sx, sy;
- GtkWidget *child;
- GtkRequisition req;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle area;
-
- /* FIXME: is using the size request here broken? */
- child = gtk_bin_get_child (GTK_BIN (combo_box));
-
- sx = sy = 0;
-
- gtk_css_gadget_get_border_allocation (priv->gadget, &border_allocation, NULL);
- gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
- gtk_widget_get_allocation (child, &child_allocation);
-
- if (!gtk_widget_get_has_window (child))
- {
- sx += child_allocation.x;
- sy += child_allocation.y;
- }
-
- gdk_window_get_root_coords (gtk_widget_get_window (child), sx, sy, &sx, &sy);
-
- if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL)
- sx += (content_allocation.x - border_allocation.x);
- else
- sx -= (content_allocation.x - border_allocation.x);
-
- if (combo_box->priv->popup_fixed_width)
- gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
- else
- gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
-
- if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR)
- *x = sx;
- else
- *x = sx + child_allocation.width - req.width;
- *y = sy;
-
- display = gtk_widget_get_display (GTK_WIDGET (combo_box));
- monitor = gdk_display_get_monitor_at_window (display, gtk_widget_get_window (GTK_WIDGET (combo_box)));
- gdk_monitor_get_workarea (monitor, &area);
-
- if (*x < area.x)
- *x = area.x;
- else if (*x + req.width > area.x + area.width)
- *x = area.x + area.width - req.width;
-
- if (area.y + area.height - *y - child_allocation.height >= req.height)
- *y += child_allocation.height;
- else if (*y - area.y >= req.height)
- *y -= req.height;
- else if (area.y + area.height - *y - child_allocation.height > *y - area.y)
- *y += child_allocation.height;
- else
- *y -= req.height;
-
- *push_in = FALSE;
-}
-
-static void
-gtk_combo_box_menu_position_over (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
- GtkWidget *widget = GTK_WIDGET (combo_box);
- GtkComboBoxPrivate *priv = combo_box->priv;
- GtkWidget *active;
- GtkWidget *child;
- GtkAllocation content_allocation;
- GtkAllocation child_allocation;
- GList *children;
- gint menu_xpos;
- gint menu_ypos;
- gint menu_width;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle workarea;
-
- active = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
-
- gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
-
- menu_xpos = content_allocation.x;
- menu_ypos = content_allocation.y + content_allocation.height / 2 - 2;
-
- if (priv->popup_fixed_width)
- gtk_widget_get_preferred_width (GTK_WIDGET (menu), &menu_width, NULL);
- else
- gtk_widget_get_preferred_width (GTK_WIDGET (menu), NULL, &menu_width);
-
- if (active != NULL)
- {
- gtk_widget_get_allocation (active, &child_allocation);
- menu_ypos -= child_allocation.height / 2;
- }
-
- children = GTK_MENU_SHELL (priv->popup_widget)->priv->children;
- while (children)
- {
- child = children->data;
-
- if (active == child)
- break;
-
- if (gtk_widget_get_visible (child))
- {
- gtk_widget_get_allocation (child, &child_allocation);
-
- menu_ypos -= child_allocation.height;
- }
-
- children = children->next;
- }
-
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- menu_xpos = menu_xpos + content_allocation.width - menu_width;
-
- gdk_window_get_root_coords (gtk_widget_get_window (widget),
- menu_xpos, menu_ypos,
- &menu_xpos, &menu_ypos);
-
- /* Clamp the position on screen */
- display = gtk_widget_get_display (widget);
- monitor = gdk_display_get_monitor_at_window (display, gtk_widget_get_window (widget));
- gdk_monitor_get_workarea (monitor, &workarea);
-
- if (menu_xpos < workarea.x)
- menu_xpos = workarea.x;
- else if ((menu_xpos + menu_width) > workarea.x + workarea.width)
- menu_xpos -= (menu_xpos + menu_width) - (workarea.x + workarea.width);
-
- *x = menu_xpos;
- *y = menu_ypos;
-
- *push_in = TRUE;
-}
-
-static void
-gtk_combo_box_menu_position (GtkMenu *menu,
- gint *x,
- gint *y,
- gint *push_in,
- gpointer user_data)
-{
- GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
- GtkComboBoxPrivate *priv = combo_box->priv;
- GtkWidget *menu_item;
-
- if (priv->wrap_width > 0 || priv->cell_view == NULL)
- gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data);
- else
- {
- /* FIXME handle nested menus better */
- menu_item = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
- if (menu_item)
- gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->popup_widget),
- menu_item);
-
- gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
- }
-
- if (!gtk_widget_get_visible (GTK_MENU (priv->popup_widget)->priv->toplevel))
- gtk_window_set_type_hint (GTK_WINDOW (GTK_MENU (priv->popup_widget)->priv->toplevel),
- GDK_WINDOW_TYPE_HINT_COMBO);
-}
-
-static void
gtk_combo_box_list_position (GtkComboBox *combo_box,
gint *x,
gint *y,
@@ -2309,6 +2113,13 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
GtkTreePath *path;
gint active_item;
gint width, min_width, nat_width;
+ GtkAllocation border_allocation;
+ GtkAllocation content_allocation;
+ gint rect_anchor_dy = -2;
+ gint child_height;
+ GtkWidget *active;
+ GtkWidget *child;
+ GList *i;
update_menu_sensitivity (combo_box, priv->popup_widget);
@@ -2328,8 +2139,6 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
if (priv->wrap_width == 0)
{
- GtkAllocation content_allocation;
-
gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
width = content_allocation.width;
gtk_widget_set_size_request (priv->popup_widget, -1, -1);
@@ -2343,10 +2152,82 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
gtk_widget_set_size_request (priv->popup_widget, width, -1);
}
- gtk_menu_popup (GTK_MENU (priv->popup_widget),
- NULL, NULL,
- gtk_combo_box_menu_position, combo_box,
- button, activate_time);
+ g_signal_handlers_disconnect_by_func (priv->popup_widget,
+ gtk_menu_update_scroll_offset,
+ NULL);
+
+ g_object_set (priv->popup_widget, "menu-type-hint", GDK_WINDOW_TYPE_HINT_COMBO, NULL);
+
+ if (priv->wrap_width > 0 || priv->cell_view == NULL)
+ {
+ gtk_css_gadget_get_border_allocation (priv->gadget, &border_allocation, NULL);
+ gtk_css_gadget_get_content_allocation (priv->gadget, &content_allocation, NULL);
+
+ g_object_set (priv->popup_widget,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ "rect-anchor-dx", border_allocation.x - content_allocation.x,
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->popup_widget),
+ gtk_bin_get_child (GTK_BIN (combo_box)),
+ GDK_GRAVITY_SOUTH_WEST,
+ GDK_GRAVITY_NORTH_WEST,
+ NULL);
+ }
+ else
+ {
+ /* FIXME handle nested menus better */
+ active = gtk_menu_get_active (GTK_MENU (priv->popup_widget));
+
+ if (active)
+ gtk_menu_shell_select_item (GTK_MENU_SHELL (priv->popup_widget), active);
+ else
+ {
+ for (i = GTK_MENU_SHELL (priv->popup_widget)->priv->children; i && !active; i = i->next)
+ {
+ child = i->data;
+
+ if (child && gtk_widget_get_visible (child))
+ active = child;
+ }
+ }
+
+ if (active)
+ {
+ for (i = GTK_MENU_SHELL (priv->popup_widget)->priv->children; i && i->data != active; i = i->next)
+ {
+ child = i->data;
+
+ if (child && gtk_widget_get_visible (child))
+ {
+ gtk_widget_get_preferred_height (child, &child_height, NULL);
+ rect_anchor_dy -= child_height;
+ }
+ }
+
+ gtk_widget_get_preferred_height (active, &child_height, NULL);
+ rect_anchor_dy -= child_height / 2;
+ }
+
+ g_object_set (priv->popup_widget,
+ "anchor-hints", (GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ "rect-anchor-dy", rect_anchor_dy,
+ NULL);
+
+ g_signal_connect (priv->popup_widget,
+ "popped-up",
+ G_CALLBACK (gtk_menu_update_scroll_offset),
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->popup_widget),
+ GTK_WIDGET (combo_box),
+ GDK_GRAVITY_WEST,
+ GDK_GRAVITY_NORTH_WEST,
+ NULL);
+ }
}
static gboolean
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index dd792eb013..15a1588cf0 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -9430,56 +9430,10 @@ popup_menu_detach (GtkWidget *attach_widget,
priv_attach->popup_menu = NULL;
}
-static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkEntry *entry = GTK_ENTRY (user_data);
- GtkEntryPrivate *priv = entry->priv;
- GtkWidget *widget = GTK_WIDGET (entry);
- GdkDisplay *display;
- GtkRequisition menu_req;
- GdkMonitor *monitor;
- GdkRectangle area;
- gint strong_x, height;
-
- g_return_if_fail (gtk_widget_get_realized (widget));
-
- gdk_window_get_origin (priv->text_area, x, y);
-
- display = gtk_widget_get_display (widget);
- monitor = gdk_display_get_monitor_at_window (display, priv->text_area);
- gtk_menu_place_on_monitor (menu, monitor);
- gdk_monitor_get_workarea (monitor, &area);
- gtk_widget_get_preferred_size (priv->popup_menu, &menu_req, NULL);
- height = gdk_window_get_height (priv->text_area);
- gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
-
- *x += 0 + strong_x - priv->scroll_offset;
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- *x -= menu_req.width;
-
- if ((*y + height + menu_req.height) <= area.y + area.height)
- *y += height;
- else if ((*y - menu_req.height) >= area.y)
- *y -= menu_req.height;
- else if (area.y + area.height - (*y + height) > *y)
- *y += height;
- else
- *y -= menu_req.height;
-
- *push_in = FALSE;
-}
-
typedef struct
{
GtkEntry *entry;
- guint button;
- guint time;
- GdkDevice *device;
+ GdkEvent *trigger_event;
} PopupInfo;
static void
@@ -9490,6 +9444,7 @@ popup_targets_received (GtkClipboard *clipboard,
PopupInfo *info = user_data;
GtkEntry *entry = info->entry;
GtkEntryPrivate *info_entry_priv = entry->priv;
+ GdkRectangle rect = { 0, 0, 1, 0 };
if (gtk_widget_get_realized (GTK_WIDGET (entry)))
{
@@ -9540,19 +9495,26 @@ popup_targets_received (GtkClipboard *clipboard,
g_signal_emit (entry, signals[POPULATE_POPUP], 0, menu);
- if (info->device)
- gtk_menu_popup_for_device (GTK_MENU (menu),
- info->device, NULL, NULL, NULL, NULL, NULL,
- info->button, info->time);
+ if (info->trigger_event && gdk_event_triggers_context_menu (info->trigger_event))
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), info->trigger_event);
else
- {
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
- popup_position_func, entry,
- 0, gtk_get_current_event_time ());
+ {
+ gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &rect.x, NULL);
+ rect.x -= info_entry_priv->scroll_offset;
+ rect.height = gdk_window_get_height (info_entry_priv->text_area);
+
+ gtk_menu_popup_at_rect (GTK_MENU (menu),
+ info_entry_priv->text_area,
+ &rect,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ info->trigger_event);
+
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
- }
+ }
}
+ g_clear_pointer (&info->trigger_event, gdk_event_free);
g_object_unref (entry);
g_slice_free (PopupInfo, info);
}
@@ -9568,19 +9530,7 @@ gtk_entry_do_popup (GtkEntry *entry,
* we get them, then we actually pop up the menu.
*/
info->entry = g_object_ref (entry);
-
- if (event)
- {
- gdk_event_get_button (event, &info->button);
- info->time = gdk_event_get_time (event);
- info->device = gdk_event_get_device (event);
- }
- else
- {
- info->button = 0;
- info->time = gtk_get_current_event_time ();
- info->device = NULL;
- }
+ info->trigger_event = event ? gdk_event_copy (event) : gtk_get_current_event ();
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
gdk_atom_intern_static_string ("TARGETS"),
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index dd2bbbfd67..342dadfabd 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -512,7 +512,7 @@ static void gtk_label_move_cursor (GtkLabel *label,
static void gtk_label_copy_clipboard (GtkLabel *label);
static void gtk_label_select_all (GtkLabel *label);
static void gtk_label_do_popup (GtkLabel *label,
- GdkEventButton *event);
+ const GdkEvent *event);
static gint gtk_label_move_forward_word (GtkLabel *label,
gint start);
static gint gtk_label_move_backward_word (GtkLabel *label,
@@ -4954,7 +4954,7 @@ gtk_label_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
{
info->link_clicked = 1;
update_link_state (label);
- gtk_label_do_popup (label, (GdkEventButton*) event);
+ gtk_label_do_popup (label, event);
return;
}
else if (button == GDK_BUTTON_PRIMARY)
@@ -4977,7 +4977,7 @@ gtk_label_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
info->select_words = FALSE;
if (gdk_event_triggers_context_menu (event))
- gtk_label_do_popup (label, (GdkEventButton*) event);
+ gtk_label_do_popup (label, event);
else if (button == GDK_BUTTON_PRIMARY)
{
if (!gtk_widget_has_focus (widget))
@@ -6545,48 +6545,6 @@ popup_menu_detach (GtkWidget *attach_widget,
}
static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkLabel *label;
- GtkWidget *widget;
- GtkAllocation allocation;
- GtkRequisition req;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle workarea;
-
- label = GTK_LABEL (user_data);
- widget = GTK_WIDGET (label);
-
- g_return_if_fail (gtk_widget_get_realized (widget));
-
- display = gtk_widget_get_display (widget);
- monitor = gdk_display_get_monitor_at_window (display,
- gtk_widget_get_window (widget));
- gdk_monitor_get_workarea (monitor, &workarea);
-
- gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
- gtk_widget_get_allocation (widget, &allocation);
-
- *x += allocation.x;
- *y += allocation.y;
-
- gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
-
- gtk_widget_get_allocation (widget, &allocation);
-
- *x += allocation.width / 2;
- *y += allocation.height;
-
- *x = CLAMP (*x, 0, MAX (0, workarea.width - req.width));
- *y = CLAMP (*y, 0, MAX (0, workarea.height - req.height));
-}
-
-static void
open_link_activate_cb (GtkMenuItem *menuitem,
GtkLabel *label)
{
@@ -6618,7 +6576,7 @@ gtk_label_popup_menu (GtkWidget *widget)
static void
gtk_label_do_popup (GtkLabel *label,
- GdkEventButton *event)
+ const GdkEvent *event)
{
GtkLabelPrivate *priv = label->priv;
GtkWidget *menuitem;
@@ -6695,15 +6653,16 @@ gtk_label_do_popup (GtkLabel *label,
g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
- if (event)
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
- NULL, NULL,
- event->button, event->time);
+ if (event && gdk_event_triggers_context_menu ((GdkEvent *) event))
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
else
{
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
- popup_position_func, label,
- 0, gtk_get_current_event_time ());
+ gtk_menu_popup_at_widget (GTK_MENU (menu),
+ GTK_WIDGET (label),
+ GDK_GRAVITY_SOUTH,
+ GDK_GRAVITY_NORTH_WEST,
+ event);
+
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
}
}
diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c
index 1776d06e88..0ea9f6fa98 100644
--- a/gtk/gtklinkbutton.c
+++ b/gtk/gtklinkbutton.c
@@ -336,43 +336,6 @@ popup_menu_detach (GtkWidget *attach_widget,
}
static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkLinkButton *link_button = GTK_LINK_BUTTON (user_data);
- GtkLinkButtonPrivate *priv = link_button->priv;
- GtkAllocation allocation;
- GtkWidget *widget = GTK_WIDGET (link_button);
- GdkDisplay *display;
- GdkMonitor *monitor;
- GtkRequisition req;
- GdkRectangle area;
-
- g_return_if_fail (gtk_widget_get_realized (widget));
-
- gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
-
- gtk_widget_get_preferred_size (priv->popup_menu, &req, NULL);
-
- gtk_widget_get_allocation (widget, &allocation);
- *x += allocation.width / 2;
- *y += allocation.height;
-
- display = gtk_widget_get_display (widget);
- monitor = gdk_display_get_monitor_at_point (display, *x, *y);
- gtk_menu_place_on_monitor (menu, monitor);
- gdk_monitor_get_workarea (monitor, &area);
-
- *x = CLAMP (*x, area.x, area.x + MAX (0, area.width - req.width));
- *y = CLAMP (*y, area.y, area.y + MAX (0, area.height - req.height));
-
- *push_in = FALSE;
-}
-
-static void
copy_activate_cb (GtkWidget *widget,
GtkLinkButton *link_button)
{
@@ -385,22 +348,9 @@ copy_activate_cb (GtkWidget *widget,
static void
gtk_link_button_do_popup (GtkLinkButton *link_button,
- GdkEventButton *event)
+ const GdkEvent *event)
{
GtkLinkButtonPrivate *priv = link_button->priv;
- gint button;
- guint time;
-
- if (event)
- {
- button = event->button;
- time = event->time;
- }
- else
- {
- button = 0;
- time = gtk_get_current_event_time ();
- }
if (gtk_widget_get_realized (GTK_WIDGET (link_button)))
{
@@ -423,17 +373,18 @@ gtk_link_button_do_popup (GtkLinkButton *link_button,
gtk_widget_show (menu_item);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menu_item);
- if (button)
- gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
- NULL, NULL,
- button, time);
+ if (event && gdk_event_triggers_context_menu (event))
+ gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), event);
else
{
- gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
- popup_position_func, link_button,
- button, time);
- gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
- }
+ gtk_menu_popup_at_widget (GTK_MENU (priv->popup_menu),
+ GTK_WIDGET (link_button),
+ GDK_GRAVITY_SOUTH,
+ GDK_GRAVITY_NORTH_WEST,
+ event);
+
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
+ }
}
}
@@ -449,7 +400,7 @@ gtk_link_button_button_press (GtkWidget *widget,
if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
GTK_LINK_BUTTON (widget)->priv->uri != NULL)
{
- gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), event);
+ gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), (GdkEvent *) event);
return TRUE;
}
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index 1f402fab7d..347cf25b6b 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -241,189 +241,157 @@ gtk_menu_button_state_flags_changed (GtkWidget *widget,
}
static void
-menu_position_up_down_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- GtkMenuButton *menu_button)
+popup_menu (GtkMenuButton *menu_button,
+ GdkEvent *event)
{
GtkMenuButtonPrivate *priv = menu_button->priv;
- GtkWidget *widget = GTK_WIDGET (menu_button);
- GtkWidget *toplevel;
- GtkTextDirection direction;
- GdkRectangle workarea;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkWindow *window;
- GtkAllocation menu_allocation, allocation, arrow_allocation;
- GtkAlign align;
-
- /* In the common case the menu button is showing a dropdown menu, set the
- * corresponding type hint on the toplevel, so the WM can omit the top side
- * of the shadows.
- */
- if (priv->arrow_type == GTK_ARROW_DOWN)
- {
- toplevel = gtk_widget_get_toplevel (priv->menu);
- gtk_window_set_type_hint (GTK_WINDOW (toplevel), GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU);
- }
-
- align = gtk_widget_get_halign (priv->menu);
- direction = gtk_widget_get_direction (widget);
- window = gtk_widget_get_window (priv->align_widget ? priv->align_widget : widget);
-
- display = gtk_widget_get_display (GTK_WIDGET (menu));
- monitor = gdk_display_get_monitor_at_window (display, window);
- gdk_monitor_get_workarea (monitor, &workarea);
-
- gtk_widget_get_allocation (priv->align_widget ? priv->align_widget : widget, &allocation);
- gtk_widget_get_allocation (widget, &arrow_allocation);
- gtk_widget_get_allocation (priv->menu, &menu_allocation);
-
- gdk_window_get_origin (window, x, y);
- *x += allocation.x;
- *y += allocation.y;
+ GdkGravity widget_anchor = GDK_GRAVITY_SOUTH_WEST;
+ GdkGravity menu_anchor = GDK_GRAVITY_NORTH_WEST;
- /* treat the default align value like START */
- if (align == GTK_ALIGN_FILL)
- align = GTK_ALIGN_START;
+ if (priv->func)
+ priv->func (priv->user_data);
- if (align == GTK_ALIGN_CENTER)
- *x -= (menu_allocation.width - allocation.width) / 2;
- else if ((align == GTK_ALIGN_START && direction == GTK_TEXT_DIR_LTR) ||
- (align == GTK_ALIGN_END && direction == GTK_TEXT_DIR_RTL))
- *x += MAX (allocation.width - menu_allocation.width, 0);
- else if (menu_allocation.width > allocation.width)
- *x -= menu_allocation.width - allocation.width;
+ if (!priv->menu)
+ return;
- if (priv->arrow_type == GTK_ARROW_UP && *y - menu_allocation.height >= workarea.y)
- {
- *y -= menu_allocation.height;
- }
- else
+ switch (priv->arrow_type)
{
- if ((*y + arrow_allocation.height + menu_allocation.height) <= workarea.y + workarea.height)
- *y += arrow_allocation.height;
- else if ((*y - menu_allocation.height) >= workarea.y)
- *y -= menu_allocation.height;
- else if (workarea.y + workarea.height - (*y + arrow_allocation.height) > *y)
- *y += arrow_allocation.height;
- else
- *y -= menu_allocation.height;
- }
-
- *push_in = FALSE;
-}
-
-static void
-menu_position_side_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- GtkMenuButton *menu_button)
-{
- GtkMenuButtonPrivate *priv = menu_button->priv;
- GtkAllocation allocation;
- GtkAllocation menu_allocation;
- GtkWidget *widget = GTK_WIDGET (menu_button);
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle workarea;
- GdkWindow *window;
- GtkAlign align;
- GtkTextDirection direction;
-
- window = gtk_widget_get_window (widget);
-
- direction = gtk_widget_get_direction (widget);
- align = gtk_widget_get_valign (GTK_WIDGET (menu));
- display = gtk_widget_get_display (GTK_WIDGET (menu));
- monitor = gdk_display_get_monitor_at_window (display, window);
- gdk_monitor_get_workarea (monitor, &workarea);
+ case GTK_ARROW_UP:
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
- gdk_window_get_origin (gtk_button_get_event_window (GTK_BUTTON (menu_button)), x, y);
+ switch (gtk_widget_get_halign (priv->menu))
+ {
+ case GTK_ALIGN_FILL:
+ case GTK_ALIGN_START:
+ case GTK_ALIGN_BASELINE:
+ widget_anchor = GDK_GRAVITY_NORTH_WEST;
+ menu_anchor = GDK_GRAVITY_SOUTH_WEST;
+ break;
+
+ case GTK_ALIGN_END:
+ widget_anchor = GDK_GRAVITY_NORTH_EAST;
+ menu_anchor = GDK_GRAVITY_SOUTH_EAST;
+ break;
+
+ case GTK_ALIGN_CENTER:
+ widget_anchor = GDK_GRAVITY_NORTH;
+ menu_anchor = GDK_GRAVITY_SOUTH;
+ break;
+ }
- gtk_widget_get_allocation (widget, &allocation);
- gtk_widget_get_allocation (priv->menu, &menu_allocation);
+ break;
- if ((priv->arrow_type == GTK_ARROW_RIGHT && direction == GTK_TEXT_DIR_LTR) ||
- (priv->arrow_type == GTK_ARROW_LEFT && direction == GTK_TEXT_DIR_RTL))
+ case GTK_ARROW_DOWN:
+ /* In the common case the menu button is showing a dropdown menu, set the
+ * corresponding type hint on the toplevel, so the WM can omit the top side
+ * of the shadows.
+ */
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ "menu-type-hint", GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU,
+ NULL);
+
+ switch (gtk_widget_get_halign (priv->menu))
+ {
+ case GTK_ALIGN_FILL:
+ case GTK_ALIGN_START:
+ case GTK_ALIGN_BASELINE:
+ widget_anchor = GDK_GRAVITY_SOUTH_WEST;
+ menu_anchor = GDK_GRAVITY_NORTH_WEST;
+ break;
+
+ case GTK_ALIGN_END:
+ widget_anchor = GDK_GRAVITY_SOUTH_EAST;
+ menu_anchor = GDK_GRAVITY_NORTH_EAST;
+ break;
+
+ case GTK_ALIGN_CENTER:
+ widget_anchor = GDK_GRAVITY_SOUTH;
+ menu_anchor = GDK_GRAVITY_NORTH;
+ break;
+ }
- {
- if (*x + allocation.width + menu_allocation.width <= workarea.x + workarea.width)
- *x += allocation.width;
- else
- *x -= menu_allocation.width;
- }
- else
- {
- if (*x - menu_allocation.width >= workarea.x)
- *x -= menu_allocation.width;
- else
- *x += allocation.width;
- }
+ break;
- /* treat the default align value like START */
- if (align == GTK_ALIGN_FILL)
- align = GTK_ALIGN_START;
+ case GTK_ARROW_LEFT:
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_X |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
- if (align == GTK_ALIGN_CENTER)
- *y -= (menu_allocation.height - allocation.height) / 2;
- else if (align == GTK_ALIGN_END)
- *y -= menu_allocation.height - allocation.height;
+ switch (gtk_widget_get_valign (priv->menu))
+ {
+ case GTK_ALIGN_FILL:
+ case GTK_ALIGN_START:
+ case GTK_ALIGN_BASELINE:
+ widget_anchor = GDK_GRAVITY_NORTH_WEST;
+ menu_anchor = GDK_GRAVITY_NORTH_EAST;
+ break;
+
+ case GTK_ALIGN_END:
+ widget_anchor = GDK_GRAVITY_SOUTH_WEST;
+ menu_anchor = GDK_GRAVITY_SOUTH_EAST;
+ break;
+
+ case GTK_ALIGN_CENTER:
+ widget_anchor = GDK_GRAVITY_WEST;
+ menu_anchor = GDK_GRAVITY_EAST;
+ break;
+ }
- *push_in = FALSE;
-}
+ break;
-static void
-popup_menu (GtkMenuButton *menu_button,
- GdkEvent *event)
-{
- GtkMenuButtonPrivate *priv = menu_button->priv;
- GtkMenuPositionFunc func;
- GdkDevice *device;
- guint button;
- guint32 time;
+ case GTK_ARROW_RIGHT:
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_X |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
- if (priv->func)
- priv->func (priv->user_data);
+ switch (gtk_widget_get_valign (priv->menu))
+ {
+ case GTK_ALIGN_FILL:
+ case GTK_ALIGN_START:
+ case GTK_ALIGN_BASELINE:
+ widget_anchor = GDK_GRAVITY_NORTH_EAST;
+ menu_anchor = GDK_GRAVITY_NORTH_WEST;
+ break;
+
+ case GTK_ALIGN_END:
+ widget_anchor = GDK_GRAVITY_SOUTH_EAST;
+ menu_anchor = GDK_GRAVITY_SOUTH_WEST;
+ break;
+
+ case GTK_ALIGN_CENTER:
+ widget_anchor = GDK_GRAVITY_EAST;
+ menu_anchor = GDK_GRAVITY_WEST;
+ break;
+ }
- if (!priv->menu)
- return;
+ break;
- switch (priv->arrow_type)
- {
- case GTK_ARROW_LEFT:
- case GTK_ARROW_RIGHT:
- func = (GtkMenuPositionFunc) menu_position_side_func;
- break;
- default:
- func = (GtkMenuPositionFunc) menu_position_up_down_func;
- break;
- }
+ case GTK_ARROW_NONE:
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
- if (event != NULL &&
- gdk_event_get_screen (event) == gtk_widget_get_screen (GTK_WIDGET (menu_button)))
- {
- device = gdk_event_get_device (event);
- gdk_event_get_button (event, &button);
- time = gdk_event_get_time (event);
- }
- else
- {
- device = NULL;
- button = 0;
- time = gtk_get_current_event_time ();
+ break;
}
- gtk_menu_popup_for_device (GTK_MENU (priv->menu),
- device,
- NULL, NULL,
- func,
- GTK_WIDGET (menu_button),
- NULL,
- button,
- time);
+ gtk_menu_popup_at_widget (GTK_MENU (priv->menu),
+ GTK_WIDGET (menu_button),
+ widget_anchor,
+ menu_anchor,
+ event);
}
static void
diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c
index 79108069d3..17a71d4c7f 100644
--- a/gtk/gtkmenuitem.c
+++ b/gtk/gtkmenuitem.c
@@ -171,11 +171,6 @@ static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget,
static void gtk_menu_item_ensure_label (GtkMenuItem *menu_item);
static gint gtk_menu_item_popup_timeout (gpointer data);
-static void gtk_menu_item_position_menu (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data);
static void gtk_menu_item_show_all (GtkWidget *widget);
static void gtk_menu_item_forall (GtkContainer *container,
@@ -1909,19 +1904,61 @@ free_timeval (GTimeVal *val)
}
static void
-gtk_menu_item_real_popup_submenu (GtkWidget *widget,
- gboolean remember_exact_time)
+popped_up_cb (GtkMenu *menu,
+ const GdkRectangle *flipped_rect,
+ const GdkRectangle *final_rect,
+ gboolean flipped_x,
+ gboolean flipped_y,
+ GtkMenuItem *menu_item)
+{
+ GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
+ GtkMenu *parent_menu = GTK_IS_MENU (parent) ? GTK_MENU (parent) : NULL;
+
+ if (parent_menu && GTK_IS_MENU_ITEM (parent_menu->priv->parent_menu_item))
+ menu_item->priv->submenu_direction = GTK_MENU_ITEM (parent_menu->priv->parent_menu_item)->priv->submenu_direction;
+ else
+ {
+ /* this case is stateful, do it at most once */
+ g_signal_handlers_disconnect_by_func (menu, popped_up_cb, menu_item);
+ }
+
+ if (flipped_x)
+ {
+ switch (menu_item->priv->submenu_direction)
+ {
+ case GTK_DIRECTION_LEFT:
+ menu_item->priv->submenu_direction = GTK_DIRECTION_RIGHT;
+ break;
+
+ case GTK_DIRECTION_RIGHT:
+ menu_item->priv->submenu_direction = GTK_DIRECTION_LEFT;
+ break;
+ }
+ }
+}
+
+static void
+gtk_menu_item_real_popup_submenu (GtkWidget *widget,
+ const GdkEvent *trigger_event,
+ gboolean remember_exact_time)
{
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
GtkMenuItemPrivate *priv = menu_item->priv;
+ GtkSubmenuDirection submenu_direction;
+ GtkStyleContext *context;
+ GtkBorder parent_padding;
+ GtkBorder menu_padding;
+ gint horizontal_offset;
+ gint vertical_offset;
GtkWidget *parent;
+ GtkMenu *parent_menu;
parent = gtk_widget_get_parent (widget);
+ parent_menu = GTK_IS_MENU (parent) ? GTK_MENU (parent) : NULL;
if (gtk_widget_is_sensitive (priv->submenu) && parent)
{
gboolean take_focus;
- GtkMenuPositionFunc menu_position_func;
take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (parent));
gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (priv->submenu), take_focus);
@@ -1942,24 +1979,91 @@ gtk_menu_item_real_popup_submenu (GtkWidget *widget,
"gtk-menu-exact-popup-time", NULL);
}
- /* gtk_menu_item_position_menu positions the submenu from the
- * menuitems position. If the menuitem doesn't have a window,
- * that doesn't work. In that case we use the default
- * positioning function instead which places the submenu at the
- * mouse cursor.
+ /* Position the submenu at the menu item if it is mapped.
+ * Otherwise, position the submenu at the pointer device.
*/
if (gtk_widget_get_window (widget))
- menu_position_func = gtk_menu_item_position_menu;
+ {
+ switch (priv->submenu_placement)
+ {
+ case GTK_TOP_BOTTOM:
+ g_object_set (priv->submenu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ "menu-type-hint", (priv->from_menubar ?
+ GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU :
+ GDK_WINDOW_TYPE_HINT_POPUP_MENU),
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->submenu),
+ widget,
+ GDK_GRAVITY_SOUTH_WEST,
+ GDK_GRAVITY_NORTH_WEST,
+ trigger_event);
+
+ break;
+
+ case GTK_LEFT_RIGHT:
+ if (parent_menu && GTK_IS_MENU_ITEM (parent_menu->priv->parent_menu_item))
+ submenu_direction = GTK_MENU_ITEM (parent_menu->priv->parent_menu_item)->priv->submenu_direction;
+ else
+ submenu_direction = priv->submenu_direction;
+
+ g_signal_handlers_disconnect_by_func (priv->submenu, popped_up_cb, menu_item);
+ g_signal_connect (priv->submenu, "popped-up", G_CALLBACK (popped_up_cb), menu_item);
+
+ gtk_widget_style_get (priv->submenu,
+ "horizontal-offset", &horizontal_offset,
+ "vertical-offset", &vertical_offset,
+ NULL);
+
+ context = gtk_widget_get_style_context (parent);
+ gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &parent_padding);
+ context = gtk_widget_get_style_context (priv->submenu);
+ gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &menu_padding);
+
+ g_object_set (priv->submenu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_X |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ "rect-anchor-dy", vertical_offset - menu_padding.top,
+ NULL);
+
+ switch (submenu_direction)
+ {
+ case GTK_DIRECTION_RIGHT:
+ g_object_set (priv->submenu,
+ "rect-anchor-dx", horizontal_offset + parent_padding.right + menu_padding.left,
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->submenu),
+ widget,
+ GDK_GRAVITY_NORTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ trigger_event);
+
+ break;
+
+ case GTK_DIRECTION_LEFT:
+ g_object_set (priv->submenu,
+ "rect-anchor-dx", -(horizontal_offset + parent_padding.left + menu_padding.right),
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->submenu),
+ widget,
+ GDK_GRAVITY_NORTH_WEST,
+ GDK_GRAVITY_NORTH_EAST,
+ trigger_event);
+
+ break;
+ }
+
+ break;
+ }
+ }
else
- menu_position_func = NULL;
-
- gtk_menu_popup (GTK_MENU (priv->submenu),
- parent,
- widget,
- menu_position_func,
- menu_item,
- GTK_MENU_SHELL (parent)->priv->button,
- 0);
+ gtk_menu_popup_at_pointer (GTK_MENU (priv->submenu), trigger_event);
}
/* Enable themeing of the parent menu item depending on whether
@@ -1968,10 +2072,17 @@ gtk_menu_item_real_popup_submenu (GtkWidget *widget,
gtk_widget_queue_draw (widget);
}
+typedef struct
+{
+ GtkMenuItem *menu_item;
+ GdkEvent *trigger_event;
+} PopupInfo;
+
static gint
gtk_menu_item_popup_timeout (gpointer data)
{
- GtkMenuItem *menu_item = GTK_MENU_ITEM (data);
+ PopupInfo *info = data;
+ GtkMenuItem *menu_item = info->menu_item;
GtkMenuItemPrivate *priv = menu_item->priv;
GtkWidget *parent;
@@ -1980,13 +2091,19 @@ gtk_menu_item_popup_timeout (gpointer data)
if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->priv->active) ||
(GTK_IS_MENU (parent) && GTK_MENU (parent)->priv->torn_off))
{
- gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
- if (priv->timer_from_keypress && priv->submenu)
+ gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), info->trigger_event, TRUE);
+ if (info->trigger_event &&
+ info->trigger_event->type != GDK_BUTTON_PRESS &&
+ info->trigger_event->type != GDK_ENTER_NOTIFY &&
+ priv->submenu)
GTK_MENU_SHELL (priv->submenu)->priv->ignore_enter = TRUE;
}
priv->timer = 0;
+ g_clear_pointer (&info->trigger_event, gdk_event_free);
+ g_slice_free (PopupInfo, info);
+
return FALSE;
}
@@ -2022,28 +2139,21 @@ _gtk_menu_item_popup_submenu (GtkWidget *widget,
if (popup_delay > 0)
{
- GdkEvent *event = gtk_get_current_event ();
+ PopupInfo *info = g_slice_new (PopupInfo);
+
+ info->menu_item = menu_item;
+ info->trigger_event = gtk_get_current_event ();
priv->timer = gdk_threads_add_timeout (popup_delay,
gtk_menu_item_popup_timeout,
- menu_item);
+ info);
g_source_set_name_by_id (priv->timer, "[gtk+] gtk_menu_item_popup_timeout");
- if (event &&
- event->type != GDK_BUTTON_PRESS &&
- event->type != GDK_ENTER_NOTIFY)
- priv->timer_from_keypress = TRUE;
- else
- priv->timer_from_keypress = FALSE;
-
- if (event)
- gdk_event_free (event);
-
return;
}
}
- gtk_menu_item_real_popup_submenu (widget, FALSE);
+ gtk_menu_item_real_popup_submenu (widget, NULL, FALSE);
}
void
@@ -2069,176 +2179,6 @@ _gtk_menu_item_popdown_submenu (GtkWidget *widget)
}
}
-static void
-get_offsets (GtkMenu *menu,
- gint *horizontal_offset,
- gint *vertical_offset)
-{
- GtkStyleContext *context;
- GtkBorder padding;
-
- gtk_widget_style_get (GTK_WIDGET (menu),
- "horizontal-offset", horizontal_offset,
- "vertical-offset", vertical_offset,
- NULL);
-
- context = gtk_widget_get_style_context (GTK_WIDGET (menu));
- gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &padding);
-
- *vertical_offset -= padding.top;
- *horizontal_offset += padding.left;
-}
-
-static void
-gtk_menu_item_position_menu (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkMenuItem *menu_item = GTK_MENU_ITEM (user_data);
- GtkMenuItemPrivate *priv = menu_item->priv;
- GtkAllocation allocation;
- GtkWidget *widget;
- GtkMenuItem *parent_menu_item;
- GtkWidget *parent;
- GdkDisplay *display;
- gint twidth, theight;
- gint tx, ty;
- GtkTextDirection direction;
- GdkMonitor *monitor;
- GdkRectangle workarea;
- gint horizontal_offset;
- gint vertical_offset;
- gint available_left, available_right;
- GtkStyleContext *context;
- GtkBorder parent_padding;
-
- g_return_if_fail (menu != NULL);
- g_return_if_fail (x != NULL);
- g_return_if_fail (y != NULL);
-
- widget = GTK_WIDGET (user_data);
-
- if (push_in)
- *push_in = FALSE;
-
- direction = gtk_widget_get_direction (widget);
-
- twidth = gtk_widget_get_allocated_width (GTK_WIDGET (menu));
- theight = gtk_widget_get_allocated_height (GTK_WIDGET (menu));
-
- display = gtk_widget_get_display (GTK_WIDGET (menu));
- monitor = gdk_display_get_monitor_at_window (display, priv->event_window);
- gdk_monitor_get_workarea (monitor, &workarea);
-
- if (!gdk_window_get_origin (gtk_widget_get_window (widget), &tx, &ty))
- {
- g_warning ("Menu not on screen");
- return;
- }
-
- gtk_widget_get_allocation (widget, &allocation);
-
- tx += allocation.x;
- ty += allocation.y;
-
- get_offsets (menu, &horizontal_offset, &vertical_offset);
-
- available_left = tx - workarea.x;
- available_right = workarea.x + workarea.width - (tx + allocation.width);
-
- parent = gtk_widget_get_parent (widget);
- priv->from_menubar = GTK_IS_MENU_BAR (parent);
-
- switch (priv->submenu_placement)
- {
- case GTK_TOP_BOTTOM:
- if (direction == GTK_TEXT_DIR_LTR)
- priv->submenu_direction = GTK_DIRECTION_RIGHT;
- else
- {
- priv->submenu_direction = GTK_DIRECTION_LEFT;
- tx += allocation.width - twidth;
- }
- if ((ty + allocation.height + theight) <= workarea.y + workarea.height)
- ty += allocation.height;
- else if ((ty - theight) >= workarea.y)
- ty -= theight;
- else if (workarea.y + workarea.height - (ty + allocation.height) > ty)
- ty += allocation.height;
- else
- ty -= theight;
- break;
-
- case GTK_LEFT_RIGHT:
- if (GTK_IS_MENU (parent))
- parent_menu_item = GTK_MENU_ITEM (GTK_MENU (parent)->priv->parent_menu_item);
- else
- parent_menu_item = NULL;
-
- context = gtk_widget_get_style_context (parent);
- gtk_style_context_get_padding (context, gtk_style_context_get_state (context), &parent_padding);
-
- if (parent_menu_item && !GTK_MENU (parent)->priv->torn_off)
- {
- priv->submenu_direction = parent_menu_item->priv->submenu_direction;
- }
- else
- {
- if (direction == GTK_TEXT_DIR_LTR)
- priv->submenu_direction = GTK_DIRECTION_RIGHT;
- else
- priv->submenu_direction = GTK_DIRECTION_LEFT;
- }
-
- switch (priv->submenu_direction)
- {
- case GTK_DIRECTION_LEFT:
- if (tx - twidth - parent_padding.left - horizontal_offset >= workarea.x ||
- available_left >= available_right)
- tx -= twidth + parent_padding.left + horizontal_offset;
- else
- {
- priv->submenu_direction = GTK_DIRECTION_RIGHT;
- tx += allocation.width + parent_padding.right + horizontal_offset;
- }
- break;
-
- case GTK_DIRECTION_RIGHT:
- if (tx + allocation.width + parent_padding.right + horizontal_offset + twidth <= workarea.x + workarea.width ||
- available_right >= available_left)
- tx += allocation.width + parent_padding.right + horizontal_offset;
- else
- {
- priv->submenu_direction = GTK_DIRECTION_LEFT;
- tx -= twidth + parent_padding.left + horizontal_offset;
- }
- break;
- }
-
- ty += vertical_offset;
-
- /* If the height of the menu doesn't fit we move it upward. */
- ty = CLAMP (ty, workarea.y, MAX (workarea.y, workarea.y + workarea.height - theight));
- break;
- }
-
- /* If we have negative, tx, here it is because we can't get
- * the menu all the way on screen. Favor the left portion.
- */
- *x = CLAMP (tx, workarea.x, MAX (workarea.x, workarea.x + workarea.width - twidth));
- *y = ty;
-
- gtk_menu_place_on_monitor (menu, monitor);
-
- if (!gtk_widget_get_visible (menu->priv->toplevel))
- {
- gtk_window_set_type_hint (GTK_WINDOW (menu->priv->toplevel), priv->from_menubar?
- GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
- }
-}
-
/**
* gtk_menu_item_set_right_justified:
* @menu_item: a #GtkMenuItem.
diff --git a/gtk/gtkmenuitemprivate.h b/gtk/gtkmenuitemprivate.h
index 108a188b65..cb213d9edb 100644
--- a/gtk/gtkmenuitemprivate.h
+++ b/gtk/gtkmenuitemprivate.h
@@ -47,7 +47,6 @@ struct _GtkMenuItemPrivate
guint submenu_placement : 1;
guint submenu_direction : 1;
guint right_justify : 1;
- guint timer_from_keypress : 1;
guint from_menubar : 1;
guint use_action_appearance : 1;
guint reserve_indicator : 1;
diff --git a/gtk/gtkmountoperation.c b/gtk/gtkmountoperation.c
index e78a5e235a..95d856c7b2 100644
--- a/gtk/gtkmountoperation.c
+++ b/gtk/gtkmountoperation.c
@@ -1299,16 +1299,11 @@ on_end_process_activated (GtkMenuItem *item,
static gboolean
do_popup_menu_for_process_tree_view (GtkWidget *widget,
- GdkEventButton *event,
+ const GdkEvent *event,
GtkMountOperation *op)
{
GtkWidget *menu;
GtkWidget *item;
- gint button;
- gint event_time;
- gboolean popped_up_menu;
-
- popped_up_menu = FALSE;
menu = gtk_menu_new ();
gtk_style_context_add_class (gtk_widget_get_style_context (menu),
@@ -1321,14 +1316,14 @@ do_popup_menu_for_process_tree_view (GtkWidget *widget,
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show_all (menu);
- if (event != NULL)
+ if (event && gdk_event_triggers_context_menu (event))
{
GtkTreePath *path;
GtkTreeSelection *selection;
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (op->priv->process_tree_view),
- (gint) event->x,
- (gint) event->y,
+ (gint) event->button.x,
+ (gint) event->button.y,
&path,
NULL,
NULL,
@@ -1341,30 +1336,12 @@ do_popup_menu_for_process_tree_view (GtkWidget *widget,
else
{
/* don't popup a menu if the user right-clicked in an area with no rows */
- goto out;
+ return FALSE;
}
-
- button = event->button;
- event_time = event->time;
- }
- else
- {
- button = 0;
- event_time = gtk_get_current_event_time ();
}
- gtk_menu_popup (GTK_MENU (menu),
- NULL,
- widget,
- NULL,
- NULL,
- button,
- event_time);
-
- popped_up_menu = TRUE;
-
- out:
- return popped_up_menu;
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
+ return TRUE;
}
static gboolean
@@ -1387,7 +1364,7 @@ on_button_press_event_for_process_tree_view (GtkWidget *widget,
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
{
- ret = do_popup_menu_for_process_tree_view (widget, event, op);
+ ret = do_popup_menu_for_process_tree_view (widget, (GdkEvent *) event, op);
}
return ret;
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 77a8a8b6a1..4452fc64bc 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -2750,8 +2750,7 @@ gtk_notebook_button_press (GtkWidget *widget,
if (priv->menu && gdk_event_triggers_context_menu ((GdkEvent *) event))
{
- gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
- NULL, NULL, 3, event->time);
+ gtk_menu_popup_at_pointer (GTK_MENU (priv->menu), (GdkEvent *) event);
return TRUE;
}
@@ -2794,58 +2793,50 @@ gtk_notebook_button_press (GtkWidget *widget,
return TRUE;
}
-static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer data)
-{
- GtkNotebook *notebook = data;
- GtkNotebookPrivate *priv = notebook->priv;
- GtkAllocation allocation;
- GtkWidget *w;
- GtkRequisition requisition;
-
- if (priv->focus_tab)
- {
- GtkNotebookPage *page;
-
- page = priv->focus_tab->data;
- w = page->tab_label;
- }
- else
- {
- w = GTK_WIDGET (notebook);
- }
-
- gdk_window_get_origin (gtk_widget_get_window (w), x, y);
-
- gtk_widget_get_allocation (w, &allocation);
- gtk_widget_get_preferred_size (GTK_WIDGET (menu),
- &requisition, NULL);
-
- if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
- *x += allocation.x + allocation.width - requisition.width;
- else
- *x += allocation.x;
-
- *y += allocation.y + allocation.height;
-
- *push_in = FALSE;
-}
-
static gboolean
gtk_notebook_popup_menu (GtkWidget *widget)
{
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
GtkNotebookPrivate *priv = notebook->priv;
+ GtkNotebookPage *page;
+ GtkWidget *tab_label = NULL;
if (priv->menu)
{
- gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
- popup_position_func, notebook,
- 0, gtk_get_current_event_time ());
+ if (priv->focus_tab)
+ {
+ page = priv->focus_tab->data;
+ tab_label = page->tab_label;
+ }
+
+ if (tab_label)
+ {
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->menu),
+ tab_label,
+ GDK_GRAVITY_SOUTH_WEST,
+ GDK_GRAVITY_NORTH_WEST,
+ NULL);
+ }
+ else
+ {
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
+
+ gtk_menu_popup_at_widget (GTK_MENU (priv->menu),
+ widget,
+ GDK_GRAVITY_NORTH_WEST,
+ GDK_GRAVITY_NORTH_WEST,
+ NULL);
+ }
+
gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
return TRUE;
}
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index 14e44cb31a..4817c4b20a 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -1665,7 +1665,6 @@ popup_menu (GtkPlacesViewRow *row,
{
GtkPlacesViewPrivate *priv;
GtkWidget *view;
- gint button;
view = gtk_widget_get_ancestor (GTK_WIDGET (row), GTK_TYPE_PLACES_VIEW);
priv = gtk_places_view_get_instance_private (GTK_PLACES_VIEW (view));
@@ -1674,30 +1673,7 @@ popup_menu (GtkPlacesViewRow *row,
build_popup_menu (GTK_PLACES_VIEW (view), row);
- /* The event button needs to be 0 if we're popping up this menu from
- * a button release, else a 2nd click outside the menu with any button
- * other than the one that invoked the menu will be ignored (instead
- * of dismissing the menu). This is a subtle fragility of the GTK menu code.
- */
- if (event)
- {
- if (event->type == GDK_BUTTON_PRESS)
- button = 0;
- else
- button = event->button;
- }
- else
- {
- button = 0;
- }
-
- gtk_menu_popup (GTK_MENU (priv->popup_menu),
- NULL,
- NULL,
- NULL,
- NULL,
- button,
- event ? event->time : gtk_get_current_event_time ());
+ gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), (GdkEvent *) event);
}
static gboolean
diff --git a/gtk/gtkrecentchooserdefault.c b/gtk/gtkrecentchooserdefault.c
index d1e9672328..2a9cee9a84 100644
--- a/gtk/gtkrecentchooserdefault.c
+++ b/gtk/gtkrecentchooserdefault.c
@@ -1727,62 +1727,23 @@ recent_view_menu_build (GtkRecentChooserDefault *impl)
recent_view_menu_ensure_state (impl);
}
-/* taken from gtkfilechooserdefault.c */
-static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkAllocation allocation;
- GtkWidget *widget = GTK_WIDGET (user_data);
- GtkRequisition req;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle workarea;
-
- if (G_UNLIKELY (!gtk_widget_get_realized (widget)))
- return;
-
- gdk_window_get_origin (gtk_widget_get_window (widget), x, y);
-
- gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
-
- gtk_widget_get_allocation (widget, &allocation);
- *x += (allocation.width - req.width) / 2;
- *y += (allocation.height - req.height) / 2;
-
- display = gtk_widget_get_display (widget);
- monitor = gdk_display_get_monitor_at_point (display, *x, *y);
- gtk_menu_place_on_monitor (menu, monitor);
- gdk_monitor_get_workarea (monitor, &workarea);
-
- *x = CLAMP (*x, workarea.x, workarea.x + MAX (0, workarea.width - req.width));
- *y = CLAMP (*y, workarea.y, workarea.y + MAX (0, workarea.height - req.height));
-
- *push_in = FALSE;
-}
-
-
static void
recent_view_menu_popup (GtkRecentChooserDefault *impl,
GdkEventButton *event)
{
recent_view_menu_build (impl);
- if (event)
- gtk_menu_popup (GTK_MENU (impl->priv->recent_popup_menu),
- NULL, NULL, NULL, NULL,
- event->button, event->time);
+ if (event && gdk_event_triggers_context_menu ((GdkEvent *) event))
+ gtk_menu_popup_at_pointer (GTK_MENU (impl->priv->recent_popup_menu), (GdkEvent *) event);
else
{
- gtk_menu_popup (GTK_MENU (impl->priv->recent_popup_menu),
- NULL, NULL,
- popup_position_func, impl->priv->recent_view,
- 0, GDK_CURRENT_TIME);
- gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->priv->recent_popup_menu),
- FALSE);
+ gtk_menu_popup_at_widget (GTK_MENU (impl->priv->recent_popup_menu),
+ impl->priv->recent_view,
+ GDK_GRAVITY_CENTER,
+ GDK_GRAVITY_CENTER,
+ (GdkEvent *) event);
+
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->priv->recent_popup_menu), FALSE);
}
}
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index bcb0f0d1c8..37b9cdf5ef 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -9347,91 +9347,10 @@ popup_menu_detach (GtkWidget *attach_widget,
GTK_TEXT_VIEW (attach_widget)->priv->popup_menu = NULL;
}
-static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
- GtkAllocation allocation;
- GtkTextView *text_view;
- GtkWidget *widget;
- GdkRectangle cursor_rect;
- GdkRectangle onscreen_rect;
- gint root_x, root_y;
- GtkTextIter iter;
- GtkRequisition req;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle workarea;
-
- text_view = GTK_TEXT_VIEW (user_data);
- widget = GTK_WIDGET (text_view);
-
- g_return_if_fail (gtk_widget_get_realized (widget));
-
- display = gtk_widget_get_display (widget);
-
- gdk_window_get_origin (gtk_widget_get_window (widget),
- &root_x, &root_y);
-
- gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
- &iter,
- gtk_text_buffer_get_insert (get_buffer (text_view)));
-
- gtk_text_view_get_iter_location (text_view,
- &iter,
- &cursor_rect);
-
- gtk_text_view_get_visible_rect (text_view, &onscreen_rect);
-
- gtk_widget_get_preferred_size (text_view->priv->popup_menu,
- &req, NULL);
-
- gtk_widget_get_allocation (widget, &allocation);
-
- /* can't use rectangle_intersect since cursor rect can have 0 width */
- if (cursor_rect.x >= onscreen_rect.x &&
- cursor_rect.x < onscreen_rect.x + onscreen_rect.width &&
- cursor_rect.y >= onscreen_rect.y &&
- cursor_rect.y < onscreen_rect.y + onscreen_rect.height)
- {
- gtk_text_view_buffer_to_window_coords (text_view,
- GTK_TEXT_WINDOW_WIDGET,
- cursor_rect.x, cursor_rect.y,
- &cursor_rect.x, &cursor_rect.y);
-
- *x = root_x + cursor_rect.x + cursor_rect.width;
- *y = root_y + cursor_rect.y + cursor_rect.height;
- }
- else
- {
- /* Just center the menu, since cursor is offscreen. */
- *x = root_x + (allocation.width / 2 - req.width / 2);
- *y = root_y + (allocation.height / 2 - req.height / 2);
- }
-
- /* Ensure sanity */
- *x = CLAMP (*x, root_x, (root_x + allocation.width));
- *y = CLAMP (*y, root_y, (root_y + allocation.height));
-
- monitor = gdk_display_get_monitor_at_point (display, *x, *y);
- gtk_menu_place_on_monitor (menu, monitor);
- gdk_monitor_get_workarea (monitor, &workarea);
-
- *x = CLAMP (*x, workarea.x, workarea.x + MAX (0, workarea.width - req.width));
- *y = CLAMP (*y, workarea.y, workarea.y + MAX (0, workarea.height - req.height));
-
- *push_in = FALSE;
-}
-
typedef struct
{
GtkTextView *text_view;
- guint button;
- guint time;
- GdkDevice *device;
+ GdkEvent *trigger_event;
} PopupInfo;
static gboolean
@@ -9475,6 +9394,9 @@ popup_targets_received (GtkClipboard *clipboard,
gboolean can_insert;
GtkTextIter iter;
GtkTextIter sel_start, sel_end;
+ GdkRectangle iter_location;
+ GdkRectangle visible_rect;
+ gboolean is_visible;
clipboard_contains_text = gtk_selection_data_targets_include_text (data);
@@ -9532,19 +9454,46 @@ popup_targets_received (GtkClipboard *clipboard,
g_signal_emit (text_view, signals[POPULATE_POPUP],
0, priv->popup_menu);
- if (info->device)
- gtk_menu_popup_for_device (GTK_MENU (priv->popup_menu),
- info->device, NULL, NULL, NULL, NULL, NULL,
- info->button, info->time);
+ if (info->trigger_event && gdk_event_triggers_context_menu (info->trigger_event))
+ gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), info->trigger_event);
else
- {
- gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
- popup_position_func, text_view,
- 0, gtk_get_current_event_time ());
- gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
- }
+ {
+ gtk_text_view_get_iter_location (text_view, &iter, &iter_location);
+ gtk_text_view_get_visible_rect (text_view, &visible_rect);
+
+ is_visible = (iter_location.x + iter_location.width > visible_rect.x &&
+ iter_location.x < visible_rect.x + visible_rect.width &&
+ iter_location.y + iter_location.height > visible_rect.y &&
+ iter_location.y < visible_rect.y + visible_rect.height);
+
+ if (is_visible)
+ {
+ gtk_text_view_buffer_to_window_coords (text_view,
+ GTK_TEXT_WINDOW_WIDGET,
+ iter_location.x,
+ iter_location.y,
+ &iter_location.x,
+ &iter_location.y);
+
+ gtk_menu_popup_at_rect (GTK_MENU (priv->popup_menu),
+ gtk_widget_get_window (GTK_WIDGET (text_view)),
+ &iter_location,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ info->trigger_event);
+ }
+ else
+ gtk_menu_popup_at_widget (GTK_MENU (priv->popup_menu),
+ GTK_WIDGET (text_view),
+ GDK_GRAVITY_CENTER,
+ GDK_GRAVITY_CENTER,
+ info->trigger_event);
+
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
+ }
}
+ g_clear_pointer (&info->trigger_event, gdk_event_free);
g_object_unref (text_view);
g_slice_free (PopupInfo, info);
}
@@ -9560,19 +9509,7 @@ gtk_text_view_do_popup (GtkTextView *text_view,
* we get them, then we actually pop up the menu.
*/
info->text_view = g_object_ref (text_view);
-
- if (event)
- {
- gdk_event_get_button (event, &info->button);
- info->time = gdk_event_get_time (event);
- info->device = gdk_event_get_device (event);
- }
- else
- {
- info->button = 0;
- info->time = gtk_get_current_event_time ();
- info->device = NULL;
- }
+ info->trigger_event = event ? gdk_event_copy (event) : gtk_get_current_event ();
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (text_view),
GDK_SELECTION_CLIPBOARD),
diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c
index d77fef3073..80efa51320 100644
--- a/gtk/gtktoolbar.c
+++ b/gtk/gtktoolbar.c
@@ -2618,79 +2618,52 @@ gtk_toolbar_real_style_changed (GtkToolbar *toolbar,
}
static void
-menu_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
+show_menu (GtkToolbar *toolbar,
+ GdkEventButton *event)
{
- GtkAllocation allocation;
- GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
GtkToolbarPrivate *priv = toolbar->priv;
- GtkRequisition req;
- GtkRequisition menu_req;
- GdkRectangle workarea;
- GdkMonitor *monitor;
- GdkDisplay *display;
+ GtkRequisition minimum_size;
- gtk_widget_get_preferred_size (priv->arrow_button,
- &req, NULL);
- gtk_widget_get_preferred_size (GTK_WIDGET (menu),
- &menu_req, NULL);
-
- display = gtk_widget_get_display (GTK_WIDGET (menu));
- monitor = gdk_display_get_monitor_at_window (display,
- gtk_widget_get_window (priv->arrow_button));
- gdk_monitor_get_workarea (monitor, &workarea);
+ rebuild_menu (toolbar);
- gtk_widget_get_allocation (priv->arrow_button, &allocation);
+ gtk_widget_show_all (GTK_WIDGET (priv->menu));
- gdk_window_get_origin (gtk_button_get_event_window (GTK_BUTTON (priv->arrow_button)), x, y);
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
- *x += allocation.width - req.width;
- else
- *x += req.width - menu_req.width;
-
- if ((*y + allocation.height + menu_req.height) <= workarea.y + workarea.height)
- *y += allocation.height;
- else if ((*y - menu_req.height) >= workarea.y)
- *y -= menu_req.height;
- else if (workarea.y + workarea.height - (*y + allocation.height) > *y)
- *y += allocation.height;
- else
- *y -= menu_req.height;
- }
- else
+ switch (priv->orientation)
{
- if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
- *x += allocation.width;
- else
- *x -= menu_req.width;
+ case GTK_ORIENTATION_HORIZONTAL:
+ gtk_widget_get_preferred_size (priv->arrow_button, &minimum_size, NULL);
- if (*y + menu_req.height > workarea.y + workarea.height &&
- *y + allocation.height - workarea.y > workarea.y + workarea.height - *y)
- *y += allocation.height - menu_req.height;
- }
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_Y |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ "menu-type-hint", GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU,
+ "rect-anchor-dx", -minimum_size.width,
+ NULL);
- *push_in = FALSE;
-}
+ gtk_menu_popup_at_widget (priv->menu,
+ priv->arrow_button,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ (GdkEvent *) event);
-static void
-show_menu (GtkToolbar *toolbar,
- GdkEventButton *event)
-{
- GtkToolbarPrivate *priv = toolbar->priv;
+ break;
- rebuild_menu (toolbar);
+ case GTK_ORIENTATION_VERTICAL:
+ g_object_set (priv->menu,
+ "anchor-hints", (GDK_ANCHOR_FLIP_X |
+ GDK_ANCHOR_SLIDE |
+ GDK_ANCHOR_RESIZE),
+ NULL);
- gtk_widget_show_all (GTK_WIDGET (priv->menu));
+ gtk_menu_popup_at_widget (priv->menu,
+ priv->arrow_button,
+ GDK_GRAVITY_NORTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ (GdkEvent *) event);
- gtk_menu_popup (priv->menu, NULL, NULL,
- menu_position_func, toolbar,
- event? event->button : 0,
- event? event->time : gtk_get_current_event_time());
+ break;
+ }
}
static void
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 8a115d3eac..42374993aa 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -8843,15 +8843,6 @@ popup_menu_detach (GtkWidget *widget,
GTK_WINDOW (widget)->priv->popup_menu = NULL;
}
-static void
-popup_position_func (GtkMenu *menu,
- gint *x,
- gint *y,
- gboolean *push_in,
- gpointer user_data)
-{
-}
-
static GdkWindowState
gtk_window_get_state (GtkWindow *window)
{
@@ -9064,17 +9055,7 @@ gtk_window_do_popup_fallback (GtkWindow *window,
g_signal_connect (G_OBJECT (menuitem), "activate",
G_CALLBACK (close_window_clicked), window);
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- if (event)
- gtk_menu_popup (GTK_MENU (priv->popup_menu),
- NULL, NULL,
- NULL, NULL,
- event->button, event->time);
- else
- gtk_menu_popup (GTK_MENU (priv->popup_menu),
- NULL, NULL,
- popup_position_func, window,
- 0, gtk_get_current_event_time ());
+ gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), (GdkEvent *) event);
}
static void