[maemo-commits] [maemo-commits] r11364 - in projects/haf/trunk/gtk+: . gtk

From: subversion at stage.maemo.org subversion at stage.maemo.org
Date: Fri Apr 27 19:11:03 EEST 2007
Author: mitch
Date: 2007-04-27 19:11:00 +0300 (Fri, 27 Apr 2007)
New Revision: 11364

Modified:
   projects/haf/trunk/gtk+/ChangeLog
   projects/haf/trunk/gtk+/gtk/gtkmenu.c
   projects/haf/trunk/gtk+/gtk/gtkmenuitem.c
   projects/haf/trunk/gtk+/gtk/gtkmenuitem.h
   projects/haf/trunk/gtk+/gtk/gtkmenushell.c
Log:
2007-04-27  Michael Natterer  <mitch at imendio.com>

	Merge from upstream trunk, getting rid of tons and tons
	of MAEMO_CHANGES:

	Merged heavily modified patch from maemo-gtk which enables opening
	and closing submenus on click, and introduces some usability
	changes when gtk-touchscreen-mode is enabled (bug #128968):

	* gtk/gtkmenushell.c (struct GtkMenuShellPrivate): added boolean
	"activated_submenu" to indicate that the current mouse operation
	(click or drag) has opened a submenu.

	(gtk_menu_shell_button_press): pop up submenus without delay
	and record the fact in "activated_submenu".

	(gtk_menu_shell_button_release): if a submenu was explicitely
	opened, or not opened by this release's button_press, or enough
	time has passed since timeout-opening it, close the submenu here.

	(gtk_menu_shell_enter_notify): when entering a menu item with
	any mouse button pressed, open its submenu.

	(gtk_real_menu_shell_move_current): in touchsreen mode, close the
	submenu when moving the focus away from it via keyboard-navigation.

	* gtk/gtkmenuitem.[ch] (_gtk_menu_item_popup_submenu): added
	parameter "gboolean with_delay" so GtkMenuShell can control this
	for the different scenarios of submenu showing.

	(_gtk_menu_item_popdown_submenu): new function. also needed by
	GtkMenuShell for closing submenus on click.

	Renamed internal function gtk_menu_item_select_timeout() to
	gtk_menu_item_popup_timeout().

	(gtk_menu_item_real_popup_submenu): new utility function which
	does the actual popup and records the exact time of the popup when
	the menu was timeout-opened (using g_get_current_time()).

	(gtk_real_menu_item_select): don't add the popup timeout when in
	touchscreen mode.

	* gtk/gtkmenu.c (gtk_menu_popup): in touchscreen mode, select the
	first item of every opened menu.



Modified: projects/haf/trunk/gtk+/ChangeLog
===================================================================
--- projects/haf/trunk/gtk+/ChangeLog	2007-04-27 16:02:53 UTC (rev 11363)
+++ projects/haf/trunk/gtk+/ChangeLog	2007-04-27 16:11:00 UTC (rev 11364)
@@ -1,3 +1,49 @@
+2007-04-27  Michael Natterer  <mitch at imendio.com>
+
+	Merge from upstream trunk, getting rid of tons and tons
+	of MAEMO_CHANGES:
+
+	Merged heavily modified patch from maemo-gtk which enables opening
+	and closing submenus on click, and introduces some usability
+	changes when gtk-touchscreen-mode is enabled (bug #128968):
+
+	* gtk/gtkmenushell.c (struct GtkMenuShellPrivate): added boolean
+	"activated_submenu" to indicate that the current mouse operation
+	(click or drag) has opened a submenu.
+
+	(gtk_menu_shell_button_press): pop up submenus without delay
+	and record the fact in "activated_submenu".
+
+	(gtk_menu_shell_button_release): if a submenu was explicitely
+	opened, or not opened by this release's button_press, or enough
+	time has passed since timeout-opening it, close the submenu here.
+
+	(gtk_menu_shell_enter_notify): when entering a menu item with
+	any mouse button pressed, open its submenu.
+
+	(gtk_real_menu_shell_move_current): in touchsreen mode, close the
+	submenu when moving the focus away from it via keyboard-navigation.
+
+	* gtk/gtkmenuitem.[ch] (_gtk_menu_item_popup_submenu): added
+	parameter "gboolean with_delay" so GtkMenuShell can control this
+	for the different scenarios of submenu showing.
+
+	(_gtk_menu_item_popdown_submenu): new function. also needed by
+	GtkMenuShell for closing submenus on click.
+
+	Renamed internal function gtk_menu_item_select_timeout() to
+	gtk_menu_item_popup_timeout().
+
+	(gtk_menu_item_real_popup_submenu): new utility function which
+	does the actual popup and records the exact time of the popup when
+	the menu was timeout-opened (using g_get_current_time()).
+
+	(gtk_real_menu_item_select): don't add the popup timeout when in
+	touchscreen mode.
+
+	* gtk/gtkmenu.c (gtk_menu_popup): in touchscreen mode, select the
+	first item of every opened menu.
+
 2007-04-25  Michael Natterer  <mitch at imendio.com>
   
 	Merge from upstream trunk:

Modified: projects/haf/trunk/gtk+/gtk/gtkmenu.c
===================================================================
--- projects/haf/trunk/gtk+/gtk/gtkmenu.c	2007-04-27 16:02:53 UTC (rev 11363)
+++ projects/haf/trunk/gtk+/gtk/gtkmenu.c	2007-04-27 16:11:00 UTC (rev 11364)
@@ -1538,12 +1538,21 @@
                              NULL);
 
   _gtk_menu_shell_set_first_click (menu_shell);
+#endif /* MAEMO_CHANGES */
 
   /* if no item is selected, select the first one */
   if (!menu_shell->active_menu_item)
-    gtk_menu_shell_select_first (menu_shell, TRUE);
-#endif /* MAEMO_CHANGES */
+    {
+      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);
+    }
+
   /* Once everything is set up correctly, map the toplevel window on
      the screen.
    */

