From 965ce846f4d209866ea3a59a3589f6405fa5b91d Mon Sep 17 00:00:00 2001 From: Federico Angelilli Date: Sun, 12 Nov 2023 12:38:56 +0100 Subject: Add xcb event loop using glib's mainloop --- Makefile | 14 +++++----- comet.c | 31 +++++++++++++++++++-- x11.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 123 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 0494403..2e62337 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,14 @@ OBJ = $(SRC:.c=.o) BIN = comet.bin DEPS = cairo \ - xcb \ - xcb-icccm \ - xcb-xrm \ - xcb-randr \ - glib-2.0 -CFLAGS := $(shell pkg-config --cflags $(DEPS)) + xcb \ + xcb-icccm \ + xcb-xrm \ + "xcb-randr >= 1.5" \ + "glib-2.0 >= 2.44" \ + gio-2.0 + +CFLAGS := $(shell pkg-config --cflags $(DEPS)) -ggdb LDFLAGS := $(shell pkg-config --libs $(DEPS)) -lm all: $(BIN) diff --git a/comet.c b/comet.c index b125d78..40a302d 100644 --- a/comet.c +++ b/comet.c @@ -5,14 +5,41 @@ #include "log.h" #include "draw.h" + GMainLoop *mainloop = NULL; + +static gboolean mainloop_quit(gpointer data) +{ + g_main_loop_quit(mainloop); + return G_SOURCE_CONTINUE; +} + +static gboolean mainloop_do(gpointer data) +{ + draw(data); + return G_SOURCE_REMOVE; +} + int main(int argc, char **argv) { log_init(G_LOG_LEVEL_DEBUG); + mainloop = g_main_loop_new(g_main_context_default(), FALSE); + Window *win = window_create(); - draw(win); - sleep(10); + guint source_term = g_unix_signal_add(SIGTERM, mainloop_quit, mainloop); + guint source_int = g_unix_signal_add(SIGINT, mainloop_quit, mainloop); + + guint id = g_timeout_add(100, mainloop_do, win); + + log_debug("Starting main loop"); + g_main_loop_run(mainloop); + + log_debug("Cleaning main loop"); + g_clear_pointer(&mainloop, g_main_loop_unref); + + g_source_remove(source_term); + g_source_remove(source_int); window_destroy(win); return 0; diff --git a/x11.c b/x11.c index 92e8680..7d59038 100644 --- a/x11.c +++ b/x11.c @@ -1,5 +1,3 @@ -#include -#include #include #include #include @@ -28,8 +26,15 @@ struct Window { uint16_t screen_height; int x, y; int width, height; + GSource *source; }; +typedef struct { + GSource source; + Window *win; + xcb_generic_event_t *event; +} XcbSource; + static xcb_atom_t intern_atom(Window *win, const char *atom) { // TODO: Error handling @@ -37,13 +42,80 @@ static xcb_atom_t intern_atom(Window *win, const char *atom) return xcb_intern_atom_reply(win->connection, cookie, NULL)->atom; } +static gboolean xcb_source_prepare(GSource *source, gint *timeout) +{ + // Always ready to poll + if (timeout) *timeout = -1; + return G_SOURCE_REMOVE; +} + +static gboolean xcb_source_check(GSource *source) +{ + XcbSource *xsource = (XcbSource *)source; + g_assert_null(xsource->event); + xsource->event = xcb_poll_for_event(xsource->win->connection); + return xsource->event != NULL; +} + +static gboolean xcb_source_dispatch(GSource *source, GSourceFunc callback, gpointer data) +{ + XcbSource *xsource = (XcbSource *)source; + g_assert_nonnull(xsource->event); + + do { + switch (xsource->event->response_type & ~0x80) { + case 0: + log_debug("Error in Xcb event loop"); + break; + + case XCB_BUTTON_PRESS: { + log_debug("Keypress event"); + break; + } + + default: { + log_debug("Ignoring event '%d'", xsource->event->response_type); + } + } + } while ((xsource->event = xcb_poll_for_event(xsource->win->connection)) != NULL); + + return G_SOURCE_CONTINUE; +} + +static void xcb_source_finalize(GSource *source) +{ + log_debug("Xcb event loop finalized"); +} + +static GSourceFuncs source_fns = { + xcb_source_prepare, + xcb_source_check, + xcb_source_dispatch, + xcb_source_finalize, + NULL, + NULL, +}; + +static void attach_source(Window *win) +{ + XcbSource *source = (XcbSource *)g_source_new(&source_fns, sizeof(XcbSource)); + source->win = win; + source->event = NULL; + + win->source = (GSource *)source; + g_source_set_name(win->source, "XcbSource"); + + g_source_add_unix_fd(win->source, xcb_get_file_descriptor(win->connection), G_IO_IN | G_IO_HUP | G_IO_ERR); + g_source_attach(win->source, g_main_context_default()); +} + Window *window_create(void) { Window *win = g_malloc0(sizeof(Window)); int preferred_screen = 0; win->connection = xcb_connect(NULL, &preferred_screen); - assert(win->connection != NULL && !xcb_connection_has_error(win->connection)); + g_assert_true(win->connection != NULL && !xcb_connection_has_error(win->connection)); log_debug("Xcb established connection"); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(win->connection)); @@ -66,11 +138,11 @@ Window *window_create(void) &error); log_debug("RandR version %d.%d", randr_version->major_version, randr_version->minor_version); - assert(error == NULL || randr_version->major_version < 1); + g_assert_true(error == NULL || randr_version->major_version < 1); xcb_randr_get_screen_info_cookie_t cookie = xcb_randr_get_screen_info(win->connection, win->screen->root); xcb_randr_get_screen_info_reply_t *info_reply = xcb_randr_get_screen_info_reply(win->connection, cookie, &error); - assert(error == NULL); + g_assert_null(error); xcb_randr_screen_size_t *screen_size = xcb_randr_get_screen_info_sizes(info_reply); log_debug("Screen size [width=%d, height=%d]", screen_size->width, screen_size->height); @@ -88,7 +160,7 @@ Window *window_create(void) XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); win->database = xcb_xrm_database_from_default(win->connection); - assert(win->database != NULL); + g_assert_nonnull(win->database); char *dpi_value; if (xcb_xrm_resource_get_string(win->database, "Xft.dpi", "Xft.dpi", &dpi_value) >= 0) { @@ -193,13 +265,16 @@ found_visual: screen_size->width, screen_size->height); - assert(cairo_surface_status(win->surface) == CAIRO_STATUS_SUCCESS); + g_assert_cmpint(cairo_surface_status(win->surface), ==, CAIRO_STATUS_SUCCESS); win->cr = cairo_create(win->surface); - assert(cairo_status(win->cr) == CAIRO_STATUS_SUCCESS); + g_assert_cmpint(cairo_status(win->cr), ==, CAIRO_STATUS_SUCCESS); log_debug("Cairo initialized"); + attach_source(win); + log_debug("Xcb event loop attached"); + return win; } @@ -265,6 +340,9 @@ void window_paint_surface(Window *win, cairo_surface_t *surface, int width, int void window_destroy(Window *win) { + g_source_destroy(win->source); + g_source_unref(win->source); + cairo_destroy(win->cr); cairo_surface_destroy(win->surface); -- cgit v1.2.3