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 | |
49 | struct _GtkShortcut |
50 | { |
51 | GObject parent_instance; |
52 | |
53 | GtkShortcutAction *action; |
54 | GtkShortcutTrigger *trigger; |
55 | GVariant *args; |
56 | }; |
57 | |
58 | enum |
59 | { |
60 | PROP_0, |
61 | PROP_ACTION, |
62 | PROP_ARGUMENTS, |
63 | PROP_TRIGGER, |
64 | |
65 | N_PROPS |
66 | }; |
67 | |
68 | G_DEFINE_TYPE (GtkShortcut, gtk_shortcut, G_TYPE_OBJECT) |
69 | |
70 | static GParamSpec *properties[N_PROPS] = { NULL, }; |
71 | |
72 | static void |
73 | gtk_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 | |
84 | static void |
85 | gtk_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 | |
112 | static void |
113 | gtk_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 | |
140 | static void |
141 | gtk_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 | |
193 | static void |
194 | gtk_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 | */ |
211 | GtkShortcut * |
212 | gtk_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 | */ |
244 | GtkShortcut * |
245 | gtk_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 | */ |
287 | GtkShortcutAction * |
288 | gtk_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 | */ |
303 | void |
304 | gtk_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 | */ |
327 | GtkShortcutTrigger * |
328 | gtk_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 | */ |
343 | void |
344 | gtk_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 | */ |
367 | GVariant * |
368 | gtk_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 | */ |
382 | void |
383 | gtk_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 | |