1 | /* |
2 | * Copyright © 2018 Benjamin Otte |
3 | * |
4 | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2.1 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
18 | * |
19 | * Authors: Benjamin Otte <otte@gnome.org> |
20 | */ |
21 | |
22 | /** |
23 | * GtkShortcutTrigger: |
24 | * |
25 | * `GtkShortcutTrigger` tracks how a `GtkShortcut` should be activated. |
26 | * |
27 | * To find out if a `GtkShortcutTrigger` triggers, you can call |
28 | * [method@Gtk.ShortcutTrigger.trigger] on a `GdkEvent`. |
29 | * |
30 | * `GtkShortcutTriggers` contain functions that allow easy presentation |
31 | * to end users as well as being printed for debugging. |
32 | * |
33 | * All `GtkShortcutTriggers` are immutable, you can only specify their |
34 | * properties during construction. If you want to change a trigger, you |
35 | * have to replace it with a new one. |
36 | */ |
37 | |
38 | #include "config.h" |
39 | |
40 | #include "gtkshortcuttrigger.h" |
41 | |
42 | #include "gtkaccelgroupprivate.h" |
43 | #include "gtkprivate.h" |
44 | #include "gtkintl.h" |
45 | |
46 | #define GTK_SHORTCUT_TRIGGER_HASH_NEVER 0u |
47 | #define GTK_SHORTCUT_TRIGGER_HASH_KEYVAL 1u |
48 | #define GTK_SHORTCUT_TRIGGER_HASH_MNEMONIC 2u |
49 | #define GTK_SHORTCUT_TRIGGER_HASH_ALTERNATIVE 3u |
50 | |
51 | struct _GtkShortcutTrigger |
52 | { |
53 | GObject parent_instance; |
54 | }; |
55 | |
56 | struct _GtkShortcutTriggerClass |
57 | { |
58 | GObjectClass parent_class; |
59 | |
60 | GdkKeyMatch (* trigger) (GtkShortcutTrigger *trigger, |
61 | GdkEvent *event, |
62 | gboolean enable_mnemonics); |
63 | guint (* hash) (GtkShortcutTrigger *trigger); |
64 | int (* compare) (GtkShortcutTrigger *trigger1, |
65 | GtkShortcutTrigger *trigger2); |
66 | void (* print) (GtkShortcutTrigger *trigger, |
67 | GString *string); |
68 | gboolean (* print_label) (GtkShortcutTrigger *trigger, |
69 | GdkDisplay *display, |
70 | GString *string); |
71 | }; |
72 | |
73 | G_DEFINE_ABSTRACT_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, G_TYPE_OBJECT) |
74 | |
75 | static void |
76 | gtk_shortcut_trigger_class_init (GtkShortcutTriggerClass *klass) |
77 | { |
78 | } |
79 | |
80 | static void |
81 | gtk_shortcut_trigger_init (GtkShortcutTrigger *self) |
82 | { |
83 | } |
84 | |
85 | /** |
86 | * gtk_shortcut_trigger_trigger: |
87 | * @self: a `GtkShortcutTrigger` |
88 | * @event: the event to check |
89 | * @enable_mnemonics: %TRUE if mnemonics should trigger. Usually the |
90 | * value of this property is determined by checking that the passed |
91 | * in @event is a Key event and has the right modifiers set. |
92 | * |
93 | * Checks if the given @event triggers @self. |
94 | * |
95 | * Returns: Whether the event triggered the shortcut |
96 | */ |
97 | GdkKeyMatch |
98 | gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self, |
99 | GdkEvent *event, |
100 | gboolean enable_mnemonics) |
101 | { |
102 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), GDK_KEY_MATCH_NONE); |
103 | |
104 | return GTK_SHORTCUT_TRIGGER_GET_CLASS (ptr: self)->trigger (self, event, enable_mnemonics); |
105 | } |
106 | |
107 | /** |
108 | * gtk_shortcut_trigger_parse_string: (constructor) |
109 | * @string: the string to parse |
110 | * |
111 | * Tries to parse the given string into a trigger. |
112 | * |
113 | * On success, the parsed trigger is returned. |
114 | * When parsing failed, %NULL is returned. |
115 | * |
116 | * The accepted strings are: |
117 | * |
118 | * - `never`, for `GtkNeverTrigger` |
119 | * - a string parsed by gtk_accelerator_parse(), for a `GtkKeyvalTrigger`, e.g. `<Control>C` |
120 | * - underscore, followed by a single character, for `GtkMnemonicTrigger`, e.g. `_l` |
121 | * - two valid trigger strings, separated by a `|` character, for a |
122 | * `GtkAlternativeTrigger`: `<Control>q|<Control>w` |
123 | * |
124 | * Note that you will have to escape the `<` and `>` characters when specifying |
125 | * triggers in XML files, such as GtkBuilder ui files. Use `<` instead of |
126 | * `<` and `>` instead of `>`. |
127 | * |
128 | * Returns: (nullable) (transfer full): a new `GtkShortcutTrigger` |
129 | */ |
130 | GtkShortcutTrigger * |
131 | gtk_shortcut_trigger_parse_string (const char *string) |
132 | { |
133 | GdkModifierType modifiers; |
134 | guint keyval; |
135 | const char *sep; |
136 | |
137 | g_return_val_if_fail (string != NULL, NULL); |
138 | |
139 | if ((sep = strchr (s: string, c: '|')) != NULL) |
140 | { |
141 | char *frag_a = g_strndup (str: string, n: sep - string); |
142 | const char *frag_b = sep + 1; |
143 | GtkShortcutTrigger *t1, *t2; |
144 | |
145 | /* empty first slot */ |
146 | if (*frag_a == '\0') |
147 | { |
148 | g_free (mem: frag_a); |
149 | return NULL; |
150 | } |
151 | |
152 | /* empty second slot */ |
153 | if (*frag_b == '\0') |
154 | { |
155 | g_free (mem: frag_a); |
156 | return NULL; |
157 | } |
158 | |
159 | t1 = gtk_shortcut_trigger_parse_string (string: frag_a); |
160 | if (t1 == NULL) |
161 | { |
162 | g_free (mem: frag_a); |
163 | return NULL; |
164 | } |
165 | |
166 | t2 = gtk_shortcut_trigger_parse_string (string: frag_b); |
167 | if (t2 == NULL) |
168 | { |
169 | g_object_unref (object: t1); |
170 | g_free (mem: frag_a); |
171 | return NULL; |
172 | } |
173 | |
174 | g_free (mem: frag_a); |
175 | |
176 | return gtk_alternative_trigger_new (first: t1, second: t2); |
177 | } |
178 | |
179 | if (g_str_equal (v1: string, v2: "never" )) |
180 | return g_object_ref (gtk_never_trigger_get ()); |
181 | |
182 | if (string[0] == '_') |
183 | { |
184 | keyval = gdk_keyval_from_name (keyval_name: string + 1); |
185 | if (keyval != GDK_KEY_VoidSymbol) |
186 | return gtk_mnemonic_trigger_new (keyval: gdk_keyval_to_lower (keyval)); |
187 | } |
188 | |
189 | if (gtk_accelerator_parse (accelerator: string, accelerator_key: &keyval, accelerator_mods: &modifiers)) |
190 | return gtk_keyval_trigger_new (keyval, modifiers); |
191 | |
192 | return NULL; |
193 | } |
194 | |
195 | /** |
196 | * gtk_shortcut_trigger_to_string: |
197 | * @self: a `GtkShortcutTrigger` |
198 | * |
199 | * Prints the given trigger into a human-readable string. |
200 | * |
201 | * This is a small wrapper around [method@Gtk.ShortcutTrigger.print] |
202 | * to help when debugging. |
203 | * |
204 | * Returns: (transfer full): a new string |
205 | */ |
206 | char * |
207 | gtk_shortcut_trigger_to_string (GtkShortcutTrigger *self) |
208 | { |
209 | GString *string; |
210 | |
211 | g_return_val_if_fail (self != NULL, NULL); |
212 | |
213 | string = g_string_new (NULL); |
214 | |
215 | gtk_shortcut_trigger_print (self, string); |
216 | |
217 | return g_string_free (string, FALSE); |
218 | } |
219 | |
220 | /** |
221 | * gtk_shortcut_trigger_print: |
222 | * @self: a `GtkShortcutTrigger` |
223 | * @string: a `GString` to print into |
224 | * |
225 | * Prints the given trigger into a string for the developer. |
226 | * This is meant for debugging and logging. |
227 | * |
228 | * The form of the representation may change at any time |
229 | * and is not guaranteed to stay identical. |
230 | */ |
231 | void |
232 | gtk_shortcut_trigger_print (GtkShortcutTrigger *self, |
233 | GString *string) |
234 | { |
235 | g_return_if_fail (GTK_IS_SHORTCUT_TRIGGER (self)); |
236 | g_return_if_fail (string != NULL); |
237 | |
238 | GTK_SHORTCUT_TRIGGER_GET_CLASS (ptr: self)->print (self, string); |
239 | } |
240 | |
241 | /** |
242 | * gtk_shortcut_trigger_to_label: |
243 | * @self: a `GtkShortcutTrigger` |
244 | * @display: `GdkDisplay` to print for |
245 | * |
246 | * Gets textual representation for the given trigger. |
247 | * |
248 | * This function is returning a translated string for |
249 | * presentation to end users for example in menu items |
250 | * or in help texts. |
251 | * |
252 | * The @display in use may influence the resulting string in |
253 | * various forms, such as resolving hardware keycodes or by |
254 | * causing display-specific modifier names. |
255 | * |
256 | * The form of the representation may change at any time and is |
257 | * not guaranteed to stay identical. |
258 | * |
259 | * Returns: (transfer full): a new string |
260 | */ |
261 | char * |
262 | gtk_shortcut_trigger_to_label (GtkShortcutTrigger *self, |
263 | GdkDisplay *display) |
264 | { |
265 | GString *string; |
266 | |
267 | g_return_val_if_fail (self != NULL, NULL); |
268 | |
269 | string = g_string_new (NULL); |
270 | gtk_shortcut_trigger_print_label (self, display, string); |
271 | |
272 | return g_string_free (string, FALSE); |
273 | } |
274 | |
275 | /** |
276 | * gtk_shortcut_trigger_print_label: |
277 | * @self: a `GtkShortcutTrigger` |
278 | * @display: `GdkDisplay` to print for |
279 | * @string: a `GString` to print into |
280 | * |
281 | * Prints the given trigger into a string. |
282 | * |
283 | * This function is returning a translated string for presentation |
284 | * to end users for example in menu items or in help texts. |
285 | * |
286 | * The @display in use may influence the resulting string in |
287 | * various forms, such as resolving hardware keycodes or by |
288 | * causing display-specific modifier names. |
289 | * |
290 | * The form of the representation may change at any time and is |
291 | * not guaranteed to stay identical. |
292 | * |
293 | * Returns: %TRUE if something was printed or %FALSE if the |
294 | * trigger did not have a textual representation suitable |
295 | * for end users. |
296 | **/ |
297 | gboolean |
298 | gtk_shortcut_trigger_print_label (GtkShortcutTrigger *self, |
299 | GdkDisplay *display, |
300 | GString *string) |
301 | { |
302 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), FALSE); |
303 | g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); |
304 | g_return_val_if_fail (string != NULL, FALSE); |
305 | |
306 | return GTK_SHORTCUT_TRIGGER_GET_CLASS (ptr: self)->print_label (self, display, string); |
307 | } |
308 | |
309 | /** |
310 | * gtk_shortcut_trigger_hash: |
311 | * @trigger: (type GtkShortcutTrigger): a `GtkShortcutTrigger` |
312 | * |
313 | * Generates a hash value for a `GtkShortcutTrigger`. |
314 | * |
315 | * The output of this function is guaranteed to be the same for a given |
316 | * value only per-process. It may change between different processor |
317 | * architectures or even different versions of GTK. Do not use this |
318 | * function as a basis for building protocols or file formats. |
319 | * |
320 | * The types of @trigger is `gconstpointer` only to allow use of this |
321 | * function with `GHashTable`. They must each be a `GtkShortcutTrigger`. |
322 | * |
323 | * Returns: a hash value corresponding to @trigger |
324 | */ |
325 | guint |
326 | gtk_shortcut_trigger_hash (gconstpointer trigger) |
327 | { |
328 | GtkShortcutTrigger *t = (GtkShortcutTrigger *) trigger; |
329 | |
330 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t), 0); |
331 | |
332 | return GTK_SHORTCUT_TRIGGER_GET_CLASS (ptr: t)->hash (t); |
333 | } |
334 | |
335 | /** |
336 | * gtk_shortcut_trigger_equal: |
337 | * @trigger1: (type GtkShortcutTrigger): a `GtkShortcutTrigger` |
338 | * @trigger2: (type GtkShortcutTrigger): a `GtkShortcutTrigger` |
339 | * |
340 | * Checks if @trigger1 and @trigger2 trigger under the same conditions. |
341 | * |
342 | * The types of @one and @two are `gconstpointer` only to allow use of this |
343 | * function with `GHashTable`. They must each be a `GtkShortcutTrigger`. |
344 | * |
345 | * Returns: %TRUE if @trigger1 and @trigger2 are equal |
346 | */ |
347 | gboolean |
348 | gtk_shortcut_trigger_equal (gconstpointer trigger1, |
349 | gconstpointer trigger2) |
350 | { |
351 | return gtk_shortcut_trigger_compare (trigger1, trigger2) == 0; |
352 | } |
353 | |
354 | /** |
355 | * gtk_shortcut_trigger_compare: |
356 | * @trigger1: (type GtkShortcutTrigger): a `GtkShortcutTrigger` |
357 | * @trigger2: (type GtkShortcutTrigger): a `GtkShortcutTrigger` |
358 | * |
359 | * The types of @trigger1 and @trigger2 are `gconstpointer` only to allow |
360 | * use of this function as a `GCompareFunc`. |
361 | * |
362 | * They must each be a `GtkShortcutTrigger`. |
363 | * |
364 | * Returns: An integer less than, equal to, or greater than zero if |
365 | * @trigger1 is found, respectively, to be less than, to match, |
366 | * or be greater than @trigger2. |
367 | */ |
368 | int |
369 | gtk_shortcut_trigger_compare (gconstpointer trigger1, |
370 | gconstpointer trigger2) |
371 | { |
372 | GtkShortcutTrigger *t1 = (GtkShortcutTrigger *) trigger1; |
373 | GtkShortcutTrigger *t2 = (GtkShortcutTrigger *) trigger2; |
374 | GType type1, type2; |
375 | |
376 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t1), -1); |
377 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (t2), 1); |
378 | |
379 | type1 = G_OBJECT_TYPE (t1); |
380 | type2 = G_OBJECT_TYPE (t2); |
381 | |
382 | if (type1 == type2) |
383 | { |
384 | return GTK_SHORTCUT_TRIGGER_GET_CLASS (ptr: t1)->compare (t1, t2); |
385 | } |
386 | else |
387 | { /* never < keyval < mnemonic < alternative */ |
388 | if (type1 == GTK_TYPE_NEVER_TRIGGER || |
389 | type2 == GTK_TYPE_ALTERNATIVE_TRIGGER) |
390 | return -1; |
391 | if (type2 == GTK_TYPE_NEVER_TRIGGER || |
392 | type1 == GTK_TYPE_ALTERNATIVE_TRIGGER) |
393 | return 1; |
394 | |
395 | if (type1 == GTK_TYPE_KEYVAL_TRIGGER) |
396 | return -1; |
397 | else |
398 | return 1; |
399 | } |
400 | } |
401 | |
402 | struct _GtkNeverTrigger |
403 | { |
404 | GtkShortcutTrigger parent_instance; |
405 | }; |
406 | |
407 | struct _GtkNeverTriggerClass |
408 | { |
409 | GtkShortcutTriggerClass parent_class; |
410 | }; |
411 | |
412 | G_DEFINE_TYPE (GtkNeverTrigger, gtk_never_trigger, GTK_TYPE_SHORTCUT_TRIGGER) |
413 | |
414 | static void G_GNUC_NORETURN |
415 | gtk_never_trigger_finalize (GObject *gobject) |
416 | { |
417 | g_assert_not_reached (); |
418 | |
419 | G_OBJECT_CLASS (gtk_never_trigger_parent_class)->finalize (gobject); |
420 | } |
421 | |
422 | static GdkKeyMatch |
423 | gtk_never_trigger_trigger (GtkShortcutTrigger *trigger, |
424 | GdkEvent *event, |
425 | gboolean enable_mnemonics) |
426 | { |
427 | return GDK_KEY_MATCH_NONE; |
428 | } |
429 | |
430 | static guint |
431 | gtk_never_trigger_hash (GtkShortcutTrigger *trigger) |
432 | { |
433 | return GTK_SHORTCUT_TRIGGER_HASH_NEVER; |
434 | } |
435 | |
436 | static int |
437 | gtk_never_trigger_compare (GtkShortcutTrigger *trigger1, |
438 | GtkShortcutTrigger *trigger2) |
439 | { |
440 | return 0; |
441 | } |
442 | |
443 | static void |
444 | gtk_never_trigger_print (GtkShortcutTrigger *trigger, |
445 | GString *string) |
446 | { |
447 | g_string_append (string, val: "never" ); |
448 | } |
449 | |
450 | static gboolean |
451 | gtk_never_trigger_print_label (GtkShortcutTrigger *trigger, |
452 | GdkDisplay *display, |
453 | GString *string) |
454 | { |
455 | return FALSE; |
456 | } |
457 | |
458 | static void |
459 | gtk_never_trigger_class_init (GtkNeverTriggerClass *klass) |
460 | { |
461 | GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (ptr: klass); |
462 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
463 | |
464 | gobject_class->finalize = gtk_never_trigger_finalize; |
465 | |
466 | trigger_class->trigger = gtk_never_trigger_trigger; |
467 | trigger_class->hash = gtk_never_trigger_hash; |
468 | trigger_class->compare = gtk_never_trigger_compare; |
469 | trigger_class->print = gtk_never_trigger_print; |
470 | trigger_class->print_label = gtk_never_trigger_print_label; |
471 | } |
472 | |
473 | static void |
474 | gtk_never_trigger_init (GtkNeverTrigger *self) |
475 | { |
476 | } |
477 | |
478 | /** |
479 | * gtk_never_trigger_get: |
480 | * |
481 | * Gets the never trigger. |
482 | * |
483 | * This is a singleton for a trigger that never triggers. |
484 | * Use this trigger instead of %NULL because it implements |
485 | * all virtual functions. |
486 | * |
487 | * Returns: (type GtkNeverTrigger) (transfer none): The never trigger |
488 | */ |
489 | GtkShortcutTrigger * |
490 | gtk_never_trigger_get (void) |
491 | { |
492 | static GtkShortcutTrigger *never = NULL; |
493 | |
494 | if (G_UNLIKELY (never == NULL)) |
495 | never = g_object_new (GTK_TYPE_NEVER_TRIGGER, NULL); |
496 | |
497 | return never; |
498 | } |
499 | |
500 | struct _GtkKeyvalTrigger |
501 | { |
502 | GtkShortcutTrigger parent_instance; |
503 | |
504 | guint keyval; |
505 | GdkModifierType modifiers; |
506 | }; |
507 | |
508 | struct _GtkKeyvalTriggerClass |
509 | { |
510 | GtkShortcutTriggerClass parent_class; |
511 | }; |
512 | |
513 | G_DEFINE_TYPE (GtkKeyvalTrigger, gtk_keyval_trigger, GTK_TYPE_SHORTCUT_TRIGGER) |
514 | |
515 | enum |
516 | { |
517 | KEYVAL_PROP_KEYVAL = 1, |
518 | KEYVAL_PROP_MODIFIERS, |
519 | KEYVAL_N_PROPS |
520 | }; |
521 | |
522 | static GParamSpec *keyval_props[KEYVAL_N_PROPS]; |
523 | |
524 | static GdkKeyMatch |
525 | gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger, |
526 | GdkEvent *event, |
527 | gboolean enable_mnemonics) |
528 | { |
529 | GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (ptr: trigger); |
530 | |
531 | if (gdk_event_get_event_type (event) != GDK_KEY_PRESS) |
532 | return GDK_KEY_MATCH_NONE; |
533 | |
534 | return gdk_key_event_matches (event, keyval: self->keyval, modifiers: self->modifiers); |
535 | } |
536 | |
537 | static guint |
538 | gtk_keyval_trigger_hash (GtkShortcutTrigger *trigger) |
539 | { |
540 | GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (ptr: trigger); |
541 | |
542 | return (self->modifiers << 24) |
543 | | (self->modifiers >> 8) |
544 | | (self->keyval << 16) |
545 | | GTK_SHORTCUT_TRIGGER_HASH_KEYVAL; |
546 | } |
547 | |
548 | static int |
549 | gtk_keyval_trigger_compare (GtkShortcutTrigger *trigger1, |
550 | GtkShortcutTrigger *trigger2) |
551 | { |
552 | GtkKeyvalTrigger *self1 = GTK_KEYVAL_TRIGGER (ptr: trigger1); |
553 | GtkKeyvalTrigger *self2 = GTK_KEYVAL_TRIGGER (ptr: trigger2); |
554 | |
555 | if (self1->modifiers != self2->modifiers) |
556 | return self2->modifiers - self1->modifiers; |
557 | |
558 | return self1->keyval - self2->keyval; |
559 | } |
560 | |
561 | static void |
562 | gtk_keyval_trigger_print (GtkShortcutTrigger *trigger, |
563 | GString *string) |
564 | { |
565 | GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (ptr: trigger); |
566 | char *accelerator_name; |
567 | |
568 | accelerator_name = gtk_accelerator_name (accelerator_key: self->keyval, accelerator_mods: self->modifiers); |
569 | g_string_append (string, val: accelerator_name); |
570 | g_free (mem: accelerator_name); |
571 | } |
572 | |
573 | static gboolean |
574 | gtk_keyval_trigger_print_label (GtkShortcutTrigger *trigger, |
575 | GdkDisplay *display, |
576 | GString *string) |
577 | { |
578 | GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (ptr: trigger); |
579 | |
580 | gtk_accelerator_print_label (gstring: string, accelerator_key: self->keyval, accelerator_mods: self->modifiers); |
581 | |
582 | return TRUE; |
583 | } |
584 | |
585 | static void |
586 | gtk_keyval_trigger_set_property (GObject *gobject, |
587 | guint prop_id, |
588 | const GValue *value, |
589 | GParamSpec *pspec) |
590 | { |
591 | GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (ptr: gobject); |
592 | |
593 | switch (prop_id) |
594 | { |
595 | case KEYVAL_PROP_KEYVAL: |
596 | { |
597 | guint keyval = g_value_get_uint (value); |
598 | |
599 | /* We store keyvals as lower key */ |
600 | if (keyval == GDK_KEY_ISO_Left_Tab) |
601 | self->keyval = GDK_KEY_Tab; |
602 | else |
603 | self->keyval = gdk_keyval_to_lower (keyval); |
604 | } |
605 | break; |
606 | |
607 | case KEYVAL_PROP_MODIFIERS: |
608 | self->modifiers = g_value_get_flags (value); |
609 | break; |
610 | |
611 | default: |
612 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
613 | } |
614 | } |
615 | |
616 | static void |
617 | gtk_keyval_trigger_get_property (GObject *gobject, |
618 | guint prop_id, |
619 | GValue *value, |
620 | GParamSpec *pspec) |
621 | { |
622 | GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (ptr: gobject); |
623 | |
624 | switch (prop_id) |
625 | { |
626 | case KEYVAL_PROP_KEYVAL: |
627 | g_value_set_uint (value, v_uint: self->keyval); |
628 | break; |
629 | |
630 | case KEYVAL_PROP_MODIFIERS: |
631 | g_value_set_flags (value, v_flags: self->modifiers); |
632 | break; |
633 | |
634 | default: |
635 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
636 | } |
637 | } |
638 | |
639 | static void |
640 | gtk_keyval_trigger_class_init (GtkKeyvalTriggerClass *klass) |
641 | { |
642 | GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (ptr: klass); |
643 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
644 | |
645 | gobject_class->set_property = gtk_keyval_trigger_set_property; |
646 | gobject_class->get_property = gtk_keyval_trigger_get_property; |
647 | |
648 | trigger_class->trigger = gtk_keyval_trigger_trigger; |
649 | trigger_class->hash = gtk_keyval_trigger_hash; |
650 | trigger_class->compare = gtk_keyval_trigger_compare; |
651 | trigger_class->print = gtk_keyval_trigger_print; |
652 | trigger_class->print_label = gtk_keyval_trigger_print_label; |
653 | |
654 | /** |
655 | * GtkKeyvalTrigger:keyval: (attributes org.gtk.Property.get=gtk_keyval_trigger_get_keyval) |
656 | * |
657 | * The key value for the trigger. |
658 | */ |
659 | keyval_props[KEYVAL_PROP_KEYVAL] = |
660 | g_param_spec_uint (I_("keyval" ), |
661 | P_("Key value" ), |
662 | P_("The key value for the trigger" ), |
663 | minimum: 0, G_MAXINT, |
664 | default_value: 0, |
665 | G_PARAM_STATIC_STRINGS | |
666 | G_PARAM_CONSTRUCT_ONLY | |
667 | G_PARAM_READWRITE); |
668 | |
669 | /** |
670 | * GtkKeyvalTrigger:modifiers: (attributes org.gtk.Property.get=gtk_keyval_trigger_get_modifiers) |
671 | * |
672 | * The key modifiers for the trigger. |
673 | */ |
674 | keyval_props[KEYVAL_PROP_MODIFIERS] = |
675 | g_param_spec_flags (I_("modifiers" ), |
676 | P_("Modifiers" ), |
677 | P_("The key modifiers for the trigger" ), |
678 | flags_type: GDK_TYPE_MODIFIER_TYPE, |
679 | default_value: 0, |
680 | G_PARAM_STATIC_STRINGS | |
681 | G_PARAM_CONSTRUCT_ONLY | |
682 | G_PARAM_READWRITE); |
683 | |
684 | g_object_class_install_properties (oclass: gobject_class, n_pspecs: KEYVAL_N_PROPS, pspecs: keyval_props); |
685 | } |
686 | |
687 | static void |
688 | gtk_keyval_trigger_init (GtkKeyvalTrigger *self) |
689 | { |
690 | } |
691 | |
692 | /** |
693 | * gtk_keyval_trigger_new: |
694 | * @keyval: The keyval to trigger for |
695 | * @modifiers: the modifiers that need to be present |
696 | * |
697 | * Creates a `GtkShortcutTrigger` that will trigger whenever |
698 | * the key with the given @keyval and @modifiers is pressed. |
699 | * |
700 | * Returns: A new `GtkShortcutTrigger` |
701 | */ |
702 | GtkShortcutTrigger * |
703 | gtk_keyval_trigger_new (guint keyval, |
704 | GdkModifierType modifiers) |
705 | { |
706 | return g_object_new (GTK_TYPE_KEYVAL_TRIGGER, |
707 | first_property_name: "keyval" , keyval, |
708 | "modifiers" , modifiers, |
709 | NULL); |
710 | } |
711 | |
712 | /** |
713 | * gtk_keyval_trigger_get_modifiers: (attributes org.gtk.Method.get_property=modifiers) |
714 | * @self: a keyval `GtkShortcutTrigger` |
715 | * |
716 | * Gets the modifiers that must be present to succeed |
717 | * triggering @self. |
718 | * |
719 | * Returns: the modifiers |
720 | */ |
721 | GdkModifierType |
722 | gtk_keyval_trigger_get_modifiers (GtkKeyvalTrigger *self) |
723 | { |
724 | g_return_val_if_fail (GTK_IS_KEYVAL_TRIGGER (self), 0); |
725 | |
726 | return self->modifiers; |
727 | } |
728 | |
729 | /** |
730 | * gtk_keyval_trigger_get_keyval: (attributes org.gtk.Method.get_property=keyval) |
731 | * @self: a keyval `GtkShortcutTrigger` |
732 | * |
733 | * Gets the keyval that must be pressed to succeed |
734 | * triggering @self. |
735 | * |
736 | * Returns: the keyval |
737 | */ |
738 | guint |
739 | gtk_keyval_trigger_get_keyval (GtkKeyvalTrigger *self) |
740 | { |
741 | g_return_val_if_fail (GTK_IS_KEYVAL_TRIGGER (self), 0); |
742 | |
743 | return self->keyval; |
744 | } |
745 | |
746 | /*** GTK_MNEMONIC_TRIGGER ***/ |
747 | |
748 | struct _GtkMnemonicTrigger |
749 | { |
750 | GtkShortcutTrigger parent_instance; |
751 | |
752 | guint keyval; |
753 | }; |
754 | |
755 | struct _GtkMnemonicTriggerClass |
756 | { |
757 | GtkShortcutTriggerClass parent_class; |
758 | }; |
759 | |
760 | G_DEFINE_TYPE (GtkMnemonicTrigger, gtk_mnemonic_trigger, GTK_TYPE_SHORTCUT_TRIGGER) |
761 | |
762 | enum |
763 | { |
764 | MNEMONIC_PROP_KEYVAL = 1, |
765 | MNEMONIC_N_PROPS |
766 | }; |
767 | |
768 | static GParamSpec *mnemonic_props[MNEMONIC_N_PROPS]; |
769 | |
770 | static GdkKeyMatch |
771 | gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger, |
772 | GdkEvent *event, |
773 | gboolean enable_mnemonics) |
774 | { |
775 | GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (ptr: trigger); |
776 | guint keyval; |
777 | |
778 | if (!enable_mnemonics) |
779 | return GDK_KEY_MATCH_NONE; |
780 | |
781 | if (gdk_event_get_event_type (event) != GDK_KEY_PRESS) |
782 | return GDK_KEY_MATCH_NONE; |
783 | |
784 | /* XXX: This needs to deal with groups */ |
785 | keyval = gdk_key_event_get_keyval (event); |
786 | |
787 | if (keyval == GDK_KEY_ISO_Left_Tab) |
788 | keyval = GDK_KEY_Tab; |
789 | else |
790 | keyval = gdk_keyval_to_lower (keyval); |
791 | |
792 | if (keyval != self->keyval) |
793 | return GDK_KEY_MATCH_NONE; |
794 | |
795 | return GDK_KEY_MATCH_EXACT; |
796 | } |
797 | |
798 | static guint |
799 | gtk_mnemonic_trigger_hash (GtkShortcutTrigger *trigger) |
800 | { |
801 | GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (ptr: trigger); |
802 | |
803 | return (self->keyval << 8) |
804 | | GTK_SHORTCUT_TRIGGER_HASH_MNEMONIC; |
805 | } |
806 | |
807 | static int |
808 | gtk_mnemonic_trigger_compare (GtkShortcutTrigger *trigger1, |
809 | GtkShortcutTrigger *trigger2) |
810 | { |
811 | GtkMnemonicTrigger *self1 = GTK_MNEMONIC_TRIGGER (ptr: trigger1); |
812 | GtkMnemonicTrigger *self2 = GTK_MNEMONIC_TRIGGER (ptr: trigger2); |
813 | |
814 | return self1->keyval - self2->keyval; |
815 | } |
816 | |
817 | static void |
818 | gtk_mnemonic_trigger_print (GtkShortcutTrigger *trigger, |
819 | GString *string) |
820 | { |
821 | GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (ptr: trigger); |
822 | const char *keyval_str; |
823 | |
824 | keyval_str = gdk_keyval_name (keyval: self->keyval); |
825 | if (keyval_str == NULL) |
826 | keyval_str = "???" ; |
827 | |
828 | g_string_append (string, val: "<Mnemonic>" ); |
829 | g_string_append (string, val: keyval_str); |
830 | } |
831 | |
832 | static gboolean |
833 | gtk_mnemonic_trigger_print_label (GtkShortcutTrigger *trigger, |
834 | GdkDisplay *display, |
835 | GString *string) |
836 | { |
837 | GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (ptr: trigger); |
838 | const char *keyval_str; |
839 | |
840 | keyval_str = gdk_keyval_name (keyval: self->keyval); |
841 | if (keyval_str == NULL) |
842 | return FALSE; |
843 | |
844 | g_string_append (string, val: keyval_str); |
845 | |
846 | return TRUE; |
847 | } |
848 | |
849 | static void |
850 | gtk_mnemonic_trigger_set_property (GObject *gobject, |
851 | guint prop_id, |
852 | const GValue *value, |
853 | GParamSpec *pspec) |
854 | { |
855 | GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (ptr: gobject); |
856 | |
857 | switch (prop_id) |
858 | { |
859 | case MNEMONIC_PROP_KEYVAL: |
860 | { |
861 | guint keyval = g_value_get_uint (value); |
862 | |
863 | /* We store keyvals as lower key */ |
864 | if (keyval == GDK_KEY_ISO_Left_Tab) |
865 | self->keyval = GDK_KEY_Tab; |
866 | else |
867 | self->keyval = gdk_keyval_to_lower (keyval); |
868 | } |
869 | break; |
870 | |
871 | default: |
872 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
873 | } |
874 | } |
875 | |
876 | static void |
877 | gtk_mnemonic_trigger_get_property (GObject *gobject, |
878 | guint prop_id, |
879 | GValue *value, |
880 | GParamSpec *pspec) |
881 | { |
882 | GtkMnemonicTrigger *self = GTK_MNEMONIC_TRIGGER (ptr: gobject); |
883 | |
884 | switch (prop_id) |
885 | { |
886 | case MNEMONIC_PROP_KEYVAL: |
887 | g_value_set_uint (value, v_uint: self->keyval); |
888 | break; |
889 | |
890 | default: |
891 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
892 | } |
893 | } |
894 | |
895 | static void |
896 | gtk_mnemonic_trigger_class_init (GtkMnemonicTriggerClass *klass) |
897 | { |
898 | GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (ptr: klass); |
899 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
900 | |
901 | gobject_class->set_property = gtk_mnemonic_trigger_set_property; |
902 | gobject_class->get_property = gtk_mnemonic_trigger_get_property; |
903 | |
904 | trigger_class->trigger = gtk_mnemonic_trigger_trigger; |
905 | trigger_class->hash = gtk_mnemonic_trigger_hash; |
906 | trigger_class->compare = gtk_mnemonic_trigger_compare; |
907 | trigger_class->print = gtk_mnemonic_trigger_print; |
908 | trigger_class->print_label = gtk_mnemonic_trigger_print_label; |
909 | |
910 | /** |
911 | * GtkMnemonicTrigger:keyval: (attributes org.gtk.Property.get=gtk_mnemonic_trigger_get_keyval) |
912 | * |
913 | * The key value for the trigger. |
914 | */ |
915 | mnemonic_props[KEYVAL_PROP_KEYVAL] = |
916 | g_param_spec_uint (I_("keyval" ), |
917 | P_("Key value" ), |
918 | P_("The key value for the trigger" ), |
919 | minimum: 0, G_MAXINT, |
920 | default_value: 0, |
921 | G_PARAM_STATIC_STRINGS | |
922 | G_PARAM_CONSTRUCT_ONLY | |
923 | G_PARAM_READWRITE); |
924 | |
925 | g_object_class_install_properties (oclass: gobject_class, n_pspecs: MNEMONIC_N_PROPS, pspecs: mnemonic_props); |
926 | } |
927 | |
928 | static void |
929 | gtk_mnemonic_trigger_init (GtkMnemonicTrigger *self) |
930 | { |
931 | } |
932 | |
933 | /** |
934 | * gtk_mnemonic_trigger_new: |
935 | * @keyval: The keyval to trigger for |
936 | * |
937 | * Creates a `GtkShortcutTrigger` that will trigger whenever the key with |
938 | * the given @keyval is pressed and mnemonics have been activated. |
939 | * |
940 | * Mnemonics are activated by calling code when a key event with the right |
941 | * modifiers is detected. |
942 | * |
943 | * Returns: (transfer full) (type GtkMnemonicTrigger): A new `GtkShortcutTrigger` |
944 | */ |
945 | GtkShortcutTrigger * |
946 | gtk_mnemonic_trigger_new (guint keyval) |
947 | { |
948 | return g_object_new (GTK_TYPE_MNEMONIC_TRIGGER, |
949 | first_property_name: "keyval" , keyval, |
950 | NULL); |
951 | } |
952 | |
953 | /** |
954 | * gtk_mnemonic_trigger_get_keyval: (attributes org.gtk.Method.get_property=keyval) |
955 | * @self: a mnemonic `GtkShortcutTrigger` |
956 | * |
957 | * Gets the keyval that must be pressed to succeed triggering @self. |
958 | * |
959 | * Returns: the keyval |
960 | */ |
961 | guint |
962 | gtk_mnemonic_trigger_get_keyval (GtkMnemonicTrigger *self) |
963 | { |
964 | g_return_val_if_fail (GTK_IS_MNEMONIC_TRIGGER (self), 0); |
965 | |
966 | return self->keyval; |
967 | } |
968 | |
969 | /*** GTK_ALTERNATIVE_TRIGGER ***/ |
970 | |
971 | struct _GtkAlternativeTrigger |
972 | { |
973 | GtkShortcutTrigger parent_instance; |
974 | |
975 | GtkShortcutTrigger *first; |
976 | GtkShortcutTrigger *second; |
977 | }; |
978 | |
979 | struct _GtkAlternativeTriggerClass |
980 | { |
981 | GtkShortcutTriggerClass parent_class; |
982 | }; |
983 | |
984 | G_DEFINE_TYPE (GtkAlternativeTrigger, gtk_alternative_trigger, GTK_TYPE_SHORTCUT_TRIGGER) |
985 | |
986 | enum |
987 | { |
988 | ALTERNATIVE_PROP_FIRST = 1, |
989 | ALTERNATIVE_PROP_SECOND, |
990 | ALTERNATIVE_N_PROPS |
991 | }; |
992 | |
993 | static GParamSpec *alternative_props[ALTERNATIVE_N_PROPS]; |
994 | |
995 | static void |
996 | gtk_alternative_trigger_dispose (GObject *gobject) |
997 | { |
998 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: gobject); |
999 | |
1000 | g_clear_object (&self->first); |
1001 | g_clear_object (&self->second); |
1002 | |
1003 | G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->dispose (gobject); |
1004 | } |
1005 | |
1006 | static GdkKeyMatch |
1007 | gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger, |
1008 | GdkEvent *event, |
1009 | gboolean enable_mnemonics) |
1010 | { |
1011 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: trigger); |
1012 | |
1013 | return MAX (gtk_shortcut_trigger_trigger (self->first, event, enable_mnemonics), |
1014 | gtk_shortcut_trigger_trigger (self->second, event, enable_mnemonics)); |
1015 | } |
1016 | |
1017 | static guint |
1018 | gtk_alternative_trigger_hash (GtkShortcutTrigger *trigger) |
1019 | { |
1020 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: trigger); |
1021 | guint result; |
1022 | |
1023 | result = gtk_shortcut_trigger_hash (trigger: self->first); |
1024 | result <<= 5; |
1025 | |
1026 | result |= gtk_shortcut_trigger_hash (trigger: self->second); |
1027 | result <<= 5; |
1028 | |
1029 | return result | GTK_SHORTCUT_TRIGGER_HASH_ALTERNATIVE; |
1030 | } |
1031 | |
1032 | static int |
1033 | gtk_alternative_trigger_compare (GtkShortcutTrigger *trigger1, |
1034 | GtkShortcutTrigger *trigger2) |
1035 | { |
1036 | GtkAlternativeTrigger *self1 = GTK_ALTERNATIVE_TRIGGER (ptr: trigger1); |
1037 | GtkAlternativeTrigger *self2 = GTK_ALTERNATIVE_TRIGGER (ptr: trigger2); |
1038 | int cmp; |
1039 | |
1040 | cmp = gtk_shortcut_trigger_compare (trigger1: self1->first, trigger2: self2->first); |
1041 | if (cmp != 0) |
1042 | return cmp; |
1043 | |
1044 | return gtk_shortcut_trigger_compare (trigger1: self1->second, trigger2: self2->second); |
1045 | } |
1046 | |
1047 | static void |
1048 | gtk_alternative_trigger_print (GtkShortcutTrigger *trigger, |
1049 | GString *string) |
1050 | { |
1051 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: trigger); |
1052 | |
1053 | gtk_shortcut_trigger_print (self: self->first, string); |
1054 | g_string_append (string, val: "|" ); |
1055 | gtk_shortcut_trigger_print (self: self->second, string); |
1056 | } |
1057 | |
1058 | static gboolean |
1059 | gtk_alternative_trigger_print_label (GtkShortcutTrigger *trigger, |
1060 | GdkDisplay *display, |
1061 | GString *string) |
1062 | { |
1063 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: trigger); |
1064 | |
1065 | if (gtk_shortcut_trigger_print_label (self: self->first, display, string)) |
1066 | { |
1067 | g_string_append (string, val: ", " ); |
1068 | if (!gtk_shortcut_trigger_print_label (self: self->second, display, string)) |
1069 | g_string_truncate (string, len: string->len - 2); |
1070 | return TRUE; |
1071 | } |
1072 | else |
1073 | { |
1074 | return gtk_shortcut_trigger_print_label (self: self->second, display, string); |
1075 | } |
1076 | } |
1077 | |
1078 | static void |
1079 | gtk_alternative_trigger_set_property (GObject *gobject, |
1080 | guint prop_id, |
1081 | const GValue *value, |
1082 | GParamSpec *pspec) |
1083 | { |
1084 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: gobject); |
1085 | |
1086 | switch (prop_id) |
1087 | { |
1088 | case ALTERNATIVE_PROP_FIRST: |
1089 | self->first = g_value_dup_object (value); |
1090 | break; |
1091 | |
1092 | case ALTERNATIVE_PROP_SECOND: |
1093 | self->second = g_value_dup_object (value); |
1094 | break; |
1095 | |
1096 | default: |
1097 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
1098 | } |
1099 | } |
1100 | |
1101 | static void |
1102 | gtk_alternative_trigger_get_property (GObject *gobject, |
1103 | guint prop_id, |
1104 | GValue *value, |
1105 | GParamSpec *pspec) |
1106 | { |
1107 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: gobject); |
1108 | |
1109 | switch (prop_id) |
1110 | { |
1111 | case ALTERNATIVE_PROP_FIRST: |
1112 | g_value_set_object (value, v_object: self->first); |
1113 | break; |
1114 | |
1115 | case ALTERNATIVE_PROP_SECOND: |
1116 | g_value_set_object (value, v_object: self->second); |
1117 | break; |
1118 | |
1119 | default: |
1120 | G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); |
1121 | } |
1122 | } |
1123 | |
1124 | static void |
1125 | gtk_alternative_trigger_constructed (GObject *gobject) |
1126 | { |
1127 | GtkAlternativeTrigger *self = GTK_ALTERNATIVE_TRIGGER (ptr: gobject); |
1128 | |
1129 | if (self->first == NULL || self->second == NULL) |
1130 | { |
1131 | g_critical ("Invalid alternative trigger, disabling" ); |
1132 | self->first = g_object_ref (gtk_never_trigger_get ()); |
1133 | self->second = g_object_ref (gtk_never_trigger_get ()); |
1134 | } |
1135 | |
1136 | G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->constructed (gobject); |
1137 | } |
1138 | |
1139 | static void |
1140 | gtk_alternative_trigger_class_init (GtkAlternativeTriggerClass *klass) |
1141 | { |
1142 | GtkShortcutTriggerClass *trigger_class = GTK_SHORTCUT_TRIGGER_CLASS (ptr: klass); |
1143 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
1144 | |
1145 | gobject_class->constructed = gtk_alternative_trigger_constructed; |
1146 | gobject_class->set_property = gtk_alternative_trigger_set_property; |
1147 | gobject_class->get_property = gtk_alternative_trigger_get_property; |
1148 | gobject_class->dispose = gtk_alternative_trigger_dispose; |
1149 | |
1150 | trigger_class->trigger = gtk_alternative_trigger_trigger; |
1151 | trigger_class->hash = gtk_alternative_trigger_hash; |
1152 | trigger_class->compare = gtk_alternative_trigger_compare; |
1153 | trigger_class->print = gtk_alternative_trigger_print; |
1154 | trigger_class->print_label = gtk_alternative_trigger_print_label; |
1155 | |
1156 | /** |
1157 | * GtkAlternativeTrigger:first: (attributes org.gtk.Property.get=gtk_alternative_trigger_get_first) |
1158 | * |
1159 | * The first `GtkShortcutTrigger` to check. |
1160 | */ |
1161 | alternative_props[ALTERNATIVE_PROP_FIRST] = |
1162 | g_param_spec_object (I_("first" ), |
1163 | P_("First" ), |
1164 | P_("The first trigger to check" ), |
1165 | GTK_TYPE_SHORTCUT_TRIGGER, |
1166 | G_PARAM_STATIC_STRINGS | |
1167 | G_PARAM_CONSTRUCT_ONLY | |
1168 | G_PARAM_READWRITE); |
1169 | |
1170 | /** |
1171 | * GtkAlternativeTrigger:second: (attributes org.gtk.Property.get=gtk_alternative_trigger_get_second) |
1172 | * |
1173 | * The second `GtkShortcutTrigger` to check. |
1174 | */ |
1175 | alternative_props[ALTERNATIVE_PROP_SECOND] = |
1176 | g_param_spec_object (I_("second" ), |
1177 | P_("Second" ), |
1178 | P_("The second trigger to check" ), |
1179 | GTK_TYPE_SHORTCUT_TRIGGER, |
1180 | G_PARAM_STATIC_STRINGS | |
1181 | G_PARAM_CONSTRUCT_ONLY | |
1182 | G_PARAM_READWRITE); |
1183 | |
1184 | g_object_class_install_properties (oclass: gobject_class, n_pspecs: ALTERNATIVE_N_PROPS, pspecs: alternative_props); |
1185 | } |
1186 | |
1187 | static void |
1188 | gtk_alternative_trigger_init (GtkAlternativeTrigger *self) |
1189 | { |
1190 | } |
1191 | |
1192 | /** |
1193 | * gtk_alternative_trigger_new: |
1194 | * @first: (transfer full): The first trigger that may trigger |
1195 | * @second: (transfer full): The second trigger that may trigger |
1196 | * |
1197 | * Creates a `GtkShortcutTrigger` that will trigger whenever |
1198 | * either of the two given triggers gets triggered. |
1199 | * |
1200 | * Note that nesting is allowed, so if you want more than two |
1201 | * alternative, create a new alternative trigger for each option. |
1202 | * |
1203 | * Returns: a new `GtkShortcutTrigger` |
1204 | */ |
1205 | GtkShortcutTrigger * |
1206 | gtk_alternative_trigger_new (GtkShortcutTrigger *first, |
1207 | GtkShortcutTrigger *second) |
1208 | { |
1209 | GtkShortcutTrigger *res; |
1210 | |
1211 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (first), NULL); |
1212 | g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (second), NULL); |
1213 | |
1214 | res = g_object_new (GTK_TYPE_ALTERNATIVE_TRIGGER, |
1215 | first_property_name: "first" , first, |
1216 | "second" , second, |
1217 | NULL); |
1218 | |
1219 | g_object_unref (object: first); |
1220 | g_object_unref (object: second); |
1221 | |
1222 | return res; |
1223 | } |
1224 | |
1225 | /** |
1226 | * gtk_alternative_trigger_get_first: (attributes org.gtk.Method.get_property=first) |
1227 | * @self: an alternative `GtkShortcutTrigger` |
1228 | * |
1229 | * Gets the first of the two alternative triggers that may |
1230 | * trigger @self. |
1231 | * |
1232 | * [method@Gtk.AlternativeTrigger.get_second] will return |
1233 | * the other one. |
1234 | * |
1235 | * Returns: (transfer none): the first alternative trigger |
1236 | */ |
1237 | GtkShortcutTrigger * |
1238 | gtk_alternative_trigger_get_first (GtkAlternativeTrigger *self) |
1239 | { |
1240 | g_return_val_if_fail (GTK_IS_ALTERNATIVE_TRIGGER (self), NULL); |
1241 | |
1242 | return self->first; |
1243 | } |
1244 | |
1245 | /** |
1246 | * gtk_alternative_trigger_get_second: (attributes org.gtk.Method.get_property=second) |
1247 | * @self: an alternative `GtkShortcutTrigger` |
1248 | * |
1249 | * Gets the second of the two alternative triggers that may |
1250 | * trigger @self. |
1251 | * |
1252 | * [method@Gtk.AlternativeTrigger.get_first] will return |
1253 | * the other one. |
1254 | * |
1255 | * Returns: (transfer none): the second alternative trigger |
1256 | */ |
1257 | GtkShortcutTrigger * |
1258 | gtk_alternative_trigger_get_second (GtkAlternativeTrigger *self) |
1259 | { |
1260 | g_return_val_if_fail (GTK_IS_ALTERNATIVE_TRIGGER (self), NULL); |
1261 | |
1262 | return self->second; |
1263 | } |
1264 | |