[Xfce4-commits] <xfce4-panel:devel> Add blinking support to the arrow button.

Nick Schermer nick at xfce.org
Tue Aug 11 20:28:26 CEST 2009


Updating branch refs/heads/devel
         to e05a73505f76186c6801401cc67473b2b08b5641 (commit)
       from aae21cb8a2c4b240825a3adc04e3721237788a1f (commit)

commit e05a73505f76186c6801401cc67473b2b08b5641
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Feb 27 18:35:37 2009 +0100

    Add blinking support to the arrow button.
    
    The arrow button supports blinking by now. You can create a
    normal toggle button by using GTK_ARROW_NONE as arrow type.
    It is also possible to add child widgets to the arrow button,
    previously this was not possible (and not needed). When both
    an arrow is set and a child is added, the arrow will show
    shown next to the child, this will be used for group buttons in
    the tasklist plugin.
    
    Probably some allocation issues will show up, but it's a good
    start for reducing the code complexity in the wnck plugins.

 libxfce4panel/Makefile.am         |    2 -
 libxfce4panel/xfce-arrow-button.c |  326 +++++++++++++++++++++++++++++++------
 libxfce4panel/xfce-arrow-button.h |   19 ++-
 3 files changed, 285 insertions(+), 62 deletions(-)

diff --git a/libxfce4panel/Makefile.am b/libxfce4panel/Makefile.am
index 106da89..04c3442 100644
--- a/libxfce4panel/Makefile.am
+++ b/libxfce4panel/Makefile.am
@@ -34,8 +34,6 @@ libxfce4panel_la_SOURCES = \
 	$(libxfce4panel_built_sources) \
 	$(libxfce4panel_headers) \
 	xfce-arrow-button.c \
-	xfce-blink-button.c \
-	xfce-blink-button.h \
 	xfce-hvbox.c \
 	xfce-panel-convenience.c \
 	xfce-panel-plugin.c \
diff --git a/libxfce4panel/xfce-arrow-button.c b/libxfce4panel/xfce-arrow-button.c
index 52608f1..003f8f0 100644
--- a/libxfce4panel/xfce-arrow-button.c
+++ b/libxfce4panel/xfce-arrow-button.c
@@ -31,9 +31,14 @@
 
 #include <gtk/gtk.h>
 #include <libxfce4panel/libxfce4panel.h>
+#include <common/panel-private.h>
 
