aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2023-11-12 12:38:56 +0100
committerFederico Angelilli <code@fedang.net>2023-11-12 12:38:56 +0100
commit965ce846f4d209866ea3a59a3589f6405fa5b91d (patch)
tree85582d0d34cd656bf8e63d2c8bc0d6cc4d4df887
parent3868d1918c76e963a077ca0a56ef7de7409beb05 (diff)
Add xcb event loop using glib's mainloop
-rw-r--r--Makefile14
-rw-r--r--comet.c31
-rw-r--r--x11.c94
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 <stdbool.h>
-#include <assert.h>
#include <glib.h>
#include <math.h>
#include <cairo.h>
@@ -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);