--- gtk+-2.6.4/gtk/gtkmenushell.c	2005-02-09 18:46:54.000000000 +0200
+++ gtk+-2.6.4/gtk/gtkmenushell.c	2005-04-06 16:19:36.999913520 +0300
@@ -39,6 +39,8 @@
 #include "gtkmnemonichash.h"
 #include "gtktearoffmenuitem.h"
 #include "gtkwindow.h"
+#include "gtkprivate.h"
+#include "gtkintl.h"
 
 #define MENU_SHELL_TIMEOUT   500
 
@@ -52,6 +54,11 @@
   LAST_SIGNAL
 };
 
+enum {
+  PROP_0,
+  PROP_TAKE_FOCUS
+};
+
 typedef void (*GtkMenuShellSignal1) (GtkObject           *object,
 				     GtkMenuDirectionType arg1,
 				     gpointer             data);
@@ -122,10 +129,20 @@
 {
   GtkMnemonicHash *mnemonic_hash;
   GtkKeyHash *key_hash;
+  gboolean activated_submenu;
+  gboolean take_focus;
 };
 
 static void gtk_menu_shell_class_init        (GtkMenuShellClass *klass);
 static void gtk_menu_shell_init              (GtkMenuShell      *menu_shell);
+static void gtk_menu_shell_set_property      (GObject           *object,
+                                               guint              prop_id,
+                                               const GValue      *value,
+                                               GParamSpec        *pspec);
+static void gtk_menu_shell_get_property      (GObject           *object,
+                                               guint              prop_id,
+                                               GValue            *value,
+                                               GParamSpec        *pspec);
 static void gtk_menu_shell_realize           (GtkWidget         *widget);
 static void gtk_menu_shell_finalize          (GObject           *object);
 static gint gtk_menu_shell_button_press      (GtkWidget         *widget,
@@ -176,7 +193,6 @@
 static GtkContainerClass *parent_class = NULL;
 static guint menu_shell_signals[LAST_SIGNAL] = { 0 };
 
-
 GType
 gtk_menu_shell_get_type (void)
 {
@@ -220,6 +236,8 @@
   container_class = (GtkContainerClass*) klass;
 
   parent_class = g_type_class_peek_parent (klass);
+  object_class->set_property = gtk_menu_shell_set_property;
+  object_class->get_property = gtk_menu_shell_get_property;
 
   object_class->finalize = gtk_menu_shell_finalize;
 
@@ -299,9 +317,15 @@
 
 
   binding_set = gtk_binding_set_by_class (klass);
+/* Hildon : The following binding is commented out
+ * because we want the Escape key to only exit the
+ * currently opened submenu. Therefore, the handling
+ * of esc-key will be moved to gtkmenuitem.c */
+/*
   gtk_binding_entry_add_signal (binding_set,
 				GDK_Escape, 0,
 				"cancel", 0);
+*/
   gtk_binding_entry_add_signal (binding_set,
 				GDK_Return, 0,
 				"activate_current", 1,
@@ -330,7 +354,23 @@
 				GDK_F10, GDK_SHIFT_MASK,
 				"cycle_focus", 1,
                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
-
+  /**
+   * GtkMenuShell:take-focus:
+   *
+   * A boolean that determines whether the menu and its submenus grab the
+   * keyboard focus. See gtk_menu_shell_set_take_focus() and
+   * gtk_menu_shell_get_take_focus().
+   *
+   * Since: 2.8
+   **/
+  g_object_class_install_property (object_class,
+		  		   PROP_TAKE_FOCUS,
+				   g_param_spec_boolean ("take-focus",
+					   		 P_("Take Focus"),
+							 P_("A boolean that determines whether the menu grabs the keyboard focus"),
+							 TRUE,
+							 G_PARAM_READWRITE));
+  
   g_type_class_add_private (object_class, sizeof (GtkMenuShellPrivate));
 }
 
@@ -356,6 +396,46 @@
 
   priv->mnemonic_hash = NULL;
   priv->key_hash = NULL;
+  priv->take_focus = TRUE;
+  priv->activated_submenu = FALSE;
+}
+
+static void
+gtk_menu_shell_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GtkMenuShell *menu_shell = GTK_MENU_SHELL (object);
+
+  switch (prop_id)
+    {
+    case PROP_TAKE_FOCUS:
+      gtk_menu_shell_set_take_focus (menu_shell, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_menu_shell_get_property (GObject     *object,
+                             guint        prop_id,
+                             GValue      *value,
+                             GParamSpec  *pspec)
+{
+  GtkMenuShell *menu_shell = GTK_MENU_SHELL (object);
+
+  switch (prop_id)
+    {
+    case PROP_TAKE_FOCUS:
+      g_value_set_boolean (value, gtk_menu_shell_get_take_focus (menu_shell));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
 }
 
 static void
@@ -470,6 +550,7 @@
 gtk_menu_shell_button_press (GtkWidget      *widget,
 			     GdkEventButton *event)
 {
+  GtkMenuShellPrivate *priv;
   GtkMenuShell *menu_shell;
   GtkWidget *menu_item;
 
@@ -479,7 +560,22 @@
   if (event->type != GDK_BUTTON_PRESS)
     return FALSE;
 
+  priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
+
   menu_shell = GTK_MENU_SHELL (widget);
+  menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent*) event);
+
+  if (menu_shell->active && menu_item &&
+      (menu_shell->active_menu_item == 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 : We want to be able to activate submenu items. */
+      gtk_menu_shell_activate_item (menu_shell, menu_item, FALSE);
+
+      priv->activated_submenu = TRUE;
+    }
 
   if (menu_shell->parent_menu_shell)
     {
@@ -491,30 +587,29 @@
       
       menu_shell->button = event->button;
 
-      menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent *)event);
-
       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;
-		}
+	      {
+
+	        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);
-	    }
-	}
+	             gtk_menu_shell_select_item (menu_shell, menu_item);
+	           }
+	      }
     }
   else
     {
       widget = gtk_get_event_widget ((GdkEvent*) event);
       if (widget == GTK_WIDGET (menu_shell))
-	{
-	  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);
+	      }
     }
 
   return TRUE;
