2 * crossingevents.c: A test for crossing events
4 * Copyright (C) 2008 Cody Russell
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 of the License, or (at your option) any later version.
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.
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/>.
29 gboolean events_connected;
41 #define SLEEP_DURATION 100
43 void start_events (CrossingTest *test);
44 void stop_events (CrossingTest *test);
47 sleep_timeout_cb (gpointer data)
54 sleep_in_main_loop (double fraction)
56 /* process all pending idles and events */
57 while (g_main_context_pending (NULL))
58 g_main_context_iteration (NULL, FALSE);
59 /* sleeping probably isn't strictly necessary here */
60 gdk_threads_add_timeout_full (G_MAXINT, fraction * SLEEP_DURATION, sleep_timeout_cb, NULL, NULL);
62 /* process any pending idles or events that arrived during sleep */
63 while (g_main_context_pending (NULL))
64 g_main_context_iteration (NULL, FALSE);
68 set_cursor (GtkWidget *widget)
72 gdk_window_get_origin (widget->window, &x, &y);
74 x += widget->allocation.x;
75 y += widget->allocation.y;
76 w = widget->allocation.width;
77 h = widget->allocation.height;
79 gdk_display_warp_pointer (gtk_widget_get_display (widget),
80 gtk_widget_get_screen (widget),
84 sleep_in_main_loop (0.5);
88 on_enter (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
90 CrossingTest *test = (CrossingTest*)user_data;
92 CrossingEventData *evt = g_slice_new0 (CrossingEventData);
94 evt->name = g_strdup (gtk_widget_get_name (widget));
95 evt->synthesized = event->send_event;
96 evt->mode = event->mode;
97 evt->detail = event->detail;
100 test->queue = g_queue_new ();
102 g_queue_push_tail (test->queue, evt);
108 on_leave (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
110 CrossingTest *test = (CrossingTest*)user_data;
112 CrossingEventData *evt = g_slice_new0 (CrossingEventData);
113 evt->entered = FALSE;
114 evt->name = g_strdup (gtk_widget_get_name (widget));
115 evt->synthesized = event->send_event;
116 evt->mode = event->mode;
117 evt->detail = event->detail;
120 test->queue = g_queue_new ();
122 g_queue_push_tail (test->queue, evt);
128 on_check_toggled (GtkWidget *toggle, GtkWidget *button)
130 gtk_widget_set_sensitive (button, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)));
134 sensitivity_setup (CrossingTest *test,
135 gconstpointer user_data)
139 test->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
140 gtk_widget_set_name (test->window, "W");
141 frame = gtk_frame_new ("Crossing Events");
142 test->eventbox = gtk_event_box_new ();
143 gtk_widget_set_name (test->eventbox, "E");
145 GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 10);
146 gtk_container_add (GTK_CONTAINER (test->window), frame);
147 gtk_container_add (GTK_CONTAINER (frame), test->eventbox);
148 gtk_container_add (GTK_CONTAINER (test->eventbox), vbox);
150 test->button = gtk_button_new_with_label ("Click me!");
151 gtk_widget_set_name (test->button, "B");
152 gtk_box_pack_start (GTK_BOX (vbox), test->button, FALSE, TRUE, 0);
154 test->check = gtk_check_button_new_with_label ("Sensitive?");
155 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), TRUE);
156 g_signal_connect (G_OBJECT (test->check),
157 "toggled", G_CALLBACK (on_check_toggled), test->button);
158 gtk_widget_set_name (test->check, "C");
159 gtk_box_pack_start (GTK_BOX (vbox), test->check, FALSE, TRUE, 0);
161 gtk_widget_show_all (test->window);
163 gtk_window_move (GTK_WINDOW (test->window), 0, 0);
165 sleep_in_main_loop (0.5);
169 sensitivity_teardown (CrossingTest *test,
170 gconstpointer user_data)
173 gtk_widget_destroy (test->window);
175 if (test->queue != NULL)
177 g_queue_clear (test->queue);
183 start_events (CrossingTest *test)
185 if (!test->events_connected)
187 g_object_connect (G_OBJECT (test->window),
188 "signal::destroy", gtk_main_quit, NULL,
189 "signal::enter-notify-event", on_enter, test,
190 "signal::leave-notify-event", on_leave, test,
192 g_object_connect (G_OBJECT (test->eventbox),
193 "signal::enter-notify-event", on_enter, test,
194 "signal::leave-notify-event", on_leave, test,
196 g_object_connect (G_OBJECT (test->button),
197 "signal::enter-notify-event", on_enter, test,
198 "signal::leave-notify-event", on_leave, test,
200 g_object_connect (G_OBJECT (test->check),
201 "signal::enter-notify-event", on_enter, test,
202 "signal::leave-notify-event", on_leave, test,
204 test->events_connected = TRUE;
207 sleep_in_main_loop (0.5);
211 stop_events (CrossingTest *test)
213 if (test->events_connected)
215 g_object_disconnect (G_OBJECT (test->window),
216 "any_signal", gtk_main_quit, NULL,
217 "any_signal", on_enter, test,
218 "any_signal", on_leave, test,
220 g_object_disconnect (G_OBJECT (test->eventbox),
221 "any_signal", on_enter, test,
222 "any_signal", on_leave, test,
224 g_object_disconnect (G_OBJECT (test->button),
225 "any_signal", on_enter, test,
226 "any_signal", on_leave, test,
228 g_object_disconnect (G_OBJECT (test->check),
229 "any_signal", G_CALLBACK (on_check_toggled), test->button,
230 "any_signal", on_enter, test,
231 "any_signal", on_leave, test,
233 test->events_connected = FALSE;
238 move_cursor_away (CrossingTest *test)
240 gdk_display_warp_pointer (gtk_widget_get_display (test->window),
241 gtk_widget_get_screen (test->window),
244 sleep_in_main_loop (0.5);
248 check_event (CrossingTest *test,
251 gboolean synthesized,
252 GdkCrossingMode mode,
253 GdkNotifyType detail)
255 CrossingEventData *evt;
257 g_assert (test->queue != NULL);
259 evt = g_queue_pop_head (test->queue);
261 g_assert (evt->entered == entered);
262 g_assert (strcmp (evt->name, name) == 0);
263 g_assert (evt->synthesized == synthesized);
264 g_assert (evt->mode == mode);
266 if (evt->detail != detail)
267 g_print ("%s %s event, detail %d, expected detail %d\n",
268 synthesized ? "synthesized" : "native",
269 entered ? "enter" : "leave",
270 evt->detail, detail);
272 g_assert (evt->detail == detail);
275 /* Verify crossing events when moving into and out of a sensitive widget */
277 cursor_on_sensitive (CrossingTest *test,
278 gconstpointer user_data)
280 move_cursor_away (test);
284 set_cursor (test->button);
291 GDK_NOTIFY_NONLINEAR_VIRTUAL);
298 GDK_NOTIFY_NONLINEAR_VIRTUAL);
305 GDK_NOTIFY_NONLINEAR);
307 g_assert (g_queue_is_empty (test->queue));
309 move_cursor_away (test);
316 GDK_NOTIFY_NONLINEAR);
323 GDK_NOTIFY_NONLINEAR_VIRTUAL);
330 GDK_NOTIFY_NONLINEAR_VIRTUAL);
332 g_assert (g_queue_is_empty (test->queue));
338 change_sensitive_to_insensitive (CrossingTest *test,
339 gconstpointer user_data)
341 move_cursor_away (test);
342 set_cursor (test->button);
346 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
351 TRUE, /* synthesized */
352 GDK_CROSSING_STATE_CHANGED,
353 GDK_NOTIFY_ANCESTOR);
358 TRUE, /* synthesized */
359 GDK_CROSSING_STATE_CHANGED,
365 TRUE, /* synthesized */
366 GDK_CROSSING_STATE_CHANGED,
369 g_assert (g_queue_is_empty (test->queue));
375 change_insensitive_to_sensitive (CrossingTest *test,
376 gconstpointer user_data)
378 move_cursor_away (test);
379 set_cursor (test->button);
380 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
384 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), TRUE);
389 TRUE, /* synthesized */
390 GDK_CROSSING_STATE_CHANGED,
396 TRUE, /* synthesized */
397 GDK_CROSSING_STATE_CHANGED,
403 TRUE, /* synthesized */
404 GDK_CROSSING_STATE_CHANGED,
405 GDK_NOTIFY_ANCESTOR);
407 g_assert (g_queue_is_empty (test->queue));
413 cursor_from_insensitive_to_sensitive (CrossingTest *test,
414 gconstpointer user_data)
416 set_cursor (test->button);
417 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
421 set_cursor (test->check);
428 GDK_NOTIFY_NONLINEAR);
430 g_assert (g_queue_is_empty (test->queue));
436 cursor_from_sensitive_to_insensitive (CrossingTest *test,
437 gconstpointer user_data)
439 set_cursor (test->check);
440 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
444 set_cursor (test->button);
451 GDK_NOTIFY_NONLINEAR);
453 g_assert (g_queue_is_empty (test->queue));
459 add_gtk_grab (CrossingTest *test,
460 gconstpointer user_data)
462 set_cursor (test->button);
466 gtk_grab_add (test->check);
471 TRUE, /* synthesized */
472 GDK_CROSSING_GTK_GRAB,
473 GDK_NOTIFY_ANCESTOR);
478 TRUE, /* synthesized */
479 GDK_CROSSING_GTK_GRAB,
480 GDK_NOTIFY_ANCESTOR);
485 TRUE, /* synthesized */
486 GDK_CROSSING_GTK_GRAB,
487 GDK_NOTIFY_ANCESTOR);
489 g_assert (g_queue_is_empty (test->queue));
495 remove_gtk_grab (CrossingTest *test,
496 gconstpointer user_data)
498 set_cursor (test->button);
500 gtk_grab_add (test->check);
504 gtk_grab_remove (test->check);
509 TRUE, /* synthesized */
510 GDK_CROSSING_GTK_UNGRAB,
511 GDK_NOTIFY_ANCESTOR);
516 TRUE, /* synthesized */
517 GDK_CROSSING_GTK_UNGRAB,
518 GDK_NOTIFY_ANCESTOR);
523 TRUE, /* synthesized */
524 GDK_CROSSING_GTK_UNGRAB,
525 GDK_NOTIFY_ANCESTOR);
527 g_assert (g_queue_is_empty (test->queue));
533 cursor_from_shadowed_to_unshadowed (CrossingTest *test,
534 gconstpointer user_data)
536 set_cursor (test->button);
538 gtk_grab_add (test->check);
542 set_cursor (test->check);
549 GDK_NOTIFY_NONLINEAR);
556 GDK_NOTIFY_NONLINEAR);
558 g_assert (g_queue_is_empty (test->queue));
564 cursor_from_unshadowed_to_shadowed (CrossingTest *test,
565 gconstpointer user_data)
567 set_cursor (test->check);
569 gtk_grab_add (test->check);
573 set_cursor (test->button);
580 GDK_NOTIFY_NONLINEAR);
587 GDK_NOTIFY_NONLINEAR);
589 g_assert (g_queue_is_empty (test->queue));
598 gtk_test_init (&argc, &argv, NULL);
600 g_test_add ("/crossings/cursor-on-sensitive", CrossingTest, NULL,
601 sensitivity_setup, cursor_on_sensitive, sensitivity_teardown);
603 g_test_add ("/crossings/change-sensitive-to-insensitive", CrossingTest, NULL,
604 sensitivity_setup, change_sensitive_to_insensitive, sensitivity_teardown);
606 g_test_add ("/crossings/cursor-from-insensitive-to-sensitive", CrossingTest, NULL,
607 sensitivity_setup, cursor_from_insensitive_to_sensitive, sensitivity_teardown);
609 g_test_add ("/crossings/cursor-from-sensitive-to-insensitive", CrossingTest, NULL,
610 sensitivity_setup, cursor_from_sensitive_to_insensitive, sensitivity_teardown);
612 g_test_add ("/crossings/change-insensitive-to-sensitive", CrossingTest, NULL,
613 sensitivity_setup, change_insensitive_to_sensitive, sensitivity_teardown);
615 g_test_add ("/crossings/add-gtk-grab", CrossingTest, NULL,
616 sensitivity_setup, add_gtk_grab, sensitivity_teardown);
618 g_test_add ("/crossings/remove-gtk-grab", CrossingTest, NULL,
619 sensitivity_setup, remove_gtk_grab, sensitivity_teardown);
621 g_test_add ("/crossings/cursor-from-shadowed-to-unshadowed", CrossingTest, NULL,
622 sensitivity_setup, cursor_from_shadowed_to_unshadowed, sensitivity_teardown);
624 g_test_add ("/crossings/cursor-from-unshadowed-to-shadowed", CrossingTest, NULL,
625 sensitivity_setup, cursor_from_unshadowed_to_shadowed, sensitivity_teardown);
627 return g_test_run ();