]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmenuitem.c
new default color scheme based on the GNOME stock icon palette. (#80691,
[~andy/gtk] / gtk / gtkmenuitem.c
index 0589ba18b6a4db0e095a49a96430ddb6aa76d51d..9e774940b4679249f2330b54953f42043c6b6e4a 100644 (file)
 #include "gtkmenubar.h"
 #include "gtkmenuitem.h"
 #include "gtkseparatormenuitem.h"
-#include "gtksignal.h"
 
 
 #define BORDER_SPACING  3
-#define SELECT_TIMEOUT  75
 
 #define MENU_ITEM_CLASS(w)  GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
 
@@ -99,14 +97,11 @@ 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;
 
-
-
-GtkType
+GType
 gtk_menu_item_get_type (void)
 {
-  static GtkType menu_item_type = 0;
+  static GType menu_item_type = 0;
 
   if (!menu_item_type)
     {
@@ -123,7 +118,8 @@ gtk_menu_item_get_type (void)
        (GInstanceInitFunc) gtk_menu_item_init,
       };
 
-      menu_item_type = g_type_register_static (GTK_TYPE_ITEM, "GtkMenuItem", &menu_item_info, 0);
+      menu_item_type = g_type_register_static (GTK_TYPE_ITEM, "GtkMenuItem",
+                                              &menu_item_info, 0);
     }
 
   return menu_item_type;
@@ -169,46 +165,50 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
   klass->hide_on_activate = TRUE;
 
   menu_item_signals[ACTIVATE] =
-    gtk_signal_new ("activate",
-                    GTK_RUN_FIRST | GTK_RUN_ACTION,
-                    GTK_CLASS_TYPE (object_class),
-                    GTK_SIGNAL_OFFSET (GtkMenuItemClass, activate),
-                    _gtk_marshal_VOID__VOID,
-                   GTK_TYPE_NONE, 0);
+    g_signal_new ("activate",
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkMenuItemClass, activate),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
   widget_class->activate_signal = menu_item_signals[ACTIVATE];
 
   menu_item_signals[ACTIVATE_ITEM] =
-    gtk_signal_new ("activate_item",
-                    GTK_RUN_FIRST,
-                    GTK_CLASS_TYPE (object_class),
-                    GTK_SIGNAL_OFFSET (GtkMenuItemClass, activate_item),
-                    gtk_signal_default_marshaller,
-                   GTK_TYPE_NONE, 0);
+    g_signal_new ("activate_item",
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
 
   menu_item_signals[TOGGLE_SIZE_REQUEST] =
-    gtk_signal_new ("toggle_size_request",
-                    GTK_RUN_FIRST,
-                    GTK_CLASS_TYPE (object_class),
-                    GTK_SIGNAL_OFFSET (GtkMenuItemClass, toggle_size_request),
-                    _gtk_marshal_VOID__POINTER,
-                   GTK_TYPE_NONE, 1,
-                   GTK_TYPE_POINTER);
+    g_signal_new ("toggle_size_request",
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__POINTER,
+                 G_TYPE_NONE, 1,
+                 G_TYPE_POINTER);
 
   menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
-    gtk_signal_new ("toggle_size_allocate",
-                    GTK_RUN_FIRST,
-                    GTK_CLASS_TYPE (object_class),
-                    GTK_SIGNAL_OFFSET (GtkMenuItemClass, toggle_size_allocate),
-                    _gtk_marshal_NONE__INT,
-                   GTK_TYPE_NONE, 1,
-                   GTK_TYPE_INT);
+    g_signal_new ("toggle_size_allocate",
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
+                 NULL, NULL,
+                 _gtk_marshal_NONE__INT,
+                 G_TYPE_NONE, 1,
+                 G_TYPE_INT);
 
   gtk_widget_class_install_style_property_parser (widget_class,
                                                  g_param_spec_enum ("selected_shadow_type",
                                                                     "Selected Shadow Type",
                                                                     "Shadow type when item is selected",
                                                                     GTK_TYPE_SHADOW_TYPE,
-                                                                    GTK_SHADOW_OUT,
+                                                                    GTK_SHADOW_NONE,
                                                                     G_PARAM_READABLE),
                                                  gtk_rc_property_parse_enum);
 }
@@ -222,7 +222,10 @@ gtk_menu_item_init (GtkMenuItem *menu_item)
   menu_item->toggle_size = 0;
   menu_item->accelerator_width = 0;
   menu_item->show_submenu_indicator = FALSE;
-  menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
+  if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
+    menu_item->submenu_direction = GTK_DIRECTION_LEFT;
+  else
+    menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
   menu_item->submenu_placement = GTK_TOP_BOTTOM;
   menu_item->right_justify = FALSE;
 
@@ -232,7 +235,7 @@ gtk_menu_item_init (GtkMenuItem *menu_item)
 GtkWidget*
 gtk_menu_item_new (void)
 {
-  return GTK_WIDGET (gtk_type_new (gtk_menu_item_get_type ()));
+  return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
 }
 
 GtkWidget*
@@ -270,7 +273,7 @@ gtk_menu_item_new_with_mnemonic (const gchar *label)
   GtkWidget *accel_label;
 
   menu_item = gtk_menu_item_new ();
-  accel_label = gtk_type_new (GTK_TYPE_ACCEL_LABEL);
+  accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
   gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
 
@@ -399,7 +402,7 @@ gtk_menu_item_activate (GtkMenuItem *menu_item)
 {
   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
   
-  gtk_signal_emit (GTK_OBJECT (menu_item), menu_item_signals[ACTIVATE]);
+  g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
 }
 
 void
@@ -408,7 +411,7 @@ gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
 {
   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
 
-  gtk_signal_emit (GTK_OBJECT (menu_item), menu_item_signals[TOGGLE_SIZE_REQUEST], requisition);
+  g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
 }
 
 void
@@ -417,7 +420,7 @@ gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
 {
   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
 
-  gtk_signal_emit (GTK_OBJECT (menu_item), menu_item_signals[TOGGLE_SIZE_ALLOCATE], allocation);
+  g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
 }
 
 static void
@@ -486,6 +489,7 @@ gtk_menu_item_size_allocate (GtkWidget     *widget,
   GtkMenuItem *menu_item;
   GtkBin *bin;
   GtkAllocation child_allocation;
+  GtkTextDirection direction;
 
   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
   g_return_if_fail (allocation != NULL);
@@ -493,6 +497,8 @@ gtk_menu_item_size_allocate (GtkWidget     *widget,
   menu_item = GTK_MENU_ITEM (widget);
   bin = GTK_BIN (widget);
   
+  direction = gtk_widget_get_direction (widget);
+
   widget->allocation = *allocation;
 
   if (bin->child)
@@ -506,15 +512,20 @@ gtk_menu_item_size_allocate (GtkWidget     *widget,
                            widget->style->ythickness);
       child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
-      child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
+      if (direction == GTK_TEXT_DIR_LTR)
+       child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
       child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
       child_allocation.x += widget->allocation.x;
       child_allocation.y += widget->allocation.y;
 
       gtk_widget_get_child_requisition (bin->child, &child_requisition);
-      if (menu_item->submenu && menu_item->show_submenu_indicator)
-       child_allocation.width -= child_requisition.height;
-
+      if (menu_item->submenu && menu_item->show_submenu_indicator) 
+       {
+         if (direction == GTK_TEXT_DIR_RTL)
+           child_allocation.x += child_requisition.height;
+         child_allocation.width -= child_requisition.height;
+       }
+      
       if (child_allocation.width < 1)
        child_allocation.width = 1;
 
@@ -540,7 +551,7 @@ gtk_menu_item_realize (GtkWidget *widget)
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
   widget->window = gtk_widget_get_parent_window (widget);
-  gdk_window_ref (widget->window);
+  g_object_ref (widget->window);
   
   attributes.x = widget->allocation.x;
   attributes.y = widget->allocation.y;
@@ -612,7 +623,7 @@ gtk_menu_item_paint (GtkWidget    *widget,
       menu_item = GTK_MENU_ITEM (widget);
 
       state_type = widget->state;
-
+      
       x = widget->allocation.x + border_width;
       y = widget->allocation.y + border_width;
       width = widget->allocation.width - border_width * 2;
@@ -638,7 +649,11 @@ gtk_menu_item_paint (GtkWidget    *widget,
          gint arrow_x, arrow_y;
          gint arrow_size;
          gint arrow_extent;
+         GtkTextDirection direction;
+         GtkArrowType arrow_type;
 
+         direction = gtk_widget_get_direction (widget);
+      
          gtk_widget_get_child_requisition (GTK_BIN (menu_item)->child,
                                            &child_requisition);
 
@@ -649,13 +664,21 @@ gtk_menu_item_paint (GtkWidget    *widget,
          if (state_type == GTK_STATE_PRELIGHT)
            shadow_type = GTK_SHADOW_IN;
 
-         arrow_x = x + width - 1 - arrow_size + (arrow_size - arrow_extent) / 2;
+         if (direction == GTK_TEXT_DIR_LTR) {
+           arrow_x = x + width - 1 - arrow_size + (arrow_size - arrow_extent) / 2;
+           arrow_type = GTK_ARROW_RIGHT;
+         }
+         else {
+           arrow_x = x + 1 + (arrow_size - arrow_extent) / 2;
+           arrow_type = GTK_ARROW_LEFT;
+         }
+
          arrow_y = y + (height - arrow_extent) / 2;
 
          gtk_paint_arrow (widget->style, widget->window,
                           state_type, shadow_type, 
                           area, widget, "menuitem", 
-                          GTK_ARROW_RIGHT, TRUE,
+                          arrow_type, TRUE,
                           arrow_x, arrow_y,
                           arrow_extent, arrow_extent);
        }
@@ -686,6 +709,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)
 {
@@ -695,32 +739,34 @@ 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;
 
-      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);
@@ -738,9 +784,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);
@@ -748,12 +791,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);
@@ -773,7 +810,7 @@ gtk_menu_item_mnemonic_activate (GtkWidget *widget,
 
     }
   else
-    gtk_signal_emit (GTK_OBJECT (widget), menu_item_signals[ACTIVATE_ITEM]);
+    g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
   
   return TRUE;
 }
@@ -854,21 +891,24 @@ gtk_menu_item_select_timeout (gpointer data)
 static void
 gtk_menu_item_popup_submenu (gpointer data)
 {
+  GtkWidget *widget;
   GtkMenuItem *menu_item;
 
-  menu_item = GTK_MENU_ITEM (data);
+  widget = GTK_WIDGET (data);
+  menu_item = GTK_MENU_ITEM (widget);
+
+  if (menu_item->timer)
+    gtk_timeout_remove (menu_item->timer);
   menu_item->timer = 0;
 
   if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
-    {
-      gtk_menu_popup (GTK_MENU (menu_item->submenu),
-                     GTK_WIDGET (menu_item)->parent,
-                     GTK_WIDGET (menu_item),
-                     gtk_menu_item_position_menu,
-                     menu_item,
-                     GTK_MENU_SHELL (GTK_WIDGET (menu_item)->parent)->button,
-                     0);
-    }
+    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);
 }
 
 static void
