diff --git a/ChangeLog b/ChangeLog index 99d570ab48..ee0c086a87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Sun Oct 20 23:58:03 2002 Soeren Sandmann + + * gtkmenu.c, gtkmenubar.c, gtkmenuitem.c, gtkmenushell.c, + gtkmenushell.h, gtkmenushell.h + + - make the delay before submenus appear below menu bars a + GtkSetting + - make the delay before submenus pops up a GtkSetting + - make the stay up triangle slightly larger + - don't pop up the first submenu immediately. + - make the default delay for submenus 225 ms, and 0 for menubars. + - make the default delay before popping down inside the stay-up + triangle 1000 ms + + Fixes #74950 + Sun Oct 20 14:58:02 2002 Owen Taylor * gtk/gtkscrolledwindow.c (gtk_scrolled_window_class_init): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 99d570ab48..ee0c086a87 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,19 @@ +Sun Oct 20 23:58:03 2002 Soeren Sandmann + + * gtkmenu.c, gtkmenubar.c, gtkmenuitem.c, gtkmenushell.c, + gtkmenushell.h, gtkmenushell.h + + - make the delay before submenus appear below menu bars a + GtkSetting + - make the delay before submenus pops up a GtkSetting + - make the stay up triangle slightly larger + - don't pop up the first submenu immediately. + - make the default delay for submenus 225 ms, and 0 for menubars. + - make the default delay before popping down inside the stay-up + triangle 1000 ms + + Fixes #74950 + Sun Oct 20 14:58:02 2002 Owen Taylor * gtk/gtkscrolledwindow.c (gtk_scrolled_window_class_init): diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 99d570ab48..ee0c086a87 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,19 @@ +Sun Oct 20 23:58:03 2002 Soeren Sandmann + + * gtkmenu.c, gtkmenubar.c, gtkmenuitem.c, gtkmenushell.c, + gtkmenushell.h, gtkmenushell.h + + - make the delay before submenus appear below menu bars a + GtkSetting + - make the delay before submenus pops up a GtkSetting + - make the stay up triangle slightly larger + - don't pop up the first submenu immediately. + - make the default delay for submenus 225 ms, and 0 for menubars. + - make the default delay before popping down inside the stay-up + triangle 1000 ms + + Fixes #74950 + Sun Oct 20 14:58:02 2002 Owen Taylor * gtk/gtkscrolledwindow.c (gtk_scrolled_window_class_init): diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 99d570ab48..ee0c086a87 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,19 @@ +Sun Oct 20 23:58:03 2002 Soeren Sandmann + + * gtkmenu.c, gtkmenubar.c, gtkmenuitem.c, gtkmenushell.c, + gtkmenushell.h, gtkmenushell.h + + - make the delay before submenus appear below menu bars a + GtkSetting + - make the delay before submenus pops up a GtkSetting + - make the stay up triangle slightly larger + - don't pop up the first submenu immediately. + - make the default delay for submenus 225 ms, and 0 for menubars. + - make the default delay before popping down inside the stay-up + triangle 1000 ms + + Fixes #74950 + Sun Oct 20 14:58:02 2002 Owen Taylor * gtk/gtkscrolledwindow.c (gtk_scrolled_window_class_init): diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 99d570ab48..ee0c086a87 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,19 @@ +Sun Oct 20 23:58:03 2002 Soeren Sandmann + + * gtkmenu.c, gtkmenubar.c, gtkmenuitem.c, gtkmenushell.c, + gtkmenushell.h, gtkmenushell.h + + - make the delay before submenus appear below menu bars a + GtkSetting + - make the delay before submenus pops up a GtkSetting + - make the stay up triangle slightly larger + - don't pop up the first submenu immediately. + - make the default delay for submenus 225 ms, and 0 for menubars. + - make the default delay before popping down inside the stay-up + triangle 1000 ms + + Fixes #74950 + Sun Oct 20 14:58:02 2002 Owen Taylor * gtk/gtkscrolledwindow.c (gtk_scrolled_window_class_init): diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 99d570ab48..ee0c086a87 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,19 @@ +Sun Oct 20 23:58:03 2002 Soeren Sandmann + + * gtkmenu.c, gtkmenubar.c, gtkmenuitem.c, gtkmenushell.c, + gtkmenushell.h, gtkmenushell.h + + - make the delay before submenus appear below menu bars a + GtkSetting + - make the delay before submenus pops up a GtkSetting + - make the stay up triangle slightly larger + - don't pop up the first submenu immediately. + - make the default delay for submenus 225 ms, and 0 for menubars. + - make the default delay before popping down inside the stay-up + triangle 1000 ms + + Fixes #74950 + Sun Oct 20 14:58:02 2002 Owen Taylor * gtk/gtkscrolledwindow.c (gtk_scrolled_window_class_init): diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 4d93eccfa2..9d7a1972cb 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -44,8 +44,12 @@ #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_GET_CLASS (w) #define MENU_NEEDS_RESIZE(m) GTK_MENU_SHELL (m)->menu_flag -#define SUBMENU_NAV_REGION_PADDING 2 -#define SUBMENU_NAV_HYSTERESIS_TIMEOUT 333 +#define DEFAULT_POPUP_DELAY 225 +#define DEFAULT_POPDOWN_DELAY 1000 + +#define NAVIGATION_REGION_OVERSHOOT 50 /* How much the navigation region + * extends below the submenu + */ #define MENU_SCROLL_STEP 10 #define MENU_SCROLL_ARROW_HEIGHT 16 @@ -126,6 +130,7 @@ static void gtk_menu_style_set (GtkWidget *widget, GtkStyle *previous_style); static gboolean gtk_menu_focus (GtkWidget *widget, GtkDirectionType direction); +static gint gtk_menu_get_popup_delay (GtkMenuShell *menu_shell); static void gtk_menu_stop_navigating_submenu (GtkMenu *menu); @@ -255,6 +260,7 @@ gtk_menu_class_init (GtkMenuClass *class) menu_shell_class->deactivate = gtk_menu_deactivate; menu_shell_class->select_item = gtk_menu_select_item; menu_shell_class->insert = gtk_menu_real_insert; + menu_shell_class->get_popup_delay = gtk_menu_get_popup_delay; binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, @@ -303,6 +309,23 @@ gtk_menu_class_init (GtkMenuClass *class) _("Whether menu accelerators can be changed by pressing a key over the menu item"), FALSE, G_PARAM_READWRITE)); + + gtk_settings_install_property (g_param_spec_int ("gtk-menu-popup-delay", + _("Delay before submenus appear"), + _("Minimum time the pointer must stay over a menu item before the submenu appear"), + 0, + G_MAXINT, + DEFAULT_POPUP_DELAY, + G_PARAM_READWRITE)); + + gtk_settings_install_property (g_param_spec_int ("gtk-menu-popdown-delay", + _("Delay before hiding a submenu"), + _("The time before hiding a submenu when the pointer is moving towards the submenu"), + 0, + G_MAXINT, + DEFAULT_POPDOWN_DELAY, + G_PARAM_READWRITE)); + } @@ -614,7 +637,7 @@ gtk_menu_real_insert (GtkMenuShell *menu_shell, { if (GTK_WIDGET_REALIZED (menu_shell)) gtk_widget_set_parent_window (child, GTK_MENU (menu_shell)->bin_window); - + GTK_MENU_SHELL_CLASS (parent_class)->insert (menu_shell, child, position); } @@ -1969,7 +1992,7 @@ gtk_menu_motion_notify (GtkWidget *widget, if (GTK_IS_MENU (widget)) gtk_menu_handle_scrolling (GTK_MENU (widget), TRUE); - + /* We received the event for one of two reasons: * * a) We are the active menu, and did gtk_grab_add() @@ -2310,6 +2333,37 @@ gtk_menu_navigating_submenu (GtkMenu *menu, return FALSE; } +#undef DRAW_STAY_UP_TRIANGLE + +#ifdef DRAW_STAY_UP_TRIANGLE + +static void +draw_stay_up_triangle (GdkWindow *window, + GdkRegion *region) +{ + /* Draw ugly color all over the stay-up triangle */ + GdkColor ugly_color = { 0, 50000, 10000, 10000 }; + GdkGCValues gc_values; + GdkGC *ugly_gc; + GdkRectangle clipbox; + + gc_values.subwindow_mode = GDK_INCLUDE_INFERIORS; + ugly_gc = gdk_gc_new_with_values (window, &gc_values, 0 | GDK_GC_SUBWINDOW); + gdk_gc_set_rgb_fg_color (ugly_gc, &ugly_color); + gdk_gc_set_clip_region (ugly_gc, region); + + gdk_region_get_clipbox (region, &clipbox); + + gdk_draw_rectangle (window, + ugly_gc, + TRUE, + clipbox.x, clipbox.y, + clipbox.width, clipbox.height); + + g_object_unref (G_OBJECT (ugly_gc)); +} +#endif + static void gtk_menu_set_submenu_navigation_region (GtkMenu *menu, GtkMenuItem *menu_item, @@ -2331,6 +2385,7 @@ gtk_menu_set_submenu_navigation_region (GtkMenu *menu, gdk_window_get_origin (menu_item->submenu->window, &submenu_left, &submenu_top); gdk_drawable_get_size (menu_item->submenu->window, &width, &height); + submenu_right = submenu_left + width; submenu_bottom = submenu_top + height; @@ -2338,48 +2393,58 @@ gtk_menu_set_submenu_navigation_region (GtkMenu *menu, if (event->x >= 0 && event->x < width) { - /* Set navigation region */ - /* We fudge/give a little padding in case the user - * ``misses the vertex'' of the triangle/is off by a pixel or two. - */ - if (menu_item->submenu_direction == GTK_DIRECTION_RIGHT) - point[0].x = event->x_root - SUBMENU_NAV_REGION_PADDING; - else - point[0].x = event->x_root + SUBMENU_NAV_REGION_PADDING; + gint popdown_delay; - /* Exiting the top or bottom? */ + gtk_menu_stop_navigating_submenu (menu); + + if (menu_item->submenu_direction == GTK_DIRECTION_RIGHT) + { + /* right */ + point[0].x = event->x_root - 1; + point[1].x = submenu_left; + } + else + { + /* left */ + point[0].x = event->x_root + 2; + point[1].x = submenu_right; + } + if (event->y < 0) - { /* top */ + { + /* top */ point[0].y = event->y_root + 1; - point[1].y = submenu_top; + point[1].y = submenu_top - NAVIGATION_REGION_OVERSHOOT; - if (point[0].y <= point[1].y) + if (point[0].y <= submenu_top) return; } else - { /* bottom */ + { + /* bottom */ point[0].y = event->y_root; - point[1].y = submenu_bottom; + point[1].y = submenu_bottom + NAVIGATION_REGION_OVERSHOOT; - if (point[0].y >= point[1].y) + if (point[0].y >= submenu_bottom) return; } - - /* Submenu is to the left or right? */ - if (menu_item->submenu_direction == GTK_DIRECTION_RIGHT) - point[1].x = submenu_left; /* right */ - else - point[1].x = submenu_right; /* left */ - + point[2].x = point[1].x; point[2].y = point[0].y; - gtk_menu_stop_navigating_submenu (menu); - menu->navigation_region = gdk_region_polygon (point, 3, GDK_WINDING_RULE); - menu->navigation_timeout = gtk_timeout_add (SUBMENU_NAV_HYSTERESIS_TIMEOUT, + g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (menu))), + "gtk-menu-popdown-delay", &popdown_delay, + NULL); + + menu->navigation_timeout = gtk_timeout_add (popdown_delay, gtk_menu_stop_navigating_submenu_cb, menu); + +#ifdef DRAW_STAY_UP_TRIANGLE + draw_stay_up_triangle (gdk_get_default_root_window(), + menu->navigation_region); +#endif } } @@ -2794,3 +2859,15 @@ gtk_menu_set_screen (GtkMenu *menu, g_object_set_data (G_OBJECT (menu), "gtk-menu-explicit-screen", screen); } + +static gint +gtk_menu_get_popup_delay (GtkMenuShell *menu_shell) +{ + gint popup_delay; + + g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (menu_shell))), + "gtk-menu-popup-delay", &popup_delay, + NULL); + + return popup_delay; +} diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c index c76e55b8d1..766e6a2cd0 100644 --- a/gtk/gtkmenubar.c +++ b/gtk/gtkmenubar.c @@ -41,17 +41,20 @@ #define CHILD_SPACING 3 #define DEFAULT_IPADDING 1 -static void gtk_menu_bar_class_init (GtkMenuBarClass *klass); -static void gtk_menu_bar_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_menu_bar_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_menu_bar_paint (GtkWidget *widget, - GdkRectangle *area); -static gint gtk_menu_bar_expose (GtkWidget *widget, - GdkEventExpose *event); -static void gtk_menu_bar_hierarchy_changed (GtkWidget *widget, - GtkWidget *old_toplevel); +static void gtk_menu_bar_class_init (GtkMenuBarClass *klass); +static void gtk_menu_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_menu_bar_paint (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_bar_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_menu_bar_hierarchy_changed (GtkWidget *widget, + GtkWidget *old_toplevel); +static gint gtk_menu_bar_get_popup_delay (GtkMenuShell *menu_shell); + + static GtkShadowType get_shadow_type (GtkMenuBar *menubar); static GtkMenuShellClass *parent_class = NULL; @@ -104,6 +107,7 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) widget_class->hierarchy_changed = gtk_menu_bar_hierarchy_changed; menu_shell_class->submenu_placement = GTK_TOP_BOTTOM; + menu_shell_class->get_popup_delay = gtk_menu_bar_get_popup_delay; binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, @@ -164,6 +168,13 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) DEFAULT_IPADDING, G_PARAM_READABLE)); + gtk_settings_install_property (g_param_spec_int ("gtk-menu-bar-popup-delay", + _("Delay before drop down menus appear"), + _("Delay before the submenus of a menu bar appear"), + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); } GtkWidget* @@ -575,6 +586,17 @@ get_shadow_type (GtkMenuBar *menubar) "shadow_type", &shadow_type, NULL); - return shadow_type; } + +static gint +gtk_menu_bar_get_popup_delay (GtkMenuShell *menu_shell) +{ + gint popup_delay; + + g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (menu_shell))), + "gtk-menu-bar-popup-delay", &popup_delay, + NULL); + + return popup_delay; +} diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index 15dedcf96f..c0fbd92062 100644 --- a/gtk/gtkmenuitem.c +++ b/gtk/gtkmenuitem.c @@ -37,7 +37,6 @@ #define BORDER_SPACING 3 -#define SELECT_TIMEOUT 75 #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) @@ -98,9 +97,6 @@ static void gtk_menu_item_forall (GtkContainer *container, static GtkItemClass *parent_class; static guint menu_item_signals[LAST_SIGNAL] = { 0 }; -static guint32 last_submenu_deselect_time = 0; - - GType gtk_menu_item_get_type (void) @@ -690,6 +686,27 @@ gtk_menu_item_expose (GtkWidget *widget, return FALSE; } +static gint +get_popup_delay (GtkMenuItem *menu_item) +{ + GtkWidget *parent = GTK_WIDGET (menu_item)->parent; + + if (GTK_IS_MENU_SHELL (parent)) + { + return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (parent)); + } + else + { + gint popup_delay; + + g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (menu_item))), + "gtk-menu-popup-delay", &popup_delay, + NULL); + + return popup_delay; + } +} + static void gtk_real_menu_item_select (GtkItem *item) { @@ -699,32 +716,35 @@ gtk_real_menu_item_select (GtkItem *item) menu_item = GTK_MENU_ITEM (item); - /* if (menu_item->submenu && !GTK_WIDGET_VISIBLE (menu_item->submenu))*/ if (menu_item->submenu) { - guint32 etime; - GdkEvent *event = gtk_get_current_event (); + gint popup_delay; + GtkWidget *parent; - etime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME; - if (event && - etime >= last_submenu_deselect_time && - last_submenu_deselect_time + SELECT_TIMEOUT > etime) + if (menu_item->timer) + gtk_timeout_remove (menu_item->timer); + + popup_delay = get_popup_delay (menu_item); + + if (popup_delay > 0) { - if (!menu_item->timer) - menu_item->timer = gtk_timeout_add (SELECT_TIMEOUT - (etime - last_submenu_deselect_time), - gtk_menu_item_select_timeout, - menu_item); + GdkEvent *event = gtk_get_current_event (); + + menu_item->timer = gtk_timeout_add (popup_delay, + gtk_menu_item_select_timeout, + menu_item); if (event && event->type != GDK_BUTTON_PRESS && event->type != GDK_ENTER_NOTIFY) menu_item->timer_from_keypress = TRUE; else menu_item->timer_from_keypress = FALSE; + + if (event) + gdk_event_free(event); } else gtk_menu_item_popup_submenu (menu_item); - if (event) - gdk_event_free(event); } gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT); @@ -742,9 +762,6 @@ gtk_real_menu_item_deselect (GtkItem *item) if (menu_item->submenu) { - guint32 etime; - GdkEvent *event = gtk_get_current_event (); - if (menu_item->timer) { gtk_timeout_remove (menu_item->timer); @@ -752,12 +769,6 @@ gtk_real_menu_item_deselect (GtkItem *item) } else gtk_menu_popdown (GTK_MENU (menu_item->submenu)); - - etime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME; - if (etime > last_submenu_deselect_time) - last_submenu_deselect_time = etime; - if (event) - gdk_event_free(event); } gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL); @@ -861,6 +872,9 @@ gtk_menu_item_popup_submenu (gpointer data) GtkMenuItem *menu_item; menu_item = GTK_MENU_ITEM (data); + + if (menu_item->timer) + gtk_timeout_remove (menu_item->timer); menu_item->timer = 0; if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu)) diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c index 6f90e6154c..683de2666b 100644 --- a/gtk/gtkmenushell.c +++ b/gtk/gtkmenushell.c @@ -1185,3 +1185,25 @@ gtk_real_menu_shell_cycle_focus (GtkMenuShell *menu_shell, if (menu_shell) _gtk_menu_bar_cycle_focus (GTK_MENU_BAR (menu_shell), dir); } + +gint +_gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell) +{ + GtkMenuShellClass *klass = GTK_MENU_SHELL_GET_CLASS (menu_shell); + + if (klass->get_popup_delay) + { + return klass->get_popup_delay (menu_shell); + } + else + { + gint popup_delay; + GtkWidget *widget = GTK_WIDGET (menu_shell); + + g_object_get (G_OBJECT (gtk_widget_get_settings (widget)), + "gtk-menu-popup-delay", &popup_delay, + NULL); + + return popup_delay; + } +} diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h index ec11500738..2177223059 100644 --- a/gtk/gtkmenushell.h +++ b/gtk/gtkmenushell.h @@ -86,34 +86,34 @@ struct _GtkMenuShellClass void (*insert) (GtkMenuShell *menu_shell, GtkWidget *child, gint position); + gint (*get_popup_delay) (GtkMenuShell *menu_shell); /* Padding for future expansion */ void (*_gtk_reserved1) (void); void (*_gtk_reserved2) (void); void (*_gtk_reserved3) (void); - void (*_gtk_reserved4) (void); }; -GType gtk_menu_shell_get_type (void) G_GNUC_CONST; -void gtk_menu_shell_append (GtkMenuShell *menu_shell, - GtkWidget *child); -void gtk_menu_shell_prepend (GtkMenuShell *menu_shell, - GtkWidget *child); -void gtk_menu_shell_insert (GtkMenuShell *menu_shell, - GtkWidget *child, - gint position); -void gtk_menu_shell_deactivate (GtkMenuShell *menu_shell); -void gtk_menu_shell_select_item (GtkMenuShell *menu_shell, - GtkWidget *menu_item); -void gtk_menu_shell_deselect (GtkMenuShell *menu_shell); -void gtk_menu_shell_activate_item (GtkMenuShell *menu_shell, - GtkWidget *menu_item, - gboolean force_deactivate); - -void gtk_menu_shell_select_first (GtkMenuShell *menu_shell, - gboolean search_sensitive); -void _gtk_menu_shell_activate (GtkMenuShell *menu_shell); +GType gtk_menu_shell_get_type (void) G_GNUC_CONST; +void gtk_menu_shell_append (GtkMenuShell *menu_shell, + GtkWidget *child); +void gtk_menu_shell_prepend (GtkMenuShell *menu_shell, + GtkWidget *child); +void gtk_menu_shell_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position); +void gtk_menu_shell_deactivate (GtkMenuShell *menu_shell); +void gtk_menu_shell_select_item (GtkMenuShell *menu_shell, + GtkWidget *menu_item); +void gtk_menu_shell_deselect (GtkMenuShell *menu_shell); +void gtk_menu_shell_activate_item (GtkMenuShell *menu_shell, + GtkWidget *menu_item, + gboolean force_deactivate); +void gtk_menu_shell_select_first (GtkMenuShell *menu_shell, + gboolean search_sensitive); +void _gtk_menu_shell_activate (GtkMenuShell *menu_shell); +gint _gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell); #ifdef __cplusplus }