Modified: projects/haf/trunk/gtk+/gtk/gtkmenuitem.c
===================================================================
--- projects/haf/trunk/gtk+/gtk/gtkmenuitem.c	2007-04-27 16:02:53 UTC (rev 11363)
+++ projects/haf/trunk/gtk+/gtk/gtkmenuitem.c	2007-04-27 16:11:00 UTC (rev 11364)
@@ -71,9 +71,6 @@
 
 static void gtk_real_menu_item_select               (GtkItem     *item);
 static void gtk_real_menu_item_deselect             (GtkItem     *item);
-#ifdef MAEMO_CHANGES
-static void gtk_real_menu_item_activate             (GtkMenuItem *item);
-#endif /* MAEMO_CHANGES */
 static void gtk_real_menu_item_activate_item        (GtkMenuItem *item);
 static void gtk_real_menu_item_toggle_size_request  (GtkMenuItem *menu_item,
 						     gint        *requisition);
@@ -82,7 +79,7 @@
 static gboolean gtk_menu_item_mnemonic_activate     (GtkWidget   *widget,
 						     gboolean     group_cycling);
 
-static gint gtk_menu_item_select_timeout (gpointer          data);
+static gint gtk_menu_item_popup_timeout  (gpointer          data);
 static void gtk_menu_item_position_menu  (GtkMenu          *menu,
 					  gint             *x,
 					  gint             *y,
@@ -133,11 +130,7 @@
   item_class->select = gtk_real_menu_item_select;
   item_class->deselect = gtk_real_menu_item_deselect;
 
-#ifdef MAEMO_CHANGES
-  klass->activate = gtk_real_menu_item_activate;
-#else
   klass->activate = NULL;
-#endif /* MAEMO_CHANGES */
   klass->activate_item = gtk_real_menu_item_activate_item;
   klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
   klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
@@ -896,75 +889,28 @@
   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 (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)
 {
   GtkMenuItem *menu_item;
+  gboolean touchscreen_mode;
 
   g_return_if_fail (GTK_IS_MENU_ITEM (item));
 
   menu_item = GTK_MENU_ITEM (item);
 
-  if (menu_item->submenu &&
+  g_object_get (gtk_widget_get_settings (GTK_WIDGET (item)),
+                "gtk-touchscreen-mode", &touchscreen_mode,
+                NULL);
+
+  if (!touchscreen_mode &&
+      menu_item->submenu &&
       (!GTK_WIDGET_MAPPED (menu_item->submenu) ||
        GTK_MENU (menu_item->submenu)->tearoff_active))
     {
-      gint popup_delay;
-
-      if (menu_item->timer)
-	{
-	  g_source_remove (menu_item->timer);
-	  menu_item->timer = 0;
-	  popup_delay = 0;
-	}
-      else
-	popup_delay = get_popup_delay (menu_item);
-      
-      if (popup_delay > 0)
-	{
-	  GdkEvent *event = gtk_get_current_event ();
-
-#ifndef MAEMO_CHANGES
-	  menu_item->timer = g_timeout_add (popup_delay,
-					    gtk_menu_item_select_timeout,
-					    menu_item);
-#endif /* !MAEMO_CHANGES */
-
-	  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 (GTK_WIDGET (menu_item));
+      _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
     }
-  
+
   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
   gtk_widget_queue_draw (GTK_WIDGET (menu_item));
 }
@@ -972,18 +918,6 @@
 static void
 gtk_real_menu_item_deselect (GtkItem *item)
 {
-#ifdef MAEMO_CHANGES
-  GtkWidget *menu_item;
-
-  g_return_if_fail (GTK_IS_MENU_ITEM (item));
-
-  menu_item = GTK_WIDGET (item);
-
-  _gtk_menu_item_popdown_submenu (menu_item);
-
-  gtk_widget_set_state (menu_item, GTK_STATE_NORMAL);
-  gtk_widget_queue_draw (menu_item);
-#else
   GtkMenuItem *menu_item;
 
   g_return_if_fail (GTK_IS_MENU_ITEM (item));
@@ -991,19 +925,10 @@
   menu_item = GTK_MENU_ITEM (item);
 
   if (menu_item->submenu)
-    {
-      if (menu_item->timer)
-	{
-	  g_source_remove (menu_item->timer);
-	  menu_item->timer = 0;
-	}
-      else
-	gtk_menu_popdown (GTK_MENU (menu_item->submenu));
-    }
+    _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
 
   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
   gtk_widget_queue_draw (GTK_WIDGET (menu_item));
-#endif /* MAEMO_CHANGES */
 }
 
 static gboolean
@@ -1024,51 +949,7 @@
   return TRUE;
 }
 
-#ifdef MAEMO_CHANGES
-/* This function exists only for opening submenus on
- * activation.
- */
 static void
-gtk_real_menu_item_activate (GtkMenuItem *item)
-{
-  GdkEvent *event;
-  gint popup_delay;
-
-  g_return_if_fail (GTK_IS_MENU_ITEM (item));
-
-  if (!GTK_IS_MENU (item->submenu) ||
-      GTK_WIDGET_VISIBLE (item->submenu))
-    return;
-
-  event = gtk_get_current_event ();
-
-  /* Add a delay before opening a new menu */
-  if (item->timer)
-    {
-      g_source_remove (item->timer);
-      item->timer = 0;
-      popup_delay = 0;
-    }
-  else
-    popup_delay = get_popup_delay (item);
-
-  item->timer = g_timeout_add (popup_delay,
-                               gtk_menu_item_select_timeout,
-                               item);
-
-  /* We don't want to select first item if the submenu
-   * is opened with mouse release because the selection
-   * would move straigh back under the cursor.
-   */
-  if ((event == NULL) || (event->type != GDK_BUTTON_RELEASE))
-    gtk_menu_shell_select_first (GTK_MENU_SHELL (item->submenu), TRUE);
-
-  if (event)
-    gdk_event_free (event);
-}
-#endif /* MAEMO_CHANGES */
-
-static void
 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
 {
   GtkWidget *widget;
@@ -1089,14 +970,14 @@
 
 	  _gtk_menu_shell_activate (menu_shell);
 
-	  gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget); 
+	  gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget);
+	  _gtk_menu_item_popup_submenu (widget, FALSE);
 
-	  _gtk_menu_item_popup_submenu (widget); 
-
 	  gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
 	}
     }
 }
