aboutsummaryrefslogtreecommitdiff
path: root/x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11.c')
-rw-r--r--x11.c559
1 files changed, 0 insertions, 559 deletions
diff --git a/x11.c b/x11.c
deleted file mode 100644
index beb65b8..0000000
--- a/x11.c
+++ /dev/null
@@ -1,559 +0,0 @@
-#include <glib.h>
-#include <unistd.h>
-#include <math.h>
-#include <cairo.h>
-#include <cairo-xcb.h>
-#include <xcb/xcb.h>
-#include <xcb/xproto.h>
-#include <xcb/xcb_aux.h>
-#include <xcb/xcb_icccm.h>
-#include <xcb/xcb_ewmh.h>
-#include <xcb/xcb_xrm.h>
-#include <xcb/xcb_errors.h>
-#include <xcb/randr.h>
-#include <xcb/shape.h>
-
-#include "x11.h"
-#include "log.h"
-
-// TODO: Event logic should be decoupled from Window logic
-#include "draw.h"
-
-struct Window {
- xcb_connection_t *connection;
- xcb_screen_t *screen;
- xcb_randr_screen_size_t *screen_size;
- xcb_xrm_database_t *database;
- xcb_errors_context_t *errors;
- xcb_drawable_t window;
- xcb_visualtype_t *visual_type;
- xcb_ewmh_connection_t ewmh;
- cairo_surface_t *surface;
- cairo_t *cr;
- double dpi;
- int x, y;
- int width, height;
- GSource *source;
-};
-
-typedef struct {
- GSource source;
- Window *win;
- xcb_generic_event_t *event;
-} XcbSource;
-
-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);
- g_assert_nonnull(callback);
- g_assert_nonnull(data);
-
- Window *win = (Window *)data;
-
- do {
- switch (xsource->event->response_type & ~0x80) {
- case 0: {
- xcb_generic_error_t *error = (xcb_generic_error_t *)xsource->event;
-
- const char *extension;
- const char *name = xcb_errors_get_name_for_error(win->errors, error->error_code, &extension);
- const char *major = xcb_errors_get_name_for_major_code(win->errors, error->major_code);
- const char *minor = xcb_errors_get_name_for_minor_code(win->errors, error->major_code, error->minor_code);
-
- // TODO: Handle errors instead of aborting
- log_error("Xcb error '%s' [extension=%s, major=%s, minor=%s, resource=%u, sequence=%u]",
- name,
- extension ? extension : "none",
- major,
- minor ? minor : "none",
- (unsigned int)error->resource_id,
- (unsigned int)error->sequence);
- break;
- }
-
- case XCB_EXPOSE: {
- xcb_expose_event_t *expose = (xcb_expose_event_t *)xsource->event;
- log_debug("Processing event 'Expose' [type=%d]", XCB_EXPOSE);
-
- // Redraw
- callback(data);
- break;
- }
-
- case XCB_BUTTON_RELEASE: {
- log_debug("Mouse event");
- break;
- }
-
- case XCB_PROPERTY_NOTIFY: {
- xcb_property_notify_event_t *property = (xcb_property_notify_event_t *)xsource->event;
- log_debug("Processing event 'PropertyNotify' [type=%d]", XCB_PROPERTY_NOTIFY);
-
- if (property->atom == XCB_ATOM_RESOURCE_MANAGER) {
- window_update_scale(data);
-
- // Redraw
- callback(data);
- }
- break;
- }
-
- default: {
- const char *extension;
- const char *name = xcb_errors_get_name_for_xcb_event(win->errors, xsource->event, &extension);
-
- log_debug("Ignoring event '%s' [extension=%s, type=%d]",
- name,
- extension ? extension : "none",
- xsource->event->response_type & 0x7f);
- }
- }
- } 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 = {
- NULL,
- xcb_source_check,
- xcb_source_dispatch,
- xcb_source_finalize,
-};
-
-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_static_name(win->source, "XcbSource");
-
- // TODO: Draw should be decoupled from this file
- g_source_set_callback(win->source, G_SOURCE_FUNC(draw), win, NULL);
-
- 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, NULL);
-}
-
-static bool query_xrm(Window *win, const char *res, char **value)
-{
- if (xcb_xrm_resource_get_string(win->database,res, res, value) >= 0) {
- log_debug("Xrm query '%s' found '%s'", res, *value);
- return true;
- }
-
- log_debug("Xrm query '%s' not found", res);
- return false;
-}
-
-static xcb_atom_t intern_atom(Window *win, const char *atom)
-{
- xcb_generic_error_t *error;
- xcb_intern_atom_cookie_t cookie = xcb_intern_atom(win->connection, false, strlen(atom), atom);
- xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(win->connection, cookie, &error);
-
- g_assert_null(error);
- xcb_atom_t id = reply->atom;
- g_free(reply);
- return id;
-}
-
-static void wm_set_size(Window *win)
-{
- xcb_size_hints_t hints;
- xcb_icccm_size_hints_set_size(&hints, false, win->width, win->height);
- xcb_icccm_size_hints_set_min_size(&hints, win->width, win->height);
- xcb_icccm_size_hints_set_max_size(&hints, win->width, win->height);
- xcb_icccm_size_hints_set_base_size(&hints, win->width, win->height);
- xcb_icccm_size_hints_set_position(&hints, false, win->x, win->y);
-
- xcb_icccm_set_wm_size_hints(win->connection, win->window, XCB_ATOM_WM_NORMAL_HINTS, &hints);
- log_debug("Xcb icccm updated size hints");
-}
-
-static void wm_set_struts(Window *win)
-{
- const uint32_t end = MAX(0, win->x + win->width - 1);
-
- const uint32_t values[12] = {
- 0, 0, win->height, 0, // left, right, top, bottom
- 0, 0, 0, 0, // left y0, left y1, right y0, right y1
- win->x, end, 0, 0, // top y0, top y1, bottom y0, bottom y1
- };
-
- xcb_change_property(win->connection,
- XCB_PROP_MODE_REPLACE,
- win->window,
- win->ewmh._NET_WM_STRUT,
- XCB_ATOM_CARDINAL,
- 32,
- 4,
- values);
-
- xcb_change_property(win->connection,
- XCB_PROP_MODE_REPLACE,
- win->window,
- win->ewmh._NET_WM_STRUT_PARTIAL,
- XCB_ATOM_CARDINAL,
- 32,
- 12,
- values);
-
- log_debug("Xcb ewmh struts updated");
-}
-
-static void wm_setup(Window *win)
-{
- const char *title = "comet";
- xcb_icccm_set_wm_name(win->connection, win->window, XCB_ATOM_STRING, 8, strlen(title), title);
- log_debug("Window updated title [%s]", title);
-
- const char class[] = "comet\0Comet";
- xcb_icccm_set_wm_class(win->connection, win->window, strlen(class), class);
- log_debug("Window updated class [%s]", "comet\\0Comet");
-
- xcb_generic_error_t *error;
- xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(win->connection, &win->ewmh);
-
- g_assert_true(xcb_ewmh_init_atoms_replies(&win->ewmh, ewmh_cookie, &error));
- g_assert_null(error);
- log_debug("Xcb ewmh connected");
-
- xcb_ewmh_set_wm_window_type(&win->ewmh, win->window, 1, &win->ewmh._NET_WM_WINDOW_TYPE_DOCK);
-
- xcb_atom_t state[] = {
- win->ewmh._NET_WM_STATE_STICKY,
- win->ewmh._NET_WM_STATE_ABOVE
- };
- xcb_ewmh_set_wm_state(&win->ewmh, win->window, G_N_ELEMENTS(state), state);
-
- xcb_ewmh_set_wm_desktop(&win->ewmh, win->window, 0xFFFFFFFF);
-
- xcb_ewmh_set_wm_pid(&win->ewmh, win->window, getpid());
-
- wm_set_size(win);
-
- wm_set_struts(win);
-}
-
-Window *window_create(void)
-{
- Window *win = g_malloc0(sizeof(Window));
-
- int preferred_screen = 0;
- win->connection = xcb_connect(NULL, &preferred_screen);
- g_assert_true(win->connection != NULL && !xcb_connection_has_error(win->connection));
- log_debug("Xcb connected");
-
- xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(win->connection));
- log_debug("Default screen %d", preferred_screen);
-
- while (preferred_screen != 0 && iter.rem) {
- xcb_screen_next(&iter);
- preferred_screen--;
- }
-
- win->screen = iter.data;
-
- xcb_randr_query_version_cookie_t version_cookie = xcb_randr_query_version(win->connection,
- XCB_RANDR_MAJOR_VERSION,
- XCB_RANDR_MINOR_VERSION);
-
- xcb_generic_error_t *error;
- xcb_randr_query_version_reply_t *randr_version = xcb_randr_query_version_reply(win->connection,
- version_cookie,
- &error);
-
- g_assert_null(error);
- log_debug("RandR loaded [version=%d.%d]", randr_version->major_version, randr_version->minor_version);
- g_assert_cmpint(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);
- g_assert_null(error);
-
- win->screen_size = xcb_randr_get_screen_info_sizes(info_reply);
- g_assert_nonnull(win->screen_size);
- log_debug("Screen size [width=%d, height=%d]", win->screen_size->width, win->screen_size->height);
-
- win->width = win->height = 0;
- win->x = win->y = 0;
-
- xcb_randr_select_input(win->connection,
- win->screen->root,
- XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
- XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
- XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
-
- win->database = xcb_xrm_database_from_default(win->connection);
- g_assert_nonnull(win->database);
-
- window_update_scale(win);
-
- g_assert(xcb_errors_context_new(win->connection, &win->errors) == 0);
- log_debug("Xcb errors loaded");
-
- xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(win->screen);
- while (depth_iter.rem) {
- xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
-
- while (visual_iter.rem) {
- if (win->screen->root_visual == visual_iter.data->visual_id) {
- win->visual_type = visual_iter.data;
- goto found_visual;
- }
- xcb_visualtype_next(&visual_iter);
- }
- xcb_depth_next(&depth_iter);
- }
-
-found_visual:
- log_debug("Xcb visual type found [id=%u]", win->visual_type->visual_id);
-
- const uint32_t value_mask = XCB_CW_BACK_PIXMAP | XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL
- | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
-
- const uint32_t event_mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY
- | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_FOCUS_CHANGE
- | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS;
-
- xcb_colormap_t colormap = xcb_generate_id(win->connection);
- xcb_create_colormap(win->connection, XCB_COLORMAP_ALLOC_NONE, colormap, win->screen->root, win->visual_type->visual_id);
- log_debug("Xcb colormap created [id=%u]", colormap);
-
- const uint32_t value_list[] = {
- XCB_NONE, // back pixmap
- 0x000000, // back pixel
- 0x000000, // border pixel
- true, // override redirect
- event_mask, // event mask
- colormap // colormap
- };
-
- win->width = win->height = 1;
- log_debug("Window temporary size [width=%d, height=%d]", win->width, win->height);
-
- win->x = win->y = 0;
- log_debug("Window temporary position [x=%d, y=%d]", win->x, win->y);
-
- win->window = xcb_generate_id(win->connection);
- xcb_create_window(win->connection,
- XCB_COPY_FROM_PARENT,
- win->window, win->screen->root,
- win->x, win->y,
- win->width, win->height,
- 0, // border
- XCB_WINDOW_CLASS_INPUT_OUTPUT,
- win->screen->root_visual,
- value_mask,
- value_list);
-
- log_debug("Xcb window created [id=%u]", win->window);
-
- wm_setup(win);
- log_debug("Window wm options completed");
-
- xcb_map_window(win->connection, win->window);
- xcb_flush(win->connection);
- log_debug("Xcb initialized");
-
- win->surface = cairo_xcb_surface_create(win->connection,
- win->window,
- win->visual_type,
- win->screen_size->width,
- win->screen_size->height);
-
- g_assert_cmpint(cairo_surface_status(win->surface), ==, CAIRO_STATUS_SUCCESS);
- log_debug("Cairo surface created");
-
- win->cr = cairo_create(win->surface);
- g_assert_cmpint(cairo_status(win->cr), ==, CAIRO_STATUS_SUCCESS);
- log_debug("Cairo context created");
-
-
- attach_source(win);
- log_debug("Xcb event loop attached");
-
- return win;
-}
-
-cairo_t *window_get_context(Window *win)
-{
- return win->cr;
-}
-
-void window_update_scale(Window *win)
-{
- const char *dpi_res = "Xft.dpi";
- char *dpi_value;
-
- if (query_xrm(win, dpi_res, &dpi_value)) {
- win->dpi = strtod(dpi_value, NULL);
- g_free(dpi_value);
- } else {
- win->dpi = (double)win->screen_size->height * 25.4 / (double)win->screen_size->mheight;
- log_debug("Fallback dpi value '%.2lf'", win->dpi);
- }
-}
-
-double window_get_scale(Window *win)
-{
- return MAX(1, win->dpi/96.);
-}
-
-void window_get_screen_size(Window *win, int *width, int *height)
-{
- *width = win->screen_size->width;
- *height = win->screen_size->height;
-}
-
-void window_set_opacity(Window *win, double alpha)
-{
- // Value between 0 and 1
- g_assert_true(alpha >= 0 && alpha <= 1);
- unsigned long opacity = 0xffffffff * alpha;
-
- xcb_atom_t _NET_WM_WINDOW_OPACITY = intern_atom(win, "_NET_WM_WINDOW_OPACITY");
- xcb_change_property(win->connection,
- XCB_PROP_MODE_REPLACE,
- win->window,
- _NET_WM_WINDOW_OPACITY,
- XCB_ATOM_CARDINAL,
- 32,
- 1,
- (char *)&opacity);
-
- log_debug("Window updated opacity [%.2lf%%]", alpha * 100.0);
-
-}
-
-void window_move(Window *win, int x, int y)
-{
- if (win->x == x && win->y == y) return;
-
- win->x = x;
- win->y = y;
-
- const uint32_t values[] = { x, y };
- xcb_configure_window(win->connection,
- win->window,
- XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
- values);
-
- log_debug("Window updated position [x=%d, y=%d]", win->x, win->y);
-}
-
-void window_resize(Window *win, int width, int height)
-{
- if (win->width == width && win->height == height) return;
-
- win->width = width;
- win->height = height;
-
- const uint32_t values[] = { width, height };
- xcb_configure_window(win->connection,
- win->window,
- XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
- values);
-
- log_debug("Window updated size [width=%d, height=%d]", win->width, win->height);
-
- wm_set_size(win);
-}
-
-static void window_paint_corners(Window *win)
-{
- // TODO: Actually make this a parameter
- int radius = win->height / 2;
- double degree = M_PI / 180.0;
-
- // TODO: Check this value
- int depth = 1;
-
- xcb_pixmap_t bitmap = xcb_generate_id(win->connection);
- xcb_create_pixmap(win->connection, depth, bitmap, win->window, win->width, win->height);
- log_debug("Xcb pixmap created [id=%u]", bitmap);
-
- cairo_surface_t *surface = cairo_xcb_surface_create_for_bitmap(win->connection,
- win->screen,
- bitmap,
- win->width,
- win->height);
-
- cairo_t *cr = cairo_create(surface);
-
- // TODO: Fix antialiasing situation
- //cairo_set_antialias(cr, CAIRO_ANTIALIAS_GOOD);
-
- cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-
- cairo_set_source_rgba(cr, 0, 0, 0, 0);
- cairo_paint(cr);
-
- // TODO: Decouple somewhat drawing and X11
- cairo_set_source_rgba(cr, 1, 1, 1, 1);
- cairo_arc(cr, radius, radius, radius, 90.0 * degree, 270 * degree);
- cairo_arc(cr, win->width - radius, radius, radius, 270 * degree, 450 * degree);
- cairo_fill(cr);
-
- log_debug("Xcb shape painted");
-
- cairo_show_page(cr);
- cairo_destroy(cr);
- cairo_surface_flush(surface);
- cairo_surface_destroy(surface);
-
- xcb_shape_mask(win->connection, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, win->window, 0, 0, bitmap);
- xcb_shape_select_input(win->connection, win->window, XCB_SHAPE_NOTIFY);
- log_debug("Xcb shape mask configured");
-
- xcb_free_pixmap(win->connection, bitmap);
-}
-
-void window_paint_surface(Window *win, cairo_surface_t *surface, int width, int height)
-{
- cairo_xcb_surface_set_size(win->surface, width, height);
- xcb_clear_area(win->connection, false, win->window, 0, 0, 0, 0);
-
- cairo_set_source_surface(win->cr, surface, 0, 0);
- cairo_paint(win->cr);
- cairo_show_page(win->cr);
-
- window_paint_corners(win);
-
- xcb_circulate_window(win->connection, XCB_CIRCULATE_RAISE_LOWEST, win->window);
- xcb_flush(win->connection);
-}
-
-void window_destroy(Window *win)
-{
- g_source_destroy(win->source);
- g_source_unref(win->source);
-
- cairo_destroy(win->cr);
- cairo_surface_destroy(win->surface);
-
- xcb_ewmh_connection_wipe(&win->ewmh);
- xcb_errors_context_free(win->errors);
- xcb_xrm_database_free(win->database);
- xcb_disconnect(win->connection);
- g_free(win);
-}
-
-// vim: ts=4 sw=4 et