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.
This commit is contained in:
Matthias Clasen 2003-09-17 23:58:28 +00:00 committed by Matthias Clasen
parent a7ad2a4663
commit 0ceb0db081
13 changed files with 460 additions and 58 deletions

View File

@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de> 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. * gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de> 2003-09-17 Matthias Clasen <maclas@gmx.de>

View File

@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de> 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. * gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de> 2003-09-17 Matthias Clasen <maclas@gmx.de>

View File

@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de> 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. * gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de> 2003-09-17 Matthias Clasen <maclas@gmx.de>

View File

@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de> 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. * gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de> 2003-09-17 Matthias Clasen <maclas@gmx.de>

View File

@ -1,5 +1,46 @@
2003-09-18 Matthias Clasen <maclas@gmx.de> 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. * gtk/gtkuimanager.c (update_node): Robustness improvements.
2003-09-17 Matthias Clasen <maclas@gmx.de> 2003-09-17 Matthias Clasen <maclas@gmx.de>

View File

@ -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> 2003-09-16 Matthias Clasen <maclas@gmx.de>
* gtk/tmpl/gtkaction.sgml: * gtk/tmpl/gtkaction.sgml:

View File

@ -110,9 +110,12 @@ gtk_action_create_tool_item
gtk_action_connect_proxy gtk_action_connect_proxy
gtk_action_disconnect_proxy gtk_action_disconnect_proxy
gtk_action_get_proxies gtk_action_get_proxies
gtk_action_connect_accelerator
gtk_action_disconnect_accelerator
gtk_action_block_activate_from gtk_action_block_activate_from
gtk_action_unblock_activate_from gtk_action_unblock_activate_from
gtk_action_set_accel_path gtk_action_set_accel_path
gtk_action_set_accel_group
<SUBSECTION Standard> <SUBSECTION Standard>
GTK_TYPE_ACTION GTK_TYPE_ACTION
GTK_ACTION GTK_ACTION

View File

