window: Stop using glib mainloop in toy toolkit
diff --git a/clients/window.c b/clients/window.c
index 48b444a..e7a61ef 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -32,9 +32,9 @@
#include <time.h>
#include <cairo.h>
#include <glib.h>
-#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <sys/mman.h>
+#include <sys/epoll.h>
#include <wayland-egl.h>
@@ -51,7 +51,6 @@
#include <linux/input.h>
#include "wayland-util.h"
#include "wayland-client.h"
-#include "wayland-glib.h"
#include "cairo-util.h"
#include "window.h"
@@ -68,9 +67,14 @@
EGLConfig premultiplied_argb_config;
EGLContext ctx;
cairo_device_t *device;
- int fd;
- GMainLoop *loop;
- GSource *source;
+
+ int display_fd;
+ uint32_t mask;
+ struct task display_task;
+
+ int epoll_fd;
+ struct wl_list deferred_list;
+
struct wl_list window_list;
struct wl_list input_list;
char *device_name;
@@ -99,6 +103,7 @@
int x, y;
int resize_edges;
int redraw_scheduled;
+ struct task redraw_task;
int minimum_width, minimum_height;
int margin;
int type;
@@ -1374,23 +1379,22 @@
}
}
-static gboolean
-idle_redraw(void *data)
+static void
+idle_redraw(struct task *task, uint32_t events)
{
- struct window *window = data;
+ struct window *window =
+ container_of(task, struct window, redraw_task);
window->redraw_handler(window, window->user_data);
-
window->redraw_scheduled = 0;
-
- return FALSE;
}
void
window_schedule_redraw(struct window *window)
{
if (!window->redraw_scheduled) {
- g_idle_add(idle_redraw, window);
+ window->redraw_task.run = idle_redraw;
+ display_defer(window->display, &window->redraw_task);
window->redraw_scheduled = 1;
}
}
@@ -1927,6 +1931,25 @@
return 0;
}
+static int
+event_mask_update(uint32_t mask, void *data)
+{
+ struct display *d = data;
+
+ d->mask = mask;
+
+ return 0;
+}
+
+static void
+handle_display_data(struct task *task, uint32_t events)
+{
+ struct display *display =
+ container_of(task, struct display, display_task);
+
+ wl_display_iterate(display->display, display->mask);
+}
+
struct display *
display_create(int *argc, char **argv[], const GOptionEntry *option_entries)
{
@@ -1967,6 +1990,12 @@
return NULL;
}
+ d->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ d->display_fd = wl_display_get_fd(d->display, event_mask_update, d);
+ d->display_task.run = handle_display_data;
+ display_watch_fd(d, d->display_fd, EPOLLIN, &d->display_task);
+
+ wl_list_init(&d->deferred_list);
wl_list_init(&d->input_list);
/* Set up listener so we'll catch all events. */
@@ -1987,10 +2016,6 @@
display_render_frame(d);
- d->loop = g_main_loop_new(NULL, FALSE);
- d->source = wl_glib_source_new(d->display);
- g_source_attach(d->source, NULL);
-
wl_list_init(&d->window_list);
init_xkb(d);
@@ -2060,7 +2085,46 @@
}
void
-display_run(struct display *d)
+display_defer(struct display *display, struct task *task)
{
- g_main_loop_run(d->loop);
+ wl_list_insert(&display->deferred_list, &task->link);
+}
+
+void
+display_watch_fd(struct display *display,
+ int fd, uint32_t events, struct task *task)
+{
+ struct epoll_event ep;
+
+ ep.events = events;
+ ep.data.ptr = task;
+ epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep);
+}
+
+void
+display_run(struct display *display)
+{
+ struct task *task;
+ struct epoll_event ep[16];
+ int i, count;
+
+ while (1) {
+ while (display->mask & WL_DISPLAY_WRITABLE)
+ wl_display_iterate(display->display,
+ WL_DISPLAY_WRITABLE);
+
+ count = epoll_wait(display->epoll_fd,
+ ep, ARRAY_LENGTH(ep), -1);
+ for (i = 0; i < count; i++) {
+ task = ep[i].data.ptr;
+ task->run(task, ep[i].events);
+ }
+
+ while (!wl_list_empty(&display->deferred_list)) {
+ task = container_of(display->deferred_list.next,
+ struct task, link);
+ wl_list_remove(&task->link);
+ task->run(task, 0);
+ }
+ }
}