1 #include <config.h>
2 #include <string.h>
3 #include <gtk/gtk.h>
4 #include <goocanvas.h>
5 
6 
7 static gboolean
on_widget_draw(GtkWidget * widget,cairo_t * cr,char * item_id)8 on_widget_draw (GtkWidget *widget,
9 		  cairo_t *cr,
10 		  char *item_id)
11 {
12   GtkAllocation allocation;
13 
14   g_print ("%s received 'draw' signal\n", item_id);
15 
16   gtk_widget_get_allocation (widget, &allocation);
17 
18   cairo_rectangle (cr, 0, 0,
19 		   allocation.width, allocation.height);
20   cairo_stroke (cr);
21 
22   return FALSE;
23 }
24 
25 
26 static gboolean
on_widget_enter_notify(GtkWidget * widget,GdkEventCrossing * event,char * item_id)27 on_widget_enter_notify (GtkWidget *widget,
28 			GdkEventCrossing *event,
29 			char *item_id)
30 {
31   g_print ("%s received 'enter-notify' signal\n", item_id);
32   return TRUE;
33 }
34 
35 
36 static gboolean
on_widget_leave_notify(GtkWidget * widget,GdkEventCrossing * event,char * item_id)37 on_widget_leave_notify (GtkWidget *widget,
38 			GdkEventCrossing *event,
39 			char *item_id)
40 {
41   g_print ("%s received 'leave-notify' signal\n", item_id);
42   return TRUE;
43 }
44 
45 
46 static gboolean
on_widget_motion_notify(GtkWidget * widget,GdkEventMotion * event,char * item_id)47 on_widget_motion_notify (GtkWidget *widget,
48 			 GdkEventMotion *event,
49 			 char *item_id)
50 {
51   GdkDevice *device = gdk_event_get_device ((GdkEvent*) event);
52 
53   g_print ("%s received 'motion-notify' signal (window: %p)\n", item_id,
54 	   event->window);
55 
56   if (event->is_hint && device)
57     gdk_window_get_device_position (event->window, device, NULL, NULL, NULL);
58 
59   return TRUE;
60 }
61 
62 
63 static gboolean
on_widget_button_press(GtkWidget * widget,GdkEventButton * event,char * item_id)64 on_widget_button_press (GtkWidget *widget,
65 			GdkEventButton *event,
66 			char *item_id)
67 {
68   GdkDevice *device = gdk_event_get_device ((GdkEvent*) event);
69 
70   g_print ("%s received 'button-press' signal\n", item_id);
71 
72   if (device && strstr (item_id, "explicit"))
73     {
74       GdkGrabStatus status;
75 
76 #if GTK_CHECK_VERSION(3,20,0)
77       status = gdk_seat_grab (gdk_device_get_seat (device),
78 			      gtk_widget_get_window (widget),
79 			      GDK_SEAT_CAPABILITY_ALL_POINTING,
80 			      FALSE, NULL, (GdkEvent*) event, NULL, NULL);
81 #else
82       GdkEventMask mask = GDK_BUTTON_PRESS_MASK
83 	| GDK_BUTTON_RELEASE_MASK
84 	| GDK_POINTER_MOTION_MASK
85 	| GDK_POINTER_MOTION_HINT_MASK
86 	| GDK_ENTER_NOTIFY_MASK
87 	| GDK_LEAVE_NOTIFY_MASK;
88 
89       status = gdk_device_grab (device, gtk_widget_get_window (widget),
90 				GDK_OWNERSHIP_NONE, FALSE, mask,
91 				NULL, event->time);
92 #endif
93 
94       if (status == GDK_GRAB_SUCCESS)
95 	g_print ("grabbed pointer\n");
96       else
97 	g_print ("pointer grab failed\n");
98     }
99 
100   return TRUE;
101 }
102 
103 
104 static gboolean
on_widget_button_release(GtkWidget * widget,GdkEventButton * event,char * item_id)105 on_widget_button_release (GtkWidget *widget,
106 			  GdkEventButton *event,
107 			  char *item_id)
108 {
109   GdkDevice *device = gdk_event_get_device ((GdkEvent*) event);
110 
111   g_print ("%s received 'button-release' signal\n", item_id);
112 
113   if (device && strstr (item_id, "explicit"))
114     {
115 #if GTK_CHECK_VERSION(3,20,0)
116       gdk_seat_ungrab (gdk_device_get_seat (device));
117 #else
118       gdk_device_ungrab (device, event->time);
119 #endif
120       g_print ("released pointer grab\n");
121     }
122 
123   return TRUE;
124 }
125 
126 
127 
128 
129 static gboolean
on_enter_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEventCrossing * event,gpointer data)130 on_enter_notify (GooCanvasItem *item,
131 		 GooCanvasItem *target,
132 		 GdkEventCrossing *event,
133 		 gpointer data)
134 {
135   GooCanvasItemModel *model = goo_canvas_item_get_model (target);
136   char *item_id = g_object_get_data (G_OBJECT (model), "id");
137 
138   g_print ("%s received 'enter-notify' signal\n", item_id);
139   return FALSE;
140 }
141 
142 
143 static gboolean
on_leave_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEventCrossing * event,gpointer data)144 on_leave_notify (GooCanvasItem *item,
145 		 GooCanvasItem *target,
146 		 GdkEventCrossing *event,
147 		 gpointer data)
148 {
149   GooCanvasItemModel *model = goo_canvas_item_get_model (target);
150   char *item_id = g_object_get_data (G_OBJECT (model), "id");
151 
152   g_print ("%s received 'leave-notify' signal\n", item_id);
153   return FALSE;
154 }
155 
156 
157 static gboolean
on_motion_notify(GooCanvasItem * item,GooCanvasItem * target,GdkEventMotion * event,gpointer data)158 on_motion_notify (GooCanvasItem *item,
159 		  GooCanvasItem *target,
160 		  GdkEventMotion *event,
161 		  gpointer data)
162 {
163   GooCanvasItemModel *model = goo_canvas_item_get_model (target);
164   char *item_id = g_object_get_data (G_OBJECT (model), "id");
165 
166   g_print ("%s received 'motion-notify' signal\n", item_id);
167   return FALSE;
168 }
169 
170 
171 static gboolean
on_button_press(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)172 on_button_press (GooCanvasItem *item,
173 		 GooCanvasItem *target,
174 		 GdkEventButton *event,
175 		 gpointer data)
176 {
177   GooCanvasItemModel *model = goo_canvas_item_get_model (target);
178   char *item_id = g_object_get_data (G_OBJECT (model), "id");
179 
180   g_print ("%s received 'button-press' signal\n", item_id);
181 
182   if (strstr (item_id, "explicit"))
183     {
184       GooCanvas *canvas;
185       GdkGrabStatus status;
186       GdkEventMask mask = GDK_BUTTON_PRESS_MASK
187 	| GDK_BUTTON_RELEASE_MASK
188 	| GDK_POINTER_MOTION_MASK
189 	| GDK_POINTER_MOTION_HINT_MASK
190 	| GDK_ENTER_NOTIFY_MASK
191 	| GDK_LEAVE_NOTIFY_MASK;
192 
193       canvas = goo_canvas_item_get_canvas (item);
194       status = goo_canvas_pointer_grab (canvas, item, mask, NULL, event->time);
195       if (status == GDK_GRAB_SUCCESS)
196 	g_print ("grabbed pointer\n");
197       else
198 	g_print ("pointer grab failed\n");
199     }
200 
201   return FALSE;
202 }
203 
204 
205 static gboolean
on_button_release(GooCanvasItem * item,GooCanvasItem * target,GdkEventButton * event,gpointer data)206 on_button_release (GooCanvasItem *item,
207 		   GooCanvasItem *target,
208 		   GdkEventButton *event,
209 		   gpointer data)
210 {
211   GooCanvasItemModel *model = goo_canvas_item_get_model (target);
212   char *item_id = g_object_get_data (G_OBJECT (model), "id");
213 
214   g_print ("%s received 'button-release' signal\n", item_id);
215 
216   if (strstr (item_id, "explicit"))
217     {
218       GooCanvas *canvas;
219 
220       canvas = goo_canvas_item_get_canvas (item);
221       goo_canvas_pointer_ungrab (canvas, item, event->time);
222       g_print ("released pointer grab\n");
223     }
224 
225   return FALSE;
226 }
227 
228 
229 static void
create_fixed(GtkGrid * grid,gint row,gchar * text,gchar * id)230 create_fixed (GtkGrid *grid, gint row, gchar *text, gchar *id)
231 {
232   GtkWidget *label, *fixed, *drawing_area;
233   char *view_id;
234 
235   label = gtk_label_new (text);
236   gtk_grid_attach (grid, label, 0, row, 1, 1);
237   gtk_widget_show (label);
238 
239   fixed = gtk_fixed_new ();
240   gtk_widget_set_has_window (fixed, TRUE);
241   gtk_widget_set_events (fixed,
242 			 GDK_EXPOSURE_MASK
243 			 | GDK_BUTTON_PRESS_MASK
244 			 | GDK_BUTTON_RELEASE_MASK
245 			 | GDK_POINTER_MOTION_MASK
246 			 | GDK_POINTER_MOTION_HINT_MASK
247 			 | GDK_KEY_PRESS_MASK
248 			 | GDK_KEY_RELEASE_MASK
249 			 | GDK_ENTER_NOTIFY_MASK
250 			 | GDK_LEAVE_NOTIFY_MASK
251 			 | GDK_FOCUS_CHANGE_MASK);
252   gtk_widget_set_size_request (fixed, 200, 100);
253   gtk_grid_attach (GTK_GRID (grid), fixed, 1, row, 1, 1);
254   gtk_widget_show (fixed);
255 
256   view_id = g_strdup_printf ("%s-background", id);
257   g_signal_connect (fixed, "draw",
258 		    G_CALLBACK (on_widget_draw), view_id);
259 
260   g_signal_connect (fixed, "enter_notify_event",
261 		    G_CALLBACK (on_widget_enter_notify), view_id);
262   g_signal_connect (fixed, "leave_notify_event",
263 		    G_CALLBACK (on_widget_leave_notify), view_id);
264   g_signal_connect (fixed, "motion_notify_event",
265 		    G_CALLBACK (on_widget_motion_notify), view_id);
266   g_signal_connect (fixed, "button_press_event",
267 		    G_CALLBACK (on_widget_button_press), view_id);
268   g_signal_connect (fixed, "button_release_event",
269 		    G_CALLBACK (on_widget_button_release), view_id);
270 
271 
272   drawing_area = gtk_drawing_area_new ();
273   gtk_widget_set_events (drawing_area,
274 			 GDK_EXPOSURE_MASK
275 			 | GDK_BUTTON_PRESS_MASK
276 			 | GDK_BUTTON_RELEASE_MASK
277 			 | GDK_POINTER_MOTION_MASK
278 			 | GDK_POINTER_MOTION_HINT_MASK
279 			 | GDK_KEY_PRESS_MASK
280 			 | GDK_KEY_RELEASE_MASK
281 			 | GDK_ENTER_NOTIFY_MASK
282 			 | GDK_LEAVE_NOTIFY_MASK
283 			 | GDK_FOCUS_CHANGE_MASK);
284 
285   gtk_widget_set_size_request (drawing_area, 60, 60);
286   gtk_fixed_put (GTK_FIXED (fixed), drawing_area, 20, 20);
287   gtk_widget_show (drawing_area);
288 
289   view_id = g_strdup_printf ("%s-left", id);
290   g_signal_connect (drawing_area, "draw",
291 		    G_CALLBACK (on_widget_draw), view_id);
292 
293   g_signal_connect (drawing_area, "enter_notify_event",
294 		    G_CALLBACK (on_widget_enter_notify), view_id);
295   g_signal_connect (drawing_area, "leave_notify_event",
296 		    G_CALLBACK (on_widget_leave_notify), view_id);
297   g_signal_connect (drawing_area, "motion_notify_event",
298 		    G_CALLBACK (on_widget_motion_notify), view_id);
299   g_signal_connect (drawing_area, "button_press_event",
300 		    G_CALLBACK (on_widget_button_press), view_id);
301   g_signal_connect (drawing_area, "button_release_event",
302 		    G_CALLBACK (on_widget_button_release), view_id);
303 
304 
305   drawing_area = gtk_drawing_area_new ();
306   gtk_widget_set_events (drawing_area,
307 			 GDK_EXPOSURE_MASK
308 			 | GDK_BUTTON_PRESS_MASK
309 			 | GDK_BUTTON_RELEASE_MASK
310 			 | GDK_POINTER_MOTION_MASK
311 			 | GDK_POINTER_MOTION_HINT_MASK
312 			 | GDK_KEY_PRESS_MASK
313 			 | GDK_KEY_RELEASE_MASK
314 			 | GDK_ENTER_NOTIFY_MASK
315 			 | GDK_LEAVE_NOTIFY_MASK
316 			 | GDK_FOCUS_CHANGE_MASK);
317 
318   gtk_widget_set_size_request (drawing_area, 60, 60);
319   gtk_fixed_put (GTK_FIXED (fixed), drawing_area, 120, 20);
320   gtk_widget_show (drawing_area);
321 
322   view_id = g_strdup_printf ("%s-right", id);
323   g_signal_connect (drawing_area, "draw",
324 		    G_CALLBACK (on_widget_draw), view_id);
325 
326   g_signal_connect (drawing_area, "enter_notify_event",
327 		    G_CALLBACK (on_widget_enter_notify), view_id);
328   g_signal_connect (drawing_area, "leave_notify_event",
329 		    G_CALLBACK (on_widget_leave_notify), view_id);
330   g_signal_connect (drawing_area, "motion_notify_event",
331 		    G_CALLBACK (on_widget_motion_notify), view_id);
332   g_signal_connect (drawing_area, "button_press_event",
333 		    G_CALLBACK (on_widget_button_press), view_id);
334   g_signal_connect (drawing_area, "button_release_event",
335 		    G_CALLBACK (on_widget_button_release), view_id);
336 }
337 
338 
339 static void
on_item_created(GooCanvas * canvas,GooCanvasItem * item,GooCanvasItemModel * model,gpointer data)340 on_item_created (GooCanvas          *canvas,
341 		 GooCanvasItem      *item,
342 		 GooCanvasItemModel *model,
343 		 gpointer            data)
344 {
345   if (GOO_IS_CANVAS_RECT (model))
346     {
347       g_signal_connect (item, "enter_notify_event",
348 			G_CALLBACK (on_enter_notify), NULL);
349       g_signal_connect (item, "leave_notify_event",
350 			G_CALLBACK (on_leave_notify), NULL);
351       g_signal_connect (item, "motion_notify_event",
352 			G_CALLBACK (on_motion_notify), NULL);
353       g_signal_connect (item, "button_press_event",
354 			G_CALLBACK (on_button_press), NULL);
355       g_signal_connect (item, "button_release_event",
356 			G_CALLBACK (on_button_release), NULL);
357     }
358 }
359 
360 
361 static void
create_canvas(GtkGrid * grid,gint row,gchar * text,gchar * id)362 create_canvas (GtkGrid *grid, gint row, gchar *text, gchar *id)
363 {
364   GtkWidget *label, *canvas;
365   GooCanvasItemModel *root, *rect;
366   char *view_id;
367 
368   label = gtk_label_new (text);
369   gtk_grid_attach (grid, label, 0, row, 1, 1);
370   gtk_widget_show (label);
371 
372   canvas = goo_canvas_new ();
373 
374   g_signal_connect (canvas, "item_created",
375 		    G_CALLBACK (on_item_created), NULL);
376 
377   gtk_widget_set_size_request (canvas, 200, 100);
378   goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 200, 100);
379   gtk_grid_attach (grid, canvas, 1, row, 1, 1);
380   gtk_widget_show (canvas);
381 
382   root = goo_canvas_group_model_new (NULL, NULL);
383   goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
384   g_object_unref (root);
385 
386   rect = goo_canvas_rect_model_new (root, 0, 0, 200, 100,
387 				    "stroke-pattern", NULL,
388 				    "fill-color", "yellow",
389 				    NULL);
390   view_id = g_strdup_printf ("%s-yellow", id);
391   g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);
392 
393   rect = goo_canvas_rect_model_new (root, 20, 20, 60, 60,
394 				    "stroke-pattern", NULL,
395 				    "fill-color", "blue",
396 				    NULL);
397   view_id = g_strdup_printf ("%s-blue", id);
398   g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);
399 
400   rect = goo_canvas_rect_model_new (root, 120, 20, 60, 60,
401 				    "stroke-pattern", NULL,
402 				    "fill-color", "red",
403 				    NULL);
404   view_id = g_strdup_printf ("%s-red", id);
405   g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);
406 }
407 
408 
409 GtkWidget *
create_grabs_page(void)410 create_grabs_page (void)
411 {
412   GtkWidget *vbox, *grid, *label;
413 
414   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
415   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
416   gtk_widget_show (vbox);
417 
418   label = gtk_label_new ("Move the mouse over the widgets and canvas items on the right to see what events they receive.\nClick buttons to start explicit or implicit pointer grabs and see what events they receive now.\n(They should all receive the same events.)");
419   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
420   gtk_widget_show (label);
421 
422   grid = gtk_grid_new ();
423   gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
424   gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
425   gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
426   gtk_box_pack_start (GTK_BOX (vbox), grid, FALSE, FALSE, 0);
427   g_object_set (grid, "halign", GTK_ALIGN_CENTER, NULL);
428   gtk_widget_show (grid);
429 
430   /* Drawing area with explicit grabs. */
431   create_fixed (GTK_GRID (grid), 1,
432 		"Widget with Explicit Grabs:",
433 		"widget-explicit");
434 
435   /* Drawing area with implicit grabs. */
436   create_fixed (GTK_GRID (grid), 2,
437 		"Widget with Implicit Grabs:",
438 		"widget-implicit");
439 
440   /* Canvas with explicit grabs. */
441   create_canvas (GTK_GRID (grid), 3,
442 		 "Canvas with Explicit Grabs:",
443 		 "canvas-explicit");
444 
445   /* Canvas with implicit grabs. */
446   create_canvas (GTK_GRID (grid), 4,
447 		 "Canvas with Implicit Grabs:",
448 		 "canvas-implicit");
449 
450   return vbox;
451 }
452