Accelerator-only actions



This is the last major API change which I want to get into the action
menu code to make it ready for 2.4: Switch back to installing
accelerators on the actions, instead of the proxies. This is relatively
straightforward except for a little problem with editing of
accelerators. I'd be most interested in feedback on the way I solved
this in gtkmenu.c. Since the patch is unfortunately a little blown up by
formatting changes (I recently discovered egtk-format-protos...), here
is a quick summary:

- the accel_group reference moves from the ui manager to the action
groups. An action group creates its own accel group by default, but you
can set a different one.
- actions install their accelerator when their accel path is set,
meaning that action can activated via accelerator even if they don't
have any proxies.
- making accelerators do nothing on insensitive actions is done in the
same way as for menuitems: the accel_closure simply returns

Matthias


Index: gtk/gtkaction.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkaction.c,v
retrieving revision 1.5
diff -u -p -r1.5 gtkaction.c
--- gtk/gtkaction.c	4 Sep 2003 21:34:15 -0000	1.5
+++ gtk/gtkaction.c	5 Sep 2003 09:06:20 -0000
@@ -59,7 +59,9 @@ struct _GtkActionPrivate 
   guint is_important    : 1;
 
   /* accelerator */
-  GQuark accel_quark;
+  GClosure      *accel_closure;
+  GtkAccelGroup *accel_group;
+  GQuark         accel_quark;
 
   /* list of proxy widgets */
   GSList *proxies;
@@ -118,22 +120,28 @@ gtk_action_get_type (void)
   return type;
 }
 
-static void gtk_action_finalize     (GObject *object);
-static void gtk_action_set_property (GObject         *object,
-				     guint            prop_id,
-				     const GValue    *value,
-				     GParamSpec      *pspec);
-static void gtk_action_get_property (GObject         *object,
-				     guint            prop_id,
-				     GValue          *value,
-				     GParamSpec      *pspec);
-
-static GtkWidget *create_menu_item    (GtkAction *action);
-static GtkWidget *create_tool_item    (GtkAction *action);
-static void       connect_proxy       (GtkAction *action,
-				       GtkWidget *proxy);
-static void       disconnect_proxy    (GtkAction *action,
-				       GtkWidget *proxy);
+static void       gtk_action_finalize     (GObject      *object);
+static void       gtk_action_set_property (GObject      *object,
+					   guint         prop_id,
+					   const GValue *value,
+					   GParamSpec   *pspec);
+static void       gtk_action_get_property (GObject      *object,
+					   guint         prop_id,
+					   GValue       *value,
+					   GParamSpec   *pspec);
+static void       closure_accel_activate  (GClosure     *closure,
+					   GValue       *return_value,
+					   guint         n_param_values,
+					   const GValue *param_values,
+					   gpointer      invocation_hint,
+					   gpointer      marshal_data);
+static GtkWidget *create_menu_item        (GtkAction    *action);
+static GtkWidget *create_tool_item        (GtkAction    *action);
+static void       connect_proxy           (GtkAction    *action,
+					   GtkWidget    *proxy);
+static void       disconnect_proxy        (GtkAction    *action,
+					   GtkWidget    *proxy);
+
 
 static GObjectClass *parent_class = NULL;
 static guint         action_signals[LAST_SIGNAL] = { 0 };
@@ -260,6 +268,13 @@ gtk_action_init (GtkAction *action)
   action->private_data->label_set = FALSE;
   action->private_data->short_label_set = FALSE;
 
+  action->private_data->accel_closure = g_closure_new_object (sizeof (GClosure),
+							      G_OBJECT (action));
+  g_closure_set_marshal (action->private_data->accel_closure, closure_accel_activate);
+  g_closure_ref (action->private_data->accel_closure);
+  g_closure_sink (action->private_data->accel_closure);
+
+  action->private_data->accel_group = NULL;
   action->private_data->accel_quark = 0;
 
   action->private_data->proxies = NULL;
