]> Pileus Git - ~andy/gtk/blob - gdk/wayland/gdkdisplay-wayland.c
wayland: Support setting cursors
[~andy/gtk] / gdk / wayland / gdkdisplay-wayland.c
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <wayland-egl.h>
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29
30 #include <glib.h>
31 #include "gdkwayland.h"
32 #include "gdkdisplay.h"
33 #include "gdkdisplay-wayland.h"
34 #include "gdkscreen.h"
35 #include "gdkscreen-wayland.h"
36 #include "gdkinternals.h"
37 #include "gdkdeviceprivate.h"
38 #include "gdkdevicemanager.h"
39 #include "gdkdevicemanager-wayland.h"
40 #include "gdkkeysprivate.h"
41
42 typedef struct _GdkEventTypeWayland GdkEventTypeWayland;
43
44 struct _GdkEventTypeWayland
45 {
46   gint base;
47   gint n_events;
48 };
49
50 G_DEFINE_TYPE (GdkDisplayWayland, _gdk_display_wayland, GDK_TYPE_DISPLAY)
51
52 /* GDK_VISIBILITY,
53  * GDK_MAP,
54  * GDK_UNMAP,
55  * GDK_PROPERTY_NOTIFY
56  * GDK_SELECTION_CLEAR
57  * GDK_SELECTION_ REQUEST
58  * GDK_SELECTION_NOTIFY
59  * GDK_CLIENT_EVENT,
60  *
61  * new keyboard mapping: _gdk_keymap_keys_changed (display);
62  *
63  * Selection owner change: GDK_OWNER_CHANGE;
64  *
65  * Screen size changes: _gdk_wayland_screen_size_changed (screen, xevent);
66  *
67  * XkbStateNotify: _gdk_keymap_state_changed (display, xevent);
68  */
69
70 static void
71 gdk_input_init (GdkDisplay *display)
72 {
73   GdkDisplayWayland *display_wayland;
74   GdkDeviceManager *device_manager;
75   GdkDevice *device;
76   GList *list, *l;
77
78   display_wayland = GDK_DISPLAY_WAYLAND (display);
79   device_manager = gdk_display_get_device_manager (display);
80
81   /* For backwards compatibility, just add
82    * floating devices that are not keyboards.
83    */
84   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
85
86   for (l = list; l; l = l->next)
87     {
88       device = l->data;
89
90       if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
91         continue;
92
93       display_wayland->input_devices = g_list_prepend (display_wayland->input_devices, l->data);
94     }
95
96   g_list_free (list);
97
98   /* Now set "core" pointer to the first
99    * master device that is a pointer.
100    */
101   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
102
103   for (l = list; l; l = l->next)
104     {
105       device = list->data;
106
107       if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
108         continue;
109
110       display->core_pointer = device;
111       break;
112     }
113
114   /* Add the core pointer to the devices list */
115   display_wayland->input_devices = g_list_prepend (display_wayland->input_devices, display->core_pointer);
116
117   g_list_free (list);
118 }
119
120 static void
121 shell_handle_configure(void *data, struct wl_shell *shell,
122                        uint32_t time, uint32_t edges,
123                        struct wl_surface *surface,
124                        int32_t width, int32_t height)
125 {
126   GdkWindow *window;
127   GdkDisplay *display;
128   GdkEvent *event;
129
130   window = wl_surface_get_user_data(surface);
131
132   printf("got configure: window %p, %dx%d, edges %d\n",
133          window, width, height, edges);
134
135   display = gdk_window_get_display (window);
136
137   event = gdk_event_new (GDK_CONFIGURE);
138   event->configure.window = window;
139   event->configure.send_event = FALSE;
140   event->configure.width = width;
141   event->configure.height = height;
142
143   window->width = width;
144   window->height = height;
145
146   _gdk_window_update_size (window);
147   _gdk_wayland_window_update_size (window);
148
149   g_object_ref(window);
150
151   _gdk_wayland_display_deliver_event (display, event);
152 }
153
154 static const struct wl_shell_listener shell_listener = {
155   shell_handle_configure,
156 };
157
158 static void
159 output_handle_geometry(void *data,
160                        struct wl_output *output,
161                        int32_t x, int32_t y, int32_t width, int32_t height)
162 {
163   /*
164     g_signal_emit_by_name (screen, "monitors-changed");
165     g_signal_emit_by_name (screen, "size-changed");
166   */
167 }
168
169 static const struct wl_output_listener output_listener = {
170         output_handle_geometry,
171 };
172
173 static void
174 gdk_display_handle_global(struct wl_display *display, uint32_t id,
175                           const char *interface, uint32_t version, void *data)
176 {
177   GdkDisplayWayland *display_wayland = data;
178   GdkDisplay *gdk_display = GDK_DISPLAY_OBJECT (data);
179   struct wl_input_device *input;
180
181   if (strcmp(interface, "compositor") == 0) {
182     display_wayland->compositor = wl_compositor_create(display, id);
183   } else if (strcmp(interface, "shm") == 0) {
184     display_wayland->shm = wl_shm_create(display, id);
185   } else if (strcmp(interface, "shell") == 0) {
186     display_wayland->shell = wl_shell_create(display, id);
187     wl_shell_add_listener(display_wayland->shell,
188                           &shell_listener, display_wayland);
189   } else if (strcmp(interface, "output") == 0) {
190     display_wayland->output = wl_output_create(display, id);
191     wl_output_add_listener(display_wayland->output,
192                            &output_listener, display_wayland);
193   } else if (strcmp(interface, "input_device") == 0) {
194     input = wl_input_device_create(display, id);
195     gdk_device_manager_core_add_device (gdk_display->device_manager, input);
196   }
197 }
198
199 static gboolean
200 gdk_display_init_egl(GdkDisplay *display)
201 {
202   GdkDisplayWayland *display_wayland = GDK_DISPLAY_WAYLAND (display);
203   EGLint major, minor, i;
204   void *p;
205
206   static const struct { const char *f; unsigned int offset; }
207   extension_functions[] = {
208     { "glEGLImageTargetTexture2DOES", offsetof(GdkDisplayWayland, image_target_texture_2d) },
209     { "eglCreateImageKHR", offsetof(GdkDisplayWayland, create_image) },
210     { "eglDestroyImageKHR", offsetof(GdkDisplayWayland, destroy_image) }
211   };
212
213   display_wayland->egl_display =
214     eglGetDisplay(display_wayland->native_display);
215   if (!eglInitialize(display_wayland->egl_display, &major, &minor)) {
216     fprintf(stderr, "failed to initialize display\n");
217     return FALSE;
218   }
219
220   eglBindAPI(EGL_OPENGL_API);
221
222   display_wayland->egl_context =
223     eglCreateContext(display_wayland->egl_display, NULL, EGL_NO_CONTEXT, NULL);
224   if (display_wayland->egl_context == NULL) {
225     fprintf(stderr, "failed to create context\n");
226     return FALSE;
227   }
228
229   if (!eglMakeCurrent(display_wayland->egl_display,
230                       NULL, NULL, display_wayland->egl_context)) {
231     fprintf(stderr, "faile to make context current\n");
232     return FALSE;
233   }
234
235   display_wayland->cairo_device =
236     cairo_egl_device_create(display_wayland->egl_display,
237                             display_wayland->egl_context);
238   if (cairo_device_status (display_wayland->cairo_device) != CAIRO_STATUS_SUCCESS) {
239     fprintf(stderr, "failed to get cairo drm device\n");
240     return FALSE;
241   }
242
243   for (i = 0; i < G_N_ELEMENTS(extension_functions); i++) {
244     p = eglGetProcAddress(extension_functions[i].f);
245     *(void **) ((char *) display_wayland + extension_functions[i].offset) = p;
246     if (p == NULL) {
247       fprintf(stderr, "failed to look up %s\n", extension_functions[i].f);
248       return FALSE;
249     }
250   }
251
252   fprintf(stderr, "egl initialized\n");
253
254   return TRUE;
255 }
256
257 GdkDisplay *
258 _gdk_wayland_display_open (const gchar *display_name)
259 {
260   struct wl_display *wl_display;
261   GdkDisplay *display;
262   GdkDisplayWayland *display_wayland;
263
264   gint i;
265
266   wl_display = wl_display_connect(display_name);
267   if (!wl_display)
268     return NULL;
269
270   display = g_object_new (GDK_TYPE_DISPLAY_WAYLAND, NULL);
271   display_wayland = GDK_DISPLAY_WAYLAND (display);
272
273   display_wayland->wl_display = wl_display;
274
275   display_wayland->native_display = wl_egl_display_create(wl_display);
276   if (display_wayland->native_display == NULL) {
277     wl_display_destroy(wl_display);
278     return NULL;
279   }
280
281   /* initialize the display's screens */
282   display_wayland->screens = g_new (GdkScreen *, 1);
283   for (i = 0; i < 1; i++)
284     display_wayland->screens[i] = _gdk_wayland_screen_new (display);
285
286   /*set the default screen */
287   display_wayland->default_screen = display_wayland->screens[0];
288
289   display->device_manager = _gdk_device_manager_new (display);
290
291   /* Set up listener so we'll catch all events. */
292   wl_display_add_global_listener(display_wayland->wl_display,
293                                  gdk_display_handle_global, display_wayland);
294
295   gdk_display_init_egl(display);
296
297   display_wayland->event_source = _gdk_wayland_display_event_source_new (display);
298
299   gdk_input_init (display);
300
301   g_signal_emit_by_name (display, "opened");
302   g_signal_emit_by_name (gdk_display_manager_get(), "display_opened", display);
303
304   return display;
305 }
306
307 static void
308 gdk_wayland_display_dispose (GObject *object)
309 {
310   GdkDisplayWayland *display_wayland = GDK_DISPLAY_WAYLAND (object);
311   gint           i;
312
313   _gdk_wayland_display_manager_remove_display (gdk_display_manager_get (),
314                                                GDK_DISPLAY (display_wayland));
315   g_list_foreach (display_wayland->input_devices,
316                   (GFunc) g_object_run_dispose, NULL);
317
318   for (i = 0; i < 1; i++)
319     _gdk_screen_close (display_wayland->screens[i]);
320
321   if (display_wayland->event_source)
322     {
323       g_source_destroy (display_wayland->event_source);
324       g_source_unref (display_wayland->event_source);
325       display_wayland->event_source = NULL;
326     }
327
328   eglTerminate(display_wayland->egl_display);
329   wl_egl_display_destroy(display_wayland->native_display);
330
331   G_OBJECT_CLASS (_gdk_display_wayland_parent_class)->dispose (object);
332 }
333
334 static void
335 gdk_wayland_display_finalize (GObject *object)
336 {
337   GdkDisplayWayland *display_wayland = GDK_DISPLAY_WAYLAND (object);
338   gint           i;
339
340   /* Keymap */
341   if (display_wayland->keymap)
342     g_object_unref (display_wayland->keymap);
343
344   /* input GdkDevice list */
345   g_list_foreach (display_wayland->input_devices, (GFunc) g_object_unref, NULL);
346   g_list_free (display_wayland->input_devices);
347
348   /* input GdkWindow list */
349   g_list_foreach (display_wayland->input_windows, (GFunc) g_free, NULL);
350   g_list_free (display_wayland->input_windows);
351
352   /* Free all GdkScreens */
353   for (i = 0; i < 1; i++)
354     g_object_unref (display_wayland->screens[i]);
355   g_free (display_wayland->screens);
356
357   g_free (display_wayland->startup_notification_id);
358
359   G_OBJECT_CLASS (_gdk_display_wayland_parent_class)->finalize (object);
360 }
361
362 static G_CONST_RETURN gchar *
363 gdk_wayland_display_get_name (GdkDisplay *display)
364 {
365   return "Wayland";
366 }
367
368 static gint
369 gdk_wayland_display_get_n_screens (GdkDisplay *display)
370 {
371   return 1;
372 }
373
374 static GdkScreen *
375 gdk_wayland_display_get_screen (GdkDisplay *display, 
376                                 gint        screen_num)
377 {
378   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
379   g_return_val_if_fail (screen_num == 0, NULL);
380
381   return GDK_DISPLAY_WAYLAND (display)->screens[0];
382 }
383
384 static GdkScreen *
385 gdk_wayland_display_get_default_screen (GdkDisplay *display)
386 {
387   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
388
389   return GDK_DISPLAY_WAYLAND (display)->default_screen;
390 }
391
392 static void
393 gdk_wayland_display_beep (GdkDisplay *display)
394 {
395   g_return_if_fail (GDK_IS_DISPLAY (display));
396 }
397
398 static void
399 sync_callback(void *data)
400 {
401   gboolean *done = data;
402
403   *done = TRUE;
404 }
405
406 static void
407 gdk_wayland_display_sync (GdkDisplay *display)
408 {
409   GdkDisplayWayland *display_wayland;
410   gboolean done;
411
412   g_return_if_fail (GDK_IS_DISPLAY (display));
413
414   display_wayland = GDK_DISPLAY_WAYLAND (display);
415
416   wl_display_sync_callback(display_wayland->wl_display, sync_callback, &done);
417   wl_display_iterate(display_wayland->wl_display, WL_DISPLAY_WRITABLE);
418   while (!done)
419     wl_display_iterate(display_wayland->wl_display, WL_DISPLAY_READABLE);
420 }
421
422 static void
423 gdk_wayland_display_flush (GdkDisplay *display)
424 {
425   g_return_if_fail (GDK_IS_DISPLAY (display));
426
427   if (!display->closed)
428     _gdk_wayland_display_flush (display,
429                                 GDK_DISPLAY_WAYLAND (display)->event_source);
430 }
431
432 static gboolean
433 gdk_wayland_display_has_pending (GdkDisplay *display)
434 {
435   return FALSE;
436 }
437
438 static GdkWindow *
439 gdk_wayland_display_get_default_group (GdkDisplay *display)
440 {
441   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
442
443   return NULL;
444 }
445
446
447 static gboolean
448 gdk_wayland_display_supports_selection_notification (GdkDisplay *display)
449 {
450   return TRUE;
451 }
452
453 static gboolean
454 gdk_wayland_display_request_selection_notification (GdkDisplay *display,
455                                                     GdkAtom     selection)
456
457 {
458     return FALSE;
459 }
460
461 static gboolean
462 gdk_wayland_display_supports_clipboard_persistence (GdkDisplay *display)
463 {
464   return FALSE;
465 }
466
467 static void
468 gdk_wayland_display_store_clipboard (GdkDisplay    *display,
469                                      GdkWindow     *clipboard_window,
470                                      guint32        time_,
471                                      const GdkAtom *targets,
472                                      gint           n_targets)
473 {
474 }
475
476 static gboolean
477 gdk_wayland_display_supports_shapes (GdkDisplay *display)
478 {
479   return TRUE;
480 }
481
482 static gboolean
483 gdk_wayland_display_supports_input_shapes (GdkDisplay *display)
484 {
485   return TRUE;
486 }
487
488 static gboolean
489 gdk_wayland_display_supports_composite (GdkDisplay *display)
490 {
491   return TRUE;
492 }
493
494 static GList *
495 gdk_wayland_display_list_devices (GdkDisplay *display)
496 {
497   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
498
499   return GDK_DISPLAY_WAYLAND (display)->input_devices;
500 }
501
502 static void
503 gdk_wayland_display_before_process_all_updates (GdkDisplay *display)
504 {
505 }
506
507 static void
508 gdk_wayland_display_after_process_all_updates (GdkDisplay *display)
509 {
510   /* Post the damage here instead? */
511 }
512
513 static gulong
514 gdk_wayland_display_get_next_serial (GdkDisplay *display)
515 {
516   return 0;
517 }
518
519 void
520 _gdk_wayland_display_make_default (GdkDisplay *display)
521 {
522 }
523
524 /**
525  * gdk_wayland_display_broadcast_startup_message:
526  * @display: a #GdkDisplay
527  * @message_type: startup notification message type ("new", "change",
528  * or "remove")
529  * @...: a list of key/value pairs (as strings), terminated by a
530  * %NULL key. (A %NULL value for a key will cause that key to be
531  * skipped in the output.)
532  *
533  * Sends a startup notification message of type @message_type to
534  * @display. 
535  *
536  * This is a convenience function for use by code that implements the
537  * freedesktop startup notification specification. Applications should
538  * not normally need to call it directly. See the <ulink
539  * url="http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt">Startup
540  * Notification Protocol specification</ulink> for
541  * definitions of the message types and keys that can be used.
542  *
543  * Since: 2.12
544  **/
545 void
546 gdk_wayland_display_broadcast_startup_message (GdkDisplay *display,
547                                                const char *message_type,
548                                                ...)
549 {
550   GString *message;
551   va_list ap;
552   const char *key, *value, *p;
553
554   message = g_string_new (message_type);
555   g_string_append_c (message, ':');
556
557   va_start (ap, message_type);
558   while ((key = va_arg (ap, const char *)))
559     {
560       value = va_arg (ap, const char *);
561       if (!value)
562         continue;
563
564       g_string_append_printf (message, " %s=\"", key);
565       for (p = value; *p; p++)
566         {
567           switch (*p)
568             {
569             case ' ':
570             case '"':
571             case '\\':
572               g_string_append_c (message, '\\');
573               break;
574             }
575
576           g_string_append_c (message, *p);
577         }
578       g_string_append_c (message, '\"');
579     }
580   va_end (ap);
581
582   printf ("startup message: %s\n", message->str);
583
584   g_string_free (message, TRUE);
585 }
586
587 static void
588 gdk_wayland_display_notify_startup_complete (GdkDisplay  *display,
589                                              const gchar *startup_id)
590 {
591   gdk_wayland_display_broadcast_startup_message (display, "remove",
592                                                  "ID", startup_id,
593                                                  NULL);
594 }
595
596 static void
597 gdk_wayland_display_event_data_copy (GdkDisplay     *display,
598                                      const GdkEvent *src,
599                                      GdkEvent       *dst)
600 {
601 }
602
603 static void
604 gdk_wayland_display_event_data_free (GdkDisplay *display,
605                                      GdkEvent   *event)
606 {
607 }
608
609 static GdkKeymap *
610 gdk_wayland_display_get_keymap (GdkDisplay *display)
611 {
612   GdkDisplayWayland *display_wayland;
613
614   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
615   display_wayland = GDK_DISPLAY_WAYLAND (display);
616
617   if (!display_wayland->keymap)
618     display_wayland->keymap = _gdk_wayland_keymap_new (display);
619
620   return display_wayland->keymap;
621 }
622
623 static void
624 gdk_wayland_display_push_error_trap (GdkDisplay *display)
625 {
626 }
627
628 static gint
629 gdk_wayland_display_pop_error_trap (GdkDisplay *display,
630                                     gboolean    ignored)
631 {
632   return 0;
633 }
634
635 static void
636 _gdk_display_wayland_class_init (GdkDisplayWaylandClass * class)
637 {
638   GObjectClass *object_class = G_OBJECT_CLASS (class);
639   GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
640
641   object_class->dispose = gdk_wayland_display_dispose;
642   object_class->finalize = gdk_wayland_display_finalize;
643
644   display_class->window_type = _gdk_wayland_window_get_type ();
645   display_class->get_name = gdk_wayland_display_get_name;
646   display_class->get_n_screens = gdk_wayland_display_get_n_screens;
647   display_class->get_screen = gdk_wayland_display_get_screen;
648   display_class->get_default_screen = gdk_wayland_display_get_default_screen;
649   display_class->beep = gdk_wayland_display_beep;
650   display_class->sync = gdk_wayland_display_sync;
651   display_class->flush = gdk_wayland_display_flush;
652   display_class->has_pending = gdk_wayland_display_has_pending;
653   display_class->queue_events = _gdk_wayland_display_queue_events;
654   display_class->get_default_group = gdk_wayland_display_get_default_group;
655   display_class->supports_selection_notification = gdk_wayland_display_supports_selection_notification;
656   display_class->request_selection_notification = gdk_wayland_display_request_selection_notification;
657   display_class->supports_clipboard_persistence = gdk_wayland_display_supports_clipboard_persistence;
658   display_class->store_clipboard = gdk_wayland_display_store_clipboard;
659   display_class->supports_shapes = gdk_wayland_display_supports_shapes;
660   display_class->supports_input_shapes = gdk_wayland_display_supports_input_shapes;
661   display_class->supports_composite = gdk_wayland_display_supports_composite;
662   display_class->list_devices = gdk_wayland_display_list_devices;
663   display_class->get_app_launch_context = _gdk_wayland_display_get_app_launch_context;
664   display_class->get_default_cursor_size = _gdk_wayland_display_get_default_cursor_size;
665   display_class->get_maximal_cursor_size = _gdk_wayland_display_get_maximal_cursor_size;
666   display_class->get_cursor_for_type = _gdk_wayland_display_get_cursor_for_type;
667   display_class->get_cursor_for_name = _gdk_wayland_display_get_cursor_for_name;
668   display_class->get_cursor_for_pixbuf = _gdk_wayland_display_get_cursor_for_pixbuf;
669   display_class->supports_cursor_alpha = _gdk_wayland_display_supports_cursor_alpha;
670   display_class->supports_cursor_color = _gdk_wayland_display_supports_cursor_color;
671   display_class->before_process_all_updates = gdk_wayland_display_before_process_all_updates;
672   display_class->after_process_all_updates = gdk_wayland_display_after_process_all_updates;
673   display_class->get_next_serial = gdk_wayland_display_get_next_serial;
674   display_class->notify_startup_complete = gdk_wayland_display_notify_startup_complete;
675   display_class->event_data_copy = gdk_wayland_display_event_data_copy;
676   display_class->event_data_free = gdk_wayland_display_event_data_free;
677   display_class->create_window_impl = _gdk_wayland_display_create_window_impl;
678   display_class->get_keymap = gdk_wayland_display_get_keymap;
679   display_class->push_error_trap = gdk_wayland_display_push_error_trap;
680   display_class->pop_error_trap = gdk_wayland_display_pop_error_trap;
681   display_class->get_selection_owner = _gdk_wayland_display_get_selection_owner;
682   display_class->set_selection_owner = _gdk_wayland_display_set_selection_owner;
683   display_class->send_selection_notify = _gdk_wayland_display_send_selection_notify;
684   display_class->get_selection_property = _gdk_wayland_display_get_selection_property;
685   display_class->convert_selection = _gdk_wayland_display_convert_selection;
686   display_class->text_property_to_utf8_list = _gdk_wayland_display_text_property_to_utf8_list;
687   display_class->utf8_to_string_target = _gdk_wayland_display_utf8_to_string_target;
688 }
689
690 static void
691 _gdk_display_wayland_init (GdkDisplayWayland *display)
692 {
693   _gdk_wayland_display_manager_add_display (gdk_display_manager_get (),
694                                             GDK_DISPLAY (display));
695 }