-#define ARROW_WIDTH   (8)
-#define ARROW_PADDING (2)
+#define XFCE_ARROW_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+                                            XFCE_TYPE_ARROW_BUTTON, \
+                                            XfceArrowButtonPrivate))
+
+#define ARROW_WIDTH        (8)
+#define MAX_BLINKING_COUNT (16)
 
 enum
 {
@@ -55,13 +60,31 @@ static void     xfce_arrow_button_get_property  (GObject               *object,
                                                  guint                  prop_id,
                                                  GValue                *value,
                                                  GParamSpec            *pspec);
+static void     xfce_arrow_button_finalize      (GObject               *object);
 static gboolean xfce_arrow_button_expose_event  (GtkWidget             *widget,
                                                  GdkEventExpose        *event);
 static void     xfce_arrow_button_size_request  (GtkWidget             *widget,
                                                  GtkRequisition        *requisition);
-static void     xfce_arrow_button_add           (GtkContainer          *container,
-                                                 GtkWidget             *child);
-static GType    xfce_arrow_button_child_type    (GtkContainer          *container);
+static void     xfce_arrow_button_size_allocate (GtkWidget             *widget,
+                                                 GtkAllocation         *allocation);
+                                                 
+
+
+struct _XfceArrowButtonPrivate
+{
+  /* arrow type of the button */
+  GtkArrowType   arrow_type;
+
+  /* blinking timeout id */
+  guint          blinking_timeout_id;
+
+  /* counter to make the blinking stop when
+   * MAX_BLINKING_COUNT is reached */
+  guint          blinking_counter;
+
+  /* button relief when the blinking starts */
+  GtkReliefStyle last_relief;
+};
 
 
 
@@ -76,21 +99,20 @@ G_DEFINE_TYPE (XfceArrowButton, xfce_arrow_button, GTK_TYPE_TOGGLE_BUTTON)
 static void
 xfce_arrow_button_class_init (XfceArrowButtonClass * klass)
 {
-  GObjectClass      *gobject_class;
-  GtkWidgetClass    *gtkwidget_class;
-  GtkContainerClass *gtkcontainer_class;
+  GObjectClass   *gobject_class;
+  GtkWidgetClass *gtkwidget_class;
+
+  g_type_class_add_private (klass, sizeof (XfceArrowButtonPrivate));
 
   gobject_class = G_OBJECT_CLASS (klass);
   gobject_class->get_property = xfce_arrow_button_get_property;
   gobject_class->set_property = xfce_arrow_button_set_property;
+  gobject_class->finalize = xfce_arrow_button_finalize;
 
   gtkwidget_class = GTK_WIDGET_CLASS (klass);
   gtkwidget_class->expose_event = xfce_arrow_button_expose_event;
   gtkwidget_class->size_request = xfce_arrow_button_size_request;
-
-  gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
-  gtkcontainer_class->add = xfce_arrow_button_add;
-  gtkcontainer_class->child_type = xfce_arrow_button_child_type;
+  gtkwidget_class->size_allocate = xfce_arrow_button_size_allocate;
 
   /**
    * XfceArrowButton::arrow-type-changed
@@ -122,7 +144,8 @@ xfce_arrow_button_class_init (XfceArrowButtonClass * klass)
                                                       "The arrow type of the menu button",
                                                       GTK_TYPE_ARROW_TYPE,
                                                       GTK_ARROW_UP,
-                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+                                                      G_PARAM_READWRITE 
+                                                      | G_PARAM_STATIC_STRINGS));
 }
 
 
@@ -130,9 +153,19 @@ xfce_arrow_button_class_init (XfceArrowButtonClass * klass)
 static void
 xfce_arrow_button_init (XfceArrowButton *button)
 {
-  GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_NO_WINDOW);
+  /* set private pointer */
+  button->priv = XFCE_ARROW_BUTTON_GET_PRIVATE (button);
 
-  button->arrow_type = GTK_ARROW_UP;
+  /* initialize button values */
+  button->priv->arrow_type = GTK_ARROW_UP;
+  button->priv->blinking_timeout_id = 0;
+  button->priv->blinking_counter = 0;
+  button->priv->last_relief = GTK_RELIEF_NORMAL;
+
+  /* set some widget properties */
+  GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_NO_WINDOW);
+  GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);
+  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
 }
 
 
