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