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, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
31 gboolean events_connected;
43 #define SLEEP_DURATION 100
45 void start_events (CrossingTest *test);
46 void stop_events (CrossingTest *test);
49 sleep_timeout_cb (gpointer data)
56 sleep_in_main_loop (double fraction)
58 /* process all pending idles and events */
59 while (g_main_context_pending (NULL))
60 g_main_context_iteration (NULL, FALSE);
61 /* sleeping probably isn't strictly necessary here */
62 gdk_threads_add_timeout_full (G_MAXINT, fraction * SLEEP_DURATION, sleep_timeout_cb, NULL, NULL);
64 /* process any pending idles or events that arrived during sleep */
65 while (g_main_context_pending (NULL))
66 g_main_context_iteration (NULL, FALSE);
70 set_cursor (GtkWidget *widget)
74 gdk_window_get_origin (widget->window, &x, &y);
76 x += widget->allocation.x;
77 y += widget->allocation.y;
78 w = widget->allocation.width;
79 h = widget->allocation.height;
81 gdk_display_warp_pointer (gtk_widget_get_display (widget),
82 gtk_widget_get_screen (widget),
86 sleep_in_main_loop (0.5);
90 on_enter (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
92 CrossingTest *test = (CrossingTest*)user_data;
94 CrossingEventData *evt = g_slice_new0 (CrossingEventData);
96 evt->name = g_strdup (gtk_widget_get_name (widget));
97 evt->synthesized = event->send_event;
98 evt->mode = event->mode;
99 evt->detail = event->detail;
102 test->queue = g_queue_new ();
104 g_queue_push_tail (test->queue, evt);
110 on_leave (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
112 CrossingTest *test = (CrossingTest*)user_data;
114 CrossingEventData *evt = g_slice_new0 (CrossingEventData);
115 evt->entered = FALSE;
116 evt->name = g_strdup (gtk_widget_get_name (widget));
117 evt->synthesized = event->send_event;
118 evt->mode = event->mode;
119 evt->detail = event->detail;
122 test->queue = g_queue_new ();
124 g_queue_push_tail (test->queue, evt);
130 on_check_toggled (GtkWidget *toggle, GtkWidget *button)
132 gtk_widget_set_sensitive (button, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)));
136 sensitivity_setup (CrossingTest *test,
137 gconstpointer user_data)
141 test->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
142 gtk_widget_set_name (test->window, "W");
143 frame = gtk_frame_new ("Crossing Events");
144 test->eventbox = gtk_event_box_new ();
145 gtk_widget_set_name (test->eventbox, "E");
147 GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 10);
148 gtk_container_add (GTK_CONTAINER (test->window), frame);
149 gtk_container_add (GTK_CONTAINER (frame), test->eventbox);
150 gtk_container_add (GTK_CONTAINER (test->eventbox), vbox);
152 test->button = gtk_button_new_with_label ("Click me!");
153 gtk_widget_set_name (test->button, "B");
154 gtk_box_pack_start (GTK_BOX (vbox), test->button, FALSE, TRUE, 0);
156 test->check = gtk_check_button_new_with_label ("Sensitive?");
157 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), TRUE);
158 g_signal_connect (G_OBJECT (test->check),
159 "toggled", G_CALLBACK (on_check_toggled), test->button);
160 gtk_widget_set_name (test->check, "C");
161 gtk_box_pack_start (GTK_BOX (vbox), test->check, FALSE, TRUE, 0);
163 gtk_widget_show_all (test->window);
165 gtk_window_move (GTK_WINDOW (test->window), 0, 0);
167 sleep_in_main_loop (0.5);
171 sensitivity_teardown (CrossingTest *test,
172 gconstpointer user_data)
175 gtk_widget_destroy (test->window);
177 if (test->queue != NULL)
179 g_queue_clear (test->queue);
185 start_events (CrossingTest *test)
187 if (!test->events_connected)
189 g_object_connect (G_OBJECT (test->window),
190 "signal::destroy", gtk_main_quit, NULL,
191 "signal::enter-notify-event", on_enter, test,
192 "signal::leave-notify-event", on_leave, test,
194 g_object_connect (G_OBJECT (test->eventbox),
195 "signal::enter-notify-event", on_enter, test,
196 "signal::leave-notify-event", on_leave, test,
198 g_object_connect (G_OBJECT (test->button),
199 "signal::enter-notify-event", on_enter, test,
200 "signal::leave-notify-event", on_leave, test,
202 g_object_connect (G_OBJECT (test->check),
203 "signal::enter-notify-event", on_enter, test,
204 "signal::leave-notify-event", on_leave, test,
206 test->events_connected = TRUE;
209 sleep_in_main_loop (0.5);
213 stop_events (CrossingTest *test)
215 if (test->events_connected)
217 g_object_disconnect (G_OBJECT (test->window),
218 "any_signal", gtk_main_quit, NULL,
219 "any_signal", on_enter, test,
220 "any_signal", on_leave, test,
222 g_object_disconnect (G_OBJECT (test->eventbox),
223 "any_signal", on_enter, test,
224 "any_signal", on_leave, test,
226 g_object_disconnect (G_OBJECT (test->button),
227 "any_signal", on_enter, test,
228 "any_signal", on_leave, test,
230 g_object_disconnect (G_OBJECT (test->check),
231 "any_signal", G_CALLBACK (on_check_toggled), test->button,
232 "any_signal", on_enter, test,
233 "any_signal", on_leave, test,
235 test->events_connected = FALSE;
240 move_cursor_away (CrossingTest *test)
242 gdk_display_warp_pointer (gtk_widget_get_display (test->window),
243 gtk_widget_get_screen (test->window),
246 sleep_in_main_loop (0.5);
250 check_event (CrossingTest *test,
253 gboolean synthesized,
254 GdkCrossingMode mode,
255 GdkNotifyType detail)
257 CrossingEventData *evt;
259 g_assert (test->queue != NULL);
261 evt = g_queue_pop_head (test->queue);
263 g_assert (evt->entered == entered);
264 g_assert (strcmp (evt->name, name) == 0);
265 g_assert (evt->synthesized == synthesized);
266 g_assert (evt->mode == mode);
268 if (evt->detail != detail)
269 g_print ("%s %s event, detail %d, expected detail %d\n",
270 synthesized ? "synthesized" : "native",
271 entered ? "enter" : "leave",
272 evt->detail, detail);
274 g_assert (evt->detail == detail);
277 /* Verify crossing events when moving into and out of a sensitive widget */
279 cursor_on_sensitive (CrossingTest *test,
280 gconstpointer user_data)
282 move_cursor_away (test);
286 set_cursor (test->button);
293 GDK_NOTIFY_NONLINEAR_VIRTUAL);
300 GDK_NOTIFY_NONLINEAR_VIRTUAL);
307 GDK_NOTIFY_NONLINEAR);
309 g_assert (g_queue_is_empty (test->queue));
311 move_cursor_away (test);
318 GDK_NOTIFY_NONLINEAR);
325 GDK_NOTIFY_NONLINEAR_VIRTUAL);
332 GDK_NOTIFY_NONLINEAR_VIRTUAL);
334 g_assert (g_queue_is_empty (test->queue));
340 change_sensitive_to_insensitive (CrossingTest *test,
341 gconstpointer user_data)
343 move_cursor_away (test);
344 set_cursor (test->button);
348 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
353 TRUE, /* synthesized */
354 GDK_CROSSING_STATE_CHANGED,
355 GDK_NOTIFY_ANCESTOR);
360 TRUE, /* synthesized */
361 GDK_CROSSING_STATE_CHANGED,
367 TRUE, /* synthesized */
368 GDK_CROSSING_STATE_CHANGED,
371 g_assert (g_queue_is_empty (test->queue));
377 change_insensitive_to_sensitive (CrossingTest *test,
378 gconstpointer user_data)
380 move_cursor_away (test);
381 set_cursor (test->button);
382 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
386 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), TRUE);
391 TRUE, /* synthesized */
392 GDK_CROSSING_STATE_CHANGED,
398 TRUE, /* synthesized */
399 GDK_CROSSING_STATE_CHANGED,
405 TRUE, /* synthesized */
406 GDK_CROSSING_STATE_CHANGED,
407 GDK_NOTIFY_ANCESTOR);
409 g_assert (g_queue_is_empty (test->queue));
415 cursor_from_insensitive_to_sensitive (CrossingTest *test,
416 gconstpointer user_data)
418 set_cursor (test->button);
419 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
423 set_cursor (test->check);
430 GDK_NOTIFY_NONLINEAR);
432 g_assert (g_queue_is_empty (test->queue));
438 cursor_from_sensitive_to_insensitive (CrossingTest *test,
439 gconstpointer user_data)
441 set_cursor (test->check);
442 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (test->check), FALSE);
446 set_cursor (test->button);
453 GDK_NOTIFY_NONLINEAR);
455 g_assert (g_queue_is_empty (test->queue));
461 add_gtk_grab (CrossingTest *test,
462 gconstpointer user_data)
464 set_cursor (test->button);
468 gtk_grab_add (test->check);
473 TRUE, /* synthesized */
474 GDK_CROSSING_GTK_GRAB,
475 GDK_NOTIFY_ANCESTOR);
480 TRUE, /* synthesized */
481 GDK_CROSSING_GTK_GRAB,
482 GDK_NOTIFY_ANCESTOR);
487 TRUE, /* synthesized */
488 GDK_CROSSING_GTK_GRAB,
489 GDK_NOTIFY_ANCESTOR);
491 g_assert (g_queue_is_empty (test->queue));
497 remove_gtk_grab (CrossingTest *test,
498 gconstpointer user_data)
500 set_cursor (test->button);
502 gtk_grab_add (test->check);
506 gtk_grab_remove (test->check);
511 TRUE, /* synthesized */
512 GDK_CROSSING_GTK_UNGRAB,
513 GDK_NOTIFY_ANCESTOR);
518 TRUE, /* synthesized */
519 GDK_CROSSING_GTK_UNGRAB,
520 GDK_NOTIFY_ANCESTOR);
525 TRUE, /* synthesized */
526 GDK_CROSSING_GTK_UNGRAB,
527 GDK_NOTIFY_ANCESTOR);
529 g_assert (g_queue_is_empty (test->queue));
535 cursor_from_shadowed_to_unshadowed (CrossingTest *test,
536 gconstpointer user_data)
538 set_cursor (test->button);
540 gtk_grab_add (test->check);
544 set_cursor (test->check);
551 GDK_NOTIFY_NONLINEAR);
558 GDK_NOTIFY_NONLINEAR);
560 g_assert (g_queue_is_empty (test->queue));
566 cursor_from_unshadowed_to_shadowed (CrossingTest *test,
567 gconstpointer user_data)
569 set_cursor (test->check);
571 gtk_grab_add (test->check);
575 set_cursor (test->button);
582 GDK_NOTIFY_NONLINEAR);
589 GDK_NOTIFY_NONLINEAR);
591 g_assert (g_queue_is_empty (test->queue));
600 gtk_test_init (&argc, &argv, NULL);
602 g_test_add ("/crossings/cursor-on-sensitive", CrossingTest, NULL,
603 sensitivity_setup, cursor_on_sensitive, sensitivity_teardown);
605 g_test_add ("/crossings/change-sensitive-to-insensitive", CrossingTest, NULL,
606 sensitivity_setup, change_sensitive_to_insensitive, sensitivity_teardown);
608 g_test_add ("/crossings/cursor-from-insensitive-to-sensitive", CrossingTest, NULL,
609 sensitivity_setup, cursor_from_insensitive_to_sensitive, sensitivity_teardown);
611 g_test_add ("/crossings/cursor-from-sensitive-to-insensitive", CrossingTest, NULL,
612 sensitivity_setup, cursor_from_sensitive_to_insensitive, sensitivity_teardown);
614 g_test_add ("/crossings/change-insensitive-to-sensitive", CrossingTest, NULL,
615 sensitivity_setup, change_insensitive_to_sensitive, sensitivity_teardown);
617 g_test_add ("/crossings/add-gtk-grab", CrossingTest, NULL,
618 sensitivity_setup, add_gtk_grab, sensitivity_teardown);
620 g_test_add ("/crossings/remove-gtk-grab", CrossingTest, NULL,
621 sensitivity_setup, remove_gtk_grab, sensitivity_teardown);
623 g_test_add ("/crossings/cursor-from-shadowed-to-unshadowed", CrossingTest, NULL,
624 sensitivity_setup, cursor_from_shadowed_to_unshadowed, sensitivity_teardown);
626 g_test_add ("/crossings/cursor-from-unshadowed-to-shadowed", CrossingTest, NULL,
627 sensitivity_setup, cursor_from_unshadowed_to_shadowed, sensitivity_teardown);
629 return g_test_run ();