eglut_wayland.c revision 32001f49
1#include <wayland-client.h>
2#include <wayland-egl.h>
3
4#include <poll.h>
5#include <errno.h>
6#include <string.h>
7
8#include "eglutint.h"
9
10struct display {
11   struct wl_display *display;
12   struct wl_compositor *compositor;
13   struct wl_shell *shell;
14   uint32_t mask;
15};
16
17struct window {
18   struct wl_surface *surface;
19   struct wl_shell_surface *shell_surface;
20   struct wl_callback *callback;
21};
22
23static struct display display = {0, };
24static struct window window = {0, };
25
26static void
27registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
28                       const char *interface, uint32_t version)
29{
30   struct display *d = data;
31
32   if (strcmp(interface, "wl_compositor") == 0) {
33      d->compositor =
34         wl_registry_bind(registry, id, &wl_compositor_interface, 1);
35   } else if (strcmp(interface, "wl_shell") == 0) {
36      d->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
37   }
38}
39
40static void
41registry_handle_global_remove(void *data, struct wl_registry *registry,
42                              uint32_t name)
43{
44}
45
46static const struct wl_registry_listener registry_listener = {
47   registry_handle_global,
48   registry_handle_global_remove
49};
50
51static void
52sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
53{
54   int *done = data;
55
56   *done = 1;
57   wl_callback_destroy(callback);
58}
59
60static const struct wl_callback_listener sync_listener = {
61   sync_callback
62};
63
64static int
65wayland_roundtrip(struct wl_display *display)
66{
67   struct wl_callback *callback;
68   int done = 0, ret = 0;
69
70   callback = wl_display_sync(display);
71   wl_callback_add_listener(callback, &sync_listener, &done);
72   while (ret != -1 && !done)
73      ret = wl_display_dispatch(display);
74
75   if (!done)
76      wl_callback_destroy(callback);
77
78   return ret;
79}
80
81void
82_eglutNativeInitDisplay(void)
83{
84   struct wl_registry *registry;
85
86   _eglut->native_dpy =  display.display = wl_display_connect(NULL);
87
88   if (!_eglut->native_dpy)
89      _eglutFatal("failed to initialize native display");
90
91   registry = wl_display_get_registry(_eglut->native_dpy);
92   wl_registry_add_listener(registry, &registry_listener, &display);
93   wayland_roundtrip(_eglut->native_dpy);
94   wl_registry_destroy(registry);
95
96   _eglut->surface_type = EGL_WINDOW_BIT;
97}
98
99void
100_eglutNativeFiniDisplay(void)
101{
102   wl_display_flush(_eglut->native_dpy);
103   wl_display_disconnect(_eglut->native_dpy);
104}
105
106void
107_eglutNativeInitWindow(struct eglut_window *win, const char *title,
108                       int x, int y, int w, int h)
109{
110   struct wl_egl_window *native;
111   struct wl_region *region;
112
113   window.surface = wl_compositor_create_surface(display.compositor);
114
115   region = wl_compositor_create_region(display.compositor);
116   wl_region_add(region, 0, 0, w, h);
117   wl_surface_set_opaque_region(window.surface, region);
118   wl_region_destroy(region);
119
120   window.shell_surface = wl_shell_get_shell_surface(display.shell,
121         window.surface);
122   native = wl_egl_window_create(window.surface, w, h);
123
124   wl_shell_surface_set_toplevel(window.shell_surface);
125
126   win->native.u.window = native;
127   win->native.width = w;
128   win->native.height = h;
129}
130
131void
132_eglutNativeFiniWindow(struct eglut_window *win)
133{
134   wl_egl_window_destroy(win->native.u.window);
135
136   wl_shell_surface_destroy(window.shell_surface);
137   wl_surface_destroy(window.surface);
138
139   if (window.callback)
140      wl_callback_destroy(window.callback);
141}
142
143static void
144draw(void *data, struct wl_callback *callback, uint32_t time);
145
146static const struct wl_callback_listener frame_listener = {
147   draw
148};
149
150static void
151draw(void *data, struct wl_callback *callback, uint32_t time)
152{
153   struct window *window = (struct window *)data;
154   struct eglut_window *win = _eglut->current;
155
156   if (win->display_cb)
157      win->display_cb();
158   eglSwapBuffers(_eglut->dpy, win->surface);
159
160   if (callback)
161      wl_callback_destroy(callback);
162
163   window->callback = wl_surface_frame(window->surface);
164   wl_callback_add_listener(window->callback, &frame_listener, window);
165}
166
167void
168_eglutNativeEventLoop(void)
169{
170   struct pollfd pollfd;
171   int ret;
172
173   draw(&window, NULL, 0);
174
175   pollfd.fd = wl_display_get_fd(display.display);
176   pollfd.events = POLLIN;
177   pollfd.revents = 0;
178
179   while (1) {
180      wl_display_dispatch_pending(display.display);
181
182      if (_eglut->idle_cb)
183         _eglut->idle_cb();
184
185      ret = wl_display_flush(display.display);
186      if (ret < 0 && errno == EAGAIN)
187         pollfd.events |= POLLOUT;
188      else if (ret < 0)
189         break;
190
191      if (poll(&pollfd, 1, _eglut->redisplay ? 0 : -1) == -1)
192         break;
193
194      if (pollfd.revents & (POLLERR | POLLHUP))
195         break;
196
197      if (pollfd.revents & POLLIN) {
198         ret = wl_display_dispatch(display.display);
199         if (ret == -1)
200            break;
201      }
202
203      if (pollfd.revents & POLLOUT) {
204         ret = wl_display_flush(display.display);
205         if (ret == 0)
206            pollfd.events &= ~POLLOUT;
207         else if (ret == -1 && errno != EAGAIN)
208            break;
209      }
210
211      if (_eglut->redisplay) {
212         struct eglut_window *win = _eglut->current;
213
214         _eglut->redisplay = 0;
215
216         if (win->display_cb)
217            win->display_cb();
218
219         eglSwapBuffers(_eglut->dpy, win->surface);
220      }
221   }
222}
223