@ -15,7 +15,7 @@ action groups.
The UI definitions are specified in an XML format which can be The UI definitions are specified in an XML format which can be
roughly described by the following DTD. roughly described by the following DTD.
<programlisting> <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 menubar (menuitem|separator|placeholder|menu)* &gt;
&lt;!ELEMENT menu (menuitem|separator|placeholder|menu)* &gt; &lt;!ELEMENT menu (menuitem|separator|placeholder|menu)* &gt;
&lt;!ELEMENT popup (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 menuitem EMPTY &gt;
&lt;!ELEMENT toolitem EMPTY &gt; &lt;!ELEMENT toolitem EMPTY &gt;
&lt;!ELEMENT separator EMPTY &gt; &lt;!ELEMENT separator EMPTY &gt;
&lt;!ELEMENT accelerator EMPTY &gt;
&lt;!ATTLIST menubar name &num;IMPLIED &gt; &lt;!ATTLIST menubar name &num;IMPLIED &gt;
&lt;!ATTLIST toolbar name &num;IMPLIED &gt; &lt;!ATTLIST toolbar name &num;IMPLIED &gt;
&lt;!ATTLIST popup 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 &lt;!ATTLIST toolitem name &num;IMPLIED
action &num;REQUIRED action &num;REQUIRED
position (top|bot) &num;IMPLIED &gt; position (top|bot) &num;IMPLIED &gt;
&lt;!ATTLIST accelerator name &num;IMPLIED
action &num;REQUIRED &gt;
</programlisting> </programlisting>
There are some additional restrictions beyond those specified in the There are some additional restrictions beyond those specified in the
DTD, e.g. every toolitem must have a toolbar in its anchestry and 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 <listitem><para>a #GtkSeparatorMenuItem or
#GtkSeparatorToolItem</para></listitem> #GtkSeparatorToolItem</para></listitem>
</varlistentry> </varlistentry>
<varlistentry><term>accelerator</term>
<listitem><para>a keyboard accelerator</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
<para> <para>
@ -127,6 +133,16 @@ has the path <literal>/ui/menubar/JustifyMenu/Left</literal> and the
toolitem with the same name has path toolitem with the same name has path
<literal>/ui/toolbar1/JustifyToolItems/Left</literal>. <literal>/ui/toolbar1/JustifyToolItems/Left</literal>.
</para> </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"> <refsect2 id="Smart-Separators">
<title>Smart Separators</title> <title>Smart Separators</title>
<para> <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. separator will end up in such an unfortunate position.
</para> </para>
</refsect2> </refsect2>
</refsect2>
<!-- ##### SECTION See_Also ##### --> <!-- ##### SECTION See_Also ##### -->
<para> <para>
@ -282,6 +297,7 @@ what UI element to create.
@GTK_UI_MANAGER_MENUITEM: Create a menuitem. @GTK_UI_MANAGER_MENUITEM: Create a menuitem.
@GTK_UI_MANAGER_TOOLITEM: Create a toolitem. @GTK_UI_MANAGER_TOOLITEM: Create a toolitem.
@GTK_UI_MANAGER_SEPARATOR: Create a separator. @GTK_UI_MANAGER_SEPARATOR: Create a separator.
@GTK_UI_MANAGER_ACCELERATOR: Install an accelerator.
<!-- ##### FUNCTION gtk_ui_manager_add_ui ##### --> <!-- ##### FUNCTION gtk_ui_manager_add_ui ##### -->
<para> <para>

View File

@ -59,6 +59,9 @@ struct _GtkActionPrivate
guint is_important : 1; guint is_important : 1;
/* accelerator */ /* accelerator */
guint accel_count;
GtkAccelGroup *accel_group;
GClosure *accel_closure;
GQuark accel_quark; GQuark accel_quark;
/* list of proxy widgets */ /* list of proxy widgets */
@ -134,6 +137,12 @@ static void connect_proxy (GtkAction *action,
GtkWidget *proxy); GtkWidget *proxy);
static void disconnect_proxy (GtkAction *action, static void disconnect_proxy (GtkAction *action,
GtkWidget *proxy); 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 GObjectClass *parent_class = NULL;
static guint action_signals[LAST_SIGNAL] = { 0 }; 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->label_set = FALSE;
action->private_data->short_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_quark = 0;
action->private_data->accel_count = 0;
action->private_data->accel_group = NULL;
action->private_data->proxies = 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->short_label);
g_free (action->private_data->tooltip); g_free (action->private_data->tooltip);
g_free (action->private_data->stock_id); 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 static void
@ -441,7 +464,7 @@ remove_proxy (GtkWidget *proxy,
GtkAction *action) GtkAction *action)
{ {
if (GTK_IS_MENU_ITEM (proxy)) 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); action->private_data->proxies = g_slist_remove (action->private_data->proxies, proxy);
} }
@ -552,6 +575,13 @@ connect_proxy (GtkAction *action,
GtkWidget *label; GtkWidget *label;
/* menu item specific synchronisers ... */ /* 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; label = GTK_BIN (proxy)->child;
/* make sure label is a label */ /* make sure label is a label */
@ -560,16 +590,20 @@ connect_proxy (GtkAction *action,
gtk_container_remove (GTK_CONTAINER (proxy), label); gtk_container_remove (GTK_CONTAINER (proxy), label);
label = NULL; label = NULL;
} }
if (!label) if (!label)
{
label = g_object_new (GTK_TYPE_ACCEL_LABEL, label = g_object_new (GTK_TYPE_ACCEL_LABEL,
"use_underline", TRUE, "use_underline", TRUE,
"xalign", 0.0, "xalign", 0.0,
"visible", TRUE, "visible", TRUE,
"parent", proxy, "parent", proxy,
"accel_widget", proxy,
NULL); 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); gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
g_signal_connect_object (action, "notify::label", g_signal_connect_object (action, "notify::label",
G_CALLBACK (gtk_action_sync_label), proxy, 0); G_CALLBACK (gtk_action_sync_label), proxy, 0);
@ -599,15 +633,10 @@ connect_proxy (GtkAction *action,
proxy, 0); 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_signal_connect_object (proxy, "activate",
G_CALLBACK (gtk_action_activate), action, G_CALLBACK (gtk_action_activate), action,
G_CONNECT_SWAPPED); G_CONNECT_SWAPPED);
} }
else if (GTK_IS_TOOL_BUTTON (proxy)) else if (GTK_IS_TOOL_BUTTON (proxy))
{ {
@ -923,6 +952,21 @@ gtk_action_unblock_activate_from (GtkAction *action,
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: * gtk_action_set_accel_path:
* @action: the action object * @action: the action object
@ -938,5 +982,93 @@ void
gtk_action_set_accel_path (GtkAction *action, gtk_action_set_accel_path (GtkAction *action,
const gchar *accel_path) const gchar *accel_path)
{ {
g_return_if_fail (GTK_IS_ACTION (action));
action->private_data->accel_quark = g_quark_from_string (accel_path); 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);
}

View File

@ -90,7 +90,8 @@ void gtk_action_connect_proxy (GtkAction *action,
void gtk_action_disconnect_proxy (GtkAction *action, void gtk_action_disconnect_proxy (GtkAction *action,
GtkWidget *proxy); GtkWidget *proxy);
GSList* gtk_action_get_proxies (GtkAction *action); 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 */ /* protected ... for use by child actions */
void gtk_action_block_activate_from (GtkAction *action, void gtk_action_block_activate_from (GtkAction *action,
@ -98,11 +99,11 @@ void gtk_action_block_activate_from (GtkAction *action,
void gtk_action_unblock_activate_from (GtkAction *action, void gtk_action_unblock_activate_from (GtkAction *action,
GtkWidget *proxy); GtkWidget *proxy);
/* protected ... for use by action groups */ /* protected ... for use by action groups */
void gtk_action_set_accel_path (GtkAction *action, void gtk_action_set_accel_path (GtkAction *action,
const gchar *accel_path); const gchar *accel_path);
void gtk_action_set_accel_group (GtkAction *action,
GtkAccelGroup *accel_group);
#endif /* __GTK_ACTION_H__ */ #endif /* __GTK_ACTION_H__ */

View File

@ -56,6 +56,7 @@ typedef enum
NODE_TYPE_MENUITEM, NODE_TYPE_MENUITEM,
NODE_TYPE_TOOLITEM, NODE_TYPE_TOOLITEM,
NODE_TYPE_SEPARATOR, NODE_TYPE_SEPARATOR,
NODE_TYPE_ACCELERATOR
} NodeType; } NodeType;
@ -861,6 +862,24 @@ start_element_handler (GMarkupParseContext *context,
switch (element_name[0]) 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': case 'u':
if (ctx->state == STATE_START && !strcmp (element_name, "ui")) if (ctx->state == STATE_START && !strcmp (element_name, "ui"))
{ {
@ -1131,7 +1150,6 @@ static GMarkupParser ui_parser = {
cleanup cleanup
}; };
static guint static guint
add_ui_from_string (GtkUIManager *self, add_ui_from_string (GtkUIManager *self,
const gchar *buffer, const gchar *buffer,
@ -1205,8 +1223,8 @@ gtk_ui_manager_add_ui_from_string (GtkUIManager *self,
const gchar *p; const gchar *p;
const gchar *end; const gchar *end;
g_return_val_if_fail (GTK_IS_UI_MANAGER (self), FALSE); g_return_val_if_fail (GTK_IS_UI_MANAGER (self), 0);
g_return_val_if_fail (buffer != NULL, FALSE); g_return_val_if_fail (buffer != NULL, 0);
if (length < 0) if (length < 0)
length = strlen (buffer); length = strlen (buffer);
@ -1246,6 +1264,8 @@ gtk_ui_manager_add_ui_from_file (GtkUIManager *self,
gint length; gint length;
guint res; guint res;
g_return_val_if_fail (GTK_IS_UI_MANAGER (self), 0);
if (!g_file_get_contents (filename, &buffer, &length, error)) if (!g_file_get_contents (filename, &buffer, &length, error))
return 0; return 0;
@ -1365,6 +1385,9 @@ gtk_ui_manager_add_ui (GtkUIManager *self,
case GTK_UI_MANAGER_POPUP: case GTK_UI_MANAGER_POPUP:
node_type = NODE_TYPE_POPUP; node_type = NODE_TYPE_POPUP;
break; break;
case GTK_UI_MANAGER_ACCELERATOR:
node_type = NODE_TYPE_ACCELERATOR;
break;
default: ; default: ;
/* do nothing */ /* do nothing */
} }
@ -1734,6 +1757,9 @@ update_node (GtkUIManager *self,
goto recurse_children; 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 /* If the widget already has a proxy and the action hasn't changed, then
* we only have to update the tearoff menu items. * we only have to update the tearoff menu items.
*/ */
@ -1765,11 +1791,7 @@ update_node (GtkUIManager *self,
break; break;
case NODE_TYPE_POPUP: case NODE_TYPE_POPUP:
if (info->proxy == NULL) if (info->proxy == NULL)
{
info->proxy = gtk_menu_new (); info->proxy = gtk_menu_new ();
gtk_menu_set_accel_group (GTK_MENU (info->proxy),
self->private_data->accel_group);
}
break; break;
case NODE_TYPE_MENU: case NODE_TYPE_MENU:
{ {
@ -1806,7 +1828,6 @@ update_node (GtkUIManager *self,
tearoff = gtk_tearoff_menu_item_new (); tearoff = gtk_tearoff_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), tearoff); gtk_menu_shell_append (GTK_MENU_SHELL (menu), tearoff);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), menu); 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); gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos);
} }
} }
@ -2045,6 +2066,9 @@ update_node (GtkUIManager *self,
} }
} }
break; break;
case NODE_TYPE_ACCELERATOR:
gtk_action_connect_accelerator (action);
break;
} }
if (action) if (action)
@ -2081,6 +2105,8 @@ update_node (GtkUIManager *self,
gtk_widget_destroy (info->proxy); gtk_widget_destroy (info->proxy);
if (info->extra) if (info->extra)
gtk_widget_destroy (info->extra); gtk_widget_destroy (info->extra);
if (info->type == NODE_TYPE_ACCELERATOR)
gtk_action_disconnect_accelerator (info->action);
free_node (node); free_node (node);
g_node_destroy (node); g_node_destroy (node);
} }
@ -2181,7 +2207,8 @@ static const gchar *open_tag_format[] = {
"%*s<popup name='%s' action=\"%s\">\n", "%*s<popup name='%s' action=\"%s\">\n",
"%*s<menuitem name=\"%s\" action=\"%s\"/>\n", "%*s<menuitem name=\"%s\" action=\"%s\"/>\n",
"%*s<toolitem 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[] = { static const gchar *close_tag_format[] = {
@ -2196,6 +2223,7 @@ static const gchar *close_tag_format[] = {
"", "",
"", "",
"", "",
"",
}; };
static void static void

