Button patch (Was: enhancing GTK visual quality)



Antonio Campos wrote:
> 
> Derek Simkowiak wrote:

[snip]

> > -> 2) The long and interminable story of the buttons don't getting
> > -> depressed (visually) when the users click on them using the keyboard
> >
> >         This has come up before.
> >
> 
> Yes, but without any solutions.
> Does anybody have one?

I can't remember if there is already a patch floating around to do this.
But anyway, I've had a quick go and a patch is attached (for 1.2.7, though
it should be OK with 1.2.8).

It makes sure the button's state is ACTIVE in the "clicked" signal,
and uses a timeout callback to reset it.

This means that it will also happen if you call gtk_button_clicked(),
which we may not want. In that case we'd have to create another
signal to use as the activate_signal, and do all this there.

Damon
--- gtkbutton.h.orig	Wed Feb 24 10:14:57 1999
+++ gtkbutton.h	Fri Aug 25 14:48:41 2000
@@ -58,6 +58,9 @@
   guint in_button : 1;
   guint button_down : 1;
   guint relief : 2;
+
+  /* Timeout ID used when the button is activated by the keyboard. */
+  guint activate_timeout_id;
 };
 
 struct _GtkButtonClass
--- gtkbutton.c.orig	Tue May 11 03:31:08 1999
+++ gtkbutton.c	Fri Aug 25 15:32:46 2000
@@ -36,6 +36,9 @@
 #define DEFAULT_TOP_POS   4
 #define DEFAULT_SPACING   7
 
+/* The timeout before the button is reset to the normal/prelight state after
+   being activated by the keyboard (or by a function call). */
+#define GTK_BUTTON_ACTIVATE_TIMEOUT	100
 
 enum {
   PRESSED,
@@ -55,6 +58,7 @@
 
 static void gtk_button_class_init     (GtkButtonClass   *klass);
 static void gtk_button_init           (GtkButton        *button);
+static void gtk_button_destroy	      (GtkObject	*object);
 static void gtk_button_set_arg        (GtkObject        *object,
 				       GtkArg           *arg,
 				       guint		 arg_id);
@@ -92,9 +96,11 @@
 				       GtkWidget        *widget);
 static void gtk_real_button_pressed   (GtkButton        *button);
 static void gtk_real_button_released  (GtkButton        *button);
+static void gtk_real_button_clicked   (GtkButton	*button);
 static void gtk_real_button_enter     (GtkButton        *button);
 static void gtk_real_button_leave     (GtkButton        *button);
 static GtkType gtk_button_child_type  (GtkContainer     *container);
+static gboolean gtk_button_activate_timeout_cb	(gpointer data);
 
 
 static GtkBinClass *parent_class = NULL;
@@ -181,6 +187,7 @@
 
   gtk_object_class_add_signals (object_class, button_signals, LAST_SIGNAL);
 
+  object_class->destroy = gtk_button_destroy;
   object_class->set_arg = gtk_button_set_arg;
   object_class->get_arg = gtk_button_get_arg;
 
@@ -205,7 +212,7 @@
 
   klass->pressed = gtk_real_button_pressed;
   klass->released = gtk_real_button_released;
-  klass->clicked = NULL;
+  klass->clicked = gtk_real_button_clicked;
   klass->enter = gtk_real_button_enter;
   klass->leave = gtk_real_button_leave;
 }
@@ -222,6 +229,25 @@
   button->relief = GTK_RELIEF_NORMAL;
 }
 
+static void
+gtk_button_destroy      (GtkObject	*object)
+{
+  GtkButton *button;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_BUTTON (object));
+
+  button = GTK_BUTTON (object);
+
+  if (button->activate_timeout_id) {
+    g_source_remove (button->activate_timeout_id);
+    button->activate_timeout_id = 0;
+  }
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
 static GtkType
 gtk_button_child_type  (GtkContainer     *container)
 {
@@ -865,6 +891,39 @@
 }
 
 static void
+gtk_real_button_clicked (GtkButton *button)
+{
+  gboolean add_timeout = FALSE;
+
+  g_return_if_fail (button != NULL);
+  g_return_if_fail (GTK_IS_BUTTON (button));
+
+  /* If the button wasn't active (e.g. it was activated by the keyboard)
+     we make it active here. */
+  if (GTK_WIDGET_STATE (button) != GTK_STATE_ACTIVE)
+    {
+      gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_ACTIVE);
+      /* We don't want to queue a draw, since if we do the button will only get
+	 redrawn after the action has been performed, which may take time. */
+      gtk_widget_draw (GTK_WIDGET (button), NULL);
+      add_timeout = TRUE;
+    }
+
+  /* Remove any existing timeout. */
+  if (button->activate_timeout_id)
+    {
+      g_source_remove (button->activate_timeout_id);
+      add_timeout = TRUE;
+    }
+
+  /* Add a new timeout to restore the state. */
+  if (add_timeout)
+    button->activate_timeout_id = g_timeout_add (GTK_BUTTON_ACTIVATE_TIMEOUT,
+						 gtk_button_activate_timeout_cb,
+						 button);
+}
+
+static void
 gtk_real_button_enter (GtkButton *button)
 {
   GtkStateType new_state;
@@ -893,3 +952,35 @@
       gtk_widget_queue_draw (GTK_WIDGET (button));
     }
 }
+
+
+static gboolean
+gtk_button_activate_timeout_cb	(gpointer data)
+{
+  GtkButton *button;
+  GtkStateType new_state;
+
+  GDK_THREADS_ENTER ();
+
+  button = GTK_BUTTON (data);
+
+  if (button->button_down && button->in_button)
+    new_state = GTK_STATE_ACTIVE;
+  else if (button->in_button)
+    new_state = GTK_STATE_PRELIGHT;
+  else
+    new_state = GTK_STATE_NORMAL;
+
+  if (GTK_WIDGET_STATE (button) != new_state)
+    {
+      gtk_widget_set_state (GTK_WIDGET (button), new_state);
+      gtk_widget_queue_draw (GTK_WIDGET (button));
+    }
+
+  button->activate_timeout_id = 0;
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]