@@ -272,6 +287,12 @@ gtk_action_finalize (GObject *object)
 
   action = GTK_ACTION (object);
 
+  if (action->private_data->accel_closure)
+    g_closure_unref (action->private_data->accel_closure);
+
+  if (action->private_data->accel_group)
+    g_object_unref (action->private_data->accel_group);
+
   g_free (action->private_data->name);
   g_free (action->private_data->label);
   g_free (action->private_data->short_label);
@@ -564,7 +585,7 @@ connect_proxy (GtkAction *action, 
 				"xalign", 0.0,
 				"visible", TRUE,
 				"parent", proxy,
-				"accel_widget", proxy,
+				"accel_closure", action->private_data->accel_closure,
 				NULL);
 	}
       gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
@@ -928,6 +949,22 @@ gtk_action_unblock_activate_from (GtkAct
 				     action);
 }
 
+static void
+closure_accel_activate (GClosure     *closure,
+                        GValue       *return_value,
+                        guint         n_param_values,
+                        const GValue *param_values,
+                        gpointer      invocation_hint,
+                        gpointer      marshal_data)
+{
+  if (GTK_ACTION (closure->data)->private_data->sensitive)
+    g_signal_emit (closure->data, action_signals[ACTIVATE], 0);
+
+  /* we handled the accelerator */
+  g_value_set_boolean (return_value, TRUE);
+}
+
+
 /**
  * gtk_action_set_accel_path:
  * @action: the action object
@@ -940,8 +977,43 @@ gtk_action_unblock_activate_from (GtkAct
  * Since: 2.4
  */
 void
-gtk_action_set_accel_path (GtkAction   *action, 
-			   const gchar *accel_path)
+gtk_action_set_accel_path (GtkAction     *action, 
+			   const gchar   *accel_path,
+			   GtkAccelGroup *accel_group)
 {
+  g_return_if_fail (GTK_IS_ACTION (action));
+  g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
+
+  g_object_ref (accel_group);
+  if (action->private_data->accel_group)
+    g_object_unref (action->private_data->accel_group);
+  action->private_data->accel_group = accel_group;
+		   
   action->private_data->accel_quark = g_quark_from_string (accel_path);
+
+  gtk_accel_group_connect_by_path (accel_group,
+				   g_quark_to_string (action->private_data->accel_quark),
+				   action->private_data->accel_closure);
+}
+
+const gchar *
+gtk_action_get_accel_path (GtkAction *action,
+			   gboolean  *locked)
+{
+  g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
+
+  if (action->private_data->accel_quark)
+    {
+      if (locked)
+	*locked = action->private_data->accel_group->lock_count > 0;
+
+      return g_quark_to_string (action->private_data->accel_quark);
+    }
+  else
+    {
+      if (locked)
+	*locked = TRUE;
+
+      return NULL;
+    }
 }
Index: gtk/gtkaction.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkaction.h,v
retrieving revision 1.1
diff -u -p -r1.1 gtkaction.h
--- gtk/gtkaction.h	24 Aug 2003 19:58:28 -0000	1.1
+++ gtk/gtkaction.h	5 Sep 2003 09:06:20 -0000
@@ -78,30 +78,32 @@ struct _GtkActionClass
   void (*_gtk_reserved4) (void);
 };
 
