X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmenu.c;h=79bde09ab0686f4fd643d437724058a47320fe66;hb=1247a842a228980a06893e6167ae8c73a4bb6eed;hp=5cf965b12c55ec0d3e3238147d344c236e3c5b7c;hpb=a1ce49c30eac1749d42f3dd11d4dba9250ac60c9;p=~andy%2Fgtk diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 5cf965b12..79bde09ab 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -37,7 +35,7 @@ * #GtkMenuItem in a #GtkMenuBar or popped up by activating a * #GtkMenuItem in another #GtkMenu. * - * A #GtkMenu can also be popped up by activating a #GtkOptionMenu. + * A #GtkMenu can also be popped up by activating a #GtkComboBox. * Other composite widgets such as the #GtkNotebook can pop up a * #GtkMenu as well. * @@ -75,7 +73,7 @@ * if (event->type == GDK_BUTTON_PRESS) * { * event_button = (GdkEventButton *) event; - * if (event_button->button == 3) + * if (event_button->button == GDK_BUTTON_SECONDARY) * { * gtk_menu_popup (menu, NULL, NULL, NULL, NULL, * event_button->button, event_button->time); @@ -97,6 +95,7 @@ #include "gtkaccellabel.h" #include "gtkaccelmap.h" +#include "gtkadjustment.h" #include "gtkbindings.h" #include "gtkcheckmenuitem.h" #include "gtkmain.h" @@ -104,15 +103,22 @@ #include "gtkmenuprivate.h" #include "gtkmenuitemprivate.h" #include "gtkmenushellprivate.h" -#include "gtktearoffmenuitem.h" #include "gtkwindow.h" -#include "gtkhbox.h" +#include "gtkbox.h" #include "gtkscrollbar.h" #include "gtksettings.h" #include "gtkprivate.h" +#include "gtkwidgetpath.h" #include "gtkwidgetprivate.h" +#include "gtkdnd.h" #include "gtkintl.h" #include "gtktypebuiltins.h" +#include "gtkwidgetprivate.h" + +#include "deprecated/gtktearoffmenuitem.h" + + +#include "a11y/gtkmenuaccessible.h" #define NAVIGATION_REGION_OVERSHOOT 50 /* How much the navigation region * extends below the submenu @@ -136,46 +142,6 @@ struct _GtkMenuAttachData GtkMenuDetachFunc detacher; }; -struct _OldGtkMenuPrivate -{ - gint x; - gint y; - gboolean initially_pushed_in; - - GDestroyNotify position_func_data_destroy; - - /* info used for the table */ - guint *heights; - gint heights_length; - gint requested_height; - - gint monitor_num; - - /* Cached layout information */ - gint n_rows; - gint n_columns; - - guint accel_size; - - gchar *title; - - /* Arrow states */ - GtkStateFlags lower_arrow_state; - GtkStateFlags upper_arrow_state; - - /* navigation region */ - int navigation_x; - int navigation_y; - int navigation_width; - int navigation_height; - - guint have_layout : 1; - guint seen_item_enter : 1; - guint have_position : 1; - guint ignore_button_release : 1; - guint no_toggle_size : 1; -}; - struct _GtkMenuPopdownData { GtkMenu *menu; @@ -263,12 +229,13 @@ static void gtk_menu_scroll_to (GtkMenu *menu, gint offset); static void gtk_menu_grab_notify (GtkWidget *widget, gboolean was_grabbed); +static gboolean gtk_menu_captured_event (GtkWidget *widget, + GdkEvent *event); + static void gtk_menu_stop_scrolling (GtkMenu *menu); static void gtk_menu_remove_scroll_timeout (GtkMenu *menu); static gboolean gtk_menu_scroll_timeout (gpointer data); -static gboolean gtk_menu_scroll_timeout_initial (gpointer data); -static void gtk_menu_start_scrolling (GtkMenu *menu); static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell, GtkWidget *menu_item); @@ -674,15 +641,6 @@ gtk_menu_class_init (GtkMenuClass *class) -1, G_MAXINT, -1, GTK_PARAM_READWRITE)); - gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("vertical-padding", - P_("Vertical Padding"), - P_("Extra space at the top and bottom of the menu"), - 0, - G_MAXINT, - 1, - GTK_PARAM_READABLE)); - /** * GtkMenu:reserve-toggle-size: * @@ -704,6 +662,15 @@ gtk_menu_class_init (GtkMenuClass *class) TRUE, GTK_PARAM_READWRITE)); + /** + * GtkMenu:horizontal-padding: + * + * Extra space at the left and right edges of the menu. + * + * Deprecated: 3.8: use the standard padding CSS property (through objects + * like #GtkStyleContext and #GtkCssProvider); the value of this style + * property is ignored. + */ gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("horizontal-padding", P_("Horizontal Padding"), @@ -711,7 +678,27 @@ gtk_menu_class_init (GtkMenuClass *class) 0, G_MAXINT, 0, - GTK_PARAM_READABLE)); + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); + + /** + * GtkMenu:vertical-padding: + * + * Extra space at the top and bottom of the menu. + * + * Deprecated: 3.8: use the standard padding CSS property (through objects + * like #GtkStyleContext and #GtkCssProvider); the value of this style + * property is ignored. + */ + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("vertical-padding", + P_("Vertical Padding"), + P_("Extra space at the top and bottom of the menu"), + 0, + G_MAXINT, + 1, + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("vertical-offset", @@ -786,7 +773,7 @@ gtk_menu_class_init (GtkMenuClass *class) GTK_PARAM_READWRITE)); /** - * GtkMenu:arrow-scaling + * GtkMenu:arrow-scaling: * * Arbitrary constant to scale down the size of the scroll arrow. * @@ -882,6 +869,8 @@ gtk_menu_class_init (GtkMenuClass *class) GTK_SCROLL_PAGE_DOWN); g_type_class_add_private (gobject_class, sizeof (GtkMenuPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_MENU_ACCESSIBLE); } @@ -1054,6 +1043,15 @@ gtk_menu_window_event (GtkWidget *window, case GDK_KEY_RELEASE: handled = gtk_widget_event (menu, event); break; + case GDK_WINDOW_STATE: + /* Window for the menu has been closed by the display server or by GDK. + * Update the internal state as if the user had clicked outside the + * menu + */ + if (event->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN && + event->window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN) + gtk_menu_shell_deactivate (GTK_MENU_SHELL(menu)); + break; default: break; } @@ -1091,9 +1089,12 @@ gtk_menu_init (GtkMenu *menu) priv->needs_destruction_ref = TRUE; priv->monitor_num = -1; + priv->drag_start_y = -1; context = gtk_widget_get_style_context (GTK_WIDGET (menu)); gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU); + + _gtk_widget_set_captured_event_handler (GTK_WIDGET (menu), gtk_menu_captured_event); } static void @@ -1233,12 +1234,10 @@ gtk_menu_attach_to_widget (GtkMenu *menu, g_object_set_data_full (G_OBJECT (attach_widget), I_(ATTACHED_MENUS), list, (GDestroyNotify) g_list_free); - if (gtk_widget_get_state_flags (GTK_WIDGET (menu)) != 0) - gtk_widget_set_state_flags (GTK_WIDGET (menu), 0, TRUE); + /* Attach the widget to the toplevel window. */ + gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), attach_widget); - /* we don't need to set the style here, since - * we are a toplevel widget. - */ + _gtk_widget_update_parent_muxer (GTK_WIDGET (menu)); /* Fallback title for menu comes from attach widget */ gtk_menu_update_title (menu); @@ -1292,6 +1291,9 @@ gtk_menu_detach (GtkMenu *menu) } g_object_set_data (G_OBJECT (menu), I_(attach_data_key), NULL); + /* Detach the toplevel window. */ + gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), NULL); + g_signal_handlers_disconnect_by_func (data->attach_widget, (gpointer) attach_widget_screen_changed, menu); @@ -1311,9 +1313,12 @@ gtk_menu_detach (GtkMenu *menu) g_slice_free (GtkMenuAttachData, data); + _gtk_widget_update_parent_muxer (GTK_WIDGET (menu)); + /* Fallback title for menu comes from attach widget */ gtk_menu_update_title (menu); + g_object_notify (G_OBJECT (menu), "attach-widget"); g_object_unref (menu); } @@ -1426,6 +1431,7 @@ popup_grab_on_window (GdkWindow *window, if (pointer && gdk_device_grab (pointer, window, GDK_OWNERSHIP_WINDOW, TRUE, + GDK_SMOOTH_SCROLL_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK, @@ -1496,7 +1502,7 @@ gtk_menu_popup_for_device (GtkMenu *menu, GtkMenuShell *menu_shell; gboolean grab_keyboard; GtkWidget *parent_toplevel; - GdkDevice *keyboard, *pointer; + GdkDevice *keyboard, *pointer, *source_device = NULL; g_return_if_fail (GTK_IS_MENU (menu)); g_return_if_fail (device == NULL || GDK_IS_DEVICE (device)); @@ -1633,6 +1639,7 @@ gtk_menu_popup_for_device (GtkMenu *menu, (current_event->type != GDK_ENTER_NOTIFY)) menu_shell->priv->ignore_enter = TRUE; + source_device = gdk_event_get_source_device (current_event); gdk_event_free (current_event); } else @@ -1702,17 +1709,9 @@ gtk_menu_popup_for_device (GtkMenu *menu, gtk_menu_scroll_to (menu, priv->scroll_offset); /* if no item is selected, select the first one */ - if (!menu_shell->priv->active_menu_item) - { - gboolean touchscreen_mode; - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - - if (touchscreen_mode) - gtk_menu_shell_select_first (menu_shell, TRUE); - } + if (!menu_shell->priv->active_menu_item && + source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN) + gtk_menu_shell_select_first (menu_shell, TRUE); /* Once everything is set up correctly, map the toplevel */ gtk_widget_show (priv->toplevel); @@ -1736,13 +1735,13 @@ gtk_menu_popup_for_device (GtkMenu *menu, } /** - * gtk_menu_popup: (skip) + * gtk_menu_popup: * @menu: a #GtkMenu * @parent_menu_shell: (allow-none): the menu shell containing the * triggering menu item, or %NULL * @parent_menu_item: (allow-none): the menu item whose activation * triggered the popup, or %NULL - * @func: (allow-none): a user supplied function used to position + * @func: (scope async) (allow-none): a user supplied function used to position * the menu, or %NULL * @data: user supplied data to be passed to @func. * @button: the mouse button which was pressed to initiate the event. @@ -1886,7 +1885,7 @@ gtk_menu_popdown (GtkMenu *menu) * @menu: a #GtkMenu * * Returns the selected menu item from the menu. This is used by the - * #GtkOptionMenu. + * #GtkComboBox. * * Returns: (transfer none): the #GtkMenuItem that was last selected * in the menu. If a selection has not yet been made, the @@ -1931,7 +1930,7 @@ gtk_menu_get_active (GtkMenu *menu) * from 0 to n-1 * * Selects the specified menu item within the menu. This is used by - * the #GtkOptionMenu and should not be used by anyone else. + * the #GtkComboBox and should not be used by anyone else. */ void gtk_menu_set_active (GtkMenu *menu, @@ -2023,7 +2022,7 @@ gtk_menu_real_can_activate_accel (GtkWidget *widget, } /** - * gtk_menu_set_accel_path + * gtk_menu_set_accel_path: * @menu: a valid #GtkMenu * @accel_path: (allow-none): a valid accelerator path * @@ -2066,7 +2065,7 @@ gtk_menu_set_accel_path (GtkMenu *menu, } /** - * gtk_menu_get_accel_path + * gtk_menu_get_accel_path: * @menu: a valid #GtkMenu * * Retrieves the accelerator path set on the menu. @@ -2408,7 +2407,7 @@ gtk_menu_set_title (GtkMenu *menu, * has no title set on it. This string is owned by GTK+ * and should not be modified or freed. **/ -G_CONST_RETURN gchar * +const gchar * gtk_menu_get_title (GtkMenu *menu) { g_return_val_if_fail (GTK_IS_MENU (menu), NULL); @@ -2528,8 +2527,6 @@ gtk_menu_realize (GtkWidget *widget) gint border_width; GtkWidget *child; GList *children; - guint vertical_padding; - guint horizontal_padding; GtkBorder arrow_border, padding; g_return_if_fail (GTK_IS_MENU (widget)); @@ -2554,25 +2551,20 @@ gtk_menu_realize (GtkWidget *widget) window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gtk_widget_set_window (widget, window); - gdk_window_set_user_data (window, widget); + gtk_widget_register_window (widget, window); get_menu_padding (widget, &padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); context = gtk_widget_get_style_context (widget); - gtk_widget_style_get (GTK_WIDGET (menu), - "vertical-padding", &vertical_padding, - "horizontal-padding", &horizontal_padding, - NULL); - gtk_widget_get_allocation (widget, &allocation); - attributes.x = border_width + padding.left + horizontal_padding; - attributes.y = border_width + padding.top + vertical_padding; + attributes.x = border_width + padding.left; + attributes.y = border_width + padding.top; attributes.width = allocation.width - - (2 * (border_width + horizontal_padding)) - padding.left - padding.right; + (2 * border_width) - padding.left - padding.right; attributes.height = allocation.height - - (2 * (border_width + vertical_padding)) - padding.top - padding.bottom; + (2 * border_width) - padding.top - padding.bottom; get_arrows_border (menu, &arrow_border); attributes.y += arrow_border.top; @@ -2584,15 +2576,15 @@ gtk_menu_realize (GtkWidget *widget) priv->view_window = gdk_window_new (window, &attributes, attributes_mask); - gdk_window_set_user_data (priv->view_window, menu); + gtk_widget_register_window (widget, priv->view_window); gtk_widget_get_allocation (widget, &allocation); attributes.x = 0; attributes.y = 0; - attributes.width = allocation.width + (2 * (border_width + horizontal_padding)) + + attributes.width = allocation.width + (2 * border_width) + padding.left + padding.right; - attributes.height = priv->requested_height - (2 * (border_width + vertical_padding)) + + attributes.height = priv->requested_height - (2 * border_width) + padding.top + padding.bottom; attributes.width = MAX (1, attributes.width); @@ -2600,7 +2592,7 @@ gtk_menu_realize (GtkWidget *widget) priv->bin_window = gdk_window_new (priv->view_window, &attributes, attributes_mask); - gdk_window_set_user_data (priv->bin_window, menu); + gtk_widget_register_window (widget, priv->bin_window); children = GTK_MENU_SHELL (menu)->priv->children; while (children) @@ -2656,7 +2648,7 @@ menu_grab_transfer_window_get (GtkMenu *menu) window = gdk_window_new (gtk_widget_get_root_window (GTK_WIDGET (menu)), &attributes, attributes_mask); - gdk_window_set_user_data (window, menu); + gtk_widget_register_window (GTK_WIDGET (menu), window); gdk_window_show (window); @@ -2672,7 +2664,7 @@ menu_grab_transfer_window_destroy (GtkMenu *menu) GdkWindow *window = g_object_get_data (G_OBJECT (menu), "gtk-menu-transfer-window"); if (window) { - gdk_window_set_user_data (window, NULL); + gtk_widget_unregister_window (GTK_WIDGET (menu), window); gdk_window_destroy (window); g_object_set_data (G_OBJECT (menu), I_("gtk-menu-transfer-window"), NULL); } @@ -2686,11 +2678,11 @@ gtk_menu_unrealize (GtkWidget *widget) menu_grab_transfer_window_destroy (menu); - gdk_window_set_user_data (priv->view_window, NULL); + gtk_widget_unregister_window (widget, priv->view_window); gdk_window_destroy (priv->view_window); priv->view_window = NULL; - gdk_window_set_user_data (priv->bin_window, NULL); + gtk_widget_unregister_window (widget, priv->bin_window); gdk_window_destroy (priv->bin_window); priv->bin_window = NULL; @@ -2708,7 +2700,6 @@ calculate_line_heights (GtkMenu *menu, GtkMenuShell *menu_shell; GtkWidget *child, *widget; GList *children; - guint horizontal_padding; guint border_width; guint n_columns; gint n_heights; @@ -2726,13 +2717,10 @@ calculate_line_heights (GtkMenu *menu, n_columns = gtk_menu_get_n_columns (menu); avail_width = for_width - (2 * priv->toggle_size + priv->accel_size) * n_columns; - gtk_widget_style_get (GTK_WIDGET (menu), - "horizontal-padding", &horizontal_padding, - NULL); get_menu_padding (widget, &padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu)); - avail_width -= (border_width + horizontal_padding) * 2 + padding.left + padding.right; + avail_width -= (border_width) * 2 + padding.left + padding.right; for (children = menu_shell->priv->children; children; children = children->next) { @@ -2788,8 +2776,6 @@ gtk_menu_size_allocate (GtkWidget *widget, gint x, y, i; gint width, height; guint border_width; - guint vertical_padding; - guint horizontal_padding; GtkBorder padding; g_return_if_fail (GTK_IS_MENU (widget)); @@ -2801,11 +2787,6 @@ gtk_menu_size_allocate (GtkWidget *widget, gtk_widget_set_allocation (widget, allocation); - gtk_widget_style_get (GTK_WIDGET (menu), - "vertical-padding", &vertical_padding, - "horizontal-padding", &horizontal_padding, - NULL); - get_menu_padding (widget, &padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu)); @@ -2816,16 +2797,15 @@ gtk_menu_size_allocate (GtkWidget *widget, NULL); /* refresh our cached height request */ - priv->requested_height = (2 * (border_width + vertical_padding)) + - padding.top + padding.bottom; + priv->requested_height = (2 * border_width) + padding.top + padding.bottom; for (i = 0; i < priv->heights_length; i++) priv->requested_height += priv->heights[i]; - x = border_width + padding.left + horizontal_padding; - y = border_width + padding.top + vertical_padding; - width = allocation->width - (2 * (border_width + horizontal_padding)) - + x = border_width + padding.left; + y = border_width + padding.top; + width = allocation->width - (2 * border_width) - padding.left - padding.right; - height = allocation->height - (2 * (border_width + vertical_padding)) - + height = allocation->height - (2 * border_width) - padding.top - padding.bottom; if (menu_shell->priv->active) @@ -2955,22 +2935,18 @@ get_arrows_visible_area (GtkMenu *menu, GtkArrowPlacement arrow_placement; GtkWidget *widget = GTK_WIDGET (menu); guint border_width; - guint vertical_padding; - guint horizontal_padding; gint scroll_arrow_height; GtkBorder menu_padding; gtk_widget_style_get (widget, - "vertical-padding", &vertical_padding, - "horizontal-padding", &horizontal_padding, "scroll-arrow-vlength", &scroll_arrow_height, "arrow-placement", &arrow_placement, NULL); get_menu_padding (widget, &menu_padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - border->x = border_width + menu_padding.left + horizontal_padding; - border->y = border_width + menu_padding.top + vertical_padding; + border->x = border_width + menu_padding.left; + border->y = border_width + menu_padding.top; border->width = gdk_window_get_width (gtk_widget_get_window (widget)); border->height = gdk_window_get_height (gtk_widget_get_window (widget)); @@ -3155,7 +3131,6 @@ gtk_menu_get_preferred_width (GtkWidget *widget, GList *children; guint max_toggle_size; guint max_accel_width; - guint horizontal_padding; guint border_width; gint child_min, child_nat; gint min_width, nat_width; @@ -3214,19 +3189,19 @@ gtk_menu_get_preferred_width (GtkWidget *widget, !priv->no_toggle_size) { GtkStyleContext *context; - GtkWidgetPath *menu_path, *check_path; + GtkWidgetPath *check_path; guint toggle_spacing; guint indicator_size; - context = gtk_widget_get_style_context (widget); - menu_path = gtk_widget_path_copy (gtk_style_context_get_path (context)); + context = gtk_style_context_new (); /* Create a GtkCheckMenuItem path, only to query indicator spacing */ - check_path = gtk_widget_path_copy (menu_path); + check_path = _gtk_widget_create_path (widget); gtk_widget_path_append_type (check_path, GTK_TYPE_CHECK_MENU_ITEM); gtk_style_context_set_path (context, check_path); gtk_widget_path_free (check_path); + gtk_style_context_set_screen (context, gtk_widget_get_screen (widget)); gtk_style_context_get_style (context, "toggle-spacing", &toggle_spacing, @@ -3235,9 +3210,7 @@ gtk_menu_get_preferred_width (GtkWidget *widget, max_toggle_size = indicator_size + toggle_spacing; - /* Restore real widget path */ - gtk_style_context_set_path (context, menu_path); - gtk_widget_path_free (menu_path); + g_object_unref (context); } min_width += 2 * max_toggle_size + max_accel_width; @@ -3246,16 +3219,10 @@ gtk_menu_get_preferred_width (GtkWidget *widget, nat_width += 2 * max_toggle_size + max_accel_width; nat_width *= gtk_menu_get_n_columns (menu); - gtk_widget_style_get (GTK_WIDGET (menu), - "horizontal-padding", &horizontal_padding, - NULL); - get_menu_padding (widget, &padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu)); - min_width += (2 * (border_width + horizontal_padding)) + - padding.left + padding.right; - nat_width += (2 * (border_width + horizontal_padding)) + - padding.left + padding.right; + min_width += (2 * border_width) + padding.left + padding.right; + nat_width += (2 * border_width) + padding.left + padding.right; priv->toggle_size = max_toggle_size; priv->accel_size = max_accel_width; @@ -3297,16 +3264,14 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget, GtkMenu *menu = GTK_MENU (widget); GtkMenuPrivate *priv = menu->priv; guint *min_heights, *nat_heights; - guint vertical_padding, border_width; + guint border_width; gint n_heights, i; gint min_height, nat_height; - gtk_widget_style_get (widget, "vertical-padding", &vertical_padding, NULL); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu)); get_menu_padding (widget, &padding); - min_height = nat_height = (border_width + vertical_padding) * 2 + - padding.top + padding.bottom; + min_height = nat_height = (2 * border_width) + padding.top + padding.bottom; n_heights = calculate_line_heights (menu, for_size, &min_heights, &nat_heights); @@ -3322,7 +3287,7 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget, GdkScreen *screen = gtk_widget_get_screen (priv->toplevel); GdkRectangle monitor; - gdk_screen_get_monitor_geometry (screen, priv->monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, priv->monitor_num, &monitor); if (priv->position_y + min_height > monitor.y + monitor.height) min_height = monitor.y + monitor.height - priv->position_y; @@ -3347,34 +3312,6 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget, g_free (nat_heights); } - - -static gboolean -gtk_menu_button_scroll (GtkMenu *menu, - GdkEventButton *event) -{ - GtkMenuPrivate *priv = menu->priv; - - if (priv->upper_arrow_prelight || priv->lower_arrow_prelight) - { - gboolean touchscreen_mode; - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - - if (touchscreen_mode) - gtk_menu_handle_scrolling (menu, - event->x_root, event->y_root, - event->type == GDK_BUTTON_PRESS, - FALSE); - - return TRUE; - } - - return FALSE; -} - static gboolean pointer_in_menu_window (GtkWidget *widget, gdouble x_root, @@ -3411,13 +3348,16 @@ static gboolean gtk_menu_button_press (GtkWidget *widget, GdkEventButton *event) { + GdkDevice *source_device; + GtkWidget *event_widget; + GtkMenu *menu; + if (event->type != GDK_BUTTON_PRESS) return FALSE; - /* Don't pass down to menu shell for presses over scroll arrows - */ - if (gtk_menu_button_scroll (GTK_MENU (widget), event)) - return TRUE; + source_device = gdk_event_get_source_device ((GdkEvent *) event); + event_widget = gtk_get_event_widget ((GdkEvent *) event); + menu = GTK_MENU (widget); /* Don't pass down to menu shell if a non-menuitem part of the menu * was clicked. The check for the event_widget being a GtkMenuShell @@ -3426,10 +3366,16 @@ gtk_menu_button_press (GtkWidget *widget, * the menu or on its border are delivered relative to * menu_shell->window. */ - if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) && + if (GTK_IS_MENU_SHELL (event_widget) && pointer_in_menu_window (widget, event->x_root, event->y_root)) return TRUE; + if (GTK_IS_MENU_ITEM (event_widget) && + gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN && + GTK_MENU_ITEM (event_widget)->priv->submenu != NULL && + !gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu)) + menu->priv->ignore_button_release = TRUE; + return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event); } @@ -3448,11 +3394,6 @@ gtk_menu_button_release (GtkWidget *widget, if (event->type != GDK_BUTTON_RELEASE) return FALSE; - /* Don't pass down to menu shell for releases over scroll arrows - */ - if (gtk_menu_button_scroll (GTK_MENU (widget), event)) - return TRUE; - /* Don't pass down to menu shell if a non-menuitem part of the menu * was clicked (see comment in button_press()). */ @@ -3578,17 +3519,19 @@ gtk_menu_key_press (GtkWidget *widget, } /* Figure out what modifiers went into determining the key symbol */ - gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display), + _gtk_translate_keyboard_accel_state (gdk_keymap_get_for_display (display), event->hardware_keycode, - event->state, event->group, - NULL, NULL, NULL, &consumed_modifiers); + event->state, + gtk_accelerator_get_default_mod_mask (), + event->group, + &accel_key, NULL, NULL, &consumed_modifiers); - accel_key = gdk_keyval_to_lower (event->keyval); + accel_key = gdk_keyval_to_lower (accel_key); accel_mods = event->state & gtk_accelerator_get_default_mod_mask () & ~consumed_modifiers; /* If lowercasing affects the keysym, then we need to include SHIFT - * in the modifiers, we re-uppercase when we match against the keyval, - * but display and save in caseless form. + * in the modifiers, We re-upper case when we match against the + * keyval, but display and save in caseless form. */ if (accel_key != event->keyval) accel_mods |= GDK_SHIFT_MASK; @@ -3694,10 +3637,14 @@ gtk_menu_motion_notify (GtkWidget *widget, GtkMenu *menu; GtkMenuShell *menu_shell; GtkWidget *parent; + GdkDevice *source_device; gboolean need_enter; - if (GTK_IS_MENU (widget)) + source_device = gdk_event_get_source_device ((GdkEvent *) event); + + if (GTK_IS_MENU (widget) && + gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN) { GtkMenuPrivate *priv = GTK_MENU(widget)->priv; @@ -3861,90 +3808,17 @@ gtk_menu_scroll_by (GtkMenu *menu, gtk_menu_scroll_to (menu, offset); } -static void -gtk_menu_do_timeout_scroll (GtkMenu *menu, - gboolean touchscreen_mode) -{ - GtkMenuPrivate *priv = menu->priv; - gboolean upper_visible; - gboolean lower_visible; - - upper_visible = priv->upper_arrow_visible; - lower_visible = priv->lower_arrow_visible; - - gtk_menu_scroll_by (menu, priv->scroll_step); - - if (touchscreen_mode && - (upper_visible != priv->upper_arrow_visible || - lower_visible != priv->lower_arrow_visible)) - { - /* We are about to hide a scroll arrow while the mouse is pressed, - * this would cause the uncovered menu item to be activated on button - * release. Therefore we need to ignore button release here - */ - GTK_MENU_SHELL (menu)->priv->ignore_enter = TRUE; - priv->ignore_button_release = TRUE; - } -} - static gboolean gtk_menu_scroll_timeout (gpointer data) { GtkMenu *menu; - gboolean touchscreen_mode; menu = GTK_MENU (data); - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - - gtk_menu_do_timeout_scroll (menu, touchscreen_mode); + gtk_menu_scroll_by (menu, menu->priv->scroll_step); return TRUE; } -static gboolean -gtk_menu_scroll_timeout_initial (gpointer data) -{ - GtkMenu *menu; - guint timeout; - gboolean touchscreen_mode; - - menu = GTK_MENU (data); - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-timeout-repeat", &timeout, - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - - gtk_menu_do_timeout_scroll (menu, touchscreen_mode); - - gtk_menu_remove_scroll_timeout (menu); - - menu->priv->scroll_timeout = - gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu); - - return FALSE; -} - -static void -gtk_menu_start_scrolling (GtkMenu *menu) -{ - guint timeout; - gboolean touchscreen_mode; - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-timeout-repeat", &timeout, - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - - gtk_menu_do_timeout_scroll (menu, touchscreen_mode); - - menu->priv->scroll_timeout = - gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu); -} - static gboolean gtk_menu_scroll (GtkWidget *widget, GdkEventScroll *event) @@ -3961,6 +3835,9 @@ gtk_menu_scroll (GtkWidget *widget, case GDK_SCROLL_UP: gtk_menu_scroll_by (menu, - MENU_SCROLL_STEP2); break; + case GDK_SCROLL_SMOOTH: + gtk_menu_scroll_by (menu, event->delta_y); + break; } return TRUE; @@ -3976,7 +3853,6 @@ get_arrows_sensitive_area (GtkMenu *menu, GdkWindow *window; gint width, height; guint border; - guint vertical_padding; gint win_x, win_y; gint scroll_arrow_height; GtkBorder padding; @@ -3986,12 +3862,11 @@ get_arrows_sensitive_area (GtkMenu *menu, height = gdk_window_get_height (window); gtk_widget_style_get (widget, - "vertical-padding", &vertical_padding, "scroll-arrow-vlength", &scroll_arrow_height, "arrow-placement", &arrow_placement, NULL); - border = gtk_container_get_border_width (GTK_CONTAINER (menu)) + vertical_padding; + border = gtk_container_get_border_width (GTK_CONTAINER (menu)); get_menu_padding (widget, &padding); gdk_window_get_position (window, &win_x, &win_y); @@ -4068,14 +3943,9 @@ gtk_menu_handle_scrolling (GtkMenu *menu, gboolean in_arrow; gboolean scroll_fast = FALSE; gint top_x, top_y; - gboolean touchscreen_mode; menu_shell = GTK_MENU_SHELL (menu); - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - gdk_window_get_position (gtk_widget_get_window (priv->toplevel), &top_x, &top_y); x -= top_x; @@ -4093,82 +3963,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu, in_arrow = TRUE; } - if (touchscreen_mode) - priv->upper_arrow_prelight = in_arrow; - if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0) { gboolean arrow_pressed = FALSE; if (priv->upper_arrow_visible && !priv->tearoff_active) { - if (touchscreen_mode) + scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE); + + if (enter && in_arrow && + (!priv->upper_arrow_prelight || + priv->scroll_fast != scroll_fast)) { - if (enter && priv->upper_arrow_prelight) - { - if (priv->scroll_timeout == 0) - { - /* Deselect the active item so that - * any submenus are popped down - */ - gtk_menu_shell_deselect (menu_shell); - - gtk_menu_remove_scroll_timeout (menu); - priv->scroll_step = -MENU_SCROLL_STEP2; /* always fast */ - - if (!motion) - { - /* Only do stuff on click. */ - gtk_menu_start_scrolling (menu); - arrow_pressed = TRUE; - } - } - else - { - arrow_pressed = TRUE; - } - } - else if (!enter) - { - gtk_menu_stop_scrolling (menu); - } + priv->upper_arrow_prelight = TRUE; + priv->scroll_fast = scroll_fast; + + /* Deselect the active item so that + * any submenus are popped down + */ + gtk_menu_shell_deselect (menu_shell); + + gtk_menu_remove_scroll_timeout (menu); + priv->scroll_step = scroll_fast + ? -MENU_SCROLL_STEP2 + : -MENU_SCROLL_STEP1; + + priv->scroll_timeout = + gdk_threads_add_timeout (scroll_fast + ? MENU_SCROLL_TIMEOUT2 + : MENU_SCROLL_TIMEOUT1, + gtk_menu_scroll_timeout, menu); } - else /* !touchscreen_mode */ + else if (!enter && !in_arrow && priv->upper_arrow_prelight) { - scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE); - - if (enter && in_arrow && - (!priv->upper_arrow_prelight || - priv->scroll_fast != scroll_fast)) - { - priv->upper_arrow_prelight = TRUE; - priv->scroll_fast = scroll_fast; - - /* Deselect the active item so that - * any submenus are popped down - */ - gtk_menu_shell_deselect (menu_shell); - - gtk_menu_remove_scroll_timeout (menu); - priv->scroll_step = scroll_fast - ? -MENU_SCROLL_STEP2 - : -MENU_SCROLL_STEP1; - - priv->scroll_timeout = - gdk_threads_add_timeout (scroll_fast - ? MENU_SCROLL_TIMEOUT2 - : MENU_SCROLL_TIMEOUT1, - gtk_menu_scroll_timeout, menu); - } - else if (!enter && !in_arrow && priv->upper_arrow_prelight) - { - gtk_menu_stop_scrolling (menu); - } + gtk_menu_stop_scrolling (menu); } } - /* gtk_menu_start_scrolling() might have hit the top of the - * menu, so check if the button isn't insensitive before + /* check if the button isn't insensitive before * changing it to something else. */ if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0) @@ -4203,82 +4035,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu, in_arrow = TRUE; } - if (touchscreen_mode) - priv->lower_arrow_prelight = in_arrow; - if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0) { gboolean arrow_pressed = FALSE; if (priv->lower_arrow_visible && !priv->tearoff_active) { - if (touchscreen_mode) + scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE); + + if (enter && in_arrow && + (!priv->lower_arrow_prelight || + priv->scroll_fast != scroll_fast)) { - if (enter && priv->lower_arrow_prelight) - { - if (priv->scroll_timeout == 0) - { - /* Deselect the active item so that - * any submenus are popped down - */ - gtk_menu_shell_deselect (menu_shell); - - gtk_menu_remove_scroll_timeout (menu); - priv->scroll_step = MENU_SCROLL_STEP2; /* always fast */ - - if (!motion) - { - /* Only do stuff on click. */ - gtk_menu_start_scrolling (menu); - arrow_pressed = TRUE; - } - } - else - { - arrow_pressed = TRUE; - } - } - else if (!enter) - { - gtk_menu_stop_scrolling (menu); - } + priv->lower_arrow_prelight = TRUE; + priv->scroll_fast = scroll_fast; + + /* Deselect the active item so that + * any submenus are popped down + */ + gtk_menu_shell_deselect (menu_shell); + + gtk_menu_remove_scroll_timeout (menu); + priv->scroll_step = scroll_fast + ? MENU_SCROLL_STEP2 + : MENU_SCROLL_STEP1; + + priv->scroll_timeout = + gdk_threads_add_timeout (scroll_fast + ? MENU_SCROLL_TIMEOUT2 + : MENU_SCROLL_TIMEOUT1, + gtk_menu_scroll_timeout, menu); } - else /* !touchscreen_mode */ + else if (!enter && !in_arrow && priv->lower_arrow_prelight) { - scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE); - - if (enter && in_arrow && - (!priv->lower_arrow_prelight || - priv->scroll_fast != scroll_fast)) - { - priv->lower_arrow_prelight = TRUE; - priv->scroll_fast = scroll_fast; - - /* Deselect the active item so that - * any submenus are popped down - */ - gtk_menu_shell_deselect (menu_shell); - - gtk_menu_remove_scroll_timeout (menu); - priv->scroll_step = scroll_fast - ? MENU_SCROLL_STEP2 - : MENU_SCROLL_STEP1; - - priv->scroll_timeout = - gdk_threads_add_timeout (scroll_fast - ? MENU_SCROLL_TIMEOUT2 - : MENU_SCROLL_TIMEOUT1, - gtk_menu_scroll_timeout, menu); - } - else if (!enter && !in_arrow && priv->lower_arrow_prelight) - { - gtk_menu_stop_scrolling (menu); - } + gtk_menu_stop_scrolling (menu); } } - /* gtk_menu_start_scrolling() might have hit the bottom of the - * menu, so check if the button isn't insensitive before + /* check if the button isn't insensitive before * changing it to something else. */ if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0) @@ -4308,19 +4102,18 @@ gtk_menu_enter_notify (GtkWidget *widget, { GtkWidget *menu_item; GtkWidget *parent; - gboolean touchscreen_mode; + GdkDevice *source_device; if (event->mode == GDK_CROSSING_GTK_GRAB || event->mode == GDK_CROSSING_GTK_UNGRAB || event->mode == GDK_CROSSING_STATE_CHANGED) return TRUE; - g_object_get (gtk_widget_get_settings (widget), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - + source_device = gdk_event_get_source_device ((GdkEvent *) event); menu_item = gtk_get_event_widget ((GdkEvent*) event); - if (GTK_IS_MENU (widget)) + + if (GTK_IS_MENU (widget) && + gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN) { GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget); @@ -4329,7 +4122,8 @@ gtk_menu_enter_notify (GtkWidget *widget, event->x_root, event->y_root, TRUE, TRUE); } - if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item)) + if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN && + GTK_IS_MENU_ITEM (menu_item)) { GtkWidget *menu = gtk_widget_get_parent (menu_item); @@ -4386,6 +4180,7 @@ gtk_menu_leave_notify (GtkWidget *widget, GtkMenu *menu; GtkMenuItem *menu_item; GtkWidget *event_widget; + GdkDevice *source_device; if (event->mode == GDK_CROSSING_GTK_GRAB || event->mode == GDK_CROSSING_GTK_UNGRAB || @@ -4398,7 +4193,10 @@ gtk_menu_leave_notify (GtkWidget *widget, if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root)) return TRUE; - gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE); + source_device = gdk_event_get_source_device ((GdkEvent *) event); + + if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN) + gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE); event_widget = gtk_get_event_widget ((GdkEvent*) event); @@ -4433,6 +4231,144 @@ gtk_menu_leave_notify (GtkWidget *widget, return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event); } +static gboolean +pointer_on_menu_widget (GtkMenu *menu, + gdouble x_root, + gdouble y_root) +{ + GtkMenuPrivate *priv = menu->priv; + GtkAllocation allocation; + gint window_x, window_y; + + gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation); + gdk_window_get_position (gtk_widget_get_window (priv->toplevel), + &window_x, &window_y); + + if (x_root >= window_x && x_root < window_x + allocation.width && + y_root >= window_y && y_root < window_y + allocation.height) + return TRUE; + + return FALSE; +} + +static gboolean +gtk_menu_captured_event (GtkWidget *widget, + GdkEvent *event) +{ + GdkDevice *source_device; + gboolean retval = FALSE; + GtkMenuPrivate *priv; + GtkMenu *menu; + gdouble x_root, y_root; + guint button; + GdkModifierType state; + + menu = GTK_MENU (widget); + priv = menu->priv; + + if (!priv->upper_arrow_visible && !priv->lower_arrow_visible && priv->drag_start_y < 0) + return retval; + + source_device = gdk_event_get_source_device (event); + gdk_event_get_root_coords (event, &x_root, &y_root); + + switch (event->type) + { + case GDK_TOUCH_BEGIN: + case GDK_BUTTON_PRESS: + if ((!gdk_event_get_button (event, &button) || button == 1) && + gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN && + pointer_on_menu_widget (menu, x_root, y_root)) + { + priv->drag_start_y = event->button.y_root; + priv->initial_drag_offset = priv->scroll_offset; + priv->drag_scroll_started = FALSE; + } + else + priv->drag_start_y = -1; + + priv->drag_already_pressed = TRUE; + break; + case GDK_TOUCH_END: + case GDK_BUTTON_RELEASE: + if (priv->drag_scroll_started) + { + priv->drag_scroll_started = FALSE; + priv->drag_start_y = -1; + priv->drag_already_pressed = FALSE; + retval = TRUE; + } + break; + case GDK_TOUCH_UPDATE: + case GDK_MOTION_NOTIFY: + if ((!gdk_event_get_state (event, &state) || (state & GDK_BUTTON1_MASK) != 0) && + gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN) + { + if (!priv->drag_already_pressed) + { + if (pointer_on_menu_widget (menu, x_root, y_root)) + { + priv->drag_start_y = y_root; + priv->initial_drag_offset = priv->scroll_offset; + priv->drag_scroll_started = FALSE; + } + else + priv->drag_start_y = -1; + + priv->drag_already_pressed = TRUE; + } + + if (priv->drag_start_y < 0 && !priv->drag_scroll_started) + break; + + if (priv->drag_scroll_started) + { + gint offset, view_height; + GtkBorder arrow_border; + gdouble y_diff; + + y_diff = y_root - priv->drag_start_y; + offset = priv->initial_drag_offset - y_diff; + + view_height = gdk_window_get_height (gtk_widget_get_window (widget)); + get_arrows_border (menu, &arrow_border); + + if (priv->upper_arrow_visible) + view_height -= arrow_border.top; + + if (priv->lower_arrow_visible) + view_height -= arrow_border.bottom; + + offset = CLAMP (offset, + MIN (priv->scroll_offset, 0), + MAX (priv->scroll_offset, priv->requested_height - view_height)); + + gtk_menu_scroll_to (menu, offset); + + retval = TRUE; + } + else if (gtk_drag_check_threshold (widget, + 0, priv->drag_start_y, + 0, y_root)) + { + priv->drag_scroll_started = TRUE; + gtk_menu_shell_deselect (GTK_MENU_SHELL (menu)); + retval = TRUE; + } + } + break; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (priv->drag_scroll_started) + retval = TRUE; + break; + default: + break; + } + + return retval; +} + static void gtk_menu_stop_navigating_submenu (GtkMenu *menu) { @@ -4645,7 +4581,6 @@ gtk_menu_position (GtkMenu *menu, GtkRequisition requisition; gint x, y; gint scroll_offset; - gint menu_height; GdkScreen *screen; GdkScreen *pointer_screen; GdkRectangle monitor; @@ -4692,7 +4627,7 @@ gtk_menu_position (GtkMenu *menu, if (priv->monitor_num < 0) priv->monitor_num = gdk_screen_get_monitor_at_point (screen, x, y); - gdk_screen_get_monitor_geometry (screen, priv->monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, priv->monitor_num, &monitor); } else { @@ -4722,7 +4657,7 @@ gtk_menu_position (GtkMenu *menu, * Positioning in the vertical direction is similar: first try below * mouse cursor, then above. */ - gdk_screen_get_monitor_geometry (screen, priv->monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, priv->monitor_num, &monitor); space_left = x - monitor.x; space_right = monitor.x + monitor.width - x - 1; @@ -4816,24 +4751,20 @@ gtk_menu_position (GtkMenu *menu, scroll_offset = 0; - if (priv->initially_pushed_in) + if (y + requisition.height > monitor.y + monitor.height) { - menu_height = requisition.height; - - if (y + menu_height > monitor.y + monitor.height) - { - scroll_offset -= y + menu_height - (monitor.y + monitor.height); - y = (monitor.y + monitor.height) - menu_height; - } + if (priv->initially_pushed_in) + scroll_offset += (monitor.y + monitor.height) - requisition.height - y; + y = (monitor.y + monitor.height) - requisition.height; + } - if (y < monitor.y) - { - scroll_offset += monitor.y - y; - y = monitor.y; - } + if (y < monitor.y) + { + if (priv->initially_pushed_in) + scroll_offset += monitor.y - y; + y = monitor.y; } - /* FIXME: should this be done in the various position_funcs ? */ x = CLAMP (x, monitor.x, MAX (monitor.x, monitor.x + monitor.width - requisition.width)); if (GTK_MENU_SHELL (menu)->priv->active) @@ -4843,17 +4774,7 @@ gtk_menu_position (GtkMenu *menu, priv->position_y = y; } - if (y + requisition.height > monitor.y + monitor.height) - requisition.height = (monitor.y + monitor.height) - y; - - if (y < monitor.y) - { - scroll_offset += monitor.y - y; - requisition.height -= monitor.y - y; - y = monitor.y; - } - - if (scroll_offset > 0) + if (scroll_offset != 0) { GtkBorder arrow_border; @@ -4890,19 +4811,10 @@ static void gtk_menu_stop_scrolling (GtkMenu *menu) { GtkMenuPrivate *priv = menu->priv; - gboolean touchscreen_mode; gtk_menu_remove_scroll_timeout (menu); - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); - - if (!touchscreen_mode) - { - priv->upper_arrow_prelight = FALSE; - priv->lower_arrow_prelight = FALSE; - } + priv->upper_arrow_prelight = FALSE; + priv->lower_arrow_prelight = FALSE; } static void @@ -4910,15 +4822,12 @@ gtk_menu_scroll_to (GtkMenu *menu, gint offset) { GtkMenuPrivate *priv = menu->priv; - GtkAllocation allocation; GtkBorder arrow_border, padding; GtkWidget *widget; gint x, y; gint view_width, view_height; gint border_width; gint menu_height; - guint vertical_padding; - guint horizontal_padding; gboolean double_arrows; widget = GTK_WIDGET (menu); @@ -4927,27 +4836,20 @@ gtk_menu_scroll_to (GtkMenu *menu, gtk_adjustment_set_value (priv->tearoff_adjustment, offset); /* Move/resize the viewport according to arrows: */ - gtk_widget_get_allocation (widget, &allocation); - view_width = allocation.width; - view_height = allocation.height; - - gtk_widget_style_get (GTK_WIDGET (menu), - "vertical-padding", &vertical_padding, - "horizontal-padding", &horizontal_padding, - NULL); + view_width = gtk_widget_get_allocated_width (widget); + view_height = gtk_widget_get_allocated_height (widget); get_menu_padding (widget, &padding); double_arrows = get_double_arrows (menu); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu)); - view_width -= (2 * (border_width + horizontal_padding)) + padding.left + padding.right; - view_height -= (2 * (border_width + vertical_padding)) + padding.top + padding.bottom; - menu_height = priv->requested_height - (2 * (border_width + vertical_padding)) - - padding.top - padding.bottom; + view_width -= (2 * border_width) + padding.left + padding.right; + view_height -= (2 * border_width) + padding.top + padding.bottom; + menu_height = priv->requested_height - (2 * border_width) - padding.top - padding.bottom; - x = border_width + padding.left + horizontal_padding; - y = border_width + padding.top + vertical_padding; + x = border_width + padding.left; + y = border_width + padding.top; if (double_arrows && !priv->tearoff_active) { @@ -5078,10 +4980,10 @@ gtk_menu_scroll_to (GtkMenu *menu, /* Scroll the menu: */ if (gtk_widget_get_realized (widget)) - gdk_window_move (priv->bin_window, 0, -offset); - - if (gtk_widget_get_realized (widget)) - gdk_window_move_resize (priv->view_window, x, y, view_width, view_height); + { + gdk_window_move (priv->bin_window, 0, -offset); + gdk_window_move_resize (priv->view_window, x, y, view_width, view_height); + } priv->scroll_offset = offset; } @@ -5144,23 +5046,18 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell, if (compute_child_offset (menu, menu_item, &child_offset, &child_height, &last_child)) { - guint vertical_padding; gboolean double_arrows; GtkBorder padding; y = priv->scroll_offset; height = gdk_window_get_height (gtk_widget_get_window (widget)); - gtk_widget_style_get (widget, - "vertical-padding", &vertical_padding, - NULL); - double_arrows = get_double_arrows (menu); get_menu_padding (widget, &padding); height -= 2 * gtk_container_get_border_width (GTK_CONTAINER (menu)) + - padding.top + padding.bottom + - 2 * vertical_padding; + padding.top + padding.bottom; + if (child_offset < y) { /* Ignore the enter event we might get if the pointer @@ -5608,15 +5505,13 @@ static gint get_menu_height (GtkMenu *menu) { GtkMenuPrivate *priv = menu->priv; - GtkAllocation allocation; GtkWidget *widget = GTK_WIDGET (menu); GtkBorder padding; gint height; - gtk_widget_get_allocation (widget, &allocation); get_menu_padding (widget, &padding); - height = allocation.height; + height = priv->requested_height; height -= (gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2) + padding.top + padding.bottom; @@ -5680,6 +5575,7 @@ gtk_menu_real_move_scroll (GtkMenu *menu, GtkWidget *new_child; gboolean new_upper_arrow_visible = priv->upper_arrow_visible && !priv->tearoff_active; GtkBorder arrow_border; + get_arrows_border (menu, &arrow_border); if (priv->scroll_offset != old_offset) @@ -5696,13 +5592,11 @@ gtk_menu_real_move_scroll (GtkMenu *menu, case GTK_SCROLL_START: /* Ignore the enter event we might get if the pointer is on the menu */ menu_shell->priv->ignore_enter = TRUE; - gtk_menu_scroll_to (menu, 0); gtk_menu_shell_select_first (menu_shell, TRUE); break; case GTK_SCROLL_END: /* Ignore the enter event we might get if the pointer is on the menu */ menu_shell->priv->ignore_enter = TRUE; - gtk_menu_scroll_to (menu, end_position - page_size); _gtk_menu_shell_select_last (menu_shell, TRUE); break; default: @@ -5710,7 +5604,6 @@ gtk_menu_real_move_scroll (GtkMenu *menu, } } - /** * gtk_menu_set_monitor: * @menu: a #GtkMenu @@ -5787,11 +5680,13 @@ static void gtk_menu_grab_notify (GtkWidget *widget, gboolean was_grabbed) { + GtkMenu *menu; GtkWidget *toplevel; GtkWindowGroup *group; GtkWidget *grab; GdkDevice *pointer; + menu = GTK_MENU (widget); pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget)); if (!pointer || @@ -5808,6 +5703,8 @@ gtk_menu_grab_notify (GtkWidget *widget, if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab)) gtk_menu_shell_cancel (GTK_MENU_SHELL (widget)); + + menu->priv->drag_scroll_started = FALSE; } /** @@ -5857,3 +5754,32 @@ gtk_menu_get_reserve_toggle_size (GtkMenu *menu) return !menu->priv->no_toggle_size; } + +/** + * gtk_menu_new_from_model: + * @model: a #GMenuModel + * + * Creates a #GtkMenu and populates it with menu items and + * submenus according to @model. + * + * The created menu items are connected to actions found in the + * #GtkApplicationWindow to which the menu belongs - typically + * by means of being attached to a widget (see gtk_menu_attach_to_widget()) + * that is contained within the #GtkApplicationWindows widget hierarchy. + * + * Returns: a new #GtkMenu + * + * Since: 3.4 + */ +GtkWidget * +gtk_menu_new_from_model (GMenuModel *model) +{ + GtkWidget *menu; + + g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL); + + menu = gtk_menu_new (); + gtk_menu_shell_bind_model (GTK_MENU_SHELL (menu), model, NULL, TRUE); + + return menu; +}