1/*
2 * Copyright © 2018 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but 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: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gtkshortcut.h"
23
24#include "gtkintl.h"
25#include "gtkshortcutaction.h"
26#include "gtkshortcuttrigger.h"
27#include "gtkwidget.h"
28
29/**
30 * GtkShortcut:
31 *
32 * A `GtkShortcut` describes a keyboard shortcut.
33 *
34 * It contains a description of how to trigger the shortcut via a
35 * [class@Gtk.ShortcutTrigger] and a way to activate the shortcut
36 * on a widget via a [class@Gtk.ShortcutAction].
37 *
38 * The actual work is usually done via [class@Gtk.ShortcutController],
39 * which decides if and when to activate a shortcut. Using that controller
40 * directly however is rarely necessary as various higher level
41 * convenience APIs exist on `GtkWidget`s that make it easier to use
42 * shortcuts in GTK.
43 *
44 * `GtkShortcut` does provide functionality to make it easy for users
45 * to work with shortcuts, either by providing informational strings
46 * for display purposes or by allowing shortcuts to be configured.
47 */
48
49struct _GtkShortcut
50{
51 GObject parent_instance;
52
53 GtkShortcutAction *action;
54 GtkShortcutTrigger *trigger;
55 GVariant *args;
56};
57
58enum
59{
60 PROP_0,
61 PROP_ACTION,
62 PROP_ARGUMENTS,
63 PROP_TRIGGER,
64
65 N_PROPS
66};
67
68G_DEFINE_TYPE (GtkShortcut, gtk_shortcut, G_TYPE_OBJECT)
69
70static GParamSpec *properties[N_PROPS] = { NULL, };
71
72static void
73gtk_shortcut_dispose (GObject *object)
74{
75 GtkShortcut *self = GTK_SHORTCUT (ptr: object);
76
77 g_clear_object (&self->action);
78 g_clear_object (&self->trigger);
79 g_clear_pointer (&self->args, g_variant_unref);
80
81 G_OBJECT_CLASS (gtk_shortcut_parent_class)->dispose (object);
82}
83
84static void
85gtk_shortcut_get_property (GObject *object,
86 guint property_id,
87 GValue *value,
88 GParamSpec *pspec)
89{
90 GtkShortcut *self = GTK_SHORTCUT (ptr: object);
91
92 switch (property_id)
93 {
94 case PROP_ACTION:
95 g_value_set_object (value, v_object: self->action);
96 break;
97
98 case PROP_ARGUMENTS:
99 g_value_set_variant (value, variant: self->args);
100 break;
101
102 case PROP_TRIGGER:
103 g_value_set_object (value, v_object: self->trigger);
104 break;
105
106 default:
107 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
108 break;
109 }
110}
111
112static void
113gtk_shortcut_set_property (GObject *object,
114 guint property_id,
115 const GValue *value,
116 GParamSpec *pspec)
117{
118 GtkShortcut *self = GTK_SHORTCUT (ptr: object);
119
120 switch (property_id)
121 {
122 case PROP_ACTION:
123 gtk_shortcut_set_action (self, action: g_value_dup_object (value));
124 break;
125
126 case PROP_ARGUMENTS:
127 gtk_shortcut_set_arguments (self, args: g_value_get_variant (value));
128 break;
129
130 case PROP_TRIGGER:
131 gtk_shortcut_set_trigger (self, trigger: g_value_dup_object (value));
132 break;
133
134 default:
135 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
136 break;
137 }
138}
139
140static void
141gtk_shortcut_class_init (GtkShortcutClass *klass)
142{
143 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
144
145 gobject_class->dispose = gtk_shortcut_dispose;
146 gobject_class->get_property = gtk_shortcut_get_property;
147 gobject_class->set_property = gtk_shortcut_set_property;
148
149 /**
150 * GtkShortcut:action: (attributes org.gtk.Property.get=gtk_shortcut_get_action org.gtk.Property.set=gtk_shortcut_set_action)
151 *
152 * The action that gets activated by this shortcut.
153 */
154 properties[PROP_ACTION] =
155 g_param_spec_object (name: "action",
156 P_("Action"),
157 P_("The action activated by this shortcut"),
158 GTK_TYPE_SHORTCUT_ACTION,
159 flags: G_PARAM_READWRITE |
160 G_PARAM_EXPLICIT_NOTIFY |
161 G_PARAM_STATIC_STRINGS);
162
163 /**
164 * GtkShortcut:arguments: (attributes org.gtk.Property.get=gtk_shortcut_get_arguments org.gtk.Property.set=gtk_shortcut_set_arguments)
165 *
166 * Arguments passed to activation.
167 */
168 properties[PROP_ARGUMENTS] =
169 g_param_spec_variant (name: "arguments",
170 P_("Arguments"),
171 P_("Arguments passed to activation"),
172 G_VARIANT_TYPE_ANY,
173 NULL,
174 flags: G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
175
176 /**
177 * GtkShortcut:trigger: (attributes org.gtk.Property.get=gtk_shortcut_get_trigger org.gtk.Property.set=gtk_shortcut_set_trigger)
178 *
179 * The trigger that triggers this shortcut.
180 */
181 properties[PROP_TRIGGER] =
182 g_param_spec_object (name: "trigger",
183 P_("Trigger"),
184 P_("The trigger for this shortcut"),
185 GTK_TYPE_SHORTCUT_TRIGGER,
186 flags: G_PARAM_READWRITE |
187 G_PARAM_EXPLICIT_NOTIFY |
188 G_PARAM_STATIC_STRINGS);
189
190 g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPS, pspecs: properties);
191}
192
193static void
194gtk_shortcut_init (GtkShortcut *self)
195{
196 self->action = g_object_ref (gtk_nothing_action_get ());
197 self->trigger = g_object_ref (gtk_never_trigger_get ());
198}
199
200/**
201 * gtk_shortcut_new:
202 * @trigger: (transfer full) (nullable): The trigger that will trigger the shortcut
203 * @action: (transfer full) (nullable): The action that will be activated upon
204 * triggering
205 *
206 * Creates a new `GtkShortcut` that is triggered by
207 * @trigger and then activates @action.
208 *
209 * Returns: a new `GtkShortcut`
210 */
211GtkShortcut *
212gtk_shortcut_new (GtkShortcutTrigger *trigger,
213 GtkShortcutAction *action)
214{
215 GtkShortcut *shortcut;
216
217 shortcut = g_object_new (GTK_TYPE_SHORTCUT,
218 first_property_name: "action", action,
219 "trigger", trigger,
220 NULL);
221
222 if (trigger)
223 g_object_unref (object: trigger);
224 if (action)
225 g_object_unref (object: action);
226
227 return shortcut;
228}
229
230/**
231 * gtk_shortcut_new_with_arguments: (skip)
232 * @trigger: (transfer full) (nullable): The trigger that will trigger the shortcut
233 * @action: (transfer full) (nullable): The action that will be activated upon
234 * triggering
235 * @format_string: (nullable): GVariant format string for arguments or %NULL for
236 * no arguments
237 * @...: arguments, as given by format string.
238 *
239 * Creates a new `GtkShortcut` that is triggered by @trigger and then activates
240 * @action with arguments given by @format_string.
241 *
242 * Returns: a new `GtkShortcut`
243 */
244GtkShortcut *
245gtk_shortcut_new_with_arguments (GtkShortcutTrigger *trigger,
246 GtkShortcutAction *action,
247 const char *format_string,
248 ...)
249{
250 GtkShortcut *shortcut;
251 GVariant *args;
252
253 if (format_string)
254 {
255 va_list valist;
256 va_start (valist, format_string);
257 args = g_variant_new_va (format_string, NULL, app: &valist);
258 va_end (valist);
259 }
260 else
261 {
262 args = NULL;
263 }
264
265 shortcut = g_object_new (GTK_TYPE_SHORTCUT,
266 first_property_name: "action", action,
267 "arguments", args,
268 "trigger", trigger,
269 NULL);
270
271 if (trigger)
272 g_object_unref (object: trigger);
273 if (action)
274 g_object_unref (object: action);
275
276 return shortcut;
277}
278
279/**
280 * gtk_shortcut_get_action: (attributes org.gtk.Method.get_property=action)
281 * @self: a `GtkShortcut`
282 *
283 * Gets the action that is activated by this shortcut.
284 *
285 * Returns: (transfer none) (nullable): the action
286 */
287GtkShortcutAction *
288gtk_shortcut_get_action (GtkShortcut *self)
289{
290 g_return_val_if_fail (GTK_IS_SHORTCUT (self), NULL);
291
292 return self->action;
293}
294
295/**
296 * gtk_shortcut_set_action: (attributes org.gtk.Method.set_property=action)
297 * @self: a `GtkShortcut`
298 * @action: (transfer full) (nullable): The new action.
299 * If the @action is %NULL, the nothing action will be used.
300 *
301 * Sets the new action for @self to be @action.
302 */
303void
304gtk_shortcut_set_action (GtkShortcut *self,
305 GtkShortcutAction *action)
306{
307 g_return_if_fail (GTK_IS_SHORTCUT (self));
308
309 if (action == NULL)
310 action = g_object_ref (gtk_nothing_action_get ());
311
312 if (g_set_object (&self->action, action))
313 {
314 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_ACTION]);
315 g_object_unref (object: action);
316 }
317}
318
319/**
320 * gtk_shortcut_get_trigger: (attributes org.gtk.Method.get_property=trigger)
321 * @self: a `GtkShortcut`
322 *
323 * Gets the trigger used to trigger @self.
324 *
325 * Returns: (transfer none) (nullable): the trigger used
326 */
327GtkShortcutTrigger *
328gtk_shortcut_get_trigger (GtkShortcut *self)
329{
330 g_return_val_if_fail (GTK_IS_SHORTCUT (self), NULL);
331
332 return self->trigger;
333}
334
335/**
336 * gtk_shortcut_set_trigger: (attributes org.gtk.Method.set_property=trigger)
337 * @self: a `GtkShortcut`
338 * @trigger: (transfer full) (nullable): The new trigger.
339 * If the @trigger is %NULL, the never trigger will be used.
340 *
341 * Sets the new trigger for @self to be @trigger.
342 */
343void
344gtk_shortcut_set_trigger (GtkShortcut *self,
345 GtkShortcutTrigger *trigger)
346{
347 g_return_if_fail (GTK_IS_SHORTCUT (self));
348
349 if (trigger == NULL)
350 trigger = g_object_ref (gtk_never_trigger_get ());
351
352 if (g_set_object (&self->trigger, trigger))
353 {
354 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_TRIGGER]);
355 g_object_unref (object: trigger);
356 }
357}
358
359/**
360 * gtk_shortcut_get_arguments: (attributes org.gtk.Method.get_property=arguments)
361 * @self: a `GtkShortcut`
362 *
363 * Gets the arguments that are passed when activating the shortcut.
364 *
365 * Returns: (transfer none) (nullable): the arguments
366 */
367GVariant *
368gtk_shortcut_get_arguments (GtkShortcut *self)
369{
370 g_return_val_if_fail (GTK_IS_SHORTCUT (self), NULL);
371
372 return self->args;
373}
374
375/**
376 * gtk_shortcut_set_arguments: (attributes org.gtk.Method.set_property=arguments)
377 * @self: a `GtkShortcut`
378 * @args: (nullable): arguments to pass when activating @self
379 *
380 * Sets the arguments to pass when activating the shortcut.
381 */
382void
383gtk_shortcut_set_arguments (GtkShortcut *self,
384 GVariant *args)
385{
386 g_return_if_fail (GTK_IS_SHORTCUT (self));
387
388 if (self->args == args)
389 return;
390
391 g_clear_pointer (&self->args, g_variant_unref);
392 if (args)
393 self->args = g_variant_ref_sink (value: args);
394
395 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_ARGUMENTS]);
396}
397

source code of gtk/gtk/gtkshortcut.c