1#include <gtk/gtk.h>
2
3#define GTK_COMPILATION
4#include "gdk/gdkeventsprivate.h"
5
6static GdkEvent *
7key_event_new (GdkEventType event_type,
8 GdkSurface *surface,
9 GdkDevice *device,
10 GdkDevice *source_device,
11 guint32 time_,
12 guint keycode,
13 GdkModifierType state,
14 gboolean is_modifier,
15 GdkTranslatedKey *translated,
16 GdkTranslatedKey *no_lock)
17{
18 GdkKeyEvent *key_event = (GdkKeyEvent *) g_type_create_instance (GDK_TYPE_KEY_EVENT);
19 GdkEvent *event = (GdkEvent *) key_event;
20
21 event->event_type = event_type;
22 event->surface = g_object_ref (surface);
23 event->device = g_object_ref (device);
24 event->time = time_;
25
26 key_event->keycode = keycode;
27 key_event->state = state;
28 key_event->key_is_modifier = is_modifier;
29 key_event->translated[0] = *translated;
30 key_event->translated[1] = *no_lock;
31
32 return event;
33}
34
35static void
36test_trigger_basic (void)
37{
38 GtkShortcutTrigger *trigger;
39
40 trigger = gtk_never_trigger_get ();
41
42 trigger = gtk_keyval_trigger_new (GDK_KEY_a, modifiers: GDK_CONTROL_MASK);
43 g_assert_cmpint (gtk_keyval_trigger_get_keyval (GTK_KEYVAL_TRIGGER (trigger)), ==, GDK_KEY_a);
44 g_assert_cmpint (gtk_keyval_trigger_get_modifiers (GTK_KEYVAL_TRIGGER (trigger)), ==, GDK_CONTROL_MASK);
45 g_object_unref (object: trigger);
46
47 trigger = gtk_mnemonic_trigger_new (GDK_KEY_u);
48 g_assert_cmpint (gtk_mnemonic_trigger_get_keyval (GTK_MNEMONIC_TRIGGER (trigger)), ==, GDK_KEY_u);
49 g_object_unref (object: trigger);
50}
51
52static void
53test_trigger_equal (void)
54{
55 GtkShortcutTrigger *trigger1, *trigger2, *trigger3, *trigger4;
56 GtkShortcutTrigger *trigger5, *trigger6, *trigger1a, *trigger2a;
57
58 trigger1 = gtk_keyval_trigger_new (keyval: 'u', modifiers: GDK_CONTROL_MASK);
59 trigger2 = g_object_ref (gtk_never_trigger_get ());
60 trigger3 = gtk_alternative_trigger_new (g_object_ref (trigger1), g_object_ref (trigger2));
61 trigger4 = gtk_alternative_trigger_new (g_object_ref (trigger2), g_object_ref (trigger1));
62 trigger5 = gtk_keyval_trigger_new (keyval: 'u', modifiers: GDK_SHIFT_MASK);
63 trigger6 = gtk_mnemonic_trigger_new (keyval: 'u');
64
65 trigger1a = gtk_keyval_trigger_new (keyval: 'u', modifiers: GDK_CONTROL_MASK);
66 trigger2a = g_object_ref (gtk_never_trigger_get ());
67
68 g_assert_true (gtk_shortcut_trigger_equal (trigger1, trigger1));
69 g_assert_true (gtk_shortcut_trigger_equal (trigger2, trigger2));
70 g_assert_true (gtk_shortcut_trigger_equal (trigger3, trigger3));
71 g_assert_true (gtk_shortcut_trigger_equal (trigger4, trigger4));
72 g_assert_true (gtk_shortcut_trigger_equal (trigger5, trigger5));
73 g_assert_true (gtk_shortcut_trigger_equal (trigger6, trigger6));
74
75 g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger2));
76 g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger3));
77 g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger4));
78 g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger5));
79 g_assert_false (gtk_shortcut_trigger_equal (trigger1, trigger6));
80
81 g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger3));
82 g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger4));
83 g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger5));
84 g_assert_false (gtk_shortcut_trigger_equal (trigger2, trigger6));
85
86 g_assert_false (gtk_shortcut_trigger_equal (trigger3, trigger4));
87 g_assert_false (gtk_shortcut_trigger_equal (trigger3, trigger5));
88 g_assert_false (gtk_shortcut_trigger_equal (trigger3, trigger6));
89
90 g_assert_false (gtk_shortcut_trigger_equal (trigger4, trigger5));
91 g_assert_false (gtk_shortcut_trigger_equal (trigger4, trigger6));
92
93 g_assert_false (gtk_shortcut_trigger_equal (trigger5, trigger6));
94
95 g_assert_true (gtk_shortcut_trigger_equal (trigger1, trigger1a));
96 g_assert_true (gtk_shortcut_trigger_equal (trigger2, trigger2a));
97
98 g_object_unref (object: trigger1);
99 g_object_unref (object: trigger2);
100 g_object_unref (object: trigger3);
101 g_object_unref (object: trigger4);
102 g_object_unref (object: trigger5);
103 g_object_unref (object: trigger6);
104 g_object_unref (object: trigger1a);
105 g_object_unref (object: trigger2a);
106}
107
108static void
109test_trigger_parse_never (void)
110{
111 GtkShortcutTrigger *trigger;
112
113 trigger = gtk_shortcut_trigger_parse_string (string: "never");
114 g_assert_true (GTK_IS_NEVER_TRIGGER (trigger));
115
116 g_object_unref (object: trigger);
117}
118
119static void
120test_trigger_parse_keyval (void)
121{
122 const struct
123 {
124 const char *str;
125 GdkModifierType modifiers;
126 guint keyval;
127 int trigger_type;
128 } tests[] = {
129 { "<Primary><Alt>z", GDK_CONTROL_MASK | GDK_ALT_MASK, 'z' },
130 { "<Control>U", GDK_CONTROL_MASK, 'u' },
131 { "<Hyper>x", GDK_HYPER_MASK, 'x' },
132 { "<Meta>y", GDK_META_MASK, 'y' },
133 { "KP_7", 0, GDK_KEY_KP_7 },
134 { "<Shift>exclam", GDK_SHIFT_MASK, '!' },
135 };
136
137 for (int i = 0; i < G_N_ELEMENTS (tests); i++)
138 {
139 g_test_message (format: "Checking: '%s'", tests[i].str);
140
141 GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (string: tests[i].str);
142
143 g_assert_true (GTK_IS_KEYVAL_TRIGGER (trigger));
144 g_assert_cmpint (gtk_keyval_trigger_get_modifiers (GTK_KEYVAL_TRIGGER (trigger)),
145 ==,
146 tests[i].modifiers);
147 g_assert_cmpuint (gtk_keyval_trigger_get_keyval (GTK_KEYVAL_TRIGGER (trigger)),
148 ==,
149 tests[i].keyval);
150 g_object_unref (object: trigger);
151 }
152}
153
154static void
155test_trigger_parse_mnemonic (void)
156{
157 struct
158 {
159 const char *str;
160 guint keyval;
161 } tests[] = {
162 { "_A", GDK_KEY_a },
163 { "_s", GDK_KEY_s },
164 };
165
166 for (int i = 0; i < G_N_ELEMENTS (tests); i++)
167 {
168 g_test_message (format: "Checking: '%s'", tests[i].str);
169
170 GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (string: tests[i].str);
171
172 g_assert_true (GTK_IS_MNEMONIC_TRIGGER (trigger));
173 g_assert_cmpuint (gtk_mnemonic_trigger_get_keyval (GTK_MNEMONIC_TRIGGER (trigger)),
174 ==,
175 tests[i].keyval);
176 g_object_unref (object: trigger);
177 }
178}
179
180static void
181test_trigger_parse_alternative (void)
182{
183 enum
184 {
185 TRIGGER_NEVER,
186 TRIGGER_KEYVAL,
187 TRIGGER_MNEMONIC,
188 TRIGGER_ALTERNATIVE
189 };
190
191 const struct
192 {
193 const char *str;
194 int first;
195 int second;
196 } tests[] = {
197 { "U|<Primary>U", TRIGGER_KEYVAL, TRIGGER_KEYVAL },
198 { "_U|<Shift>u", TRIGGER_MNEMONIC, TRIGGER_KEYVAL },
199 { "x|_x|<Primary>x", TRIGGER_KEYVAL, TRIGGER_ALTERNATIVE },
200 };
201
202 for (int i = 0; i < G_N_ELEMENTS (tests); i++)
203 {
204 g_test_message (format: "Checking: '%s'", tests[i].str);
205
206 GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (string: tests[i].str);
207
208 g_assert_true (GTK_IS_ALTERNATIVE_TRIGGER (trigger));
209
210 GtkShortcutTrigger *t1 = gtk_alternative_trigger_get_first (self: GTK_ALTERNATIVE_TRIGGER (ptr: trigger));
211
212 switch (tests[i].first)
213 {
214 case TRIGGER_NEVER:
215 g_assert_true (GTK_IS_NEVER_TRIGGER (t1));
216 break;
217
218 case TRIGGER_KEYVAL:
219 g_assert_true (GTK_IS_KEYVAL_TRIGGER (t1));
220 break;
221
222 case TRIGGER_MNEMONIC:
223 g_assert_true (GTK_IS_MNEMONIC_TRIGGER (t1));
224 break;
225
226 case TRIGGER_ALTERNATIVE:
227 g_assert_true (GTK_IS_ALTERNATIVE_TRIGGER (t1));
228 break;
229
230 default:
231 g_assert_not_reached ();
232 break;
233 }
234
235 GtkShortcutTrigger *t2 = gtk_alternative_trigger_get_second (self: GTK_ALTERNATIVE_TRIGGER (ptr: trigger));
236
237 switch (tests[i].second)
238 {
239 case TRIGGER_NEVER:
240 g_assert_true (GTK_IS_NEVER_TRIGGER (t2));
241 break;
242
243 case TRIGGER_KEYVAL:
244 g_assert_true (GTK_IS_KEYVAL_TRIGGER (t2));
245 break;
246
247 case TRIGGER_MNEMONIC:
248 g_assert_true (GTK_IS_MNEMONIC_TRIGGER (t2));
249 break;
250
251 case TRIGGER_ALTERNATIVE:
252 g_assert_true (GTK_IS_ALTERNATIVE_TRIGGER (t2));
253 break;
254
255 default:
256 g_assert_not_reached ();
257 break;
258 }
259
260 g_object_unref (object: trigger);
261 }
262}
263
264static void
265test_trigger_parse_invalid (void)
266{
267 const char *tests[] = {
268 "<never>",
269 "Never",
270 "Foo",
271 "<Foo>Nyaa",
272 "never|",
273 "|never",
274 };
275
276 for (int i = 0; i < G_N_ELEMENTS (tests); i++)
277 {
278 g_test_message (format: "Checking: '%s'", tests[i]);
279
280 GtkShortcutTrigger *trigger = gtk_shortcut_trigger_parse_string (string: tests[i]);
281
282 g_assert_null (trigger);
283 }
284}
285
286static void
287test_trigger_trigger (void)
288{
289 GtkShortcutTrigger *trigger[4];
290 GdkDisplay *display;
291 GdkSeat *seat;
292 GdkSurface *surface;
293 GdkDevice *device;
294 GdkEvent *event;
295 struct {
296 guint keyval;
297 GdkModifierType state;
298 gboolean mnemonic;
299 GdkKeyMatch result[4];
300 } tests[] = {
301 { GDK_KEY_a, GDK_CONTROL_MASK, FALSE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT } },
302 { GDK_KEY_a, GDK_CONTROL_MASK, TRUE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT } },
303 { GDK_KEY_a, GDK_SHIFT_MASK, FALSE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE } },
304 { GDK_KEY_a, GDK_SHIFT_MASK, TRUE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE } },
305 { GDK_KEY_u, GDK_SHIFT_MASK, FALSE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE } },
306 { GDK_KEY_u, GDK_SHIFT_MASK, TRUE, { GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_NONE, GDK_KEY_MATCH_EXACT, GDK_KEY_MATCH_EXACT } },
307 };
308 int i, j;
309
310 display = gdk_display_get_default ();
311 seat = gdk_display_get_default_seat (display);
312 if (!seat)
313 {
314 g_test_skip (msg: "Display has no seat");
315 return;
316 }
317
318 trigger[0] = g_object_ref (gtk_never_trigger_get ());
319 trigger[1] = gtk_keyval_trigger_new (GDK_KEY_a, modifiers: GDK_CONTROL_MASK);
320 trigger[2] = gtk_mnemonic_trigger_new (GDK_KEY_u);
321 trigger[3] = gtk_alternative_trigger_new (g_object_ref (trigger[1]),
322 g_object_ref (trigger[2]));
323
324 device = gdk_seat_get_keyboard (seat);
325 surface = gdk_surface_new_toplevel (display);
326
327 for (i = 0; i < G_N_ELEMENTS (tests); i++)
328 {
329 GdkKeymapKey *keys;
330 int n_keys;
331 GdkTranslatedKey translated;
332
333 if (!gdk_display_map_keyval (display, keyval: tests[i].keyval, keys: &keys, n_keys: &n_keys))
334 continue;
335
336 translated.keyval = tests[i].keyval;
337 translated.consumed = 0;
338 translated.layout = keys[0].group;
339 translated.level = keys[0].level;
340 event = key_event_new (event_type: GDK_KEY_PRESS,
341 surface,
342 device,
343 source_device: device,
344 GDK_CURRENT_TIME,
345 keycode: keys[0].keycode,
346 state: tests[i].state,
347 FALSE,
348 translated: &translated,
349 no_lock: &translated);
350 for (j = 0; j < 4; j++)
351 {
352 g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger[j], event, tests[i].mnemonic), ==, tests[i].result[j]);
353 }
354
355 gdk_event_unref (event);
356
357 g_free (mem: keys);
358 }
359
360 gdk_surface_destroy (surface);
361 g_object_unref (object: surface);
362
363 g_object_unref (object: trigger[0]);
364 g_object_unref (object: trigger[1]);
365 g_object_unref (object: trigger[2]);
366 g_object_unref (object: trigger[3]);
367}
368
369static gboolean
370callback (GtkWidget *widget,
371 GVariant *args,
372 gpointer user_data)
373{
374 int *callback_count = user_data;
375 *callback_count += 1;
376 return TRUE;
377}
378
379static void
380test_action_basic (void)
381{
382 GtkShortcutAction *action;
383
384 action = gtk_signal_action_new (signal_name: "activate");
385 g_assert_cmpstr (gtk_signal_action_get_signal_name (GTK_SIGNAL_ACTION (action)), ==, "activate");
386 g_object_unref (object: action);
387
388 action = gtk_named_action_new (name: "text.undo");
389 g_assert_cmpstr (gtk_named_action_get_action_name (GTK_NAMED_ACTION (action)), ==, "text.undo");
390 g_object_unref (object: action);
391}
392
393static void
394test_action_activate (void)
395{
396 GtkShortcutAction *action;
397 GtkWidget *widget;
398 int callback_count;
399
400 widget = gtk_label_new (str: "");
401 g_object_ref_sink (widget);
402
403 action = gtk_nothing_action_get ();
404 g_assert_false (gtk_shortcut_action_activate (action, 0, widget, NULL));
405
406 callback_count = 0;
407 action = gtk_callback_action_new (callback, data: &callback_count, NULL);
408 g_assert_true (gtk_shortcut_action_activate (action, 0, widget, NULL));
409 g_assert_cmpint (callback_count, ==, 1);
410 g_object_unref (object: action);
411
412 g_object_unref (object: widget);
413}
414
415static void
416test_action_parse (void)
417{
418 GtkShortcutAction *action;
419
420 action = gtk_shortcut_action_parse_string (string: "nothing");
421 g_assert_true (GTK_IS_NOTHING_ACTION (action));
422 g_object_unref (object: action);
423
424 action = gtk_shortcut_action_parse_string (string: "activate");
425 g_assert_true (GTK_IS_ACTIVATE_ACTION (action));
426 g_object_unref (object: action);
427
428 action = gtk_shortcut_action_parse_string (string: "mnemonic-activate");
429 g_assert_true (GTK_IS_MNEMONIC_ACTION (action));
430 g_object_unref (object: action);
431
432 action = gtk_shortcut_action_parse_string (string: "action(win.dark)");
433 g_assert_true (GTK_IS_NAMED_ACTION (action));
434 g_object_unref (object: action);
435
436 action = gtk_shortcut_action_parse_string (string: "signal(frob)");
437 g_assert_true (GTK_IS_SIGNAL_ACTION (action));
438 g_object_unref (object: action);
439}
440
441int
442main (int argc, char *argv[])
443{
444 gtk_test_init (argcp: &argc, argvp: &argv);
445
446 g_test_add_func (testpath: "/shortcuts/trigger/basic", test_func: test_trigger_basic);
447 g_test_add_func (testpath: "/shortcuts/trigger/equal", test_func: test_trigger_equal);
448 g_test_add_func (testpath: "/shortcuts/trigger/parse/never", test_func: test_trigger_parse_never);
449 g_test_add_func (testpath: "/shortcuts/trigger/parse/keyval", test_func: test_trigger_parse_keyval);
450 g_test_add_func (testpath: "/shortcuts/trigger/parse/mnemonic", test_func: test_trigger_parse_mnemonic);
451 g_test_add_func (testpath: "/shortcuts/trigger/parse/alternative", test_func: test_trigger_parse_alternative);
452 g_test_add_func (testpath: "/shortcuts/trigger/parse/invalid", test_func: test_trigger_parse_invalid);
453 g_test_add_func (testpath: "/shortcuts/trigger/trigger", test_func: test_trigger_trigger);
454 g_test_add_func (testpath: "/shortcuts/action/basic", test_func: test_action_basic);
455 g_test_add_func (testpath: "/shortcuts/action/activate", test_func: test_action_activate);
456 g_test_add_func (testpath: "/shortcuts/action/parse", test_func: test_action_parse);
457
458 return g_test_run ();
459}
460

source code of gtk/testsuite/gtk/shortcuts.c