port to new gtk_menu_popup_at_* () functions

https://bugzilla.gnome.org/show_bug.cgi?id=756579
This commit is contained in:
William Hua 2016-07-12 14:08:36 -04:00
parent 05b9bc5cff
commit 8701e34f74
19 changed files with 560 additions and 1149 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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"),

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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),

View File

@ -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

View File

@ -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