]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkoptionmenu.c
set RECEIVES_DEFAULT on init, and a button press on the widget doesn't
[~andy/gtk] / gtk / gtkoptionmenu.c
index 4b3f798cb082b7bd09624496ec818ec2c640fbef..bf42d863e8d27c959783c53029a8747386ef5b5f 100644 (file)
@@ -20,6 +20,7 @@
 #include "gtkmenuitem.h"
 #include "gtkoptionmenu.h"
 #include "gtksignal.h"
+#include "gdk/gdkkeysyms.h"
 
 
 #define CHILD_LEFT_SPACING        5
@@ -46,6 +47,8 @@ static gint gtk_option_menu_expose          (GtkWidget          *widget,
                                             GdkEventExpose     *event);
 static gint gtk_option_menu_button_press    (GtkWidget          *widget,
                                             GdkEventButton     *event);
+static gint gtk_option_menu_key_press      (GtkWidget          *widget,
+                                            GdkEventKey        *event);
 static void gtk_option_menu_deactivate      (GtkMenuShell       *menu_shell,
                                             GtkOptionMenu      *option_menu);
 static void gtk_option_menu_update_contents (GtkOptionMenu      *option_menu);
@@ -57,27 +60,30 @@ static void gtk_option_menu_position        (GtkMenu            *menu,
                                             gpointer            user_data);
 static void gtk_option_menu_show_all        (GtkWidget          *widget);
 static void gtk_option_menu_hide_all        (GtkWidget          *widget);
+static GtkType gtk_option_menu_child_type   (GtkContainer       *container);
 
+                                      
 
 static GtkButtonClass *parent_class = NULL;
 
 
-guint
+GtkType
 gtk_option_menu_get_type (void)
 {
-  static guint option_menu_type = 0;
+  static GtkType option_menu_type = 0;
 
   if (!option_menu_type)
     {
-      GtkTypeInfo option_menu_info =
+      static const GtkTypeInfo option_menu_info =
       {
        "GtkOptionMenu",
        sizeof (GtkOptionMenu),
        sizeof (GtkOptionMenuClass),
        (GtkClassInitFunc) gtk_option_menu_class_init,
        (GtkObjectInitFunc) gtk_option_menu_init,
-       (GtkArgSetFunc) NULL,
-        (GtkArgGetFunc) NULL,
+       /* reserved_1 */ NULL,
+        /* reserved_2 */ NULL,
+        (GtkClassInitFunc) NULL,
       };
 
       option_menu_type = gtk_type_unique (gtk_button_get_type (), &option_menu_info);
@@ -92,29 +98,40 @@ gtk_option_menu_class_init (GtkOptionMenuClass *class)
   GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkButtonClass *button_class;
+  GtkContainerClass *container_class;
 
   object_class = (GtkObjectClass*) class;
   widget_class = (GtkWidgetClass*) class;
   button_class = (GtkButtonClass*) class;
+  container_class = (GtkContainerClass*) class;
 
   parent_class = gtk_type_class (gtk_button_get_type ());
 
   object_class->destroy = gtk_option_menu_destroy;
 
   widget_class->draw = gtk_option_menu_draw;
-  widget_class->draw_focus = NULL;
   widget_class->size_request = gtk_option_menu_size_request;
   widget_class->size_allocate = gtk_option_menu_size_allocate;
   widget_class->expose_event = gtk_option_menu_expose;
   widget_class->button_press_event = gtk_option_menu_button_press;
+  widget_class->key_press_event = gtk_option_menu_key_press;
   widget_class->show_all = gtk_option_menu_show_all;
   widget_class->hide_all = gtk_option_menu_hide_all;
+
+  container_class->child_type = gtk_option_menu_child_type;
+}
+
+static GtkType
+gtk_option_menu_child_type (GtkContainer       *container)
+{
+  return GTK_TYPE_NONE;
 }
 
 static void
 gtk_option_menu_init (GtkOptionMenu *option_menu)
 {
-  GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_FOCUS);
+  GTK_WIDGET_SET_FLAGS (option_menu, GTK_CAN_FOCUS);
+  GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT);
 
   option_menu->menu = NULL;
   option_menu->menu_item = NULL;
@@ -255,11 +272,11 @@ gtk_option_menu_size_request (GtkWidget      *widget,
                        option_menu->width +
                        OPTION_INDICATOR_WIDTH +
                        OPTION_INDICATOR_SPACING * 5 +
-                       CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING);
+                       CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING + 2);
   requisition->height = ((GTK_CONTAINER (widget)->border_width +
                          GTK_WIDGET (widget)->style->klass->ythickness) * 2 +
                         option_menu->height +
-                        CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING);
+                        CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING + 2);
 
   tmp = (requisition->height - option_menu->height +
         OPTION_INDICATOR_HEIGHT + OPTION_INDICATOR_SPACING * 2);
