1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "gdkprivate-wayland.h"
21
22#include "gdkeventsprivate.h"
23
24#include <unistd.h>
25#include <errno.h>
26
27typedef struct _GdkWaylandEventSource {
28 GSource source;
29 GPollFD pfd;
30 uint32_t mask;
31 GdkDisplay *display;
32 gboolean reading;
33} GdkWaylandEventSource;
34
35static gboolean
36gdk_event_source_prepare (GSource *base,
37 int *timeout)
38{
39 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
40 GdkWaylandDisplay *display = (GdkWaylandDisplay *) source->display;
41 GList *l;
42
43 *timeout = -1;
44
45 if (source->display->event_pause_count > 0)
46 return _gdk_event_queue_find_first (source->display) != NULL;
47
48 /* We have to add/remove the GPollFD if we want to update our
49 * poll event mask dynamically. Instead, let's just flush all
50 * write on idle instead, which is what this amounts to.
51 */
52
53 if (_gdk_event_queue_find_first (source->display) != NULL)
54 return TRUE;
55
56 /* wl_display_prepare_read() needs to be balanced with either
57 * wl_display_read_events() or wl_display_cancel_read()
58 * (in gdk_event_source_check() */
59 if (source->reading)
60 return FALSE;
61
62 /* if prepare_read() returns non-zero, there are events to be dispatched */
63 if (wl_display_prepare_read (display->wl_display) != 0)
64 return TRUE;
65
66 /* We need to check whether there are pending events on the surface queues as well,
67 * but we also need to make sure to only have one active "read" in the end,
68 * or none if we immediately return TRUE, as multiple reads expect reads from
69 * as many threads.
70 */
71 for (l = display->event_queues; l; l = l->next)
72 {
73 struct wl_event_queue *queue = l->data;
74
75 if (wl_display_prepare_read_queue (display->wl_display, queue) != 0)
76 {
77 wl_display_cancel_read (display->wl_display);
78 return TRUE;
79 }
80 wl_display_cancel_read (display->wl_display);
81 }
82
83 source->reading = TRUE;
84
85 if (wl_display_flush (display->wl_display) < 0)
86 {
87 g_message ("Error flushing display: %s", g_strerror (errno));
88 _exit (1);
89 }
90
91 return FALSE;
92}
93
94static gboolean
95gdk_event_source_check (GSource *base)
96{
97 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
98 GdkWaylandDisplay *display_wayland = (GdkWaylandDisplay *) source->display;
99
100 if (source->display->event_pause_count > 0)
101 {
102 if (source->reading)
103 wl_display_cancel_read (display_wayland->wl_display);
104 source->reading = FALSE;
105
106 return _gdk_event_queue_find_first (source->display) != NULL;
107 }
108
109 /* read the events from the wayland fd into their respective queues if we have data */
110 if (source->reading)
111 {
112 if (source->pfd.revents & G_IO_IN)
113 {
114 if (wl_display_read_events (display_wayland->wl_display) < 0)
115 {
116 g_message ("Error reading events from display: %s", g_strerror (errno));
117 _exit (1);
118 }
119 }
120 else
121 wl_display_cancel_read (display_wayland->wl_display);
122 source->reading = FALSE;
123 }
124
125 return _gdk_event_queue_find_first (source->display) != NULL ||
126 source->pfd.revents;
127}
128
129static gboolean
130gdk_event_source_dispatch (GSource *base,
131 GSourceFunc callback,
132 gpointer data)
133{
134 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
135 GdkDisplay *display = source->display;
136 GdkEvent *event;
137
138 event = gdk_display_get_event (display);
139
140 if (event)
141 {
142 _gdk_event_emit (event);
143
144 gdk_event_unref (event);
145 }
146
147 return TRUE;
148}
149
150static void
151gdk_event_source_finalize (GSource *base)
152{
153 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
154 GdkWaylandDisplay *display = (GdkWaylandDisplay *) source->display;
155
156 if (source->reading)
157 wl_display_cancel_read (display->wl_display);
158 source->reading = FALSE;
159}
160
161static GSourceFuncs wl_glib_source_funcs = {
162 gdk_event_source_prepare,
163 gdk_event_source_check,
164 gdk_event_source_dispatch,
165 gdk_event_source_finalize
166};
167
168void
169_gdk_wayland_display_deliver_event (GdkDisplay *display,
170 GdkEvent *event)
171{
172 GList *node;
173
174 node = _gdk_event_queue_append (display, event);
175 _gdk_windowing_got_event (display, node, event,
176 _gdk_display_get_next_serial (display));
177}
178
179GSource *
180_gdk_wayland_display_event_source_new (GdkDisplay *display)
181{
182 GSource *source;
183 GdkWaylandEventSource *wl_source;
184 GdkWaylandDisplay *display_wayland;
185 char *name;
186
187 source = g_source_new (&wl_glib_source_funcs,
188 sizeof (GdkWaylandEventSource));
189 name = g_strdup_printf ("GDK Wayland Event source (%s)",
190 gdk_display_get_name (display));
191 g_source_set_name (source, name);
192 g_free (name);
193 wl_source = (GdkWaylandEventSource *) source;
194
195 display_wayland = GDK_WAYLAND_DISPLAY (display);
196 wl_source->display = display;
197 wl_source->pfd.fd = wl_display_get_fd (display_wayland->wl_display);
198 wl_source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP;
199 g_source_add_poll (source, &wl_source->pfd);
200
201 g_source_set_priority (source, GDK_PRIORITY_EVENTS);
202 g_source_set_can_recurse (source, TRUE);
203 g_source_attach (source, NULL);
204
205 return source;
206}
207
208void
209_gdk_wayland_display_queue_events (GdkDisplay *display)
210{
211 GdkWaylandDisplay *display_wayland;
212 GdkWaylandEventSource *source;
213 GList *l;
214
215 display_wayland = GDK_WAYLAND_DISPLAY (display);
216 source = (GdkWaylandEventSource *) display_wayland->event_source;
217
218 if (wl_display_dispatch_pending (display_wayland->wl_display) < 0)
219 {
220 g_message ("Error %d (%s) dispatching to Wayland display.",
221 errno, g_strerror (errno));
222 _exit (1);
223 }
224
225 for (l = display_wayland->event_queues; l; l = l->next)
226 {
227 struct wl_event_queue *queue = l->data;
228
229 if (wl_display_dispatch_queue_pending (display_wayland->wl_display, queue) < 0)
230 {
231 g_message ("Error %d (%s) dispatching to Wayland display.",
232 errno, g_strerror (errno));
233 _exit (1);
234 }
235 }
236
237 if (source->pfd.revents & (G_IO_ERR | G_IO_HUP))
238 {
239 g_message ("Lost connection to Wayland compositor.");
240 _exit (1);
241 }
242 source->pfd.revents = 0;
243}
244

source code of gtk/gdk/wayland/gdkeventsource.c