]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkbutton.c
configure.ac: Indeed the minimum required version is 2.29.4, not 2.29.2
[~andy/gtk] / gtk / gtkbutton.c
index beece346c12456972ba379735117c917b602855d..ba121b5e6271dce6efaafe80e8cc263271e198fb 100644 (file)
@@ -55,6 +55,7 @@
 #include "gtkiconfactory.h"
 #include "gtkactivatable.h"
 #include "gtksizerequest.h"
+#include "gtktypebuiltins.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 
@@ -113,7 +114,7 @@ static void gtk_button_realize (GtkWidget * widget);
 static void gtk_button_unrealize (GtkWidget * widget);
 static void gtk_button_map (GtkWidget * widget);
 static void gtk_button_unmap (GtkWidget * widget);
-static void gtk_button_style_set (GtkWidget * widget, GtkStyle * prev_style);
+static void gtk_button_style_updated (GtkWidget * widget);
 static void gtk_button_size_allocate (GtkWidget * widget,
                                      GtkAllocation * allocation);
 static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
@@ -197,7 +198,7 @@ gtk_button_class_init (GtkButtonClass *klass)
   widget_class->unrealize = gtk_button_unrealize;
   widget_class->map = gtk_button_map;
   widget_class->unmap = gtk_button_unmap;
-  widget_class->style_set = gtk_button_style_set;
+  widget_class->style_updated = gtk_button_style_updated;
   widget_class->size_allocate = gtk_button_size_allocate;
   widget_class->draw = gtk_button_draw;
   widget_class->button_press_event = gtk_button_button_press;
@@ -265,7 +266,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    * GtkButton:xalign:
    *
    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
-   * can be used to control it's horizontal alignment. 0.0 is left aligned, 
+   * can be used to control its horizontal alignment. 0.0 is left aligned, 
    * 1.0 is right aligned.
    *
    * Since: 2.4
@@ -284,7 +285,7 @@ gtk_button_class_init (GtkButtonClass *klass)
    * GtkButton:yalign:
    *
    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
-   * can be used to control it's vertical alignment. 0.0 is top aligned, 
+   * can be used to control its vertical alignment. 0.0 is top aligned, 
    * 1.0 is bottom aligned.
    *
    * Since: 2.4