@@ -886,6 +926,7 @@ gtk_menu_item_position_menu (GtkMenu  *menu,
   gint screen_height;
   gint twidth, theight;
   gint tx, ty;
+  GtkTextDirection direction;
 
   g_return_if_fail (menu != NULL);
   g_return_if_fail (x != NULL);
@@ -894,6 +935,8 @@ gtk_menu_item_position_menu (GtkMenu  *menu,
   menu_item = GTK_MENU_ITEM (user_data);
   widget = GTK_WIDGET (user_data);
 
+  direction = gtk_widget_get_direction (widget);
+
   twidth = GTK_WIDGET (menu)->requisition.width;
   theight = GTK_WIDGET (menu)->requisition.height;
 
@@ -913,6 +956,14 @@ gtk_menu_item_position_menu (GtkMenu  *menu,
   switch (menu_item->submenu_placement)
     {
     case GTK_TOP_BOTTOM:
+      if (direction == GTK_TEXT_DIR_LTR)
+       menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
+      else 
+       {
+         menu_item->submenu_direction = GTK_DIRECTION_LEFT;
+         tx += widget->allocation.width - twidth;
+       }
+
       if ((ty + widget->allocation.height + theight) <= screen_height)
        ty += widget->allocation.height;
       else if ((ty - theight) >= 0)
@@ -924,10 +975,15 @@ gtk_menu_item_position_menu (GtkMenu  *menu,
       break;
 
     case GTK_LEFT_RIGHT:
-      menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
       parent_menu_item = GTK_MENU (widget->parent)->parent_menu_item;
-      if (parent_menu_item)
+      if (parent_menu_item && 
+         !GTK_MENU (widget->parent)->torn_off && 
+         !GTK_MENU_SHELL (menu)->active)
        menu_item->submenu_direction = GTK_MENU_ITEM (parent_menu_item)->submenu_direction;
+      else if (direction == GTK_TEXT_DIR_LTR)
+       menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
+      else
+       menu_item->submenu_direction = GTK_DIRECTION_LEFT;
 
       switch (menu_item->submenu_direction)
        {
@@ -1143,6 +1199,9 @@ _gtk_menu_item_refresh_accel_path (GtkMenuItem   *menu_item,
  * This function is basically a convenience wrapper that handles calling
  * gtk_widget_set_accel_path() with the appropriate accelerator group for
  * the menu item.
+ *
+ * Note that you do need to set an accelerator on the parent menu with
+ * gtk_menu_set_accel_group() for this to work.
  */
 void
 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,