@@ -283,18 +300,18 @@ gtk_option_menu_size_allocate (GtkWidget     *widget,
                            allocation->x, allocation->y,
                            allocation->width, allocation->height);
 
-  child = GTK_BUTTON (widget)->child;
+  child = GTK_BIN (widget)->child;
   if (child && GTK_WIDGET_VISIBLE (child))
     {
       child_allocation.x = (GTK_CONTAINER (widget)->border_width +
-                           GTK_WIDGET (widget)->style->klass->xthickness);
+                           GTK_WIDGET (widget)->style->klass->xthickness) + 1;
       child_allocation.y = (GTK_CONTAINER (widget)->border_width +
-                           GTK_WIDGET (widget)->style->klass->ythickness);
+                           GTK_WIDGET (widget)->style->klass->ythickness) + 1;
       child_allocation.width = (allocation->width - child_allocation.x * 2 -
                                OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 5 -
-                               CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING);
+                               CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING) - 2;
       child_allocation.height = (allocation->height - child_allocation.y * 2 -
-                                CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING);
+                                CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING) - 2;
       child_allocation.x += CHILD_LEFT_SPACING;
       child_allocation.y += CHILD_RIGHT_SPACING;
 
@@ -306,8 +323,7 @@ static void
 gtk_option_menu_paint (GtkWidget    *widget,
                       GdkRectangle *area)
 {
-  GdkRectangle restrict_area;
-  GdkRectangle new_area;
+  GdkRectangle button_area;
 
   g_return_if_fail (widget != NULL);
   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
@@ -315,30 +331,39 @@ gtk_option_menu_paint (GtkWidget    *widget,
 
   if (GTK_WIDGET_DRAWABLE (widget))
     {
-      restrict_area.x = GTK_CONTAINER (widget)->border_width;
-      restrict_area.y = GTK_CONTAINER (widget)->border_width;
-      restrict_area.width = widget->allocation.width - restrict_area.x * 2;
-      restrict_area.height = widget->allocation.height - restrict_area.y * 2;
-
-      if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
-       {
-         gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget));
-         gdk_window_clear_area (widget->window,
-                                new_area.x, new_area.y,
-                                new_area.width, new_area.height);
-
-         gtk_draw_shadow (widget->style, widget->window,
-                          GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
-                          restrict_area.x, restrict_area.y,
-                          restrict_area.width, restrict_area.height);
-
-         gtk_draw_shadow (widget->style, widget->window,
-                          GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
-                          restrict_area.x + restrict_area.width - restrict_area.x -
-                          OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 4,
-                          restrict_area.y + (restrict_area.height - OPTION_INDICATOR_HEIGHT) / 2,
-                          OPTION_INDICATOR_WIDTH, OPTION_INDICATOR_HEIGHT);
-       }
+      button_area.x = GTK_CONTAINER (widget)->border_width + 1;
+      button_area.y = GTK_CONTAINER (widget)->border_width + 1;
+      button_area.width = widget->allocation.width - button_area.x * 2;
+      button_area.height = widget->allocation.height - button_area.y * 2;
+
+      /* This is evil, and should be elimated here and in the button
+       * code. The point is to clear the focus, and make it
+       * sort of transparent if it isn't there.
+       */
+      gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
+      gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
+
+      gtk_paint_box(widget->style, widget->window,
+                   GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
+                   area, widget, "optionmenu",
+                   button_area.x, button_area.y,
+                   button_area.width, button_area.height);
+      
+      gtk_paint_tab (widget->style, widget->window,
+                    GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
+                    area, widget, "optionmenutab",
+                    button_area.x + button_area.width - button_area.x -
+                    OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 4,
+                    button_area.y + (button_area.height - OPTION_INDICATOR_HEIGHT) / 2,
+                    OPTION_INDICATOR_WIDTH, OPTION_INDICATOR_HEIGHT);
+      
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+       gtk_paint_focus (widget->style, widget->window,
+                        area, widget, "button",
+                        button_area.x - 1, 
+                        button_area.y - 1, 
+                        button_area.width + 1,
+                        button_area.height + 1);
     }
 }
 
