diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index 19d4bd5aac..1da3e36fe8 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -121,6 +121,8 @@ struct _GdkWaylandDisplay GHashTable *known_globals; GList *on_has_globals_closures; + GList *event_queues; + /* Keep a list of orphaned dialogs (i.e. without parent) */ GList *orphan_dialogs; diff --git a/gdk/wayland/gdkeventsource.c b/gdk/wayland/gdkeventsource.c index 86c3f86484..be31fb56de 100644 --- a/gdk/wayland/gdkeventsource.c +++ b/gdk/wayland/gdkeventsource.c @@ -37,6 +37,7 @@ gdk_event_source_prepare (GSource *base, { GdkWaylandEventSource *source = (GdkWaylandEventSource *) base; GdkWaylandDisplay *display = (GdkWaylandDisplay *) source->display; + GList *l; *timeout = -1; @@ -60,6 +61,24 @@ gdk_event_source_prepare (GSource *base, /* if prepare_read() returns non-zero, there are events to be dispatched */ if (wl_display_prepare_read (display->wl_display) != 0) return TRUE; + + /* We need to check whether there are pending events on the surface queues as well, + * but we also need to make sure to only have one active "read" in the end, + * or none if we immediately return TRUE, as multiple reads expect reads from + * as many threads. + */ + for (l = display->event_queues; l; l = l->next) + { + struct wl_event_queue *queue = l->data; + + if (wl_display_prepare_read_queue (display->wl_display, queue) != 0) + { + wl_display_cancel_read (display->wl_display); + return TRUE; + } + wl_display_cancel_read (display->wl_display); + } + source->reading = TRUE; if (wl_display_flush (display->wl_display) < 0) @@ -193,6 +212,7 @@ _gdk_wayland_display_queue_events (GdkDisplay *display) { GdkWaylandDisplay *display_wayland; GdkWaylandEventSource *source; + GList *l; display_wayland = GDK_WAYLAND_DISPLAY (display); source = (GdkWaylandEventSource *) display_wayland->event_source; @@ -204,6 +224,18 @@ _gdk_wayland_display_queue_events (GdkDisplay *display) _exit (1); } + for (l = display_wayland->event_queues; l; l = l->next) + { + struct wl_event_queue *queue = l->data; + + if (wl_display_dispatch_queue_pending (display_wayland->wl_display, queue) < 0) + { + g_message ("Error %d (%s) dispatching to Wayland display.", + errno, g_strerror (errno)); + _exit (1); + } + } + if (source->pfd.revents & (G_IO_ERR | G_IO_HUP)) { g_message ("Lost connection to Wayland compositor."); diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 02409da4e7..55134b1409 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -78,6 +78,8 @@ struct _GdkWaylandSurface struct org_kde_kwin_server_decoration *server_decoration; } display_server; + struct wl_event_queue *event_queue; + EGLSurface egl_surface; EGLSurface dummy_egl_surface; @@ -450,6 +452,7 @@ gdk_wayland_surface_request_frame (GdkSurface *surface) clock = gdk_surface_get_frame_clock (surface); callback = wl_surface_frame (impl->display_server.wl_surface); + wl_proxy_set_queue ((struct wl_proxy *) callback, NULL); wl_callback_add_listener (callback, &frame_listener, surface); impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock); impl->awaiting_frame = TRUE; @@ -643,6 +646,44 @@ gdk_wayland_surface_beep (GdkSurface *surface) return TRUE; } +static void +gdk_wayland_surface_constructed (GObject *object) +{ + GdkSurface *surface = GDK_SURFACE (object); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + + G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->constructed (object); + + impl->event_queue = wl_display_create_queue (display_wayland->wl_display); + display_wayland->event_queues = g_list_prepend (display_wayland->event_queues, + impl->event_queue); +} + +static void +gdk_wayland_surface_dispose (GObject *object) +{ + GdkSurface *surface = GDK_SURFACE (object); + GdkWaylandSurface *impl; + + g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface)); + + impl = GDK_WAYLAND_SURFACE (surface); + + if (impl->event_queue) + { + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + + display_wayland->event_queues = + g_list_remove (display_wayland->event_queues, surface); + g_clear_pointer (&impl->event_queue, wl_event_queue_destroy); + } + + G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->dispose (object); +} + static void gdk_wayland_surface_finalize (GObject *object) { @@ -1057,9 +1098,13 @@ gdk_wayland_surface_create_surface (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + struct wl_surface *wl_surface; - impl->display_server.wl_surface = wl_compositor_create_surface (display_wayland->compositor); - wl_surface_add_listener (impl->display_server.wl_surface, &surface_listener, surface); + wl_surface = wl_compositor_create_surface (display_wayland->compositor); + wl_proxy_set_queue ((struct wl_proxy *) wl_surface, impl->event_queue); + wl_surface_add_listener (wl_surface, &surface_listener, surface); + + impl->display_server.wl_surface = wl_surface; } static void @@ -1334,6 +1379,8 @@ create_xdg_toplevel_resources (GdkSurface *surface) impl->display_server.xdg_surface = xdg_wm_base_get_xdg_surface (display_wayland->xdg_wm_base, impl->display_server.wl_surface); + wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.xdg_surface, + impl->event_queue); xdg_surface_add_listener (impl->display_server.xdg_surface, &xdg_surface_listener, surface); @@ -2183,6 +2230,9 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface, impl->display_server.xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base, impl->display_server.wl_surface); + + wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.xdg_surface, + impl->event_queue); xdg_surface_add_listener (impl->display_server.xdg_surface, &xdg_surface_listener, surface); @@ -2987,6 +3037,8 @@ gdk_wayland_surface_init_gtk_surface (GdkSurface *surface) impl->display_server.gtk_surface = gtk_shell1_get_gtk_surface (display->gtk_shell, impl->display_server.wl_surface); + wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.gtk_surface, + impl->event_queue); gdk_surface_set_geometry_hints (surface, &impl->geometry_hints, impl->geometry_mask); @@ -3752,6 +3804,8 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass); + object_class->constructed = gdk_wayland_surface_constructed; + object_class->dispose = gdk_wayland_surface_dispose; object_class->finalize = gdk_wayland_surface_finalize; impl_class->show = gdk_wayland_surface_show;