diff options
author | William Hua <william.hua@canonical.com> | 2015-09-20 14:45:24 -0400 |
---|---|---|
committer | William Hua <william.hua@canonical.com> | 2016-01-06 10:37:41 -0500 |
commit | 7024004c2385d736902b35a2257bde68194559b9 (patch) | |
tree | 36e4af7132b6a864e8619dc771c3efc558f3cb24 | |
parent | 8f0d343cffa78af97af6a5784dcda232a8cf9f73 (diff) | |
download | gtk+-7024004c2385d736902b35a2257bde68194559b9.tar.gz |
gtkmenuitem: use gtk_menu_popup_with_params ()
-rw-r--r-- | gtk/gtkmenuitem.c | 322 |
1 files changed, 123 insertions, 199 deletions
diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index c931e5290c..e435034a9f 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, @@ -1906,21 +1901,49 @@ free_timeval (GTimeVal *val) } static void +get_offsets (GtkMenu *menu, + gint *horizontal_offset, + gint *vertical_offset) +{ + GtkStyleContext *context; + GtkStateFlags state; + 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)); + state = gtk_widget_get_state_flags (GTK_WIDGET (menu)); + gtk_style_context_get_padding (context, state, &padding); + + *vertical_offset -= padding.top; + *horizontal_offset += padding.left; +} + +static void gtk_menu_item_real_popup_submenu (GtkWidget *widget, gboolean remember_exact_time) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); GtkMenuItemPrivate *priv = menu_item->priv; - GtkWidget *parent; - - parent = gtk_widget_get_parent (widget); + GtkWidget *parent = gtk_widget_get_parent (widget); + GdkWindowTypeHint type_hint = GDK_WINDOW_TYPE_HINT_POPUP_MENU; + GdkAttachParams *params; + GtkMenu *parent_menu; + GtkMenuItem *parent_menu_item; + GtkStyleContext *parent_context; + GtkStateFlags parent_flags; + GtkBorder parent_padding; + GdkBorder attach_margin; + gint horizontal_offset; + gint vertical_offset; if (gtk_widget_is_sensitive (priv->submenu) && parent) { - gboolean take_focus; - GtkMenuPositionFunc menu_position_func; + gboolean take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (parent)); - 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); if (remember_exact_time) @@ -1939,24 +1962,97 @@ 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. - */ + /* Attach to the menu item if it has a window. + * Otherwise, attach to the pointer device. */ + if (gtk_widget_get_window (widget)) - menu_position_func = gtk_menu_item_position_menu; + { + params = gtk_menu_create_params (GTK_MENU (priv->submenu)); + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + menu_item->priv->submenu_direction = GTK_DIRECTION_LEFT; + else + menu_item->priv->submenu_direction = GTK_DIRECTION_RIGHT; + + if (GTK_IS_MENU (parent)) + { + parent_menu = GTK_MENU (parent); + parent_menu_item = GTK_MENU_ITEM (parent_menu->priv->parent_menu_item); + + if (parent_menu_item && !parent_menu->priv->torn_off) + menu_item->priv->submenu_direction = parent_menu_item->priv->submenu_direction; + } + + switch (priv->submenu_placement) + { + case GTK_TOP_BOTTOM: + gdk_attach_params_add_primary_rules (params, + GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MIN, + GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MAX, + NULL); + + gdk_attach_params_add_secondary_rules (params, + GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MIN, + GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MAX, + NULL); + + break; + + case GTK_LEFT_RIGHT: + parent_context = gtk_widget_get_style_context (parent); + parent_flags = gtk_widget_get_state_flags (parent); + gtk_style_context_get_padding (parent_context, parent_flags, &parent_padding); + get_offsets (GTK_MENU (priv->submenu), &horizontal_offset, &vertical_offset); + + attach_margin.top = parent_padding.top + vertical_offset; + attach_margin.left = parent_padding.left + horizontal_offset; + attach_margin.right = parent_padding.right + horizontal_offset; + attach_margin.bottom = parent_padding.bottom + vertical_offset; + + gdk_attach_params_set_attach_margin (params, &attach_margin); + + if (menu_item->priv->submenu_direction == GTK_DIRECTION_LEFT) + gdk_attach_params_add_primary_rules (params, + GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MAX, + GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MIN, + NULL); + else + gdk_attach_params_add_primary_rules (params, + GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MIN, + GDK_ATTACH_AXIS_X | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MAX, + NULL); + + gdk_attach_params_add_secondary_rules (params, + GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MIN | GDK_ATTACH_WINDOW_MIN, + GDK_ATTACH_AXIS_Y | GDK_ATTACH_RECT_MAX | GDK_ATTACH_WINDOW_MAX, + NULL); + + break; + } + + if (GTK_IS_MENU_BAR (parent)) + type_hint = GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU; + + gtk_menu_popup_with_params (GTK_MENU (priv->submenu), + NULL, + parent, + widget, + GTK_MENU_SHELL (parent)->priv->button, + 0, + FALSE, + type_hint, + params); + } else - menu_position_func = NULL; - - gtk_menu_popup (GTK_MENU (priv->submenu), - parent, - widget, - menu_position_func, - menu_item, - GTK_MENU_SHELL (parent)->priv->button, - 0); + gtk_menu_popup_with_params (GTK_MENU (priv->submenu), + NULL, + parent, + NULL, + GTK_MENU_SHELL (parent)->priv->button, + 0, + TRUE, + type_hint, + NULL); } /* Enable themeing of the parent menu item depending on whether @@ -2066,178 +2162,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; - GdkScreen *screen; - gint twidth, theight; - gint tx, ty; - GtkTextDirection direction; - GdkRectangle monitor; - gint monitor_num; - 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)); - - screen = gtk_widget_get_screen (GTK_WIDGET (menu)); - monitor_num = gdk_screen_get_monitor_at_window (screen, priv->event_window); - if (monitor_num < 0) - monitor_num = 0; - gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); - - 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 - monitor.x; - available_right = monitor.x + monitor.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) <= monitor.y + monitor.height) - ty += allocation.height; - else if ((ty - theight) >= monitor.y) - ty -= theight; - else if (monitor.y + monitor.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 >= monitor.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 <= monitor.x + monitor.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, monitor.y, MAX (monitor.y, monitor.y + monitor.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, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth)); - *y = ty; - - gtk_menu_set_monitor (menu, monitor_num); - - 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. |