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, ®istry_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