+
 static void
 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
 					gint        *requisition)
@@ -1115,8 +996,53 @@
   menu_item->toggle_size = allocation;
 }
 
+static void
+gtk_menu_item_real_popup_submenu (GtkWidget *widget,
+                                  gboolean   remember_exact_time)
+{
+  GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
+
+  if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
+    {
+      gboolean take_focus;
+
+      take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
+      gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
+                                     take_focus);
+
+      if (remember_exact_time)
+        {
+          GTimeVal *popup_time = g_new0 (GTimeVal, 1);
+
+          g_get_current_time (popup_time);
+
+          g_object_set_data_full (G_OBJECT (menu_item->submenu),
+                                  "gtk-menu-exact-popup-time", popup_time,
+                                  (GDestroyNotify) g_free);
+        }
+      else
+        {
+          g_object_set_data (G_OBJECT (menu_item->submenu),
+                             "gtk-menu-exact-popup-time", NULL);
+        }
+
+      gtk_menu_popup (GTK_MENU (menu_item->submenu),
+                      widget->parent,
+                      widget,
+                      gtk_menu_item_position_menu,
+                      menu_item,
+                      GTK_MENU_SHELL (widget->parent)->button,
+                      0);
+    }
+
+  /* Enable themeing of the parent menu item depending on whether
+   * its submenu is shown or not.
+   */
+  gtk_widget_queue_draw (widget);
+}
+
 static gint
-gtk_menu_item_select_timeout (gpointer data)
+gtk_menu_item_popup_timeout (gpointer data)
 {
   GtkMenuItem *menu_item;
   GtkWidget *parent;
@@ -1130,53 +1056,79 @@
   if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) || 
       (GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off))
     {
-      _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item));
+      gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
       if (menu_item->timer_from_keypress && menu_item->submenu)
 	GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
     }
 
+  menu_item->timer = 0;
+
   GDK_THREADS_LEAVE ();
 
   return FALSE;  
 }
 
-void
-_gtk_menu_item_popup_submenu (GtkWidget *widget)
+static gint
+get_popup_delay (GtkWidget *widget)
 {
-  GtkMenuItem *menu_item;
+  if (GTK_IS_MENU_SHELL (widget->parent))
+    {
+      return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (widget->parent));
+    }
+  else
+    {
+      gint popup_delay;
 
-  menu_item = GTK_MENU_ITEM (widget);
+      g_object_get (gtk_widget_get_settings (widget),
+                  "gtk-menu-popup-delay", &popup_delay,
+                  NULL);
 
+      return popup_delay;
+    }
+}
+
+void
+_gtk_menu_item_popup_submenu (GtkWidget *widget,
+                              gboolean   with_delay)
+{
+  GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
+
   if (menu_item->timer)
-    g_source_remove (menu_item->timer);
-  menu_item->timer = 0;
+    {
+      g_source_remove (menu_item->timer);
+      menu_item->timer = 0;
+      with_delay = FALSE;
+    }
 
-  if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
+  if (with_delay)
     {
-      gboolean take_focus;
+      gint popup_delay = get_popup_delay (widget);
 
-      take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
-      gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
-                                     take_focus);
+      if (popup_delay > 0)
+      {
+        GdkEvent *event = gtk_get_current_event ();
 
-      gtk_menu_popup (GTK_MENU (menu_item->submenu),
-                      widget->parent,
-                      widget,
-                      gtk_menu_item_position_menu,
-                      menu_item,
-                      GTK_MENU_SHELL (widget->parent)->button,
-                      0);
+        menu_item->timer = g_timeout_add (popup_delay,
+                                          gtk_menu_item_popup_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);
+
+          return;
+        }
     }
 
