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