1 | /* |
2 | * Copyright © 2012 Canonical Limited |
3 | * |
4 | * This library is free software: you can redistribute it and/or modify |
5 | * it under the terms of the GNU Lesser General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * licence or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Authors: Ryan Lortie <desrt@desrt.ca> |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include "gtkactionable.h" |
23 | |
24 | #include "gtkwidget.h" |
25 | #include "gtkintl.h" |
26 | |
27 | /** |
28 | * GtkActionable: |
29 | * |
30 | * The `GtkActionable` interface provides a convenient way of asscociating |
31 | * widgets with actions. |
32 | * |
33 | * It primarily consists of two properties: [property@Gtk.Actionable:action-name] |
34 | * and [property@Gtk.Actionable:action-target]. There are also some convenience |
35 | * APIs for setting these properties. |
36 | * |
37 | * The action will be looked up in action groups that are found among |
38 | * the widgets ancestors. Most commonly, these will be the actions with |
39 | * the “win.” or “app.” prefix that are associated with the |
40 | * `GtkApplicationWindow` or `GtkApplication`, but other action groups that |
41 | * are added with [method@Gtk.Widget.insert_action_group] will be consulted |
42 | * as well. |
43 | **/ |
44 | |
45 | /** |
46 | * GtkActionableInterface: |
47 | * @get_action_name: virtual function for [method@Actionable.get_action_name] |
48 | * @set_action_name: virtual function for [method@Actionable.set_action_name] |
49 | * @get_action_target_value: virtual function for [method@Actionable.get_action_target_value] |
50 | * @set_action_target_value: virtual function for [method@Actionable.set_action_target_value] |
51 | * |
52 | * The interface vtable for `GtkActionable`. |
53 | **/ |
54 | |
55 | G_DEFINE_INTERFACE (GtkActionable, gtk_actionable, GTK_TYPE_WIDGET) |
56 | |
57 | static void |
58 | gtk_actionable_default_init (GtkActionableInterface *iface) |
59 | { |
60 | g_object_interface_install_property (g_iface: iface, |
61 | pspec: g_param_spec_string (name: "action-name" , P_("Action name" ), |
62 | P_("The name of the associated action, like “app.quit”" ), |
63 | NULL, flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
64 | |
65 | g_object_interface_install_property (g_iface: iface, |
66 | pspec: g_param_spec_variant (name: "action-target" , P_("Action target value" ), |
67 | P_("The parameter for action invocations" ), |
68 | G_VARIANT_TYPE_ANY, NULL, flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
69 | } |
70 | |
71 | /** |
72 | * gtk_actionable_get_action_name: (attributes org.gtk.Property.get=action-name) |
73 | * @actionable: a `GtkActionable` widget |
74 | * |
75 | * Gets the action name for @actionable. |
76 | * |
77 | * Returns: (nullable): the action name |
78 | */ |
79 | const char * |
80 | gtk_actionable_get_action_name (GtkActionable *actionable) |
81 | { |
82 | g_return_val_if_fail (GTK_IS_ACTIONABLE (actionable), NULL); |
83 | |
84 | return GTK_ACTIONABLE_GET_IFACE (actionable) |
85 | ->get_action_name (actionable); |
86 | } |
87 | |
88 | /** |
89 | * gtk_actionable_set_action_name: (attributes org.gtk.Property.set=action-name) |
90 | * @actionable: a `GtkActionable` widget |
91 | * @action_name: (nullable): an action name |
92 | * |
93 | * Specifies the name of the action with which this widget should be |
94 | * associated. |
95 | * |
96 | * If @action_name is %NULL then the widget will be unassociated from |
97 | * any previous action. |
98 | * |
99 | * Usually this function is used when the widget is located (or will be |
100 | * located) within the hierarchy of a `GtkApplicationWindow`. |
101 | * |
102 | * Names are of the form “win.save” or “app.quit” for actions on the |
103 | * containing [class@ApplicationWindow] or its associated [class@Application], |
104 | * respectively. This is the same form used for actions in the [class@Gio.Menu] |
105 | * associated with the window. |
106 | */ |
107 | void |
108 | gtk_actionable_set_action_name (GtkActionable *actionable, |
109 | const char *action_name) |
110 | { |
111 | g_return_if_fail (GTK_IS_ACTIONABLE (actionable)); |
112 | |
113 | GTK_ACTIONABLE_GET_IFACE (actionable) |
114 | ->set_action_name (actionable, action_name); |
115 | } |
116 | |
117 | /** |
118 | * gtk_actionable_get_action_target_value: (attributes org.gtk.Method.get_property=action-target) |
119 | * @actionable: a `GtkActionable` widget |
120 | * |
121 | * Gets the current target value of @actionable. |
122 | * |
123 | * Returns: (nullable) (transfer none): the current target value |
124 | */ |
125 | GVariant * |
126 | gtk_actionable_get_action_target_value (GtkActionable *actionable) |
127 | { |
128 | g_return_val_if_fail (GTK_IS_ACTIONABLE (actionable), NULL); |
129 | |
130 | return GTK_ACTIONABLE_GET_IFACE (actionable) |
131 | ->get_action_target_value (actionable); |
132 | } |
133 | |
134 | /** |
135 | * gtk_actionable_set_action_target_value: (attributes org.gtk.Method.set_property=action-target) |
136 | * @actionable: a `GtkActionable` widget |
137 | * @target_value: (nullable): a [struct@GLib.Variant] to set as the target value |
138 | * |
139 | * Sets the target value of an actionable widget. |
140 | * |
141 | * If @target_value is %NULL then the target value is unset. |
142 | * |
143 | * The target value has two purposes. First, it is used as the parameter |
144 | * to activation of the action associated with the `GtkActionable` widget. |
145 | * Second, it is used to determine if the widget should be rendered as |
146 | * “active” — the widget is active if the state is equal to the given target. |
147 | * |
148 | * Consider the example of associating a set of buttons with a [iface@Gio.Action] |
149 | * with string state in a typical “radio button” situation. Each button |
150 | * will be associated with the same action, but with a different target |
151 | * value for that action. Clicking on a particular button will activate |
152 | * the action with the target of that button, which will typically cause |
153 | * the action’s state to change to that value. Since the action’s state |
154 | * is now equal to the target value of the button, the button will now |
155 | * be rendered as active (and the other buttons, with different targets, |
156 | * rendered inactive). |
157 | */ |
158 | void |
159 | gtk_actionable_set_action_target_value (GtkActionable *actionable, |
160 | GVariant *target_value) |
161 | { |
162 | g_return_if_fail (GTK_IS_ACTIONABLE (actionable)); |
163 | |
164 | GTK_ACTIONABLE_GET_IFACE (actionable) |
165 | ->set_action_target_value (actionable, target_value); |
166 | } |
167 | |
168 | /** |
169 | * gtk_actionable_set_action_target: |
170 | * @actionable: a `GtkActionable` widget |
171 | * @format_string: a [struct@GLib.Variant] format string |
172 | * @...: arguments appropriate for @format_string |
173 | * |
174 | * Sets the target of an actionable widget. |
175 | * |
176 | * This is a convenience function that calls [ctor@GLib.Variant.new] for |
177 | * @format_string and uses the result to call |
178 | * [method@Gtk.Actionable.set_action_target_value]. |
179 | * |
180 | * If you are setting a string-valued target and want to set |
181 | * the action name at the same time, you can use |
182 | * [method@Gtk.Actionable.set_detailed_action_name]. |
183 | */ |
184 | void |
185 | gtk_actionable_set_action_target (GtkActionable *actionable, |
186 | const char *format_string, |
187 | ...) |
188 | { |
189 | va_list ap; |
190 | |
191 | va_start (ap, format_string); |
192 | gtk_actionable_set_action_target_value (actionable, target_value: g_variant_new_va (format_string, NULL, app: &ap)); |
193 | va_end (ap); |
194 | } |
195 | |
196 | /** |
197 | * gtk_actionable_set_detailed_action_name: |
198 | * @actionable: a `GtkActionable` widget |
199 | * @detailed_action_name: the detailed action name |
200 | * |
201 | * Sets the action-name and associated string target value of an |
202 | * actionable widget. |
203 | * |
204 | * @detailed_action_name is a string in the format accepted by |
205 | * [func@Gio.Action.parse_detailed_name]. |
206 | */ |
207 | void |
208 | gtk_actionable_set_detailed_action_name (GtkActionable *actionable, |
209 | const char *detailed_action_name) |
210 | { |
211 | GError *error = NULL; |
212 | GVariant *target; |
213 | char *name; |
214 | |
215 | if (detailed_action_name == NULL) |
216 | { |
217 | gtk_actionable_set_action_name (actionable, NULL); |
218 | gtk_actionable_set_action_target_value (actionable, NULL); |
219 | return; |
220 | } |
221 | |
222 | if (!g_action_parse_detailed_name (detailed_name: detailed_action_name, action_name: &name, target_value: &target, error: &error)) |
223 | g_error ("gtk_actionable_set_detailed_action_name: %s" , error->message); |
224 | |
225 | gtk_actionable_set_action_name (actionable, action_name: name); |
226 | gtk_actionable_set_action_target_value (actionable, target_value: target); |
227 | |
228 | if (target) |
229 | g_variant_unref (value: target); |
230 | g_free (mem: name); |
231 | } |
232 | |