-#ifdef MAEMO_CHANGES
-  /* This is required as changed submenu arrow isn't drawn automatically
-   * and drawing it must be requested.
-   */
-  gtk_widget_queue_draw (widget);
-#endif /* MAEMO_CHANGES */
+  gtk_menu_item_real_popup_submenu (widget, FALSE);
 }
 
-#ifdef MAEMO_CHANGES
 void
 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
 {
@@ -1186,6 +1138,9 @@
 
   if (menu_item->submenu)
     {
+      g_object_set_data (G_OBJECT (menu_item->submenu),
+                         "gtk-menu-exact-popup-time", NULL);
+
       if (menu_item->timer)
         {
           g_source_remove (menu_item->timer);
@@ -1193,11 +1148,10 @@
         }
       else
         gtk_menu_popdown (GTK_MENU (menu_item->submenu));
-    }
 
-  gtk_widget_queue_draw (widget);
+      gtk_widget_queue_draw (widget);
+    }
 }
-#endif /* MAEMO_CHANGES */
 
 static void
 get_offsets (GtkMenu *menu,
@@ -1417,7 +1371,6 @@
   return menu_item->right_justify;
 }
 
-
 static void
 gtk_menu_item_show_all (GtkWidget *widget)
 {

Modified: projects/haf/trunk/gtk+/gtk/gtkmenuitem.h
===================================================================
--- projects/haf/trunk/gtk+/gtk/gtkmenuitem.h	2007-04-27 16:02:53 UTC (rev 11363)
+++ projects/haf/trunk/gtk+/gtk/gtkmenuitem.h	2007-04-27 16:11:00 UTC (rev 11364)
@@ -119,10 +119,9 @@
 					       GtkAccelGroup	   *accel_group,
 					       gboolean		    group_changed);
 gboolean  _gtk_menu_item_is_selectable        (GtkWidget           *menu_item);
-void      _gtk_menu_item_popup_submenu        (GtkWidget           *menu_item);
-#ifdef MAEMO_CHANGES
+void      _gtk_menu_item_popup_submenu        (GtkWidget           *menu_item,
+                                               gboolean             with_delay);
 void      _gtk_menu_item_popdown_submenu      (GtkWidget           *menu_item);
-#endif /* MAEMO_CHANGES */
 
 #ifndef GTK_DISABLE_DEPRECATED
 #define gtk_menu_item_right_justify(menu_item) gtk_menu_item_set_right_justified ((menu_item), TRUE)

Modified: projects/haf/trunk/gtk+/gtk/gtkmenushell.c
===================================================================
--- projects/haf/trunk/gtk+/gtk/gtkmenushell.c	2007-04-27 16:02:53 UTC (rev 11363)
+++ projects/haf/trunk/gtk+/gtk/gtkmenushell.c	2007-04-27 16:11:00 UTC (rev 11364)
@@ -32,9 +32,7 @@
 #include "gtkkeyhash.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
-#ifdef MAEMO_CHANGES
 #include "gtkmenu.h"
-#endif /* MAEMO_CHANGES */
 #include "gtkmenubar.h"
 #include "gtkmenuitem.h"
 #include "gtkmenushell.h"
@@ -135,10 +133,10 @@
   GtkMnemonicHash *mnemonic_hash;
   GtkKeyHash *key_hash;
 
-  gboolean take_focus;
+  guint take_focus : 1;
+  guint activated_submenu : 1;
 #ifdef MAEMO_CHANGES
-  gboolean activated_submenu;
-  gboolean first_click;
+  guint first_click : 1;
 #endif /* MAEMO_CHANGES */
 };
 
@@ -388,8 +386,8 @@
   priv->mnemonic_hash = NULL;
   priv->key_hash = NULL;
   priv->take_focus = TRUE;
-#ifdef MAEMO_CHANGES
   priv->activated_submenu = FALSE;
+#ifdef MAEMO_CHANGES
   priv->first_click = FALSE;
 #endif /* MAEMO_CHANGES */
 }
@@ -544,80 +542,58 @@
 gtk_menu_shell_button_press (GtkWidget      *widget,
 			     GdkEventButton *event)
 {
-#ifdef MAEMO_CHANGES
-  GtkMenuShellPrivate *priv;
-#endif /* MAEMO_CHANGES */
   GtkMenuShell *menu_shell;
   GtkWidget *menu_item;
 
-  g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
   if (event->type != GDK_BUTTON_PRESS)
     return FALSE;
 
   menu_shell = GTK_MENU_SHELL (widget);
 
-#ifdef MAEMO_CHANGES
-  priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
+  if (menu_shell->parent_menu_shell)
+    return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
+
   menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent *)event);
