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 "gdkinternals.h"
21#include "gdkprivate-wayland.h"
22
23#include <stdlib.h>
24#include <errno.h>
25
26typedef struct _GdkWaylandEventSource {
27 GSource source;
28 GPollFD pfd;
29 uint32_t mask;
30 GdkDisplay *display;
31 gboolean reading;
32} GdkWaylandEventSource;
33
34static gboolean
35gdk_event_source_prepare (GSource *base,
36 gint *timeout)
37{
38 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
39 GdkWaylandDisplay *display = (GdkWaylandDisplay *) source->display;
40
41 *timeout = -1;
42
43 if (source->display->event_pause_count > 0)
44 return _gdk_event_queue_find_first (source->display) != NULL;
45
46 /* We have to add/remove the GPollFD if we want to update our
47 * poll event mask dynamically. Instead, let's just flush all
48 * write on idle instead, which is what this amounts to.
49 */
50
51 if (_gdk_event_queue_find_first (source->display) != NULL)
52 return TRUE;
53
54 /* wl_display_prepare_read() needs to be balanced with either
55 * wl_display_read_events() or wl_display_cancel_read()
56 * (in gdk_event_source_check() */
57 if (source->reading)
58 return FALSE;
59
60 /* if prepare_read() returns non-zero, there are events to be dispatched */
61 if (wl_display_prepare_read (display->wl_display) != 0)
62 return TRUE;
63 source->reading = TRUE;
64
65 if (wl_display_flush (display->wl_display) < 0)
66 g_error ("Error flushing display: %s", g_strerror (errno));
67
68 return FALSE;
69}
70
71static gboolean
72gdk_event_source_check (GSource *base)
73{
74 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
75 GdkWaylandDisplay *display_wayland = (GdkWaylandDisplay *) source->display;
76
77 if (source->display->event_pause_count > 0)
78 {
79 if (source->reading)
80 wl_display_cancel_read (display_wayland->wl_display);
81 source->reading = FALSE;
82
83 return _gdk_event_queue_find_first (source->display) != NULL;
84 }
85
86 /* read the events from the wayland fd into their respective queues if we have data */
87 if (source->reading)
88 {
89 if (source->pfd.revents & G_IO_IN)
90 {
91 if (wl_display_read_events (display_wayland->wl_display) < 0)
92 g_error ("Error reading events from display: %s", g_strerror (errno));
93 }
94 else
95 wl_display_cancel_read (display_wayland->wl_display);
96 source->reading = FALSE;
97 }
98
99 return _gdk_event_queue_find_first (source->display) != NULL ||
100 source->pfd.revents;
101}
102
103static gboolean
104gdk_event_source_dispatch (GSource *base,
105 GSourceFunc callback,
106 gpointer data)
107{
108 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
109 GdkDisplay *display = source->display;
110 GdkEvent *event;
111
112 gdk_threads_enter ();
113
114 event = gdk_display_get_event (display);
115
116 if (event)
117 {
118 _gdk_event_emit (event);
119
120 gdk_event_free (event);
121 }
122
123 gdk_threads_leave ();
124
125 return TRUE;
126}
127
128static void
129gdk_event_source_finalize (GSource *base)
130{
131 GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
132 GdkWaylandDisplay *display = (GdkWaylandDisplay *) source->display;
133
134 if (source->reading)
135 wl_display_cancel_read (display->wl_display);
136 source->reading = FALSE;
137}
138
139static GSourceFuncs wl_glib_source_funcs = {
140 gdk_event_source_prepare,
141 gdk_event_source_check,
142 gdk_event_source_dispatch,
143 gdk_event_source_finalize
144};
145
146void
147_gdk_wayland_display_deliver_event (GdkDisplay *display,
148 GdkEvent *event)
149{
150 GList *node;
151
152 node = _gdk_event_queue_append (display, event);
153 _gdk_windowing_got_event (display, node, event,
154 _gdk_display_get_next_serial (display));
155}
156
157GSource *
158_gdk_wayland_display_event_source_new (GdkDisplay *display)
159{
160 GSource *source;
161 GdkWaylandEventSource *wl_source;
162 GdkWaylandDisplay *display_wayland;
163 char *name;
164
165 source = g_source_new (&wl_glib_source_funcs,
166 sizeof (GdkWaylandEventSource));
167 name = g_strdup_printf ("GDK Wayland Event source (%s)",
168 gdk_display_get_name (display));
169 g_source_set_name (source, name);
170 g_free (name);
171 wl_source = (GdkWaylandEventSource *) source;
172
173 display_wayland = GDK_WAYLAND_DISPLAY (display);
174 wl_source->display = display;
175 wl_source->pfd.fd = wl_display_get_fd (display_wayland->wl_display);
176 wl_source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP;
177 g_source_add_poll (source, &wl_source->pfd);
178
179 g_source_set_priority (source, GDK_PRIORITY_EVENTS);
180 g_source_set_can_recurse (source, TRUE);
181 g_source_attach (source, NULL);
182
183 return source;
184}
185
186void
187_gdk_wayland_display_queue_events (GdkDisplay *display)
188{
189 GdkWaylandDisplay *display_wayland;
190 GdkWaylandEventSource *source;
191
192 display_wayland = GDK_WAYLAND_DISPLAY (display);
193 source = (GdkWaylandEventSource *) display_wayland->event_source;
194
195 if (wl_display_dispatch_pending (display_wayland->wl_display) < 0)
196 {
197 g_warning ("Error %d (%s) dispatching to Wayland display.",
198 errno, g_strerror (errno));
199 exit (1);
200 }
201
202 if (source->pfd.revents & (G_IO_ERR | G_IO_HUP))
203 {
204 g_warning ("Lost connection to Wayland compositor.");
205 exit (1);
206 }
207 source->pfd.revents = 0;
208}
209