@@ -300,7 +301,7 @@ gtk_button_class_init (GtkButtonClass *klass)
                                                       GTK_PARAM_READWRITE));
 
   /**
-   * GtkButton::image:
+   * GtkButton:image:
    *
    * The child widget to appear next to the button text.
    *
@@ -533,6 +534,7 @@ static void
 gtk_button_init (GtkButton *button)
 {
   GtkButtonPrivate *priv;
+  GtkStyleContext *context;
 
   button->priv = G_TYPE_INSTANCE_GET_PRIVATE (button,
                                               GTK_TYPE_BUTTON,
@@ -561,6 +563,9 @@ gtk_button_init (GtkButton *button)
   priv->image_is_stock = TRUE;
   priv->image_position = GTK_POS_LEFT;
   priv->use_action_appearance = TRUE;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (button));
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
 }
 
 static void
@@ -967,6 +972,7 @@ static void
 gtk_button_construct_child (GtkButton *button)
 {
   GtkButtonPrivate *priv = button->priv;
+  GtkStyleContext *context;
   GtkStockItem item;
   GtkWidget *child;
   GtkWidget *label;
@@ -982,9 +988,11 @@ gtk_button_construct_child (GtkButton *button)
   if (!priv->label_text && !priv->image)
     return;
 
-  gtk_widget_style_get (GTK_WIDGET (button),
-                       "image-spacing", &image_spacing,
-                       NULL);
+  context = gtk_widget_get_style_context (GTK_WIDGET (button));
+
+  gtk_style_context_get_style (context,
+                               "image-spacing", &image_spacing,
+                               NULL);
 
   if (priv->image && !priv->image_is_stock)
     {
@@ -1298,8 +1306,6 @@ gtk_button_realize (GtkWidget *widget)
   priv->event_window = gdk_window_new (window,
                                        &attributes, attributes_mask);
   gdk_window_set_user_data (priv->event_window, button);
-
-  gtk_widget_style_attach (widget);
 }
 
 static void
@@ -1346,7 +1352,8 @@ gtk_button_unmap (GtkWidget *widget)
 }
 
 static void
-gtk_button_update_image_spacing (GtkButton *button)
+gtk_button_update_image_spacing (GtkButton       *button,
+                                 GtkStyleContext *context)
 {
   GtkButtonPrivate *priv = button->priv;
   GtkWidget *child; 
@@ -1365,20 +1372,25 @@ gtk_button_update_image_spacing (GtkButton *button)
       child = gtk_bin_get_child (GTK_BIN (child));
       if (GTK_IS_BOX (child))
         {
-          gtk_widget_style_get (GTK_WIDGET (button),
-                                "image-spacing", &spacing,
-                                NULL);
+          gtk_style_context_get_style (context,
+                                       "image-spacing", &spacing,
+                                       NULL);
 
           gtk_box_set_spacing (GTK_BOX (child), spacing);
         }
-    }   
+    }
 }
 
 static void
-gtk_button_style_set (GtkWidget *widget,
-                     GtkStyle  *prev_style)
+gtk_button_style_updated (GtkWidget *widget)
 {
-  gtk_button_update_image_spacing (GTK_BUTTON (widget));
+  GtkStyleContext *context;
+
+  GTK_WIDGET_CLASS (gtk_button_parent_class)->style_updated (widget);
+
+  context = gtk_widget_get_style_context (widget);
+
+  gtk_button_update_image_spacing (GTK_BUTTON (widget), context);
 }
 
 static void
@@ -1386,14 +1398,21 @@ gtk_button_get_props (GtkButton *button,
                      GtkBorder *default_border,
                      GtkBorder *default_outside_border,
                       GtkBorder *inner_border,
+                      GtkBorder *padding,
                      gboolean  *interior_focus)
 {
-  GtkWidget *widget =  GTK_WIDGET (button);
+  GtkStyleContext *context;
+  GtkStateFlags state;
   GtkBorder *tmp_border;
 
+  context = gtk_widget_get_style_context (GTK_WIDGET (button));
+  state = gtk_style_context_get_state (context);
+
   if (default_border)
     {
-      gtk_widget_style_get (widget, "default-border", &tmp_border, NULL);
+      gtk_style_context_get_style (context,
+                                   "default-border", &tmp_border,
+                                   NULL);
 
       if (tmp_border)
        {
@@ -1406,7 +1425,9 @@ gtk_button_get_props (GtkButton *button,
 
   if (default_outside_border)
     {
-      gtk_widget_style_get (widget, "default-outside-border", &tmp_border, NULL);
+      gtk_style_context_get_style (context,
+                                   "default-outside-border", &tmp_border,
+                                   NULL);
 
       if (tmp_border)
        {
@@ -1419,7 +1440,9 @@ gtk_button_get_props (GtkButton *button,
 
   if (inner_border)
     {
-      gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
+      gtk_style_context_get_style (context,
+                                   "inner-border", &tmp_border,
+                                   NULL);
 
       if (tmp_border)
        {
@@ -1431,7 +1454,14 @@ gtk_button_get_props (GtkButton *button,
     }
 
   if (interior_focus)
-    gtk_widget_style_get (widget, "interior-focus", interior_focus, NULL);
+    {
+      gtk_style_context_get_style (context,
+                                   "interior-focus", interior_focus,
+                                   NULL);
+    }
+
+  if (padding)
+    gtk_style_context_get_padding (context, state, padding);
 }
 
 static void
@@ -1441,24 +1471,23 @@ gtk_button_size_allocate (GtkWidget     *widget,
   GtkButton *button = GTK_BUTTON (widget);
   GtkButtonPrivate *priv = button->priv;
   GtkAllocation child_allocation;
-  GtkStyle *style;
+  GtkStyleContext *context;
+  GtkStateFlags state;
   GtkWidget *child;
-
-  gint xthickness, ythickness;
   GtkBorder default_border;
   GtkBorder inner_border;
+  GtkBorder padding;
   gint focus_width;
   gint focus_pad;
 
-  style = gtk_widget_get_style (widget);
-  xthickness = style->xthickness;
-  ythickness = style->ythickness;
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
 
-  gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                       "focus-line-width", &focus_width,
-                       "focus-padding", &focus_pad,
-                       NULL);
+  gtk_button_get_props (button, &default_border, NULL, &inner_border, &padding, NULL);
+  gtk_style_context_get_style (context,
+                              "focus-line-width", &focus_width,
+                              "focus-padding", &focus_pad,
+                              NULL);
 
   gtk_widget_set_allocation (widget, allocation);
 
@@ -1472,18 +1501,18 @@ gtk_button_size_allocate (GtkWidget     *widget,
   child = gtk_bin_get_child (GTK_BIN (button));
   if (child && gtk_widget_get_visible (child))
     {
-      child_allocation.x = allocation->x + inner_border.left + xthickness;
-      child_allocation.y = allocation->y + inner_border.top + ythickness;
+      child_allocation.x = allocation->x + inner_border.left + padding.left;
+      child_allocation.y = allocation->y + inner_border.top + padding.top;
 
       child_allocation.width =
        allocation->width -
-       xthickness * 2 -
+        (padding.left + padding.right) -
        inner_border.left -
        inner_border.right;
 
       child_allocation.height = 
        allocation->height -
-       ythickness * 2 -
+        (padding.top + padding.bottom) -
        inner_border.top -
        inner_border.bottom;
 
@@ -1507,11 +1536,11 @@ gtk_button_size_allocate (GtkWidget     *widget,
        {
          gint child_displacement_x;
          gint child_displacement_y;
-         
-         gtk_widget_style_get (widget,
-                               "child-displacement-x", &child_displacement_x, 
-                               "child-displacement-y", &child_displacement_y,
-                               NULL);
+
+          gtk_style_context_get_style (context,
+                                       "child-displacement-x", &child_displacement_x,
+                                       "child-displacement-y", &child_displacement_y,
+                                       NULL);
          child_allocation.x += child_displacement_x;
          child_allocation.y += child_displacement_y;
        }
@@ -1528,10 +1557,7 @@ _gtk_button_paint (GtkButton          *button,
                   cairo_t            *cr,
                    int                 width,
                    int                 height,
-                  GtkStateType        state_type,
-                  GtkShadowType       shadow_type,
-                  const gchar        *main_detail,
-                  const gchar        *default_detail)
+                  GtkStateFlags       state)
 {
   GtkButtonPrivate *priv = button->priv;
   GtkWidget *widget;
@@ -1542,20 +1568,21 @@ _gtk_button_paint (GtkButton          *button,
   gint focus_width;
   gint focus_pad;
   GtkAllocation allocation;
-  GdkWindow *window;
-  GtkStyle *style;
+  GtkStyleContext *context;
 
   widget = GTK_WIDGET (button);
+  context = gtk_widget_get_style_context (widget);
+
+  gtk_style_context_save (context);
+  gtk_style_context_set_state (context, state);
 
-  gtk_button_get_props (button, &default_border, &default_outside_border, NULL, &interior_focus);
-  gtk_widget_style_get (widget,
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL); 
+  gtk_button_get_props (button, &default_border, &default_outside_border, NULL, NULL, &interior_focus);
+  gtk_style_context_get_style (context,
+                               "focus-line-width", &focus_width,
+                               "focus-padding", &focus_pad,
+                               NULL);
 
   gtk_widget_get_allocation (widget, &allocation);
-  style = gtk_widget_get_style (widget);
-  window = gtk_widget_get_window (widget);
 
   x = 0;
   y = 0;
@@ -1563,15 +1590,12 @@ _gtk_button_paint (GtkButton          *button,
   if (gtk_widget_has_default (widget) &&
       priv->relief == GTK_RELIEF_NORMAL)
     {
-      gtk_paint_box (style, cr,
-                     GTK_STATE_NORMAL, GTK_SHADOW_IN,
-                     widget, "buttondefault",
-                     x, y, width, height);
-
       x += default_border.left;
       y += default_border.top;
       width -= default_border.left + default_border.right;
       height -= default_border.top + default_border.bottom;
+
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_DEFAULT);
     }
   else if (gtk_widget_get_can_default (widget))
     {
@@ -1590,30 +1614,37 @@ _gtk_button_paint (GtkButton          *button,
     }
 
   if (priv->relief != GTK_RELIEF_NONE || priv->depressed ||
-      gtk_widget_get_state(widget) == GTK_STATE_PRELIGHT)
-    gtk_paint_box (style, cr,
-                   state_type,
-                   shadow_type, widget, "button",
-                   x, y, width, height);
-   
+      state & GTK_STATE_FLAG_PRELIGHT)
+    {
+      gtk_render_background (context, cr,
+                            x, y, width, height);
+      gtk_render_frame (context, cr,
+                       x, y, width, height);
+    }
+
   if (gtk_widget_has_focus (widget))
     {
       gint child_displacement_x;
       gint child_displacement_y;
       gboolean displace_focus;
-      
-      gtk_widget_style_get (widget,
-                            "child-displacement-y", &child_displacement_y,
-                            "child-displacement-x", &child_displacement_x,
-                            "displace-focus", &displace_focus,
-                            NULL);
+      GtkBorder *border;
+
+      gtk_style_context_get_style (context,
+                                   "child-displacement-y", &child_displacement_y,
+                                   "child-displacement-x", &child_displacement_x,
+                                   "displace-focus", &displace_focus,
+                                   NULL);
+
+      gtk_style_context_get (context, state,
+                             "border-width", &border,
+                             NULL);
 
       if (interior_focus)
         {
-          x += style->xthickness + focus_pad;
-          y += style->ythickness + focus_pad;
-          width -= 2 * (style->xthickness + focus_pad);
-          height -=  2 * (style->ythickness + focus_pad);
+          x += border->left + focus_pad;
+          y += border->top + focus_pad;
+          width -= (2 * focus_pad) + border->left + border->right;
+          height -=  (2 * focus_pad) + border->top + border->bottom;
         }
       else
         {
@@ -1629,11 +1660,13 @@ _gtk_button_paint (GtkButton          *button,
           y += child_displacement_y;
         }
 
-      gtk_paint_focus (style, cr,
-                       gtk_widget_get_state (widget),
-                       widget, "button",
-                       x, y, width, height);
+      gtk_render_focus (context, cr,
+                       x, y, width, height);
+
+      gtk_border_free (border);
     }
+
+  gtk_style_context_restore (context);
 }
 
 static gboolean
@@ -1641,14 +1674,11 @@ gtk_button_draw (GtkWidget *widget,
                 cairo_t   *cr)
 {
   GtkButton *button = GTK_BUTTON (widget);
-  GtkButtonPrivate *priv = button->priv;
 
   _gtk_button_paint (button, cr, 
                      gtk_widget_get_allocated_width (widget),
                      gtk_widget_get_allocated_height (widget),
-                     gtk_widget_get_state (widget),
-                     priv->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
-                     "button", "buttondefault");
+                     gtk_widget_get_state_flags (widget));
 
   GTK_WIDGET_CLASS (gtk_button_parent_class)->draw (widget, cr);
 
@@ -1830,20 +1860,24 @@ gtk_real_button_activate (GtkButton *button)
   if (device && gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
     device = gdk_device_get_associated_device (device);
 
-  g_return_if_fail (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD);
-
   if (gtk_widget_get_realized (widget) && !priv->activate_timeout)
     {
       time = gtk_get_current_event_time ();
 
-      if (gdk_device_grab (device, priv->event_window,
-                           GDK_OWNERSHIP_WINDOW, TRUE,
-                           GDK_KEY_PRESS | GDK_KEY_RELEASE,
-                           NULL, time) == GDK_GRAB_SUCCESS)
-        {
-          gtk_device_grab_add (widget, device, TRUE);
-         priv->grab_keyboard = device;
-         priv->grab_time = time;
+      /* bgo#626336 - Only grab if we have a device (from an event), not if we
+       * were activated programmatically when no event is available.
+       */
+      if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+       {
+         if (gdk_device_grab (device, priv->event_window,
+                              GDK_OWNERSHIP_WINDOW, TRUE,
+                              GDK_KEY_PRESS | GDK_KEY_RELEASE,
+                              NULL, time) == GDK_GRAB_SUCCESS)
+           {
+             gtk_device_grab_add (widget, device, TRUE);
+             priv->grab_keyboard = device;
+             priv->grab_time = time;
+           }
        }
 
       priv->activate_timeout = gdk_threads_add_timeout (ACTIVATE_TIMEOUT,
@@ -1889,34 +1923,35 @@ gtk_button_get_size (GtkWidget      *widget,
                     gint           *natural_size)
 {
   GtkButton *button = GTK_BUTTON (widget);
-  GtkStyle *style;
+  GtkStyleContext *context;
+  GtkStateFlags state;
   GtkWidget *child;
   GtkBorder default_border;
   GtkBorder inner_border;
+  GtkBorder padding;
   gint focus_width;
   gint focus_pad;
   gint minimum, natural;
 
-  gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
-  gtk_widget_style_get (GTK_WIDGET (widget),
-                       "focus-line-width", &focus_width,
-                       "focus-padding", &focus_pad,
-                       NULL);
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
 
-  style = gtk_widget_get_style (GTK_WIDGET (widget));
+  gtk_button_get_props (button, &default_border, NULL, &inner_border, &padding, NULL);
+  gtk_style_context_get_style (context,
+                               "focus-line-width", &focus_width,
+                               "focus-padding", &focus_pad,
+                               NULL);
 
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
     {
-      minimum = (style->xthickness * 2 +
-                inner_border.left + inner_border.right);
+      minimum = inner_border.left + inner_border.right + padding.left + padding.right;
 
       if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
        minimum += default_border.left + default_border.right;
     }
   else
     {
-      minimum = (style->ythickness * 2 +
-                inner_border.top + inner_border.bottom);
+      minimum = inner_border.top + inner_border.bottom + padding.top + padding.bottom;
 
       if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
        minimum += default_border.top + default_border.bottom;
@@ -2201,8 +2236,8 @@ gtk_button_set_alignment (GtkButton *button,
 /**
  * gtk_button_get_alignment:
  * @button: a #GtkButton
- * @xalign: return location for horizontal alignment
- * @yalign: return location for vertical alignment
+ * @xalign: (out): return location for horizontal alignment
+ * @yalign: (out): return location for vertical alignment
  *
  * Gets the alignment of the child in the button.
  *
@@ -2246,18 +2281,6 @@ _gtk_button_set_depressed (GtkButton *button,
 
   if (depressed != priv->depressed)
     {
-      if (gtk_widget_get_realized (widget) &&
-          gtk_widget_is_drawable (widget))
-        {
-          GtkStyleContext *context;
-
-          context = gtk_widget_get_style_context (widget);
-          gtk_style_context_notify_state_change (context,
-                                                 gtk_widget_get_window (widget),
-                                                 NULL, GTK_STATE_ACTIVE,
-                                                 depressed);
-        }
-
       priv->depressed = depressed;
       gtk_widget_queue_resize (widget);
     }
@@ -2267,7 +2290,7 @@ static void
 gtk_button_update_state (GtkButton *button)
 {
   GtkButtonPrivate *priv = button->priv;
-  GtkStateType new_state;
+  GtkStateFlags new_state;
   gboolean depressed;
 
   if (priv->activate_timeout)
@@ -2275,13 +2298,17 @@ gtk_button_update_state (GtkButton *button)
   else
     depressed = priv->in_button && priv->button_down;
 
-  if (priv->in_button && (!priv->button_down || !depressed))
-    new_state = GTK_STATE_PRELIGHT;
-  else
-    new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
+  new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
+    ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE);
+
+  if (priv->in_button)
+    new_state |= GTK_STATE_FLAG_PRELIGHT;
+
+  if (priv->button_down || depressed)
+    new_state |= GTK_STATE_FLAG_ACTIVE;
 
-  _gtk_button_set_depressed (button, depressed); 
-  gtk_widget_set_state (GTK_WIDGET (button), new_state);
+  _gtk_button_set_depressed (button, depressed);
+  gtk_widget_set_state_flags (GTK_WIDGET (button), new_state, TRUE);
 }
 
 static void