-#endif /* MAEMO_CHANGES */
 
-#ifdef MAEMO_CHANGES
-  if (!menu_shell->active)
-#else
-  if (menu_shell->parent_menu_shell)
+  if (menu_item && _gtk_menu_item_is_selectable (menu_item) &&
+      menu_item != GTK_MENU_SHELL (menu_item->parent)->active_menu_item)
     {
-      return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
+      /*  select the menu item *before* activating the shell, so submenus
+       *  which might be open are closed the friendly way. If we activate
+       *  (and thus grab) this menu shell first, we might get grab_broken
+       *  events which will close the entire menu hierarchy. Selecting the
+       *  menu item also fixes up the state as if enter_notify() would
+       *  have run before (which normally selects the item).
+       */
+      if (GTK_MENU_SHELL_GET_CLASS (menu_item->parent)->submenu_placement != GTK_TOP_BOTTOM)
+        {
+          gtk_menu_shell_select_item (GTK_MENU_SHELL (menu_item->parent), menu_item);
+        }
     }
-  else if (!menu_shell->active || !menu_shell->button)
-#endif /* MAEMO_CHANGES */
+
+  if (!menu_shell->active || !menu_shell->button)
     {
       _gtk_menu_shell_activate (menu_shell);
-      
+
       menu_shell->button = event->button;
 
-#ifndef MAEMO_CHANGES
-      menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent *)event);
-#endif /* MAEMO_CHANGES */
-
-      if (menu_item && _gtk_menu_item_is_selectable (menu_item))
-	{
-	  if ((menu_item->parent == widget) &&
-	      (menu_item != menu_shell->active_menu_item))
-	    {
-	      if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
-		{
-		  menu_shell->activate_time = event->time;
-		}
-      
-	      gtk_menu_shell_select_item (menu_shell, menu_item);
-	    }
-	}
+      if (menu_item && _gtk_menu_item_is_selectable (menu_item) &&
+	  menu_item->parent == widget &&
+          menu_item != menu_shell->active_menu_item)
+        {
+          if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
+            {
+              menu_shell->activate_time = event->time;
+              gtk_menu_shell_select_item (menu_shell, menu_item);
+            }
+        }
     }
   else
     {
 #ifdef MAEMO_CHANGES
-      priv->first_click = FALSE;
+      GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
 
-      /* Activate submenu on button press, so that we can drag-move into it if
-       * necessary.
-       */
-      if (menu_item && _gtk_menu_item_is_selectable (menu_item) &&
-          GTK_MENU_ITEM (menu_item)->submenu != NULL &&
-          !GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (menu_item)->submenu))
-        {
-          /* Hildon-crack: The item could be unselected when the tap
-           * occurs, make sure it gets selected. The real fix is bug#11670,
-           * remove this crack when it is done.
-           * NB#9417
-           */
-          gtk_menu_shell_select_item (menu_shell, menu_item);
-
-          gtk_menu_shell_activate_item (menu_shell, menu_item, FALSE);
-
-          priv->activated_submenu = TRUE;
-        }
+      priv->first_click = FALSE;
 #endif /* MAEMO_CHANGES */
 
       widget = gtk_get_event_widget ((GdkEvent*) event);
@@ -628,6 +604,18 @@
 	}
     }
 
+  if (menu_item && _gtk_menu_item_is_selectable (menu_item) &&
+      GTK_MENU_ITEM (menu_item)->submenu != NULL &&
+      !GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (menu_item)->submenu))
+    {
+      GtkMenuShellPrivate *priv;
+
+      _gtk_menu_item_popup_submenu (menu_item, FALSE);
+
+      priv = GTK_MENU_SHELL_GET_PRIVATE (menu_item->parent);
+      priv->activated_submenu = TRUE;
+    }
+
   return TRUE;
 }
 
@@ -655,162 +643,141 @@
 gtk_menu_shell_button_release (GtkWidget      *widget,
 			       GdkEventButton *event)
 {
-#ifdef MAEMO_CHANGES
-  GtkMenuShellPrivate *priv;
-#endif /* MAEMO_CHANGES */
-  GtkMenuShell *menu_shell;
-  GtkWidget *menu_item;
-  gint deactivate;
+  GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
+  GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
 
-  g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  menu_shell = GTK_MENU_SHELL (widget);
-
-#ifdef MAEMO_CHANGES
-
-  priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
-
-  menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent*) event);
-
-  if (menu_item && _gtk_menu_item_is_selectable (menu_item))
+  if (menu_shell->active)
     {
-      if (GTK_MENU_ITEM (menu_item)->submenu == NULL)
-        {
-          GtkSettings *settings = gtk_widget_get_settings (widget);
-          int timeout;
+      GtkWidget *menu_item;
+      gboolean   deactivate = TRUE;
 
-          g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
+      if (menu_shell->button && (event->button != menu_shell->button))
+	{
+	  menu_shell->button = 0;
+	  if (menu_shell->parent_menu_shell)
+	    return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
+	}
 
-          /* Prevent immediate activation on first click, this is mainly
-           * for combo popups and the like. */
-          if (!priv->first_click ||
-              (menu_shell->activate_time == 0) ||
-              ((event->time - menu_shell->activate_time) > timeout))
-            gtk_menu_shell_activate_item (menu_shell, menu_item, TRUE);
+      menu_shell->button = 0;
+      menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent*) event);
 