-GType      gtk_action_get_type              (void);
-
-const gchar* gtk_action_get_name            (GtkAction   *action);
-void       gtk_action_activate              (GtkAction   *action);
-
-GtkWidget *gtk_action_create_icon           (GtkAction   *action,
-					     GtkIconSize  icon_size);
-GtkWidget *gtk_action_create_menu_item      (GtkAction   *action);
-GtkWidget *gtk_action_create_tool_item      (GtkAction   *action);
-void       gtk_action_connect_proxy         (GtkAction   *action,
-					     GtkWidget   *proxy);
-void       gtk_action_disconnect_proxy      (GtkAction   *action,
-					     GtkWidget   *proxy);
-GSList    *gtk_action_get_proxies           (GtkAction   *action);
+GType        gtk_action_get_type              (void);
+const gchar *gtk_action_get_name              (GtkAction     *action);
+void         gtk_action_activate              (GtkAction     *action);
+GtkWidget   *gtk_action_create_icon           (GtkAction     *action,
+					       GtkIconSize    icon_size);
+GtkWidget   *gtk_action_create_menu_item      (GtkAction     *action);
+GtkWidget   *gtk_action_create_tool_item      (GtkAction     *action);
+void         gtk_action_connect_proxy         (GtkAction     *action,
+					       GtkWidget     *proxy);
+void         gtk_action_disconnect_proxy      (GtkAction     *action,
+					       GtkWidget     *proxy);
+GSList      *gtk_action_get_proxies           (GtkAction     *action);
 
 /* protected ... for use by child actions */
-void       gtk_action_block_activate_from   (GtkAction   *action,
-		   		             GtkWidget   *proxy);
-void       gtk_action_unblock_activate_from (GtkAction   *action,
-				             GtkWidget   *proxy);
+void         gtk_action_block_activate_from   (GtkAction     *action,
+					       GtkWidget     *proxy);
+void         gtk_action_unblock_activate_from (GtkAction     *action,
+					       GtkWidget     *proxy);
 
 /* protected ... for use by action groups */
-void       gtk_action_set_accel_path        (GtkAction   *action,
-				             const gchar *accel_path);
+void         gtk_action_set_accel_path        (GtkAction     *action,
+					       const gchar   *accel_path,
+					       GtkAccelGroup *accel_group);
+const gchar *gtk_action_get_accel_path        (GtkAction     *action,
+					       gboolean      *locked);
+
 
 
 #endif  /* __GTK_ACTION_H__ */
