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  * SECTION:gtkactionable
29  * @title: GtkActionable
30  * @short_description: An interface for widgets that can be associated
31  *     with actions
32  *
33  * This interface provides a convenient way of associating widgets with
34  * actions on a #GtkApplicationWindow or #GtkApplication.
35  *
36  * It primarily consists of two properties: #GtkActionable:action-name
37  * and #GtkActionable:action-target. There are also some convenience APIs
38  * for setting these properties.
39  *
40  * The action will be looked up in action groups that are found among
41  * the widgets ancestors. Most commonly, these will be the actions with
42  * the “win.” or “app.” prefix that are associated with the #GtkApplicationWindow
43  * or #GtkApplication, but other action groups that are added with
44  * gtk_widget_insert_action_group() will be consulted as well.
45  *
46  * Since: 3.4
47  **/
48 
49 /**
50  * GtkActionable:
51  *
52  * An opaque pointer type.
53  **/
54 
55 /**
56  * GtkActionableInterface:
57  * @get_action_name: virtual function for gtk_actionable_get_action_name()
58  * @set_action_name: virtual function for gtk_actionable_set_action_name()
59  * @get_action_target_value: virtual function for gtk_actionable_get_action_target_value()
60  * @set_action_target_value: virtual function for gtk_actionable_set_action_target_value()
61  *
62  * The interface vtable for #GtkActionable.
63  **/
64 
G_DEFINE_INTERFACE(GtkActionable,gtk_actionable,GTK_TYPE_WIDGET)65 G_DEFINE_INTERFACE (GtkActionable, gtk_actionable, GTK_TYPE_WIDGET)
66 
67 static void
68 gtk_actionable_default_init (GtkActionableInterface *iface)
69 {
70   g_object_interface_install_property (iface,
71     g_param_spec_string ("action-name", P_("Action name"),
72                          P_("The name of the associated action, like 'app.quit'"),
73                          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
74 
75   g_object_interface_install_property (iface,
76     g_param_spec_variant ("action-target", P_("Action target value"),
77                           P_("The parameter for action invocations"),
78                           G_VARIANT_TYPE_ANY, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
79 }
80 
81 /**
82  * gtk_actionable_get_action_name:
83  * @actionable: a #GtkActionable widget
84  *
85  * Gets the action name for @actionable.
86  *
87  * See gtk_actionable_set_action_name() for more information.
88  *
89  * Returns: (nullable): the action name, or %NULL if none is set
90  *
91  * Since: 3.4
92  **/
93 const gchar *
gtk_actionable_get_action_name(GtkActionable * actionable)94 gtk_actionable_get_action_name (GtkActionable *actionable)
95 {
96   g_return_val_if_fail (GTK_IS_ACTIONABLE (actionable), NULL);
97 
98   return GTK_ACTIONABLE_GET_IFACE (actionable)
99     ->get_action_name (actionable);
100 }
101 
102 /**
103  * gtk_actionable_set_action_name:
104  * @actionable: a #GtkActionable widget
105  * @action_name: (nullable): an action name, or %NULL
106  *
107  * Specifies the name of the action with which this widget should be
108  * associated.  If @action_name is %NULL then the widget will be
109  * unassociated from any previous action.
110  *
111  * Usually this function is used when the widget is located (or will be
112  * located) within the hierarchy of a #GtkApplicationWindow.
113  *
114  * Names are of the form “win.save” or “app.quit” for actions on the
115  * containing #GtkApplicationWindow or its associated #GtkApplication,
116  * respectively.  This is the same form used for actions in the #GMenu
117  * associated with the window.
118  *
119  * Since: 3.4
120  **/
121 void
gtk_actionable_set_action_name(GtkActionable * actionable,const gchar * action_name)122 gtk_actionable_set_action_name (GtkActionable *actionable,
123                                 const gchar   *action_name)
124 {
125   g_return_if_fail (GTK_IS_ACTIONABLE (actionable));
126 
127   GTK_ACTIONABLE_GET_IFACE (actionable)
128     ->set_action_name (actionable, action_name);
129 }
130 
131 /**
132  * gtk_actionable_get_action_target_value:
133  * @actionable: a #GtkActionable widget
134  *
135  * Gets the current target value of @actionable.
136  *
137  * See gtk_actionable_set_action_target_value() for more information.
138  *
139  * Returns: (transfer none): the current target value
140  *
141  * Since: 3.4
142  **/
143 GVariant *
gtk_actionable_get_action_target_value(GtkActionable * actionable)144 gtk_actionable_get_action_target_value (GtkActionable *actionable)
145 {
146   g_return_val_if_fail (GTK_IS_ACTIONABLE (actionable), NULL);
147 
148   return GTK_ACTIONABLE_GET_IFACE (actionable)
149     ->get_action_target_value (actionable);
150 }
151 
152 /**
153  * gtk_actionable_set_action_target_value:
154  * @actionable: a #GtkActionable widget
155  * @target_value: (nullable): a #GVariant to set as the target value, or %NULL
156  *
157  * Sets the target value of an actionable widget.
158  *
159  * If @target_value is %NULL then the target value is unset.
160  *
161  * The target value has two purposes.  First, it is used as the
162  * parameter to activation of the action associated with the
163  * #GtkActionable widget. Second, it is used to determine if the widget
164  * should be rendered as “active” — the widget is active if the state
165  * is equal to the given target.
166  *
167  * Consider the example of associating a set of buttons with a #GAction
168  * with string state in a typical “radio button” situation.  Each button
169  * will be associated with the same action, but with a different target
170  * value for that action.  Clicking on a particular button will activate
171  * the action with the target of that button, which will typically cause
172  * the action’s state to change to that value.  Since the action’s state
173  * is now equal to the target value of the button, the button will now
174  * be rendered as active (and the other buttons, with different targets,
175  * rendered inactive).
176  *
177  * Since: 3.4
178  **/
179 void
gtk_actionable_set_action_target_value(GtkActionable * actionable,GVariant * target_value)180 gtk_actionable_set_action_target_value (GtkActionable *actionable,
181                                         GVariant      *target_value)
182 {
183   g_return_if_fail (GTK_IS_ACTIONABLE (actionable));
184 
185   GTK_ACTIONABLE_GET_IFACE (actionable)
186     ->set_action_target_value (actionable, target_value);
187 }
188 
189 /**
190  * gtk_actionable_set_action_target:
191  * @actionable: a #GtkActionable widget
192  * @format_string: a GVariant format string
193  * @...: arguments appropriate for @format_string
194  *
195  * Sets the target of an actionable widget.
196  *
197  * This is a convenience function that calls g_variant_new() for
198  * @format_string and uses the result to call
199  * gtk_actionable_set_action_target_value().
200  *
201  * If you are setting a string-valued target and want to set the action
202  * name at the same time, you can use
203  * gtk_actionable_set_detailed_action_name ().
204  *
205  * Since: 3.4
206  **/
207 void
gtk_actionable_set_action_target(GtkActionable * actionable,const gchar * format_string,...)208 gtk_actionable_set_action_target (GtkActionable *actionable,
209                                   const gchar   *format_string,
210                                   ...)
211 {
212   va_list ap;
213 
214   va_start (ap, format_string);
215   gtk_actionable_set_action_target_value (actionable, g_variant_new_va (format_string, NULL, &ap));
216   va_end (ap);
217 }
218 
219 /**
220  * gtk_actionable_set_detailed_action_name:
221  * @actionable: a #GtkActionable widget
222  * @detailed_action_name: the detailed action name
223  *
224  * Sets the action-name and associated string target value of an
225  * actionable widget.
226  *
227  * @detailed_action_name is a string in the format accepted by
228  * g_action_parse_detailed_name().
229  *
230  * (Note that prior to version 3.22.25,
231  * this function is only usable for actions with a simple "s" target, and
232  * @detailed_action_name must be of the form `"action::target"` where
233  * `action` is the action name and `target` is the string to use
234  * as the target.)
235  *
236  * Since: 3.4
237  **/
238 void
gtk_actionable_set_detailed_action_name(GtkActionable * actionable,const gchar * detailed_action_name)239 gtk_actionable_set_detailed_action_name (GtkActionable *actionable,
240                                          const gchar   *detailed_action_name)
241 {
242   GError *error = NULL;
243   GVariant *target;
244   gchar *name;
245 
246   if (detailed_action_name == NULL)
247     {
248       gtk_actionable_set_action_name (actionable, NULL);
249       gtk_actionable_set_action_target_value (actionable, NULL);
250       return;
251     }
252 
253   if (!g_action_parse_detailed_name (detailed_action_name, &name, &target, &error))
254     g_error ("gtk_actionable_set_detailed_action_name: %s", error->message);
255 
256   gtk_actionable_set_action_name (actionable, name);
257   gtk_actionable_set_action_target_value (actionable, target);
258 
259   if (target)
260     g_variant_unref (target);
261   g_free (name);
262 }
263 
264