-          /* activate_item will take care of deactivation if needed */
-          deactivate = FALSE;
-        }
-      else
+      if ((event->time - menu_shell->activate_time) > MENU_SHELL_TIMEOUT)
         {
-          /* If we ended up on an item with a submenu, leave the menu up. */
-          deactivate = FALSE;
+          if (menu_item && (menu_shell->active_menu_item == menu_item) &&
+              _gtk_menu_item_is_selectable (menu_item))
+            {
+              GtkWidget *submenu = GTK_MENU_ITEM (menu_item)->submenu;
 
-          /* popdown the submenu if we didn't pop it up in this click */
-          if (!priv->activated_submenu &&
-              GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
-            _gtk_menu_item_popdown_submenu (menu_item);
-        }
-    }
-  else if (menu_item &&
-           !_gtk_menu_item_is_selectable (menu_item) &&
-           GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
-    {
-      deactivate = FALSE;
-    }
-  else if (menu_shell->parent_menu_shell)
-    {
-      /* Forward to parent (deactivate, mostly) if we have one */
-      gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
+              if (submenu == NULL)
+                {
+#ifdef MAEMO_CHANGES
+                  if (!priv->first_click)
+#endif /* MAEMO_CHANGES */
+                  gtk_menu_shell_activate_item (menu_shell, menu_item, TRUE);
 
-      deactivate = FALSE;
-    }
-  else
-    {
-      /* Not over a menuitem of any kind, no parent shell, so deactivate. */
-      deactivate = TRUE;
-    }
+                  deactivate = FALSE;
+                }
+              else if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM ||
+                       priv->activated_submenu)
+                {
+                  gint popdown_delay;
+                  GTimeVal *popup_time;
+                  gint64 usec_since_popup = 0;
 
-  if (priv->first_click)
-    {
-      /* We only ever want to prevent deactivation on the first
-       * press/release. */
-      priv->first_click = FALSE;
+                  g_object_get (gtk_widget_get_settings (widget),
+                                "gtk-menu-popdown-delay", &popdown_delay,
+                                NULL);
 
-      deactivate = FALSE;
-    }
+                  popup_time = g_object_get_data (G_OBJECT (submenu),
+                                                  "gtk-menu-exact-popup-time");
 
-  if (deactivate)
-    {
-      gtk_menu_shell_deactivate (menu_shell);
-      g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
-    }
+                  if (popup_time)
+                    {
+                      GTimeVal current_time;
 
-  priv->activated_submenu = FALSE;
+                      g_get_current_time (&current_time);
 
-#else /* !MAEMO_CHANGES */
-  if (menu_shell->active)
-    {
-      if (menu_shell->button && (event->button != menu_shell->button))
-	{
-	  menu_shell->button = 0;
-	  if (menu_shell->parent_menu_shell)
-	    return gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
-	}
+                      usec_since_popup = ((gint64) current_time.tv_sec * 1000 * 1000 +
+                                          (gint64) current_time.tv_usec -
+                                          (gint64) popup_time->tv_sec * 1000 * 1000 -
+                                          (gint64) popup_time->tv_usec);
 
-      menu_shell->button = 0;
-      menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent*) event);
+                      g_object_set_data (G_OBJECT (submenu),
+                                         "gtk-menu-exact-popup-time", NULL);
+                    }
 
-      deactivate = TRUE;
+                  /*  only close the submenu on click if we opened the
+                   *  menu explicitely (usec_since_popup == 0) or
+                   *  enough time has passed since it was opened by
+                   *  GtkMenuItem's timeout (usec_since_popup > delay).
+                   */
+                  if (!priv->activated_submenu &&
+                      (usec_since_popup == 0 ||
+                       usec_since_popup > popdown_delay * 1000))
+                    {
+                      _gtk_menu_item_popdown_submenu (menu_item);
+                    }
+                  else
+                    {
+                      gtk_menu_item_select (GTK_MENU_ITEM (menu_item));
+                    }
 
-      if ((event->time - menu_shell->activate_time) > MENU_SHELL_TIMEOUT)
-	{
-	  if (menu_item && (menu_shell->active_menu_item == menu_item) &&
-	      _gtk_menu_item_is_selectable (menu_item))
-	    {
-	      if (GTK_MENU_ITEM (menu_item)->submenu == NULL)
-		{
-		  gtk_menu_shell_activate_item (menu_shell, menu_item, TRUE);
-		  return TRUE;
-		}
-	      else if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
-		{
-		  gtk_menu_item_select (GTK_MENU_ITEM (menu_item));
-		  return TRUE;
-		}
-	    }
-	  else if (menu_item &&
-		   !_gtk_menu_item_is_selectable (menu_item) &&
-		   GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
-	    {
-	      deactivate = FALSE;
-	    }
-	  else if (menu_shell->parent_menu_shell)
-	    {
-	      menu_shell->active = TRUE;
-	      gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
-	      return TRUE;
-	    }
+                  deactivate = FALSE;
+                }
+            }
+          else if (menu_item &&
+                   !_gtk_menu_item_is_selectable (menu_item) &&
+                   GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
+            {
+              deactivate = FALSE;
+            }
+          else if (menu_shell->parent_menu_shell)
+            {
+              menu_shell->active = TRUE;
+              gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event);
+              deactivate = FALSE;
+            }
 
-	  /* If we ended up on an item with a submenu, leave the menu up.
-	   */
-	  if (menu_item && (menu_shell->active_menu_item == menu_item) &&
-	      GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
-	    {
-	      deactivate = FALSE;
-	    }
-	}
+          /* If we ended up on an item with a submenu, leave the menu up.
+           */
+          if (menu_item && (menu_shell->active_menu_item == menu_item) &&
+              GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
+            {
+              deactivate = FALSE;
+            }
+        }
       else /* a very fast press-release */
-	{
-	  /* We only ever want to prevent deactivation on the first
+        {
+          /* We only ever want to prevent deactivation on the first
            * press/release. Setting the time to zero is a bit of a
-	   * hack, since we could be being triggered in the first
-	   * few fractions of a second after a server time wraparound.
-	   * the chances of that happening are ~1/10^6, without
-	   * serious harm if we lose.
-	   */
-	  menu_shell->activate_time = 0;
-	  deactivate = FALSE;
-	}
-      
+           * hack, since we could be being triggered in the first
+           * few fractions of a second after a server time wraparound.
+           * the chances of that happening are ~1/10^6, without
+           * serious harm if we lose.
+           */
+          menu_shell->activate_time = 0;
+          deactivate = FALSE;
+        }
+
+#ifdef MAEMO_CHANGES
+      if (priv->first_click)
+        {
+          /* We only ever want to prevent deactivation on the first
+           * press/release. */
+          priv->first_click = FALSE;
+
+          deactivate = FALSE;
+        }
+#endif /* MAEMO_CHANGES */
+
       if (deactivate)