@@ -524,13 +619,20 @@
 gtk_menu_shell_button_release (GtkWidget      *widget,
 			       GdkEventButton *event)
 {
+  GtkMenuShellPrivate *priv;
   GtkMenuShell *menu_shell;
   GtkWidget *menu_item;
   gint deactivate;
+  gboolean activated_submenu;
 
   g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
+  priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
+
+  activated_submenu = priv->activated_submenu;
+  priv->activated_submenu = FALSE;
+
   menu_shell = GTK_MENU_SHELL (widget);
   if (menu_shell->active)
     {
@@ -556,11 +658,11 @@
 		  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 (!activated_submenu)
+                {
+                  /* popdown the submenu if we didn't pop it up in this click */
+                  _gtk_menu_item_popdown_submenu (menu_item);
+                }
 	    }
 	  else if (menu_item &&
 		   !_gtk_menu_item_is_selectable (menu_item) &&
@@ -630,12 +732,14 @@
 gtk_menu_shell_enter_notify (GtkWidget        *widget,
 			     GdkEventCrossing *event)
 {
+  GtkMenuShellPrivate *priv;
   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);
 
+  priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
   menu_shell = GTK_MENU_SHELL (widget);
 
   if (menu_shell->active)
@@ -658,6 +762,17 @@
 	      (GTK_WIDGET_STATE (menu_item) != GTK_STATE_PRELIGHT))
 	    {
 	      gtk_menu_shell_select_item (menu_shell, menu_item);
+              
+              /* If the pen is down, and there is a submenu that is not
+               * yet visible, activate it */
+              if ((event->state & GDK_BUTTON1_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);
+
+                  priv->activated_submenu = TRUE;
+                }
 	    }
 	}
       else if (menu_shell->parent_menu_shell)
@@ -887,8 +1002,14 @@
   /* This allows the bizarre radio buttons-with-submenus-display-history
    * behavior
    */
+  /* Hildon modification. We probably won't have those
+   * bizarre radio buttons-with-submenus so we don't
+   * need this. Also, this functionality interferes with
+   * other functionality. */
+/*
   if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu)
     gtk_widget_activate (menu_shell->active_menu_item);
+*/
 }
 
 void
@@ -919,7 +1040,9 @@
 
   g_object_ref (menu_shell);
 
-  if (deactivate)
+  /* We don't want to deactivate if we're activating
+   * a submenu item. */
+  if ((deactivate) && (GTK_MENU_ITEM (menu_item)->submenu == NULL))
     {
       GtkMenuShell *parent_menu_shell = menu_shell;
 
@@ -965,29 +1088,30 @@
       
       if (distance > 0)
 	{
+	  /*Hildon: selection no longer wraps around at the
+	  *bottom of the menu*/
+
 	  node = node->next;
-	  while (node != start_node && 
-		 (!node || !_gtk_menu_item_is_selectable (node->data)))
+	  while (node && node != start_node && 
+		 !_gtk_menu_item_is_selectable (node->data))
 	    {
-	      if (!node)
-		node = menu_shell->children;
-	      else
 		node = node->next;
 	    }
 	}
       else
 	{
+	  /*Hildon: selection no longer wraps around at the top
+	  *of the menu*/
+
 	  node = node->prev;
-	  while (node != start_node &&
-		 (!node || !_gtk_menu_item_is_selectable (node->data)))
+	  while (node && node != start_node &&
+		 !_gtk_menu_item_is_selectable (node->data))
 	    {
-	      if (!node)
-		node = g_list_last (menu_shell->children);
-	      else
 		node = node->prev;
 	    }
 	}
       
+      /*note: gtk_menu_shell_select_item won't select non-selectable items*/
       if (node)
 	gtk_menu_shell_select_item (menu_shell, node->data);
     }