View File

@ -81,7 +81,8 @@ typedef enum {
GTK_UI_MANAGER_POPUP, GTK_UI_MANAGER_POPUP,
GTK_UI_MANAGER_MENUITEM, GTK_UI_MANAGER_MENUITEM,
GTK_UI_MANAGER_TOOLITEM, GTK_UI_MANAGER_TOOLITEM,
GTK_UI_MANAGER_SEPARATOR GTK_UI_MANAGER_SEPARATOR,
GTK_UI_MANAGER_ACCELERATOR
} GtkUIManagerItemType; } GtkUIManagerItemType;
GType gtk_ui_manager_get_type (void); GType gtk_ui_manager_get_type (void);

View File

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
struct { const gchar *filename; guint merge_id; } merge_ids[] = { struct { const gchar *filename; guint merge_id; } merge_ids[] = {
@ -19,6 +20,12 @@ dump_tree (GtkWidget *button,
g_free (dump); g_free (dump);
} }
static void
dump_accels (void)
{
gtk_accel_map_save_fd (STDOUT_FILENO);
}
static void static void
toggle_tearoffs (GtkWidget *button, toggle_tearoffs (GtkWidget *button,
GtkUIManager *merge) GtkUIManager *merge)
@ -538,6 +545,10 @@ main (int argc, char **argv)
g_signal_connect (button, "clicked", G_CALLBACK (dump_tree), merge); g_signal_connect (button, "clicked", G_CALLBACK (dump_tree), merge);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); 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); view = create_tree_view (merge);
gtk_table_attach (GTK_TABLE (table), view, 1,2, 0,1, gtk_table_attach (GTK_TABLE (table), view, 1,2, 0,1,
GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0); GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);