-	{
-	  gtk_menu_shell_deactivate (menu_shell);
-	  g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
-	}
+        {
+          gtk_menu_shell_deactivate (menu_shell);
+          g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
+        }
+
+      priv->activated_submenu = FALSE;
     }
-#endif /* MAEMO_CHANGES */
 
   return TRUE;
 }
@@ -847,23 +814,17 @@
 gtk_menu_shell_enter_notify (GtkWidget        *widget,
 			     GdkEventCrossing *event)
 {
-#ifdef MAEMO_CHANGES
-  GtkMenuShellPrivate *priv;
-#endif /* MAEMO_CHANGES */
   GtkMenuShell *menu_shell;
-  GtkWidget *menu_item;
 
   g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
   menu_shell = GTK_MENU_SHELL (widget);
 
-#ifdef MAEMO_CHANGES
-  priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
-#endif /* MAEMO_CHANGES */
-
   if (menu_shell->active)
     {
+      GtkWidget *menu_item;
+
       menu_item = gtk_get_event_widget ((GdkEvent*) event);
 
       if (!menu_item ||
@@ -883,19 +844,26 @@
 	    {
 	      gtk_menu_shell_select_item (menu_shell, menu_item);
 
-#ifdef MAEMO_CHANGES
-              /* If the pen is down, and there is a submenu that is not
-               * yet visible, activate it
+              /* If any mouse button is down, and there is a submenu
+               * that is not yet visible, activate it. It's sufficient
+               * to check for any button's mask (not only the one
+               * matching menu_shell->button), because there is no
+               * situation a mouse button could be pressed while
+               * entering a menu item where we wouldn't want to show
+               * its submenu.
                */
-              if ((event->state & GDK_BUTTON1_MASK) &&
+              if ((event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON2_MASK)) &&
                   GTK_MENU_ITEM (menu_item)->submenu != NULL &&
                   !GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (menu_item)->submenu))
                 {
-                  gtk_menu_shell_activate_item (menu_shell, menu_item, FALSE);
+                  GtkMenuShellPrivate *priv;
 
+                  priv = GTK_MENU_SHELL_GET_PRIVATE (menu_item->parent);
+
+                  _gtk_menu_item_popup_submenu (menu_item, TRUE);
+
                   priv->activated_submenu = TRUE;
                 }
-#endif /* MAEMO_CHANGES */
 	    }
 	}
       else if (menu_shell->parent_menu_shell)
@@ -931,14 +899,8 @@
       if (!_gtk_menu_item_is_selectable (event_widget))
 	return TRUE;
 
-#ifdef MAEMO_CHANGES
       if ((menu_shell->active_menu_item == event_widget) &&
-          ((menu_item->submenu == NULL) ||
-           (!GTK_WIDGET_VISIBLE (menu_item->submenu))))
-#else
-      if ((menu_shell->active_menu_item == event_widget) &&
 	  (menu_item->submenu == NULL))
-#endif /* MAEMO_CHANGES */
 	{
 	  if ((event->detail != GDK_NOTIFY_INFERIOR) &&
 	      (GTK_WIDGET_STATE (menu_item) != GTK_STATE_NORMAL))
@@ -1140,13 +1102,11 @@
 				  GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement);
   gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item));
 