Index: gtk/gtkactiongroup.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkactiongroup.c,v
retrieving revision 1.11
diff -u -p -r1.11 gtkactiongroup.c
--- gtk/gtkactiongroup.c	4 Sep 2003 00:49:36 -0000	1.11
+++ gtk/gtkactiongroup.c	5 Sep 2003 09:06:20 -0000
@@ -41,6 +41,7 @@
 struct _GtkActionGroupPrivate 
 {
   gchar           *name;
+  GtkAccelGroup   *accel_group;
   GHashTable      *actions;
 
   GtkTranslateFunc translate_func;
@@ -102,9 +103,11 @@ gtk_action_group_init (GtkActionGroup *s
 {
   self->private_data = GTK_ACTION_GROUP_GET_PRIVATE (self);
   self->private_data->name = NULL;
+  self->private_data->accel_group = gtk_accel_group_new ();
   self->private_data->actions = g_hash_table_new_full (g_str_hash, g_str_equal,
 						       (GDestroyNotify) g_free,
 						       (GDestroyNotify) g_object_unref);
+
   self->private_data->translate_func = NULL;
   self->private_data->translate_data = NULL;
   self->private_data->translate_notify = NULL;
@@ -123,12 +126,19 @@ gtk_action_group_init (GtkActionGroup *s
  * Since: 2.4
  */
 GtkActionGroup *
-gtk_action_group_new (const gchar *name)
+gtk_action_group_new (const gchar   *name,
+		      GtkAccelGroup *accel_group)
 {
   GtkActionGroup *self;
 
   self = g_object_new (GTK_TYPE_ACTION_GROUP, NULL);
   self->private_data->name = g_strdup (name);
+  if (accel_group)
+    {
+      g_object_ref (accel_group);
+      g_object_unref (self->private_data->accel_group);
+      self->private_data->accel_group = accel_group;
+    }
 
   return self;
 }
@@ -144,6 +154,8 @@ gtk_action_group_finalize (GObject *obje
   self->private_data->name = NULL;
 
   g_hash_table_destroy (self->private_data->actions);
+  g_object_unref (self->private_data->accel_group);
+  self->private_data->accel_group = NULL;
   self->private_data->actions = NULL;
 
   if (self->private_data->translate_notify)
@@ -179,6 +191,24 @@ gtk_action_group_get_name (GtkActionGrou
 }
 
 /**
+ * gtk_action_group_get_accel_group:
+ * @action_group: a #GtkActionGroup object
+ * 
+ * Returns the #GtkAccelGroup associated with @action_group.
+ *
+ * Return value: the #GtkAccelGroup.
+ *
+ * Since: 2.4
+ **/
+GtkAccelGroup *
+gtk_action_group_get_accel_group (GtkActionGroup *action_group)
+{
+  g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
+
+  return action_group->private_data->accel_group;
+}
+
+/**
  * gtk_action_group_get_action:
  * @action_group: the action group
  * @action_name: the name of the action
@@ -384,7 +414,7 @@ gtk_action_group_add_actions_full (GtkAc
 	    gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
 	}
 
-      gtk_action_set_accel_path (action, accel_path);
+      gtk_action_set_accel_path (action, accel_path, action_group->private_data->accel_group);
       g_free (accel_path);
 
       gtk_action_group_add_action (action_group, action);
@@ -503,7 +533,7 @@ gtk_action_group_add_radio_actions_full 
 	    gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
 	}
 
-      gtk_action_set_accel_path (action, accel_path);
+      gtk_action_set_accel_path (action, accel_path, action_group->private_data->accel_group);
       g_free (accel_path);
       
       gtk_action_group_add_action (action_group, action);
Index: gtk/gtkactiongroup.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkactiongroup.h,v
retrieving revision 1.4
diff -u -p -r1.4 gtkactiongroup.h
--- gtk/gtkactiongroup.h	27 Aug 2003 22:22:27 -0000	1.4
+++ gtk/gtkactiongroup.h	5 Sep 2003 09:06:20 -0000
@@ -93,46 +93,45 @@ struct _GtkRadioActionEntry 
   gint  value; 
 };
 
-GType           gtk_action_group_get_type      (void);
-
-GtkActionGroup *gtk_action_group_new           (const gchar         *name);
-
-const gchar    *gtk_action_group_get_name      (GtkActionGroup      *action_group);
-GtkAction      *gtk_action_group_get_action    (GtkActionGroup      *action_group,
-						const gchar         *action_name);
-GList          *gtk_action_group_list_actions  (GtkActionGroup      *action_group);
-void            gtk_action_group_add_action    (GtkActionGroup      *action_group,
-						GtkAction           *action);
-void            gtk_action_group_remove_action (GtkActionGroup      *action_group,
-						GtkAction           *action);
-
-void            gtk_action_group_add_actions       (GtkActionGroup      *action_group,
-						    GtkActionEntry      *entries,
-						    guint                n_entries,
-						    gpointer             user_data);
-void            gtk_action_group_add_radio_actions (GtkActionGroup      *action_group,
-						    GtkRadioActionEntry *entries,
-						    guint                n_entries,
-						    GCallback            on_change,
-                                                    gpointer             user_data);
-void            gtk_action_group_add_actions_full  (GtkActionGroup      *action_group,
-						    GtkActionEntry      *entries,
-						    guint                n_entries,
-						    gpointer             user_data,
-						    GDestroyNotify       destroy);
+GType           gtk_action_group_get_type               (void);
+GtkActionGroup *gtk_action_group_new                    (const gchar         *name,
+							 GtkAccelGroup       *accel_group);
+const gchar    *gtk_action_group_get_name               (GtkActionGroup      *action_group);
+GtkAccelGroup  *gtk_action_group_get_accel_group        (GtkActionGroup      *action_group);
+GtkAction      *gtk_action_group_get_action             (GtkActionGroup      *action_group,
+							 const gchar         *action_name);
+GList          *gtk_action_group_list_actions           (GtkActionGroup      *action_group);
+void            gtk_action_group_add_action             (GtkActionGroup      *action_group,
+							 GtkAction           *action);
+void            gtk_action_group_remove_action          (GtkActionGroup      *action_group,
+							 GtkAction           *action);
+void            gtk_action_group_add_actions            (GtkActionGroup      *action_group,
+							 GtkActionEntry      *entries,
+							 guint                n_entries,
+							 gpointer             user_data);
+void            gtk_action_group_add_radio_actions      (GtkActionGroup      *action_group,
+							 GtkRadioActionEntry *entries,
+							 guint                n_entries,
+							 GCallback            on_change,
+							 gpointer             user_data);
+void            gtk_action_group_add_actions_full       (GtkActionGroup      *action_group,
+							 GtkActionEntry      *entries,
+							 guint                n_entries,
+							 gpointer             user_data,
+							 GDestroyNotify       destroy);
 void            gtk_action_group_add_radio_actions_full (GtkActionGroup      *action_group,
-						         GtkRadioActionEntry *entries,
-						         guint                n_entries,
-						         GCallback            on_change,
-                                                         gpointer             user_data,
+							 GtkRadioActionEntry *entries,
+							 guint                n_entries,
+							 GCallback            on_change,
+							 gpointer             user_data,
 							 GDestroyNotify       destroy);
-
-void            gtk_action_group_set_translate_func (GtkActionGroup      *action_group,
-						     GtkTranslateFunc     func,
-						     gpointer             data,
-						     GtkDestroyNotify     notify);
-
+void            gtk_action_group_set_translate_func     (GtkActionGroup      *action_group,
+							 GtkTranslateFunc     func,
+							 gpointer             data,
+							 GtkDestroyNotify     notify);
 void            gtk_action_group_set_translation_domain (GtkActionGroup      *action_group,
 							 const gchar         *domain);
+
+
 
 #endif  /* __GTK_ACTION_GROUP_H__ */
Index: gtk/gtkmarshal.list
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmarshal.list,v
retrieving revision 1.43
diff -u -p -r1.43 gtkmarshal.list
--- gtk/gtkmarshal.list	17 Nov 2001 23:28:50 -0000	1.43
+++ gtk/gtkmarshal.list	5 Sep 2003 09:06:20 -0000
@@ -4,6 +4,7 @@ BOOL:POINTER,POINTER,INT,INT
 BOOL:POINTER,INT,INT
 BOOL:POINTER,INT,INT,UINT
 BOOL:POINTER,STRING,STRING,POINTER
+BOOL:OBJECT
 ENUM:ENUM
 INT:POINTER
 INT:POINTER,CHAR,CHAR
Index: gtk/gtkmarshalers.list
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmarshalers.list,v
retrieving revision 1.53
diff -u -p -r1.53 gtkmarshalers.list
--- gtk/gtkmarshalers.list	11 Jul 2003 12:51:24 -0000	1.53
+++ gtk/gtkmarshalers.list	5 Sep 2003 09:06:20 -0000
@@ -28,6 +28,7 @@ BOOLEAN:ENUM,INT
 BOOLEAN:OBJECT,UINT,FLAGS
 BOOLEAN:OBJECT,INT,INT,UINT
 BOOLEAN:OBJECT,STRING,STRING,BOXED
+BOOLEAN:OBJECT
 BOOLEAN:OBJECT,BOXED
 BOOLEAN:OBJECT,BOXED,BOXED
 BOOLEAN:OBJECT,STRING,STRING
Index: gtk/gtkmenu.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.c,v
retrieving revision 1.139
diff -u -p -r1.139 gtkmenu.c
--- gtk/gtkmenu.c	3 Sep 2003 21:26:13 -0000	1.139
+++ gtk/gtkmenu.c	5 Sep 2003 09:06:21 -0000
@@ -29,6 +29,7 @@
 #include <string.h> /* memset */
 #include "gdk/gdkkeysyms.h"
 #include "gtkaccelmap.h"
+#include "gtkaction.h"
 #include "gtkbindings.h"
 #include "gtklabel.h"
 #include "gtkmain.h"
@@ -2125,6 +2126,13 @@ gtk_menu_key_press (GtkWidget	*widget,
       const gchar *path;
 
       path = _gtk_widget_get_accel_path (menu_item, &locked);
+      if (!path)
+	{
+	  GtkAction *action = g_object_get_data (G_OBJECT (menu_item), 
+						 "gtk-action");
+	  if (action)
+	    path = gtk_action_get_accel_path (action, &locked);
+	}
       if (!path || locked)
 	{
 	  /* can't change accelerators on menu_items without paths
Index: gtk/gtkuimanager.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkuimanager.c,v
retrieving revision 1.16
diff -u -p -r1.16 gtkuimanager.c
--- gtk/gtkuimanager.c	4 Sep 2003 20:39:14 -0000	1.16
+++ gtk/gtkuimanager.c	5 Sep 2003 09:06:22 -0000
@@ -80,8 +80,6 @@ struct _Node {
 
 struct _GtkUIManagerPrivate 
 {
-  GtkAccelGroup *accel_group;
-
   GNode *root_node;
   GList *action_groups;
 
@@ -261,8 +259,6 @@ gtk_ui_manager_init (GtkUIManager *self)
 
   self->private_data = GTK_UI_MANAGER_GET_PRIVATE (self);
 
-  self->private_data->accel_group = gtk_accel_group_new ();
-
   self->private_data->root_node = NULL;
   self->private_data->action_groups = NULL;
 
@@ -470,24 +466,6 @@ gtk_ui_manager_get_action_groups (GtkUIM
 }
 
 /**
- * gtk_ui_manager_get_accel_group:
- * @self: a #GtkUIManager object
- * 
- * Returns the #GtkAccelGroup associated with @self.
- *
- * Return value: the #GtkAccelGroup.
- *
- * Since: 2.4
- **/
-GtkAccelGroup *
-gtk_ui_manager_get_accel_group (GtkUIManager   *self)
-{
-  g_return_val_if_fail (GTK_IS_UI_MANAGER (self), NULL);
-
-  return self->private_data->accel_group;
-}
-
-/**
  * gtk_ui_manager_get_widget:
  * @self: a #GtkUIManager
  * @path: a path
@@ -1636,8 +1614,6 @@ update_node (GtkUIManager *self, 
 	  if (info->proxy == NULL) 
 	    {
 	      info->proxy = gtk_menu_new ();
-	      gtk_menu_set_accel_group (GTK_MENU (info->proxy), 
-					self->private_data->accel_group);
 	    }
 	  break;
 	case NODE_TYPE_MENU:
@@ -1672,7 +1648,6 @@ update_node (GtkUIManager *self, 
 		    GtkWidget *tearoff = gtk_tearoff_menu_item_new ();
 		    gtk_menu_shell_append (GTK_MENU_SHELL (menu), tearoff);
 		    gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), menu);
-		    gtk_menu_set_accel_group (GTK_MENU (menu), self->private_data->accel_group);
 		    gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos);
 		  }
 	      }
Index: gtk/gtkuimanager.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkuimanager.h,v
retrieving revision 1.10
diff -u -p -r1.10 gtkuimanager.h
--- gtk/gtkuimanager.h	4 Sep 2003 20:39:14 -0000	1.10
+++ gtk/gtkuimanager.h	5 Sep 2003 09:06:22 -0000
@@ -95,7 +95,6 @@ void           gtk_ui_manager_insert_act
 void           gtk_ui_manager_remove_action_group (GtkUIManager          *self,
 						   GtkActionGroup        *action_group);
 GList         *gtk_ui_manager_get_action_groups   (GtkUIManager          *self);
-GtkAccelGroup *gtk_ui_manager_get_accel_group     (GtkUIManager          *self);
 GtkWidget     *gtk_ui_manager_get_widget          (GtkUIManager          *self,
 						   const gchar           *path);
 GtkAction     *gtk_ui_manager_get_action          (GtkUIManager          *self,


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