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 | |
27 | typedef struct _GdkWaylandEventSource { |
28 | GSource source; |
29 | GPollFD pfd; |
30 | uint32_t mask; |
31 | GdkDisplay *display; |
32 | gboolean reading; |
33 | } GdkWaylandEventSource; |
34 | |
35 | static gboolean |
36 | gdk_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 (display: 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 (display: 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: 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: display->wl_display, queue) != 0) |
76 | { |
77 | wl_display_cancel_read (display: display->wl_display); |
78 | return TRUE; |
79 | } |
80 | wl_display_cancel_read (display: display->wl_display); |
81 | } |
82 | |
83 | source->reading = TRUE; |
84 | |
85 | if (wl_display_flush (display: display->wl_display) < 0) |
86 | { |
87 | g_message ("Error flushing display: %s" , g_strerror (errno)); |
88 | _exit (status: 1); |
89 | } |
90 | |
91 | return FALSE; |
92 | } |
93 | |
94 | static gboolean |
95 | gdk_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: display_wayland->wl_display); |
104 | source->reading = FALSE; |
105 | |
106 | return _gdk_event_queue_find_first (display: 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: display_wayland->wl_display) < 0) |
115 | { |
116 | g_message ("Error reading events from display: %s" , g_strerror (errno)); |
117 | _exit (status: 1); |
118 | } |
119 | } |
120 | else |
121 | wl_display_cancel_read (display: display_wayland->wl_display); |
122 | source->reading = FALSE; |
123 | } |
124 | |
125 | return _gdk_event_queue_find_first (display: source->display) != NULL || |
126 | source->pfd.revents; |
127 | } |
128 | |
129 | static gboolean |
130 | gdk_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 | |
150 | static void |
151 | gdk_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: display->wl_display); |
158 | source->reading = FALSE; |
159 | } |
160 | |
161 | static 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 | |
168 | void |
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, event_link: node, event, |
176 | serial: _gdk_display_get_next_serial (display)); |
177 | } |
178 | |
179 | GSource * |
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 (source_funcs: &wl_glib_source_funcs, |
188 | struct_size: sizeof (GdkWaylandEventSource)); |
189 | name = g_strdup_printf (format: "GDK Wayland Event source (%s)" , |
190 | gdk_display_get_name (display)); |
191 | g_source_set_name (source, name); |
192 | g_free (mem: 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: display_wayland->wl_display); |
198 | wl_source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP; |
199 | g_source_add_poll (source, fd: &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 | |
208 | void |
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: display_wayland->wl_display) < 0) |
219 | { |
220 | g_message ("Error %d (%s) dispatching to Wayland display." , |
221 | errno, g_strerror (errno)); |
222 | _exit (status: 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: display_wayland->wl_display, queue) < 0) |
230 | { |
231 | g_message ("Error %d (%s) dispatching to Wayland display." , |
232 | errno, g_strerror (errno)); |
233 | _exit (status: 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 (status: 1); |
241 | } |
242 | source->pfd.revents = 0; |
243 | } |
244 | |