-#ifndef MAEMO_CHANGES
   /* This allows the bizarre radio buttons-with-submenus-display-history
    * behavior
    */
   if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu)
     gtk_widget_activate (menu_shell->active_menu_item);
-#endif /* !MAEMO_CHANGES */
 }
 
 void
@@ -1168,9 +1128,6 @@
 {
   GSList *slist, *shells = NULL;
   gboolean deactivate = force_deactivate;
-#ifdef MAEMO_CHANGES
-  gboolean submenu = FALSE;
-#endif /* MAEMO_CHANGES */
 
   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
@@ -1181,16 +1138,7 @@
   g_object_ref (menu_shell);
   g_object_ref (menu_item);
 
-#ifdef MAEMO_CHANGES
-  if (GTK_MENU_ITEM (menu_item)->submenu != NULL)
-    submenu = TRUE;
-#endif /* MAEMO_CHANGES */
-
-#ifdef MAEMO_CHANGES
-  if (deactivate && !submenu)
-#else
   if (deactivate)
-#endif /* MAEMO_CHANGES */
     {
       GtkMenuShell *parent_menu_shell = menu_shell;
 
@@ -1210,29 +1158,15 @@
        */
       gdk_display_sync (gtk_widget_get_display (menu_item));
     }
-#ifdef MAEMO_CHANGES
-  else if (submenu)
-    {
-      _gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_item),
-                                    GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement);
-    }
-#endif /* MAEMO_CHANGES */
 
   gtk_widget_activate (menu_item);
 
-#ifdef MAEMO_CHANGES
-  if (!submenu)
-    {
-#endif /* MAEMO_CHANGES */
   for (slist = shells; slist; slist = slist->next)
     {
       g_signal_emit (slist->data, menu_shell_signals[SELECTION_DONE], 0);
       g_object_unref (slist->data);
     }
   g_slist_free (shells);
-#ifdef MAEMO_CHANGES
-    }
-#endif /* MAEMO_CHANGES */
 
   g_object_unref (menu_shell);
   g_object_unref (menu_item);
@@ -1372,11 +1306,7 @@
   
   if (menu_item->submenu)
     {
-#ifdef MAEMO_CHANGES
-      gtk_menu_shell_activate_item (menu_shell, GTK_WIDGET (menu_item), FALSE);
-#else
-      _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item));
-#endif /* MAEMO_CHANGES */
+      _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), FALSE);
       gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
       if (GTK_MENU_SHELL (menu_item->submenu)->active_menu_item)
 	return TRUE;
@@ -1386,8 +1316,8 @@
 }
 
 static void
-gtk_real_menu_shell_move_current (GtkMenuShell      *menu_shell,
-				  GtkMenuDirectionType direction)
+gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
+				  GtkMenuDirectionType  direction)
 {
   GtkMenuShell *parent_menu_shell = NULL;
   gboolean had_selection;
@@ -1400,21 +1330,21 @@
   switch (direction)
     {
     case GTK_MENU_DIR_PARENT:
+      if (parent_menu_shell)
+	{
+          gboolean touchscreen_mode;
 
-#ifdef MAEMO_CHANGES
-      if(!parent_menu_shell || GTK_IS_MENU_BAR (parent_menu_shell))
-        break;
+          g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
+                        "gtk-touchscreen-mode", &touchscreen_mode,
+                        NULL);
 
-      /* menu should be closed when returning from submenu.
-       * WARNING: This function is from GtkMenu, which normally
-       * shouldn't be called from GtkMenuShell, but currently
-       * there are no better alternatives.
-       */
-      gtk_menu_popdown (GTK_MENU (menu_shell));
-#endif /* MAEMO_CHANGES */
+          if (touchscreen_mode)
+            {
+              /* close menu when returning from submenu. */
+              _gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->parent_menu_item);
+              break;
+            }
 
-      if (parent_menu_shell)
-	{
 	  if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
               GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
 	    gtk_menu_shell_deselect (menu_shell);
@@ -1496,16 +1426,12 @@
   if (menu_shell->active_menu_item &&
       _gtk_menu_item_is_selectable (menu_shell->active_menu_item))
   {
-#ifndef MAEMO_CHANGES
     if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
-#endif /* !MAEMO_CHANGES */
       gtk_menu_shell_activate_item (menu_shell,
 				    menu_shell->active_menu_item,
 				    force_hide);
-#ifndef MAEMO_CHANGES
     else
-      _gtk_menu_item_popup_submenu (menu_shell->active_menu_item);
-#endif /* !MAEMO_CHANGES */
+      _gtk_menu_item_popup_submenu (menu_shell->active_menu_item, FALSE);
   }
 }
 


More information about the maemo-commits mailing list