From 8701e34f749cf196c9726c01c03f35ce4eb39836 Mon Sep 17 00:00:00 2001 From: William Hua Date: Tue, 12 Jul 2016 14:08:36 -0400 Subject: [PATCH] port to new gtk_menu_popup_at_* () functions https://bugzilla.gnome.org/show_bug.cgi?id=756579 --- demos/gtk-demo/clipboard.c | 2 +- demos/gtk-demo/main.c | 2 +- demos/gtk-demo/search_entry.c | 3 +- gtk/deprecated/gtkcolorsel.c | 53 ++--- gtk/gtkappchooserwidget.c | 3 +- gtk/gtkcombobox.c | 285 ++++++++------------------- gtk/gtkentry.c | 88 ++------- gtk/gtklabel.c | 65 ++---- gtk/gtklinkbutton.c | 73 ++----- gtk/gtkmenubutton.c | 302 +++++++++++++--------------- gtk/gtkmenuitem.c | 358 ++++++++++++++-------------------- gtk/gtkmenuitemprivate.h | 1 - gtk/gtkmountoperation.c | 39 +--- gtk/gtknotebook.c | 83 ++++---- gtk/gtkplacesview.c | 26 +-- gtk/gtkrecentchooserdefault.c | 57 +----- gtk/gtktextview.c | 147 ++++---------- gtk/gtktoolbar.c | 101 ++++------ gtk/gtkwindow.c | 21 +- 19 files changed, 560 insertions(+), 1149 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 @@ -1422,40 +1422,6 @@ palette_set_color (GtkWidget *drawing_area, I_("color_val"), new_color, (GDestroyNotify)g_free); } -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); @@ -1921,187 +1906,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, @@ -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)) @@ -6544,48 +6544,6 @@ popup_menu_detach (GtkWidget *attach_widget, priv->select_info->popup_menu = NULL; } -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 @@ -335,43 +335,6 @@ popup_menu_detach (GtkWidget *attach_widget, link_button->priv->popup_menu = NULL; } -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 @@ -240,150 +240,13 @@ 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) -{ - 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; - - /* treat the default align value like START */ - if (align == GTK_ALIGN_FILL) - align = GTK_ALIGN_START; - - 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->arrow_type == GTK_ARROW_UP && *y - menu_allocation.height >= workarea.y) - { - *y -= menu_allocation.height; - } - else - { - 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); - - gdk_window_get_origin (gtk_button_get_event_window (GTK_BUTTON (menu_button)), x, y); - - gtk_widget_get_allocation (widget, &allocation); - gtk_widget_get_allocation (priv->menu, &menu_allocation); - - if ((priv->arrow_type == GTK_ARROW_RIGHT && direction == GTK_TEXT_DIR_LTR) || - (priv->arrow_type == GTK_ARROW_LEFT && direction == GTK_TEXT_DIR_RTL)) - - { - 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; - } - - /* treat the default align value like START */ - if (align == GTK_ALIGN_FILL) - align = GTK_ALIGN_START; - - if (align == GTK_ALIGN_CENTER) - *y -= (menu_allocation.height - allocation.height) / 2; - else if (align == GTK_ALIGN_END) - *y -= menu_allocation.height - allocation.height; - - *push_in = FALSE; -} - static void popup_menu (GtkMenuButton *menu_button, GdkEvent *event) { GtkMenuButtonPrivate *priv = menu_button->priv; - GtkMenuPositionFunc func; - GdkDevice *device; - guint button; - guint32 time; + GdkGravity widget_anchor = GDK_GRAVITY_SOUTH_WEST; + GdkGravity menu_anchor = GDK_GRAVITY_NORTH_WEST; if (priv->func) priv->func (priv->user_data); @@ -393,37 +256,142 @@ popup_menu (GtkMenuButton *menu_button, 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_UP: + 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 (); + 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; + } + + break; + + 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; + } + + break; + + case GTK_ARROW_LEFT: + g_object_set (priv->menu, + "anchor-hints", (GDK_ANCHOR_FLIP_X | + GDK_ANCHOR_SLIDE | + GDK_ANCHOR_RESIZE), + NULL); + + 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; + } + + break; + + case GTK_ARROW_RIGHT: + g_object_set (priv->menu, + "anchor-hints", (GDK_ANCHOR_FLIP_X | + GDK_ANCHOR_SLIDE | + GDK_ANCHOR_RESIZE), + NULL); + + 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; + } + + break; + + case GTK_ARROW_NONE: + g_object_set (priv->menu, + "anchor-hints", (GDK_ANCHOR_FLIP_Y | + GDK_ANCHOR_SLIDE | + GDK_ANCHOR_RESIZE), + NULL); + + 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; - else - menu_position_func = NULL; + { + 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 (GTK_MENU (priv->submenu), - parent, - widget, - menu_position_func, - menu_item, - GTK_MENU_SHELL (parent)->priv->button, - 0); + 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 + 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 @@ -2617,80 +2617,53 @@ gtk_toolbar_real_style_changed (GtkToolbar *toolbar, } } -static void -menu_position_func (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) -{ - GtkAllocation allocation; - GtkToolbar *toolbar = GTK_TOOLBAR (user_data); - GtkToolbarPrivate *priv = toolbar->priv; - GtkRequisition req; - GtkRequisition menu_req; - GdkRectangle workarea; - GdkMonitor *monitor; - GdkDisplay *display; - - 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); - - gtk_widget_get_allocation (priv->arrow_button, &allocation); - - 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 - { - if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) - *x += allocation.width; - else - *x -= menu_req.width; - - 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; - } - - *push_in = FALSE; -} - static void show_menu (GtkToolbar *toolbar, GdkEventButton *event) { GtkToolbarPrivate *priv = toolbar->priv; + GtkRequisition minimum_size; rebuild_menu (toolbar); gtk_widget_show_all (GTK_WIDGET (priv->menu)); - gtk_menu_popup (priv->menu, NULL, NULL, - menu_position_func, toolbar, - event? event->button : 0, - event? event->time : gtk_get_current_event_time()); + switch (priv->orientation) + { + case GTK_ORIENTATION_HORIZONTAL: + gtk_widget_get_preferred_size (priv->arrow_button, &minimum_size, NULL); + + 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); + + gtk_menu_popup_at_widget (priv->menu, + priv->arrow_button, + GDK_GRAVITY_SOUTH_EAST, + GDK_GRAVITY_NORTH_WEST, + (GdkEvent *) event); + + break; + + case GTK_ORIENTATION_VERTICAL: + g_object_set (priv->menu, + "anchor-hints", (GDK_ANCHOR_FLIP_X | + GDK_ANCHOR_SLIDE | + GDK_ANCHOR_RESIZE), + NULL); + + gtk_menu_popup_at_widget (priv->menu, + priv->arrow_button, + GDK_GRAVITY_NORTH_EAST, + GDK_GRAVITY_NORTH_WEST, + (GdkEvent *) event); + + 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