@@ -1119,6 +1243,16 @@
   switch (direction)
     {
     case GTK_MENU_DIR_PARENT:
+
+      if(!parent_menu_shell || GTK_IS_MENU_BAR(parent_menu_shell))
+        break;
+
+      /* hildon-modification - 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));
+
       if (parent_menu_shell)
 	{
 	  if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement == 
@@ -1151,10 +1285,14 @@
 	  _gtk_menu_item_is_selectable (menu_shell->active_menu_item) &&
 	  GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu)
 	{
+          /* Hildon-modification -- submenu is not opened automatically but needs to be explicitly opened*/
+ 	  g_signal_emit (G_OBJECT (menu_shell), menu_shell_signals[ACTIVATE_CURRENT], 0, (gint) FALSE);
+
 	  if (gtk_menu_shell_select_submenu_first (menu_shell))
 	    break;
 	}
 
+#if 0
       /* Try to find a menu running the opposite direction */
       while (parent_menu_shell && 
 	     (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
@@ -1173,6 +1311,7 @@
 	  gtk_menu_shell_move_selected (parent_menu_shell, 1);
 	  gtk_menu_shell_select_submenu_first (parent_menu_shell);
 	}
+#endif
       break;
       
     case GTK_MENU_DIR_PREV:
@@ -1197,8 +1336,8 @@
 gtk_real_menu_shell_activate_current (GtkMenuShell      *menu_shell,
 				      gboolean           force_hide)
 {
-  if (menu_shell->active_menu_item &&
-      _gtk_menu_item_is_selectable (menu_shell->active_menu_item))
+  if (menu_shell->active_menu_item)/* &&
+      _gtk_menu_item_is_selectable (menu_shell->active_menu_item)) */
   {
    
     if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
@@ -1390,4 +1529,73 @@
 			     keyval, target);
   gtk_menu_shell_reset_key_hash (menu_shell);
 }
+/**
+ * gtk_menu_shell_get_take_focus:
+ * @menu: a #GtkMenuShell
+ *
+ * @returns: %TRUE if the menu_shell will take the keyboard focus on popup.
+ *
+ * Since: 2.8
+ **/
+gboolean
+gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell)
+{
+  GtkMenuShellPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
+
+  priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+  return priv->take_focus;
+}
+
+/**
+ * gtk_menu_shell_set_take_focus:
+ * @menu: a #GtkMenuShell
+ * @take_focus: %TRUE if the menu_shell should take the keyboard focus on popup.
+ *
+ * If @take_focus is %TRUE (the default) the menu will take the keyboard focus
+ * so that it will receive all keyboard events which is needed to enable
+ * keyboard navigation in menus.
+ *
+ * Setting @take_focus to %FALSE is useful only for special applications
+ * like virtual keyboard implementations which should not take keyboard
+ * focus.
+ *
+ * The @take_focus state of a menu or menu bar is automatically propagated
+ * to submenus whenever a submenu is popped up, so you don't have to worry
+ * about recursively setting it for your entire menu hierarchy. Only when
+ * programmatically picking a submenu and popping it up manually, the
+ * @take_focus property of the submenu needs to be set explicitely.
+ *
+ * Note that setting it to %FALSE has side-effects:
+ *
+ * If the focus is in some other app, it keeps the focus and keynav in
+ * the menu doesn't work. Consequently, keynav on the menu will only
+ * work if the focus is on some toplevel owned by the onscreen keyboard.
+ *
+ * To avoid confusing the user, menus with @take_focus set to %FALSE
+ * should not display mnemonics or accelerators, since it cannot be
+ * guaranteed that they will work.
+ *
+ * See also gdk_keyboard_grab()
+ *
+ * Since: 2.8
+ **/
+void
+gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell,
+                               gboolean      take_focus)
+{
+  GtkMenuShellPrivate *priv;
+
+  g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+
+  priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+  if (priv->take_focus != take_focus)
+    {
+      priv->take_focus = take_focus;
+      g_object_notify (G_OBJECT (menu_shell), "take-focus");
+    }
+}