1 | #include <gtk/gtk.h> |
2 | |
3 | #define GTK_COMPILATION |
4 | #include "gdk/gdkeventsprivate.h" |
5 | |
6 | static GdkEvent * |
7 | key_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 | |
35 | static void |
36 | test_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 | |
52 | static void |
53 | test_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 | |
108 | static void |
109 | test_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 | |
119 | static void |
120 | test_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 | |
154 | static void |
155 | test_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 | |
180 | static void |
181 | test_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 | |
264 | static void |
265 | test_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 | |
286 | static void |
287 | test_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 | |
369 | static gboolean |
370 | callback (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 | |
379 | static void |
380 | test_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 | |
393 | static void |
394 | test_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 | |
415 | static void |
416 | test_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 | |
441 | int |
442 | main (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 | |