@@ -357,7 +382,7 @@ gtk_option_menu_draw (GtkWidget    *widget,
     {
       gtk_option_menu_paint (widget, area);
 
-      child = GTK_BUTTON (widget)->child;
+      child = GTK_BIN (widget)->child;
       if (child && gtk_widget_intersect (child, area, &child_area))
        gtk_widget_draw (child, &child_area);
     }
@@ -379,6 +404,18 @@ gtk_option_menu_expose (GtkWidget      *widget,
     {
       gtk_option_menu_paint (widget, &event->area);
 
+
+      /* The following code tries to draw the child in two places at
+       * once. It fails miserably for several reasons
+       *
+       * - If the child is not no-window, removing generates
+       *   more expose events. Bad, bad, bad.
+       * 
+       * - Even if the child is no-window, removing it now (properly)
+       *   clears the space where it was, so it does no good
+       */
+      
+#if 0
       remove_child = FALSE;
       child = GTK_BUTTON (widget)->child;
 
@@ -401,6 +438,15 @@ gtk_option_menu_expose (GtkWidget      *widget,
 
       if (remove_child)
        gtk_option_menu_remove_contents (GTK_OPTION_MENU (widget));
+#else
+      remove_child = FALSE;
+      child = GTK_BIN (widget)->child;
+      child_event = *event;
+      if (child && GTK_WIDGET_NO_WINDOW (child) &&
+         gtk_widget_intersect (child, &event->area, &child_event.area))
+       gtk_widget_event (child, (GdkEvent*) &child_event);
+
+#endif /* 0 */
     }
 
   return FALSE;
@@ -416,19 +462,46 @@ gtk_option_menu_button_press (GtkWidget      *widget,
   g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
+  option_menu = GTK_OPTION_MENU (widget);
+
   if ((event->type == GDK_BUTTON_PRESS) &&
       (event->button == 1))
     {
-      option_menu = GTK_OPTION_MENU (widget);
       gtk_option_menu_remove_contents (option_menu);
       gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL,
                      gtk_option_menu_position, option_menu,
                      event->button, event->time);
+      return TRUE;
     }
 
   return FALSE;
 }
 
+static gint
+gtk_option_menu_key_press (GtkWidget   *widget,
+                          GdkEventKey *event)
+{
+  GtkOptionMenu *option_menu;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  option_menu = GTK_OPTION_MENU (widget);
+
+  switch (event->keyval)
+    {
+    case GDK_space:
+      gtk_option_menu_remove_contents (option_menu);
+      gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL,
+                     gtk_option_menu_position, option_menu,
+                     0, event->time);
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
 static void
 gtk_option_menu_deactivate (GtkMenuShell  *menu_shell,
                            GtkOptionMenu *option_menu)
@@ -459,14 +532,12 @@ gtk_option_menu_update_contents (GtkOptionMenu *option_menu)
          child = GTK_BIN (option_menu->menu_item)->child;
          if (child)
            {
-             gtk_container_block_resize (GTK_CONTAINER (option_menu));
-             if (GTK_BUTTON (option_menu)->child)
+             if (GTK_BIN (option_menu)->child)
                gtk_container_remove (GTK_CONTAINER (option_menu),
-                                     GTK_BUTTON (option_menu)->child);
+                                     GTK_BIN (option_menu)->child);
              if (GTK_WIDGET (option_menu)->state != child->state)
                gtk_widget_set_state (child, GTK_WIDGET (option_menu)->state);
              gtk_widget_reparent (child, GTK_WIDGET (option_menu));
-             gtk_container_unblock_resize (GTK_CONTAINER (option_menu));
            }
 
          gtk_widget_size_request (child, &child->requisition);
@@ -485,17 +556,14 @@ gtk_option_menu_remove_contents (GtkOptionMenu *option_menu)
   g_return_if_fail (option_menu != NULL);
   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
 
-  if (GTK_BUTTON (option_menu)->child)
+  if (GTK_BIN (option_menu)->child)
     {
-      gtk_container_block_resize (GTK_CONTAINER (option_menu));
-      if (GTK_WIDGET (option_menu->menu_item)->state != GTK_BUTTON (option_menu)->child->state)
-       gtk_widget_set_state (GTK_BUTTON (option_menu)->child,
+      if (GTK_WIDGET (option_menu->menu_item)->state != GTK_BIN (option_menu)->child->state)
+       gtk_widget_set_state (GTK_BIN (option_menu)->child,
                              GTK_WIDGET (option_menu->menu_item)->state);
-      gtk_widget_unrealize (GTK_BUTTON (option_menu)->child);
-      gtk_widget_reparent (GTK_BUTTON (option_menu)->child, option_menu->menu_item);
+      gtk_widget_reparent (GTK_BIN (option_menu)->child, option_menu->menu_item);
       gtk_widget_unref (option_menu->menu_item);
       option_menu->menu_item = NULL;
-      gtk_container_unblock_resize (GTK_CONTAINER (option_menu));
     }
 }
 
@@ -572,7 +640,9 @@ gtk_option_menu_position (GtkMenu  *menu,
       if (active == child)
        break;
 
-      menu_ypos -= child->allocation.height;
+      if (GTK_WIDGET_VISIBLE (child))
+       menu_ypos -= child->allocation.height;
+
       children = children->next;
     }