summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <maclas@gmx.de>2003-09-17 23:58:28 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2003-09-17 23:58:28 +0000
commit0ceb0db081e18718f7df81092fbc64788f22b9e3 (patch)
tree93b8695504be9469a33c086ef35beded26b34062
parenta7ad2a46634aa17687521d055bf2f47e1c9738f8 (diff)
downloadgdk-pixbuf-0ceb0db081e18718f7df81092fbc64788f22b9e3.tar.gz
Install accelerators on actions, not on proxies, support accelerator-only
2003-09-18 Matthias Clasen <maclas@gmx.de> Install accelerators on actions, not on proxies, support accelerator-only actions: * gtk/gtkmenu.c (get_accel_path): New function to get the accel path and its lock status either via _gtk_widget_get_accel_path() or by looking at the accel_path stored in the menu item itself and determining its lock status by peeking into the contained accel label. This was already (accidentally) committed a week ago. * gtk/gtkaction.h (gtk_action_set_accel_group): (gtk_action_[dis]connect_accelerator): New functions. * gtk/gtkaction.c (struct _GtkActionPrivate): Add accel_group, accel_closure and accel_count. We must have a reference to the accel_group, since we need it in connect_proxy. The count is necessary to ensure that the accelerator isn't removed before the last proxy requesting it has been unmerged. (connect_proxy): Connect the accelerator to the action now, only set the accel_path on the menuitem. (remove_proxy): Disconnect the accelerator from the action, not from the menuitem. (gtk_action_set_accel_group): Set the accel group. (gtk_action_[dis]connect_accelerator): Count the number of times this functions have been called and install/remove the accelerator if the count leaves/reaches zero. * gtk/gtkuimanager.h (GtkUIManagerItemType): Add GTK_UI_MANAGER_ACCELERATOR. * gtk/gtkuimanager.c (NodeType): Add NODE_TYPE_ACCELERATOR. (start_element_handler): Create NODE_TYPE_ACCELERATOR nodes from <accelerator> elements. (gtk_ui_manager_add_ui): Create NODE_TYPE_ACCELERATOR nodes when type is GTK_UI_MANAGER_ACCELERATOR. (update_node): Set the accel group on actions before creating their proxies. Don't set the accel group on created menus. For NODE_TYPE_ACCELERATOR nodes, [dis]connect the actions' accelerator. (print_node): Also emit <accelerator> elements. * tests/testmerge.c (dump_accels): Add a "Dump Accels" button.
-rw-r--r--ChangeLog41
-rw-r--r--ChangeLog.pre-2-1041
-rw-r--r--ChangeLog.pre-2-441
-rw-r--r--ChangeLog.pre-2-641
-rw-r--r--ChangeLog.pre-2-841
-rw-r--r--docs/reference/ChangeLog5
-rw-r--r--docs/reference/gtk/gtk-sections.txt3
-rw-r--r--docs/reference/gtk/tmpl/gtkuimanager.sgml20
-rw-r--r--gtk/gtkaction.c174
-rw-r--r--gtk/gtkaction.h43
-rw-r--r--gtk/gtkuimanager.c54
-rw-r--r--gtk/gtkuimanager.h3
-rw-r--r--tests/testmerge.c11
13 files changed, 460 insertions, 58 deletions
diff --git a/ChangeLog b/ChangeLog
index 6f05370c4..6d8a26ab4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de>
+ Install accelerators on actions, not on proxies, support
+ accelerator-only actions:
+
+ * gtk/gtkmenu.c (get_accel_path): New function to get the accel path
+ and its lock status either via _gtk_widget_get_accel_path() or by
+ looking at the accel_path stored in the menu item itself and determining
+ its lock status by peeking into the contained accel label. This was
+ already (accidentally) committed a week ago.
+
+ * gtk/gtkaction.h (gtk_action_set_accel_group):
+ (gtk_action_[dis]connect_accelerator): New functions.
+
+ * gtk/gtkaction.c (struct _GtkActionPrivate): Add accel_group,
+ accel_closure and accel_count. We must have a reference to the accel_group,
+ since we need it in connect_proxy. The count is necessary to ensure
+ that the accelerator isn't removed before the last proxy requesting
+ it has been unmerged.
+ (connect_proxy): Connect the accelerator to the
+ action now, only set the accel_path on the menuitem.
+ (remove_proxy): Disconnect the accelerator from the action, not from
+ the menuitem.
+ (gtk_action_set_accel_group): Set the accel group.
+ (gtk_action_[dis]connect_accelerator): Count the number of times
+ this functions have been called and install/remove the accelerator if
+ the count leaves/reaches zero.
+
+ * gtk/gtkuimanager.h (GtkUIManagerItemType): Add
+ GTK_UI_MANAGER_ACCELERATOR.
+
+ * gtk/gtkuimanager.c (NodeType): Add NODE_TYPE_ACCELERATOR.
+ (start_element_handler): Create NODE_TYPE_ACCELERATOR nodes from
+ <accelerator> elements.
+ (gtk_ui_manager_add_ui): Create NODE_TYPE_ACCELERATOR nodes when
+ type is GTK_UI_MANAGER_ACCELERATOR.
+ (update_node): Set the accel group on actions before creating their
+ proxies. Don't set the accel group on created menus. For
+ NODE_TYPE_ACCELERATOR nodes, [dis]connect the actions' accelerator.
+ (print_node): Also emit <accelerator> elements.
+
+ * tests/testmerge.c (dump_accels): Add a "Dump Accels" button.
+
* gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de>
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 6f05370c4..6d8a26ab4 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de>
+ Install accelerators on actions, not on proxies, support
+ accelerator-only actions:
+
+ * gtk/gtkmenu.c (get_accel_path): New function to get the accel path
+ and its lock status either via _gtk_widget_get_accel_path() or by
+ looking at the accel_path stored in the menu item itself and determining
+ its lock status by peeking into the contained accel label. This was
+ already (accidentally) committed a week ago.
+
+ * gtk/gtkaction.h (gtk_action_set_accel_group):
+ (gtk_action_[dis]connect_accelerator): New functions.
+
+ * gtk/gtkaction.c (struct _GtkActionPrivate): Add accel_group,
+ accel_closure and accel_count. We must have a reference to the accel_group,
+ since we need it in connect_proxy. The count is necessary to ensure
+ that the accelerator isn't removed before the last proxy requesting
+ it has been unmerged.
+ (connect_proxy): Connect the accelerator to the
+ action now, only set the accel_path on the menuitem.
+ (remove_proxy): Disconnect the accelerator from the action, not from
+ the menuitem.
+ (gtk_action_set_accel_group): Set the accel group.
+ (gtk_action_[dis]connect_accelerator): Count the number of times
+ this functions have been called and install/remove the accelerator if
+ the count leaves/reaches zero.
+
+ * gtk/gtkuimanager.h (GtkUIManagerItemType): Add
+ GTK_UI_MANAGER_ACCELERATOR.
+
+ * gtk/gtkuimanager.c (NodeType): Add NODE_TYPE_ACCELERATOR.
+ (start_element_handler): Create NODE_TYPE_ACCELERATOR nodes from
+ <accelerator> elements.
+ (gtk_ui_manager_add_ui): Create NODE_TYPE_ACCELERATOR nodes when
+ type is GTK_UI_MANAGER_ACCELERATOR.
+ (update_node): Set the accel group on actions before creating their
+ proxies. Don't set the accel group on created menus. For
+ NODE_TYPE_ACCELERATOR nodes, [dis]connect the actions' accelerator.
+ (print_node): Also emit <accelerator> elements.
+
+ * tests/testmerge.c (dump_accels): Add a "Dump Accels" button.
+
* gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de>
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 6f05370c4..6d8a26ab4 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de>
+ Install accelerators on actions, not on proxies, support
+ accelerator-only actions:
+
+ * gtk/gtkmenu.c (get_accel_path): New function to get the accel path
+ and its lock status either via _gtk_widget_get_accel_path() or by
+ looking at the accel_path stored in the menu item itself and determining
+ its lock status by peeking into the contained accel label. This was
+ already (accidentally) committed a week ago.
+
+ * gtk/gtkaction.h (gtk_action_set_accel_group):
+ (gtk_action_[dis]connect_accelerator): New functions.
+
+ * gtk/gtkaction.c (struct _GtkActionPrivate): Add accel_group,
+ accel_closure and accel_count. We must have a reference to the accel_group,
+ since we need it in connect_proxy. The count is necessary to ensure
+ that the accelerator isn't removed before the last proxy requesting
+ it has been unmerged.
+ (connect_proxy): Connect the accelerator to the
+ action now, only set the accel_path on the menuitem.
+ (remove_proxy): Disconnect the accelerator from the action, not from
+ the menuitem.
+ (gtk_action_set_accel_group): Set the accel group.
+ (gtk_action_[dis]connect_accelerator): Count the number of times
+ this functions have been called and install/remove the accelerator if
+ the count leaves/reaches zero.
+
+ * gtk/gtkuimanager.h (GtkUIManagerItemType): Add
+ GTK_UI_MANAGER_ACCELERATOR.
+
+ * gtk/gtkuimanager.c (NodeType): Add NODE_TYPE_ACCELERATOR.
+ (start_element_handler): Create NODE_TYPE_ACCELERATOR nodes from
+ <accelerator> elements.
+ (gtk_ui_manager_add_ui): Create NODE_TYPE_ACCELERATOR nodes when
+ type is GTK_UI_MANAGER_ACCELERATOR.
+ (update_node): Set the accel group on actions before creating their
+ proxies. Don't set the accel group on created menus. For
+ NODE_TYPE_ACCELERATOR nodes, [dis]connect the actions' accelerator.
+ (print_node): Also emit <accelerator> elements.
+
+ * tests/testmerge.c (dump_accels): Add a "Dump Accels" button.
+
* gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de>
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 6f05370c4..6d8a26ab4 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de>
+ Install accelerators on actions, not on proxies, support
+ accelerator-only actions:
+
+ * gtk/gtkmenu.c (get_accel_path): New function to get the accel path
+ and its lock status either via _gtk_widget_get_accel_path() or by
+ looking at the accel_path stored in the menu item itself and determining
+ its lock status by peeking into the contained accel label. This was
+ already (accidentally) committed a week ago.
+
+ * gtk/gtkaction.h (gtk_action_set_accel_group):
+ (gtk_action_[dis]connect_accelerator): New functions.
+
+ * gtk/gtkaction.c (struct _GtkActionPrivate): Add accel_group,
+ accel_closure and accel_count. We must have a reference to the accel_group,
+ since we need it in connect_proxy. The count is necessary to ensure
+ that the accelerator isn't removed before the last proxy requesting
+ it has been unmerged.
+ (connect_proxy): Connect the accelerator to the
+ action now, only set the accel_path on the menuitem.
+ (remove_proxy): Disconnect the accelerator from the action, not from
+ the menuitem.
+ (gtk_action_set_accel_group): Set the accel group.
+ (gtk_action_[dis]connect_accelerator): Count the number of times
+ this functions have been called and install/remove the accelerator if
+ the count leaves/reaches zero.
+
+ * gtk/gtkuimanager.h (GtkUIManagerItemType): Add
+ GTK_UI_MANAGER_ACCELERATOR.
+
+ * gtk/gtkuimanager.c (NodeType): Add NODE_TYPE_ACCELERATOR.
+ (start_element_handler): Create NODE_TYPE_ACCELERATOR nodes from
+ <accelerator> elements.
+ (gtk_ui_manager_add_ui): Create NODE_TYPE_ACCELERATOR nodes when
+ type is GTK_UI_MANAGER_ACCELERATOR.
+ (update_node): Set the accel group on actions before creating their
+ proxies. Don't set the accel group on created menus. For
+ NODE_TYPE_ACCELERATOR nodes, [dis]connect the actions' accelerator.
+ (print_node): Also emit <accelerator> elements.
+
+ * tests/testmerge.c (dump_accels): Add a "Dump Accels" button.
+
* gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de>
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 6f05370c4..6d8a26ab4 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de>
+ Install accelerators on actions, not on proxies, support
+ accelerator-only actions:
+
+ * gtk/gtkmenu.c (get_accel_path): New function to get the accel path
+ and its lock status either via _gtk_widget_get_accel_path() or by
+ looking at the accel_path stored in the menu item itself and determining
+ its lock status by peeking into the contained accel label. This was
+ already (accidentally) committed a week ago.
+
+ * gtk/gtkaction.h (gtk_action_set_accel_group):
+ (gtk_action_[dis]connect_accelerator): New functions.
+
+ * gtk/gtkaction.c (struct _GtkActionPrivate): Add accel_group,
+ accel_closure and accel_count. We must have a reference to the accel_group,
+ since we need it in connect_proxy. The count is necessary to ensure
+ that the accelerator isn't removed before the last proxy requesting
+ it has been unmerged.
+ (connect_proxy): Connect the accelerator to the
+ action now, only set the accel_path on the menuitem.
+ (remove_proxy): Disconnect the accelerator from the action, not from
+ the menuitem.
+ (gtk_action_set_accel_group): Set the accel group.
+ (gtk_action_[dis]connect_accelerator): Count the number of times
+ this functions have been called and install/remove the accelerator if
+ the count leaves/reaches zero.
+
+ * gtk/gtkuimanager.h (GtkUIManagerItemType): Add
+ GTK_UI_MANAGER_ACCELERATOR.
+
+ * gtk/gtkuimanager.c (NodeType): Add NODE_TYPE_ACCELERATOR.
+ (start_element_handler): Create NODE_TYPE_ACCELERATOR nodes from
+ <accelerator> elements.
+ (gtk_ui_manager_add_ui): Create NODE_TYPE_ACCELERATOR nodes when
+ type is GTK_UI_MANAGER_ACCELERATOR.
+ (update_node): Set the accel group on actions before creating their
+ proxies. Don't set the accel group on created menus. For
+ NODE_TYPE_ACCELERATOR nodes, [dis]connect the actions' accelerator.
+ (print_node): Also emit <accelerator> elements.
+
+ * tests/testmerge.c (dump_accels): Add a "Dump Accels" button.
+
* gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de>
diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog
index 06819cedc..90e865517 100644
--- a/docs/reference/ChangeLog
+++ b/docs/reference/ChangeLog
@@ -1,3 +1,8 @@
+2003-09-18 Matthias Clasen <maclas@gmx.de>
+
+ * gtk/gtk-sections.txt:
+ * gtk/tmpl/gtkuimanager.sgml: Updates for accelerator-only actions.
+
2003-09-16 Matthias Clasen <maclas@gmx.de>
* gtk/tmpl/gtkaction.sgml:
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 5c9cf15a3..6b396f55e 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -110,9 +110,12 @@ gtk_action_create_tool_item
gtk_action_connect_proxy
gtk_action_disconnect_proxy
gtk_action_get_proxies
+gtk_action_connect_accelerator
+gtk_action_disconnect_accelerator
gtk_action_block_activate_from
gtk_action_unblock_activate_from
gtk_action_set_accel_path
+gtk_action_set_accel_group
<SUBSECTION Standard>
GTK_TYPE_ACTION
GTK_ACTION
diff --git a/docs/reference/gtk/tmpl/gtkuimanager.sgml b/docs/reference/gtk/tmpl/gtkuimanager.sgml
index c649055d2..69aaec51a 100644
--- a/docs/reference/gtk/tmpl/gtkuimanager.sgml
+++ b/docs/reference/gtk/tmpl/gtkuimanager.sgml
@@ -15,7 +15,7 @@ action groups.
The UI definitions are specified in an XML format which can be
roughly described by the following DTD.
<programlisting>
-&lt;!ELEMENT ui (menubar|toolbar|popup)* &gt;
+&lt;!ELEMENT ui (menubar|toolbar|popup|accelerator)* &gt;
&lt;!ELEMENT menubar (menuitem|separator|placeholder|menu)* &gt;
&lt;!ELEMENT menu (menuitem|separator|placeholder|menu)* &gt;
&lt;!ELEMENT popup (menuitem|separator|placeholder|menu)* &gt;
@@ -24,6 +24,7 @@ roughly described by the following DTD.
&lt;!ELEMENT menuitem EMPTY &gt;
&lt;!ELEMENT toolitem EMPTY &gt;
&lt;!ELEMENT separator EMPTY &gt;
+&lt;!ELEMENT accelerator EMPTY &gt;
&lt;!ATTLIST menubar name &num;IMPLIED &gt;
&lt;!ATTLIST toolbar name &num;IMPLIED &gt;
&lt;!ATTLIST popup name &num;IMPLIED &gt;
@@ -37,6 +38,8 @@ roughly described by the following DTD.
&lt;!ATTLIST toolitem name &num;IMPLIED
action &num;REQUIRED
position (top|bot) &num;IMPLIED &gt;
+&lt;!ATTLIST accelerator name &num;IMPLIED
+ action &num;REQUIRED &gt;
</programlisting>
There are some additional restrictions beyond those specified in the
DTD, e.g. every toolitem must have a toolbar in its anchestry and
@@ -105,6 +108,9 @@ action</para></listitem>
<listitem><para>a #GtkSeparatorMenuItem or
#GtkSeparatorToolItem</para></listitem>
</varlistentry>
+<varlistentry><term>accelerator</term>
+<listitem><para>a keyboard accelerator</para></listitem>
+</varlistentry>
</variablelist>
</para>
<para>
@@ -127,6 +133,16 @@ has the path <literal>/ui/menubar/JustifyMenu/Left</literal> and the
toolitem with the same name has path
<literal>/ui/toolbar1/JustifyToolItems/Left</literal>.
</para>
+</refsect2>
+<refsect2>
+<title>Accelerators</title>
+<para>
+Every action has an accelerator path. Accelerators are installed together with
+menuitem proxies, but they can also be explicitly added with &lt;accelerator&gt;
+elements in the UI definition. This makes it possible to have accelerators for
+actions even if they have no visible proxies.
+</para>
+</refsect2>
<refsect2 id="Smart-Separators">
<title>Smart Separators</title>
<para>
@@ -138,7 +154,6 @@ from multiple sources can make it hard or impossible to determine in advance whe
separator will end up in such an unfortunate position.
</para>
</refsect2>
-</refsect2>
<!-- ##### SECTION See_Also ##### -->
<para>
@@ -282,6 +297,7 @@ what UI element to create.
@GTK_UI_MANAGER_MENUITEM: Create a menuitem.
@GTK_UI_MANAGER_TOOLITEM: Create a toolitem.
@GTK_UI_MANAGER_SEPARATOR: Create a separator.
+@GTK_UI_MANAGER_ACCELERATOR: Install an accelerator.
<!-- ##### FUNCTION gtk_ui_manager_add_ui ##### -->
<para>
diff --git a/gtk/gtkaction.c b/gtk/gtkaction.c
index df4301450..e4d96d88a 100644
--- a/gtk/gtkaction.c
+++ b/gtk/gtkaction.c
@@ -59,7 +59,10 @@ struct _GtkActionPrivate
guint is_important : 1;
/* accelerator */
- GQuark accel_quark;
+ guint accel_count;
+ GtkAccelGroup *accel_group;
+ GClosure *accel_closure;
+ GQuark accel_quark;
/* list of proxy widgets */
GSList *proxies;
@@ -130,10 +133,16 @@ static void gtk_action_get_property (GObject *object,
static GtkWidget *create_menu_item (GtkAction *action);
static GtkWidget *create_tool_item (GtkAction *action);
-static void connect_proxy (GtkAction *action,
- GtkWidget *proxy);
+static void connect_proxy (GtkAction *action,
+ GtkWidget *proxy);
static void disconnect_proxy (GtkAction *action,
GtkWidget *proxy);
+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 GObjectClass *parent_class = NULL;
static guint action_signals[LAST_SIGNAL] = { 0 };
@@ -260,7 +269,17 @@ gtk_action_init (GtkAction *action)
action->private_data->label_set = FALSE;
action->private_data->short_label_set = FALSE;
+ action->private_data->accel_count = 0;
+ 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_quark = 0;
+ action->private_data->accel_count = 0;
+ action->private_data->accel_group = NULL;
action->private_data->proxies = NULL;
}
@@ -277,6 +296,10 @@ gtk_action_finalize (GObject *object)
g_free (action->private_data->short_label);
g_free (action->private_data->tooltip);
g_free (action->private_data->stock_id);
+
+ g_object_unref (action->private_data->accel_closure);
+ if (action->private_data->accel_group)
+ g_object_unref (action->private_data->accel_group);
}
static void
@@ -441,7 +464,7 @@ remove_proxy (GtkWidget *proxy,
GtkAction *action)
{
if (GTK_IS_MENU_ITEM (proxy))
- gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy), NULL);
+ gtk_action_disconnect_accelerator (action);
action->private_data->proxies = g_slist_remove (action->private_data->proxies, proxy);
}
@@ -524,8 +547,8 @@ gtk_action_create_menu_proxy (GtkToolItem *tool_item,
}
static void
-connect_proxy (GtkAction *action,
- GtkWidget *proxy)
+connect_proxy (GtkAction *action,
+ GtkWidget *proxy)
{
g_object_ref (action);
g_object_set_data_full (G_OBJECT (proxy), "gtk-action", action,
@@ -552,6 +575,13 @@ connect_proxy (GtkAction *action,
GtkWidget *label;
/* menu item specific synchronisers ... */
+ if (action->private_data->accel_quark)
+ {
+ gtk_action_connect_accelerator (action);
+ gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy),
+ g_quark_to_string (action->private_data->accel_quark));
+ }
+
label = GTK_BIN (proxy)->child;
/* make sure label is a label */
@@ -560,16 +590,20 @@ connect_proxy (GtkAction *action,
gtk_container_remove (GTK_CONTAINER (proxy), label);
label = NULL;
}
+
if (!label)
- {
- label = g_object_new (GTK_TYPE_ACCEL_LABEL,
- "use_underline", TRUE,
- "xalign", 0.0,
- "visible", TRUE,
- "parent", proxy,
- "accel_widget", proxy,
- NULL);
- }
+ label = g_object_new (GTK_TYPE_ACCEL_LABEL,
+ "use_underline", TRUE,
+ "xalign", 0.0,
+ "visible", TRUE,
+ "parent", proxy,
+ NULL);
+
+ if (GTK_IS_ACCEL_LABEL (label) && action->private_data->accel_quark)
+ g_object_set (G_OBJECT (label),
+ "accel_closure", action->private_data->accel_closure,
+ NULL);
+
gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
g_signal_connect_object (action, "notify::label",
G_CALLBACK (gtk_action_sync_label), proxy, 0);
@@ -599,15 +633,10 @@ connect_proxy (GtkAction *action,
proxy, 0);
}
- if (action->private_data->accel_quark)
- {
- gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy),
- g_quark_to_string (action->private_data->accel_quark));
- }
-
g_signal_connect_object (proxy, "activate",
G_CALLBACK (gtk_action_activate), action,
G_CONNECT_SWAPPED);
+
}
else if (GTK_IS_TOOL_BUTTON (proxy))
{
@@ -923,6 +952,21 @@ gtk_action_unblock_activate_from (GtkAction *action,
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
@@ -938,5 +982,93 @@ void
gtk_action_set_accel_path (GtkAction *action,
const gchar *accel_path)
{
+ g_return_if_fail (GTK_IS_ACTION (action));
+
action->private_data->accel_quark = g_quark_from_string (accel_path);
}
+
+/**
+ * gtk_action_set_accel_group:
+ * @action: the action object
+ * @accel_group: a #GtkAccelGroup or %NULL
+ *
+ * Sets the #GtkAccelGroup in which the accelerator for this action
+ * will be installed.
+ *
+ * Since: 2.4
+ **/
+void
+gtk_action_set_accel_group (GtkAction *action,
+ GtkAccelGroup *accel_group)
+{
+ g_return_if_fail (GTK_IS_ACTION (action));
+ g_return_if_fail (accel_group == NULL || GTK_IS_ACCEL_GROUP (accel_group));
+
+ if (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;
+}
+
+/**
+ * gtk_action_connect_accelerator:
+ * @action: a #GtkAction
+ *
+ * Installs the accelerator for @action if @action has an
+ * accel path and group. See gtk_action_set_accel_path() and
+ * gtk_action_set_accel_group()
+ *
+ * Since multiple proxies may independently trigger the installation
+ * of the accelerator, the @action counts the number of times this
+ * function has been called and doesn't remove the accelerator until
+ * gtk_action_disconnect_accelerator() has been called as many times.
+ *
+ * Since: 2.4
+ **/
+void
+gtk_action_connect_accelerator (GtkAction *action)
+{
+ g_return_if_fail (GTK_IS_ACTION (action));
+
+ if (!action->private_data->accel_quark ||
+ !action->private_data->accel_group)
+ return;
+
+ if (action->private_data->accel_count == 0)
+ {
+ const gchar *accel_path =
+ g_quark_to_string (action->private_data->accel_quark);
+
+ gtk_accel_group_connect_by_path (action->private_data->accel_group,
+ accel_path,
+ action->private_data->accel_closure);
+ }
+
+ action->private_data->accel_count++;
+}
+
+/**
+ * gtk_action_disconnect_accelerator:
+ * @action: a #GtkAction
+ *
+ * Undoes the effect of one call to gtk_action_connect_accelerator().
+ *
+ * Since: 2.4
+ **/
+void
+gtk_action_disconnect_accelerator (GtkAction *action)
+{
+ g_return_if_fail (GTK_IS_ACTION (action));
+
+ if (!action->private_data->accel_quark ||
+ !action->private_data->accel_group)
+ return;
+
+ action->private_data->accel_count--;
+
+ if (action->private_data->accel_count == 0)
+ gtk_accel_group_disconnect (action->private_data->accel_group,
+ action->private_data->accel_closure);
+}
diff --git a/gtk/gtkaction.h b/gtk/gtkaction.h
index 5e6c05bc4..883229836 100644
--- a/gtk/gtkaction.h
+++ b/gtk/gtkaction.h
@@ -78,31 +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);
+void gtk_action_connect_accelerator (GtkAction *action);
+void gtk_action_disconnect_accelerator (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);
+void gtk_action_set_accel_group (GtkAction *action,
+ GtkAccelGroup *accel_group);
#endif /* __GTK_ACTION_H__ */
diff --git a/gtk/gtkuimanager.c b/gtk/gtkuimanager.c
index 838a896e2..203604712 100644
--- a/gtk/gtkuimanager.c
+++ b/gtk/gtkuimanager.c
@@ -56,6 +56,7 @@ typedef enum
NODE_TYPE_MENUITEM,
NODE_TYPE_TOOLITEM,
NODE_TYPE_SEPARATOR,
+ NODE_TYPE_ACCELERATOR
} NodeType;
@@ -861,6 +862,24 @@ start_element_handler (GMarkupParseContext *context,
switch (element_name[0])
{
+ case 'a':
+ if (ctx->state == STATE_ROOT && !strcmp (element_name, "accelerator"))
+ {
+ ctx->state = STATE_ROOT;
+ ctx->current = get_child_node (self, ctx->current,
+ node_name, strlen (node_name),
+ NODE_TYPE_ACCELERATOR,
+ TRUE, FALSE);
+ if (NODE_INFO (ctx->current)->action_name == 0)
+ NODE_INFO (ctx->current)->action_name = action_quark;
+
+ node_prepend_ui_reference (NODE_INFO (ctx->current),
+ ctx->merge_id, action_quark);
+ NODE_INFO (ctx->current)->dirty = TRUE;
+
+ raise_error = FALSE;
+ }
+ break;
case 'u':
if (ctx->state == STATE_START && !strcmp (element_name, "ui"))
{
@@ -1131,7 +1150,6 @@ static GMarkupParser ui_parser = {
cleanup
};
-
static guint
add_ui_from_string (GtkUIManager *self,
const gchar *buffer,
@@ -1205,8 +1223,8 @@ gtk_ui_manager_add_ui_from_string (GtkUIManager *self,
const gchar *p;
const gchar *end;
- g_return_val_if_fail (GTK_IS_UI_MANAGER (self), FALSE);
- g_return_val_if_fail (buffer != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_UI_MANAGER (self), 0);
+ g_return_val_if_fail (buffer != NULL, 0);
if (length < 0)
length = strlen (buffer);
@@ -1246,6 +1264,8 @@ gtk_ui_manager_add_ui_from_file (GtkUIManager *self,
gint length;
guint res;
+ g_return_val_if_fail (GTK_IS_UI_MANAGER (self), 0);
+
if (!g_file_get_contents (filename, &buffer, &length, error))
return 0;
@@ -1365,6 +1385,9 @@ gtk_ui_manager_add_ui (GtkUIManager *self,
case GTK_UI_MANAGER_POPUP:
node_type = NODE_TYPE_POPUP;
break;
+ case GTK_UI_MANAGER_ACCELERATOR:
+ node_type = NODE_TYPE_ACCELERATOR;
+ break;
default: ;
/* do nothing */
}
@@ -1734,6 +1757,9 @@ update_node (GtkUIManager *self,
goto recurse_children;
}
+ if (action)
+ gtk_action_set_accel_group (action, self->private_data->accel_group);
+
/* If the widget already has a proxy and the action hasn't changed, then
* we only have to update the tearoff menu items.
*/
@@ -1765,11 +1791,7 @@ update_node (GtkUIManager *self,
break;
case NODE_TYPE_POPUP:
if (info->proxy == NULL)
- {
- info->proxy = gtk_menu_new ();
- gtk_menu_set_accel_group (GTK_MENU (info->proxy),
- self->private_data->accel_group);
- }
+ info->proxy = gtk_menu_new ();
break;
case NODE_TYPE_MENU:
{
@@ -1806,7 +1828,6 @@ update_node (GtkUIManager *self,
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);
}
}
@@ -2045,6 +2066,9 @@ update_node (GtkUIManager *self,
}
}
break;
+ case NODE_TYPE_ACCELERATOR:
+ gtk_action_connect_accelerator (action);
+ break;
}
if (action)
@@ -2065,10 +2089,10 @@ update_node (GtkUIManager *self,
child = current->next;
update_node (self, current, add_tearoffs && (info->type != NODE_TYPE_POPUP));
}
-
- if (info->proxy)
+
+ if (info->proxy)
{
- if (info->type == NODE_TYPE_MENU)
+ if (info->type == NODE_TYPE_MENU)
update_smart_separators (gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)));
else if (info->type == NODE_TYPE_TOOLBAR)
update_smart_separators (info->proxy);
@@ -2081,6 +2105,8 @@ update_node (GtkUIManager *self,
gtk_widget_destroy (info->proxy);
if (info->extra)
gtk_widget_destroy (info->extra);
+ if (info->type == NODE_TYPE_ACCELERATOR)
+ gtk_action_disconnect_accelerator (info->action);
free_node (node);
g_node_destroy (node);
}
@@ -2181,7 +2207,8 @@ static const gchar *open_tag_format[] = {
"%*s<popup name='%s' action=\"%s\">\n",
"%*s<menuitem name=\"%s\" action=\"%s\"/>\n",
"%*s<toolitem name=\"%s\" action=\"%s\"/>\n",
- "%*s<separator/>\n",
+ "%*s<separator name=\"%s\"/>\n",
+ "%*s<accelerator name=\"%s\" action=\"%s\"/>\n",
};
static const gchar *close_tag_format[] = {
@@ -2196,6 +2223,7 @@ static const gchar *close_tag_format[] = {
"",
"",
"",
+ "",
};
static void
diff --git a/gtk/gtkuimanager.h b/gtk/gtkuimanager.h
index 844f4f051..169415941 100644
--- a/gtk/gtkuimanager.h
+++ b/gtk/gtkuimanager.h
@@ -81,7 +81,8 @@ typedef enum {
GTK_UI_MANAGER_POPUP,
GTK_UI_MANAGER_MENUITEM,
GTK_UI_MANAGER_TOOLITEM,
- GTK_UI_MANAGER_SEPARATOR
+ GTK_UI_MANAGER_SEPARATOR,
+ GTK_UI_MANAGER_ACCELERATOR
} GtkUIManagerItemType;
GType gtk_ui_manager_get_type (void);
diff --git a/tests/testmerge.c b/tests/testmerge.c
index 4b40f1262..c79090b20 100644
--- a/tests/testmerge.c
+++ b/tests/testmerge.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include <gtk/gtk.h>
struct { const gchar *filename; guint merge_id; } merge_ids[] = {
@@ -20,6 +21,12 @@ dump_tree (GtkWidget *button,
}
static void
+dump_accels (void)
+{
+ gtk_accel_map_save_fd (STDOUT_FILENO);
+}
+
+static void
toggle_tearoffs (GtkWidget *button,
GtkUIManager *merge)
{
@@ -538,6 +545,10 @@ main (int argc, char **argv)
g_signal_connect (button, "clicked", G_CALLBACK (dump_tree), merge);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+ button = gtk_button_new_with_label ("Dump Accels");
+ g_signal_connect (button, "clicked", G_CALLBACK (dump_accels), NULL);
+ gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
view = create_tree_view (merge);
gtk_table_attach (GTK_TABLE (table), view, 1,2, 0,1,
GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);