diff options
author | kotontrion <[email protected]> | 2024-06-09 20:27:00 +0200 |
---|---|---|
committer | kotontrion <[email protected]> | 2024-06-09 20:27:00 +0200 |
commit | 29b1060c6fc2614dcbfe6edc177944a31f4decd6 (patch) | |
tree | 5e0b0305206f6499edeffe5152267e4ad96b88b0 /src/wayland-source.c |
initial commit
Diffstat (limited to 'src/wayland-source.c')
-rw-r--r-- | src/wayland-source.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/wayland-source.c b/src/wayland-source.c new file mode 100644 index 0000000..d984c2e --- /dev/null +++ b/src/wayland-source.c @@ -0,0 +1,114 @@ + +#include <errno.h> +#include <glib.h> +#include <wayland-client.h> +#include "wayland-source.h" + +struct _WLSource { + GSource source; + struct wl_display *display; + gpointer fd; + int error; +}; + +static gboolean wl_source_prepare(GSource *source, + gint *timeout) { + WLSource *self = (WLSource *)source; + + *timeout = 0; + if (wl_display_prepare_read(self->display) != 0) + return TRUE; + else if (wl_display_flush(self->display) < 0) { + self->error = errno; + return TRUE; + } + *timeout = -1; + return FALSE; +} + +static gboolean wl_source_check(GSource *source) { + WLSource *self = (WLSource *)source; + + if (self->error > 0) + return TRUE; + + GIOCondition revents; + revents = g_source_query_unix_fd(source, self->fd); + + if (revents & G_IO_IN) { + if (wl_display_read_events(self->display) < 0) + self->error = errno; + } + else + wl_display_cancel_read(self->display); + + return revents > 0; +} + +static gboolean wl_source_dispatch(GSource *source, + GSourceFunc callback, + gpointer user_data) { + WLSource *self = (WLSource *)source; + GIOCondition revents; + + revents = g_source_query_unix_fd(source, self->fd); + if ((self->error > 0) || (revents & (G_IO_ERR | G_IO_HUP))) { + errno = self->error; + self->error = 0; + if ( callback != NULL ) + return callback(user_data); + return G_SOURCE_REMOVE; + } + + if (wl_display_dispatch_pending(self->display) < 0) { + if ( callback != NULL ) + return callback(user_data); + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +static void wl_source_finalize(GSource *source) { + WLSource *self = (WLSource *)source; + wl_display_disconnect(self->display); +} + +static GSourceFuncs wl_source_funcs = { + .prepare = wl_source_prepare, + .check = wl_source_check, + .dispatch = wl_source_dispatch, + .finalize = wl_source_finalize, +}; + +WLSource* wl_source_new() { + struct wl_display *display; + WLSource *self; + GSource *source; + + display = wl_display_connect(NULL); + if (display == NULL) + return NULL; + + source = g_source_new(&wl_source_funcs, sizeof(WLSource)); + self = (WLSource *)source; + self->display = display; + + self->fd = g_source_add_unix_fd(source, + wl_display_get_fd(self->display), + G_IO_IN | G_IO_ERR | G_IO_HUP); + + g_source_attach(source, NULL); + + return self; +} + +void wl_source_free(WLSource *self) { + GSource * source = (GSource *)self; + g_source_destroy(source); + g_source_unref(source); +} + +struct wl_display* wl_source_get_display(WLSource *self) { + return self->display; +} |