aboutsummaryrefslogtreecommitdiff
path: root/x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11.c')
-rw-r--r--x11.c94
1 files changed, 86 insertions, 8 deletions
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);