@@ -181,28 +214,65 @@ xfce_arrow_button_get_property (GObject    *object,
 
 
 
-static gboolean
-xfce_arrow_button_expose_event (GtkWidget      *widget,
-                                GdkEventExpose *event)
+static void
+xfce_arrow_button_finalize (GObject *object)
 {
-  gint x, y, w;
+  XfceArrowButton *button = XFCE_ARROW_BUTTON (object);
 
-  if (G_LIKELY (GTK_WIDGET_DRAWABLE (widget)))
-    {
-      w = MIN (widget->allocation.height - 2 * widget->style->ythickness,
-               widget->allocation.width  - 2 * widget->style->xthickness);
-      w = MIN (w, ARROW_WIDTH);
+  if (button->priv->blinking_timeout_id != 0)
+    g_source_remove (button->priv->blinking_timeout_id);
 
-      x = widget->allocation.x + (widget->allocation.width - w) / 2;
-      y = widget->allocation.y + (widget->allocation.height - w) / 2;
+  (*G_OBJECT_CLASS (xfce_arrow_button_parent_class)->finalize) (object);
+}
 
-      (*GTK_WIDGET_CLASS (xfce_arrow_button_parent_class)->expose_event) (widget, event);
 
+
+static gboolean
+xfce_arrow_button_expose_event (GtkWidget      *widget,
+                                GdkEventExpose *event)
+{
+  XfceArrowButton *button = XFCE_ARROW_BUTTON (widget);
+  GtkWidget       *child;
+  gint             x, y, width;
+  
+  /* draw the button */
+  (*GTK_WIDGET_CLASS (xfce_arrow_button_parent_class)->expose_event) (widget, event);
+
+  if (button->priv->arrow_type != GTK_ARROW_NONE
+      && GTK_WIDGET_DRAWABLE (widget))
+    {
+      child = gtk_bin_get_child (GTK_BIN (widget));
+      if (child != NULL && GTK_WIDGET_VISIBLE (child))
+        {
+          if (button->priv->arrow_type == GTK_ARROW_UP
+              || button->priv->arrow_type == GTK_ARROW_DOWN)
+            {
+              width = ARROW_WIDTH;
+              x = widget->allocation.x + widget->style->xthickness;
+              y = widget->allocation.y + (widget->allocation.height - width) / 2;
+            }
+          else
+            {
+              width = ARROW_WIDTH;
+              x = widget->allocation.x + (widget->allocation.width - width) / 2;
+              y = widget->allocation.y + widget->style->ythickness;
+            }
+        }
+      else
+        {
+          width = MIN (widget->allocation.height - 2 * widget->style->ythickness,
+                       widget->allocation.width  - 2 * widget->style->xthickness);
+          width = CLAMP (width, 1, ARROW_WIDTH);
+          
+          x = widget->allocation.x + (widget->allocation.width - width) / 2;
+          y = widget->allocation.y + (widget->allocation.height - width) / 2;
+        }
+      
       gtk_paint_arrow (widget->style, widget->window,
                        GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE,
                        &(event->area), widget, "xfce_arrow_button",
-                       XFCE_ARROW_BUTTON (widget)->arrow_type, FALSE,
-                       x, y, w, w);
+                       button->priv->arrow_type, FALSE,
+                       x, y, width, width);
     }
 
   return TRUE;
@@ -214,29 +284,119 @@ static void
 xfce_arrow_button_size_request (GtkWidget      *widget,
                                 GtkRequisition *requisition)
 {
-  gint size;
-
-  /* calculate the requested arrow size */
-  size = ARROW_WIDTH + ARROW_PADDING + 2 * MAX (widget->style->xthickness, widget->style->ythickness);
+  XfceArrowButton *button = XFCE_ARROW_BUTTON (widget);
+  GtkWidget *child;
 
-  requisition->width = requisition->height = size;
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (child != NULL && GTK_WIDGET_VISIBLE (child))
+    {
+      /* use gtk for the widget size */
+      (*GTK_WIDGET_CLASS (xfce_arrow_button_parent_class)->size_request) (widget, requisition);
+      
+      /* reserve space for the arrow */
+      switch (button->priv->arrow_type)
+        {
+          case GTK_ARROW_UP:
+          case GTK_ARROW_DOWN:
+            requisition->width += ARROW_WIDTH;
+            break;
+            
+          case GTK_ARROW_LEFT:
+          case GTK_ARROW_RIGHT:
+            requisition->height += ARROW_WIDTH;
+            break;
+            
+          default:
+            break;
+        }
+    }
+  else if (button->priv->arrow_type != GTK_ARROW_NONE)
+    {
+      requisition->height = ARROW_WIDTH + 2 * widget->style->xthickness;
+      requisition->width = ARROW_WIDTH + 2 * widget->style->ythickness;
+    }
 }
 
 
 
 static void
-xfce_arrow_button_add (GtkContainer *container,
-                       GtkWidget    *child)
+xfce_arrow_button_size_allocate (GtkWidget     *widget,
+                                 GtkAllocation *allocation)
 {
-  g_warning ("XfceArrowButton cannot contain any children");
+  XfceArrowButton *button = XFCE_ARROW_BUTTON (widget);
+  GtkWidget       *child;
+  GtkAllocation    child_allocation;
+
+  /* allocate the button */
+  (*GTK_WIDGET_CLASS (xfce_arrow_button_parent_class)->size_allocate) (widget, allocation);
+  
+  if (button->priv->arrow_type != GTK_ARROW_NONE)
+    {
+      child = gtk_bin_get_child (GTK_BIN (widget));
+      if (child != NULL && GTK_WIDGET_VISIBLE (child))
+        {
+          /* copy the child allocation */
+          child_allocation = child->allocation;
+          
+          /* update the allocation to make space for the arrow */
+          switch (button->priv->arrow_type)
+            {
+              case GTK_ARROW_LEFT:
+              case GTK_ARROW_RIGHT:
+                child_allocation.height -= ARROW_WIDTH;
+                child_allocation.y += ARROW_WIDTH;
+                break;
+              
+              default:
+                child_allocation.width -= ARROW_WIDTH;
+                child_allocation.x += ARROW_WIDTH;
+                break;
+            }
+          
+          /* set the child allocation again */
+          gtk_widget_size_allocate (child, &child_allocation);
+        }
+    }
 }
 
 
 
-static GType
-xfce_arrow_button_child_type (GtkContainer *container)
+static gboolean
+xfce_arrow_button_blinking_timeout (gpointer user_data)
 {
-  return GTK_TYPE_WIDGET;
+  XfceArrowButton *button = XFCE_ARROW_BUTTON (user_data);
+  GtkStyle        *style;
+  GtkRcStyle      *rc;
+
+  rc = gtk_widget_get_modifier_style (GTK_WIDGET (button));
+  if(PANEL_HAS_FLAG (rc->color_flags[GTK_STATE_NORMAL], GTK_RC_BG)
+     || button->priv->blinking_timeout_id == 0)
+    {
+      gtk_button_set_relief (GTK_BUTTON (button), button->priv->last_relief);
+      PANEL_UNSET_FLAG (rc->color_flags[GTK_STATE_NORMAL], GTK_RC_BG);
+      gtk_widget_modify_style (GTK_WIDGET (button), rc);
+    }
+  else
+    {
+      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL);
+      PANEL_SET_FLAG (rc->color_flags[GTK_STATE_NORMAL], GTK_RC_BG);
+      style = gtk_widget_get_style (GTK_WIDGET (button));
+      rc->bg[GTK_STATE_NORMAL] = style->bg[GTK_STATE_SELECTED];
+      gtk_widget_modify_style(GTK_WIDGET (button), rc);
+    }
+
+  return (button->priv->blinking_counter++ < MAX_BLINKING_COUNT);
+}
+
+
+
+static void
+xfce_arrow_button_blinking_timeout_destroyed (gpointer user_data)
+{
+  XfceArrowButton *button = XFCE_ARROW_BUTTON (user_data);
+
+  button->priv->blinking_timeout_id = 0;
+  button->priv->blinking_counter = 0;
 }
 
 
@@ -252,7 +412,26 @@ xfce_arrow_button_child_type (GtkContainer *container)
 PANEL_SYMBOL_EXPORT GtkWidget *
 xfce_arrow_button_new (GtkArrowType arrow_type)
 {
-  return g_object_new (XFCE_TYPE_ARROW_BUTTON, "arrow-type", arrow_type, NULL);
+  return g_object_new (XFCE_TYPE_ARROW_BUTTON,
+                       "arrow-type", arrow_type,
+                       NULL);
+}
+
+
+
+/**
+ * xfce_arrow_button_get_arrow_type:
+ * @button : a #XfceArrowButton
+ *
+ * Returns the value of the ::arrow-type property.
+ *
+ * Returns: the #GtkArrowType of @button.
+ **/
+PANEL_SYMBOL_EXPORT GtkArrowType
+xfce_arrow_button_get_arrow_type (XfceArrowButton *button)
+{
+  g_return_val_if_fail (XFCE_IS_ARROW_BUTTON (button), GTK_ARROW_UP);
+  return button->priv->arrow_type;
 }
 
 
@@ -270,36 +449,77 @@ xfce_arrow_button_set_arrow_type (XfceArrowButton *button,
 {
   g_return_if_fail (XFCE_IS_ARROW_BUTTON (button));
 
-  if (G_LIKELY (button->arrow_type != arrow_type))
-    {
+  if (G_LIKELY (button->priv->arrow_type != arrow_type))
+    {    
       /* store the new arrow type */
-      button->arrow_type = arrow_type;
+      button->priv->arrow_type = arrow_type;
 
       /* emit signal */
-      g_signal_emit (G_OBJECT (button), arrow_button_signals[ARROW_TYPE_CHANGED], 0, arrow_type);
+      g_signal_emit (G_OBJECT (button), 
+                     arrow_button_signals[ARROW_TYPE_CHANGED], 
+                     0, arrow_type);
 
       /* notify property change */
       g_object_notify (G_OBJECT (button), "arrow-type");
 
       /* redraw the arrow button */
-      gtk_widget_queue_draw (GTK_WIDGET (button));
+      gtk_widget_queue_resize (GTK_WIDGET (button));
     }
 }
 
 
 
 /**
- * xfce_arrow_button_get_arrow_type:
+ * xfce_arrow_button_get_blinking:
  * @button : a #XfceArrowButton
  *
- * Returns the value of the ::arrow-type property.
+ * Whether the button is blinking.
  *
- * Returns: the #GtkArrowType of @button.
+ * Returns: %TRUE when @button is blinking.
  **/
-PANEL_SYMBOL_EXPORT GtkArrowType
-xfce_arrow_button_get_arrow_type (XfceArrowButton *button)
+PANEL_SYMBOL_EXPORT gboolean
+xfce_arrow_button_get_blinking (XfceArrowButton *button)
 {
-  g_return_val_if_fail (XFCE_IS_ARROW_BUTTON (button), GTK_ARROW_UP);
+  g_return_val_if_fail (XFCE_IS_ARROW_BUTTON (button), FALSE);
+  return !!(button->priv->blinking_timeout_id != 0);
+}
+
+
+
+/**
+ * xfce_arrow_button_set_blinking:
+ * @button   : a #XfceArrowButton
+ * @blinking : %TRUE when the button should start blinking, %FALSE to
+ *             stop the blinking.
+ *
+ * Make the button blink.
+ **/
+PANEL_SYMBOL_EXPORT void
+xfce_arrow_button_set_blinking (XfceArrowButton *button,
+                                gboolean         blinking)
+{
+  g_return_if_fail (XFCE_IS_ARROW_BUTTON (button));
+
+  if (blinking)
+    {
+      /* store the relief of the button */
+      button->priv->last_relief = gtk_button_get_relief (GTK_BUTTON (button));
+
+      if (button->priv->blinking_timeout_id == 0)
+        {
+          /* start blinking timeout */
+          button->priv->blinking_timeout_id =
+              g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 500,
+                                  xfce_arrow_button_blinking_timeout, button,
+                                  xfce_arrow_button_blinking_timeout_destroyed);
+        }
+    }
+  else if (button->priv->blinking_timeout_id != 0)
+    {
+      /* stop the blinking timeout */
+      g_source_remove (button->priv->blinking_timeout_id);
+    }
 
-  return button->arrow_type;
+  /* start with a blinking or make sure the button is normal */
+  xfce_arrow_button_blinking_timeout (button);
 }
diff --git a/libxfce4panel/xfce-arrow-button.h b/libxfce4panel/xfce-arrow-button.h
index 0f4700d..1f47dcf 100644
--- a/libxfce4panel/xfce-arrow-button.h
+++ b/libxfce4panel/xfce-arrow-button.h
@@ -29,8 +29,9 @@
 
 G_BEGIN_DECLS
 
-typedef struct _XfceArrowButtonClass XfceArrowButtonClass;
-typedef struct _XfceArrowButton      XfceArrowButton;
+typedef struct _XfceArrowButtonPrivate XfceArrowButtonPrivate;
+typedef struct _XfceArrowButtonClass   XfceArrowButtonClass;
+typedef struct _XfceArrowButton        XfceArrowButton;
 
 #define XFCE_TYPE_ARROW_BUTTON            (xfce_arrow_button_get_type ())
 #define XFCE_ARROW_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_ARROW_BUTTON, XfceArrowButton))
@@ -54,18 +55,22 @@ struct _XfceArrowButton
   /*< private >*/
   GtkToggleButton __parent__;
 
-  GtkArrowType arrow_type;
+  /*< private >*/
+  XfceArrowButtonPrivate *priv;
 };
 
 PANEL_SYMBOL_EXPORT
 GType         xfce_arrow_button_get_type       (void) G_GNUC_CONST;
 
-GtkWidget    *xfce_arrow_button_new            (GtkArrowType      arrow_type) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+GtkWidget    *xfce_arrow_button_new            (GtkArrowType     arrow_type) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 
-void          xfce_arrow_button_set_arrow_type (XfceArrowButton  *button,
-                                                GtkArrowType      arrow_type);
+GtkArrowType  xfce_arrow_button_get_arrow_type (XfceArrowButton *button);
+void          xfce_arrow_button_set_arrow_type (XfceArrowButton *button,
+                                                GtkArrowType     arrow_type);
 
-GtkArrowType  xfce_arrow_button_get_arrow_type (XfceArrowButton  *button);
+gboolean      xfce_arrow_button_get_blinking   (XfceArrowButton *button);
+void          xfce_arrow_button_set_blinking   (XfceArrowButton *button,
+                                                gboolean         blinking);
 
 G_END_DECLS
 



More information about the Xfce4-commits mailing list