aboutsummaryrefslogtreecommitdiff
path: root/src/x.c
diff options
context:
space:
mode:
authorallusive-dev <[email protected]>2023-09-19 17:46:20 +1000
committerallusive-dev <[email protected]>2023-09-19 17:46:20 +1000
commit5650d887357bf2a3fac8c5fd4f467bf8795b5fc4 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/x.c
parentUpdate picom.sample.conf (diff)
downloadcompfy-5650d887357bf2a3fac8c5fd4f467bf8795b5fc4.tar.xz
compfy-5650d887357bf2a3fac8c5fd4f467bf8795b5fc4.zip
reset
Diffstat (limited to 'src/x.c')
-rw-r--r--src/x.c748
1 files changed, 0 insertions, 748 deletions
diff --git a/src/x.c b/src/x.c
deleted file mode 100644
index c146f48..0000000
--- a/src/x.c
+++ /dev/null
@@ -1,748 +0,0 @@
-// SPDX-License-Identifier: MPL-2.0
-// Copyright (c) 2018 Yuxuan Shui <[email protected]>
-#include <stdalign.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include <X11/Xutil.h>
-#include <pixman.h>
-#include <xcb/composite.h>
-#include <xcb/damage.h>
-#include <xcb/glx.h>
-#include <xcb/render.h>
-#include <xcb/sync.h>
-#include <xcb/xcb.h>
-#include <xcb/xcb_renderutil.h>
-#include <xcb/xfixes.h>
-
-#include "atom.h"
-#ifdef CONFIG_OPENGL
-#include "backend/gl/glx.h"
-#endif
-#include "common.h"
-#include "compiler.h"
-#include "kernel.h"
-#include "log.h"
-#include "region.h"
-#include "utils.h"
-#include "x.h"
-
-/**
- * Get a specific attribute of a window.
- *
- * Returns a blank structure if the returned type and format does not
- * match the requested type and format.
- *
- * @param ps current session
- * @param w window
- * @param atom atom of attribute to fetch
- * @param length length to read
- * @param rtype atom of the requested type
- * @param rformat requested format
- * @return a <code>winprop_t</code> structure containing the attribute
- * and number of items. A blank one on failure.
- */
-winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom,
- int offset, int length, xcb_atom_t rtype, int rformat) {
- xcb_get_property_reply_t *r = xcb_get_property_reply(
- c,
- xcb_get_property(c, 0, w, atom, rtype, to_u32_checked(offset),
- to_u32_checked(length)),
- NULL);
-
- if (r && xcb_get_property_value_length(r) &&
- (rtype == XCB_GET_PROPERTY_TYPE_ANY || r->type == rtype) &&
- (!rformat || r->format == rformat) &&
- (r->format == 8 || r->format == 16 || r->format == 32)) {
- auto len = xcb_get_property_value_length(r);
- return (winprop_t){
- .ptr = xcb_get_property_value(r),
- .nitems = (ulong)(len / (r->format / 8)),
- .type = r->type,
- .format = r->format,
- .r = r,
- };
- }
-
- free(r);
- return (winprop_t){
- .ptr = NULL, .nitems = 0, .type = XCB_GET_PROPERTY_TYPE_ANY, .format = 0};
-}
-
-/// Get the type, format and size in bytes of a window's specific attribute.
-winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom) {
- xcb_generic_error_t *e = NULL;
- auto r = xcb_get_property_reply(
- c, xcb_get_property(c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e);
- if (!r) {
- log_debug_x_error(e, "Failed to get property info for window %#010x", w);
- free(e);
- return (winprop_info_t){
- .type = XCB_GET_PROPERTY_TYPE_ANY, .format = 0, .length = 0};
- }
-
- winprop_info_t winprop_info = {
- .type = r->type, .format = r->format, .length = r->bytes_after};
- free(r);
-
- return winprop_info;
-}
-
-/**
- * Get the value of a type-<code>xcb_window_t</code> property of a window.
- *
- * @return the value if successful, 0 otherwise
- */
-xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t aprop) {
- // Get the attribute
- xcb_window_t p = XCB_NONE;
- winprop_t prop = x_get_prop(c, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);
-
- // Return it
- if (prop.nitems) {
- p = (xcb_window_t)*prop.p32;
- }
-
- free_winprop(&prop);
-
- return p;
-}
-
-/**
- * Get the value of a text property of a window.
- */
-bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
- int *pnstr) {
- assert(ps->server_grabbed);
- auto prop_info = x_get_prop_info(ps->c, wid, prop);
- auto type = prop_info.type;
- auto format = prop_info.format;
- auto length = prop_info.length;
-
- if (type == XCB_ATOM_NONE) {
- return false;
- }
-
- if (type != XCB_ATOM_STRING && type != ps->atoms->aUTF8_STRING &&
- type != ps->atoms->aC_STRING) {
- log_warn("Text property %d of window %#010x has unsupported type: %d",
- prop, wid, type);
- return false;
- }
-
- if (format != 8) {
- log_warn("Text property %d of window %#010x has unexpected format: %d",
- prop, wid, format);
- return false;
- }
-
- xcb_generic_error_t *e = NULL;
- auto word_count = (length + 4 - 1) / 4;
- auto r = xcb_get_property_reply(
- ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, word_count), &e);
- if (!r) {
- log_debug_x_error(e, "Failed to get window property for %#010x", wid);
- free(e);
- return false;
- }
-
- assert(length == (uint32_t)xcb_get_property_value_length(r));
-
- void *data = xcb_get_property_value(r);
- unsigned int nstr = 0;
- uint32_t current_offset = 0;
- while (current_offset < length) {
- current_offset +=
- (uint32_t)strnlen(data + current_offset, length - current_offset) + 1;
- nstr += 1;
- }
-
- if (nstr == 0) {
- // The property is set to an empty string, in that case, we return one
- // string
- char **strlst = malloc(sizeof(char *));
- strlst[0] = "";
- *pnstr = 1;
- *pstrlst = strlst;
- free(r);
- return true;
- }
-
- // Allocate the pointers and the strings together
- void *buf = NULL;
- if (posix_memalign(&buf, alignof(char *), length + sizeof(char *) * nstr + 1) != 0) {
- abort();
- }
-
- char *strlst = buf + sizeof(char *) * nstr;
- memcpy(strlst, xcb_get_property_value(r), length);
- strlst[length] = '\0'; // X strings aren't guaranteed to be null terminated
-
- char **ret = buf;
- current_offset = 0;
- nstr = 0;
- while (current_offset < length) {
- ret[nstr] = strlst + current_offset;
- current_offset += (uint32_t)strlen(strlst + current_offset) + 1;
- nstr += 1;
- }
-
- *pnstr = to_int_checked(nstr);
- *pstrlst = ret;
- free(r);
- return true;
-}
-
-// A cache of pict formats. We assume they don't change during the lifetime
-// of this program
-static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL;
-
-static inline void x_get_server_pictfmts(xcb_connection_t *c) {
- if (g_pictfmts) {
- return;
- }
- xcb_generic_error_t *e = NULL;
- // Get window picture format
- g_pictfmts =
- xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), &e);
- if (e || !g_pictfmts) {
- log_fatal("failed to get pict formats\n");
- abort();
- }
-}
-
-const xcb_render_pictforminfo_t *
-x_get_pictform_for_visual(xcb_connection_t *c, xcb_visualid_t visual) {
- x_get_server_pictfmts(c);
-
- xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual);
- for (xcb_render_pictforminfo_iterator_t i =
- xcb_render_query_pict_formats_formats_iterator(g_pictfmts);
- i.rem; xcb_render_pictforminfo_next(&i)) {
- if (i.data->id == pv->format) {
- return i.data;
- }
- }
- return NULL;
-}
-
-static xcb_visualid_t attr_pure x_get_visual_for_pictfmt(xcb_render_query_pict_formats_reply_t *r,
- xcb_render_pictformat_t fmt) {
- for (auto screen = xcb_render_query_pict_formats_screens_iterator(r); screen.rem;
- xcb_render_pictscreen_next(&screen)) {
- for (auto depth = xcb_render_pictscreen_depths_iterator(screen.data);
- depth.rem; xcb_render_pictdepth_next(&depth)) {
- for (auto pv = xcb_render_pictdepth_visuals_iterator(depth.data);
- pv.rem; xcb_render_pictvisual_next(&pv)) {
- if (pv.data->format == fmt) {
- return pv.data->visual;
- }
- }
- }
- }
- return XCB_NONE;
-}
-
-xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
- x_get_server_pictfmts(c);
-
- auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
-
- return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id);
-}
-
-xcb_render_pictformat_t
-x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
- x_get_server_pictfmts(c);
-
- auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
-
- return pictfmt->id;
-}
-
-int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
- auto setup = xcb_get_setup(c);
- for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
- xcb_screen_next(&screen)) {
- for (auto depth = xcb_screen_allowed_depths_iterator(screen.data);
- depth.rem; xcb_depth_next(&depth)) {
- const int len = xcb_depth_visuals_length(depth.data);
- const xcb_visualtype_t *visuals = xcb_depth_visuals(depth.data);
- for (int i = 0; i < len; i++) {
- if (visual == visuals[i].visual_id) {
- return depth.data->depth;
- }
- }
- }
- }
- return -1;
-}
-
-xcb_render_picture_t
-x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
- const xcb_render_pictforminfo_t *pictfmt,
- xcb_pixmap_t pixmap, uint32_t valuemask,
- const xcb_render_create_picture_value_list_t *attr) {
- void *buf = NULL;
- if (attr) {
- xcb_render_create_picture_value_list_serialize(&buf, valuemask, attr);
- if (!buf) {
- log_error("failed to serialize picture attributes");
- return XCB_NONE;
- }
- }
-
- xcb_render_picture_t tmp_picture = x_new_id(c);
- xcb_generic_error_t *e =
- xcb_request_check(c, xcb_render_create_picture_checked(
- c, tmp_picture, pixmap, pictfmt->id, valuemask, buf));
- free(buf);
- if (e) {
- log_error_x_error(e, "failed to create picture");
- return XCB_NONE;
- }
- return tmp_picture;
-}
-
-xcb_render_picture_t
-x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visual,
- xcb_pixmap_t pixmap, uint32_t valuemask,
- const xcb_render_create_picture_value_list_t *attr) {
- const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual);
- return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
-}
-
-xcb_render_picture_t
-x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard_t standard,
- xcb_pixmap_t pixmap, uint32_t valuemask,
- const xcb_render_create_picture_value_list_t *attr) {
- x_get_server_pictfmts(c);
-
- auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
- assert(pictfmt);
- return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
-}
-
-xcb_render_picture_t
-x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
- xcb_pict_standard_t standard, uint32_t valuemask,
- const xcb_render_create_picture_value_list_t *attr) {
- x_get_server_pictfmts(c);
-
- auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
- assert(pictfmt);
- return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
-}
-
-/**
- * Create an picture.
- */
-xcb_render_picture_t
-x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
- const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
- const xcb_render_create_picture_value_list_t *attr) {
- uint8_t depth = pictfmt->depth;
-
- xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, w, h);
- if (!tmp_pixmap) {
- return XCB_NONE;
- }
-
- xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap(
- c, pictfmt, tmp_pixmap, valuemask, attr);
-
- xcb_free_pixmap(c, tmp_pixmap);
-
- return picture;
-}
-
-xcb_render_picture_t
-x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
- xcb_visualid_t visual, uint32_t valuemask,
- const xcb_render_create_picture_value_list_t *attr) {
- auto pictfmt = x_get_pictform_for_visual(c, visual);
- return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
-}
-
-bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_t *res) {
- xcb_generic_error_t *e = NULL;
- xcb_xfixes_fetch_region_reply_t *xr =
- xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region(c, r), &e);
- if (!xr) {
- log_error_x_error(e, "Failed to fetch rectangles");
- return false;
- }
-
- int nrect = xcb_xfixes_fetch_region_rectangles_length(xr);
- auto b = ccalloc(nrect, pixman_box32_t);
- xcb_rectangle_t *xrect = xcb_xfixes_fetch_region_rectangles(xr);
- for (int i = 0; i < nrect; i++) {
- b[i] = (pixman_box32_t){.x1 = xrect[i].x,
- .y1 = xrect[i].y,
- .x2 = xrect[i].x + xrect[i].width,
- .y2 = xrect[i].y + xrect[i].height};
- }
- bool ret = pixman_region32_init_rects(res, b, nrect);
- free(b);
- free(xr);
- return ret;
-}
-
-void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
- int16_t clip_x_origin, int16_t clip_y_origin,
- const region_t *reg) {
- int nrects;
- const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects);
- auto xrects = ccalloc(nrects, xcb_rectangle_t);
- for (int i = 0; i < nrects; i++) {
- xrects[i] = (xcb_rectangle_t){
- .x = to_i16_checked(rects[i].x1),
- .y = to_i16_checked(rects[i].y1),
- .width = to_u16_checked(rects[i].x2 - rects[i].x1),
- .height = to_u16_checked(rects[i].y2 - rects[i].y1),
- };
- }
-
- xcb_generic_error_t *e = xcb_request_check(
- c, xcb_render_set_picture_clip_rectangles_checked(
- c, pict, clip_x_origin, clip_y_origin, to_u32_checked(nrects), xrects));
- if (e) {
- log_error_x_error(e, "Failed to set clip region");
- free(e);
- }
- free(xrects);
-}
-
-void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) {
- xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE};
- xcb_generic_error_t *e = xcb_request_check(
- c, xcb_render_change_picture(c, pict, XCB_RENDER_CP_CLIP_MASK, &v));
- if (e) {
- log_error_x_error(e, "failed to clear clip region");
- free(e);
- }
-}
-
-enum {
- XSyncBadCounter = 0,
- XSyncBadAlarm = 1,
- XSyncBadFence = 2,
-};
-
-/**
- * Convert a X11 error to string
- *
- * @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used
- * for multiple calls to this function,
- */
-static const char *
-_x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code) {
- session_t *const ps = ps_g;
-
- int o = 0;
- const char *name = "Unknown";
-
-#define CASESTRRET(s) \
- case s: \
- name = #s; \
- break
-
-#define CASESTRRET2(s) \
- case XCB_##s: name = #s; break
-
- // TODO(yshui) separate error code out from session_t
- o = error_code - ps->xfixes_error;
- switch (o) { CASESTRRET2(XFIXES_BAD_REGION); }
-
- o = error_code - ps->damage_error;
- switch (o) { CASESTRRET2(DAMAGE_BAD_DAMAGE); }
-
- o = error_code - ps->render_error;
- switch (o) {
- CASESTRRET2(RENDER_PICT_FORMAT);
- CASESTRRET2(RENDER_PICTURE);
- CASESTRRET2(RENDER_PICT_OP);
- CASESTRRET2(RENDER_GLYPH_SET);
- CASESTRRET2(RENDER_GLYPH);
- }
-
- if (ps->glx_exists) {
- o = error_code - ps->glx_error;
- switch (o) {
- CASESTRRET2(GLX_BAD_CONTEXT);
- CASESTRRET2(GLX_BAD_CONTEXT_STATE);
- CASESTRRET2(GLX_BAD_DRAWABLE);
- CASESTRRET2(GLX_BAD_PIXMAP);
- CASESTRRET2(GLX_BAD_CONTEXT_TAG);
- CASESTRRET2(GLX_BAD_CURRENT_WINDOW);
- CASESTRRET2(GLX_BAD_RENDER_REQUEST);
- CASESTRRET2(GLX_BAD_LARGE_REQUEST);
- CASESTRRET2(GLX_UNSUPPORTED_PRIVATE_REQUEST);
- CASESTRRET2(GLX_BAD_FB_CONFIG);
- CASESTRRET2(GLX_BAD_PBUFFER);
- CASESTRRET2(GLX_BAD_CURRENT_DRAWABLE);
- CASESTRRET2(GLX_BAD_WINDOW);
- CASESTRRET2(GLX_GLX_BAD_PROFILE_ARB);
- }
- }
-
- if (ps->xsync_exists) {
- o = error_code - ps->xsync_error;
- switch (o) {
- CASESTRRET(XSyncBadCounter);
- CASESTRRET(XSyncBadAlarm);
- CASESTRRET(XSyncBadFence);
- }
- }
-
- switch (error_code) {
- CASESTRRET2(ACCESS);
- CASESTRRET2(ALLOC);
- CASESTRRET2(ATOM);
- CASESTRRET2(COLORMAP);
- CASESTRRET2(CURSOR);
- CASESTRRET2(DRAWABLE);
- CASESTRRET2(FONT);
- CASESTRRET2(G_CONTEXT);
- CASESTRRET2(ID_CHOICE);
- CASESTRRET2(IMPLEMENTATION);
- CASESTRRET2(LENGTH);
- CASESTRRET2(MATCH);
- CASESTRRET2(NAME);
- CASESTRRET2(PIXMAP);
- CASESTRRET2(REQUEST);
- CASESTRRET2(VALUE);
- CASESTRRET2(WINDOW);
- }
-
-#undef CASESTRRET
-#undef CASESTRRET2
-
- thread_local static char buffer[256];
- snprintf(buffer, sizeof(buffer), "X error %d %s request %d minor %d serial %lu",
- error_code, name, major, minor, serial);
- return buffer;
-}
-
-/**
- * Log a X11 error
- */
-void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code) {
- log_debug("%s", _x_strerror(serial, major, minor, error_code));
-}
-
-/*
- * Convert a xcb_generic_error_t to a string that describes the error
- *
- * @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used
- * for multiple calls to this function,
- */
-const char *x_strerror(xcb_generic_error_t *e) {
- if (!e) {
- return "No error";
- }
- return _x_strerror(e->full_sequence, e->major_code, e->minor_code, e->error_code);
-}
-
-/**
- * Create a pixmap and check that creation succeeded.
- */
-xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable,
- int width, int height) {
- xcb_pixmap_t pix = x_new_id(c);
- xcb_void_cookie_t cookie = xcb_create_pixmap_checked(
- c, depth, pix, drawable, to_u16_checked(width), to_u16_checked(height));
- xcb_generic_error_t *err = xcb_request_check(c, cookie);
- if (err == NULL) {
- return pix;
- }
-
- log_error_x_error(err, "Failed to create pixmap");
- free(err);
- return XCB_NONE;
-}
-
-/**
- * Validate a pixmap.
- *
- * Detect whether the pixmap is valid with XGetGeometry. Well, maybe there
- * are better ways.
- */
-bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) {
- if (pixmap == XCB_NONE) {
- return false;
- }
-
- auto r = xcb_get_geometry_reply(c, xcb_get_geometry(c, pixmap), NULL);
- if (!r) {
- return false;
- }
-
- bool ret = r->width && r->height;
- free(r);
- return ret;
-}
-/// Names of root window properties that could point to a pixmap of
-/// background.
-static const char *background_props_str[] = {
- "_XROOTPMAP_ID",
- "_XSETROOT_ID",
- 0,
-};
-
-xcb_pixmap_t
-x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms) {
- xcb_pixmap_t pixmap = XCB_NONE;
-
- // Get the values of background attributes
- for (int p = 0; background_props_str[p]; p++) {
- xcb_atom_t prop_atom = get_atom(atoms, background_props_str[p]);
- winprop_t prop = x_get_prop(c, root, prop_atom, 1, XCB_ATOM_PIXMAP, 32);
- if (prop.nitems) {
- pixmap = (xcb_pixmap_t)*prop.p32;
- free_winprop(&prop);
- break;
- }
- free_winprop(&prop);
- }
-
- return pixmap;
-}
-
-bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom) {
- for (int p = 0; background_props_str[p]; p++) {
- xcb_atom_t prop_atom = get_atom(atoms, background_props_str[p]);
- if (prop_atom == atom) {
- return true;
- }
- }
- return false;
-}
-
-/**
- * Synchronizes a X Render drawable to ensure all pending painting requests
- * are completed.
- */
-bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) {
- // TODO(richardgv): If everybody just follows the rules stated in X Sync
- // prototype, we need only one fence per screen, but let's stay a bit
- // cautious right now
-
- auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f));
- if (e) {
- log_error_x_error(e, "Failed to trigger the fence");
- goto err;
- }
-
- e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f));
- if (e) {
- log_error_x_error(e, "Failed to await on a fence");
- goto err;
- }
-
- e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f));
- if (e) {
- log_error_x_error(e, "Failed to reset the fence");
- goto err;
- }
- return true;
-
-err:
- free(e);
- return false;
-}
-
-// xcb-render specific macros
-#define XFIXED_TO_DOUBLE(value) (((double)(value)) / 65536)
-#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536))
-
-/**
- * Convert a struct conv to a X picture convolution filter, normalizing the kernel
- * in the process. Allow the caller to specify the element at the center of the kernel,
- * for compatibility with legacy code.
- *
- * @param[in] kernel the convolution kernel
- * @param[in] center the element to put at the center of the matrix
- * @param[inout] ret pointer to an array of `size`, if `size` is too small, more space
- * will be allocated, and `*ret` will be updated
- * @param[inout] size size of the array pointed to by `ret`, in number of elements
- * @return number of elements filled into `*ret`
- */
-void x_create_convolution_kernel(const conv *kernel, double center,
- struct x_convolution_kernel **ret) {
- assert(ret);
- if (!*ret || (*ret)->capacity < kernel->w * kernel->h + 2) {
- free(*ret);
- *ret =
- cvalloc(sizeof(struct x_convolution_kernel) +
- (size_t)(kernel->w * kernel->h + 2) * sizeof(xcb_render_fixed_t));
- (*ret)->capacity = kernel->w * kernel->h + 2;
- }
-
- (*ret)->size = kernel->w * kernel->h + 2;
-
- auto buf = (*ret)->kernel;
- buf[0] = DOUBLE_TO_XFIXED(kernel->w);
- buf[1] = DOUBLE_TO_XFIXED(kernel->h);
-
- double sum = center;
- for (int i = 0; i < kernel->w * kernel->h; i++) {
- if (i == kernel->w * kernel->h / 2) {
- continue;
- }
- sum += kernel->data[i];
- }
-
- // Note for floating points a / b != a * (1 / b), but this shouldn't have any real
- // impact on the result
- double factor = sum != 0 ? 1.0 / sum : 1;
- for (int i = 0; i < kernel->w * kernel->h; i++) {
- buf[i + 2] = DOUBLE_TO_XFIXED(kernel->data[i] * factor);
- }
-
- buf[kernel->h / 2 * kernel->w + kernel->w / 2 + 2] =
- DOUBLE_TO_XFIXED(center * factor);
-}
-
-/// Generate a search criteria for fbconfig from a X visual.
-/// Returns {-1, -1, -1, -1, -1, 0} on failure
-struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual) {
- auto pictfmt = x_get_pictform_for_visual(c, visual);
- auto depth = x_get_visual_depth(c, visual);
- if (!pictfmt || depth == -1) {
- log_error("Invalid visual %#03x", visual);
- return (struct xvisual_info){-1, -1, -1, -1, -1, 0};
- }
- if (pictfmt->type != XCB_RENDER_PICT_TYPE_DIRECT) {
- log_error("We cannot handle non-DirectColor visuals. Report an "
- "issue if you see this error message.");
- return (struct xvisual_info){-1, -1, -1, -1, -1, 0};
- }
-
- int red_size = popcntul(pictfmt->direct.red_mask),
- blue_size = popcntul(pictfmt->direct.blue_mask),
- green_size = popcntul(pictfmt->direct.green_mask),
- alpha_size = popcntul(pictfmt->direct.alpha_mask);
-
- return (struct xvisual_info){
- .red_size = red_size,
- .green_size = green_size,
- .blue_size = blue_size,
- .alpha_size = alpha_size,
- .visual_depth = depth,
- .visual = visual,
- };
-}
-
-xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) {
- xcb_screen_iterator_t iter;
-
- iter = xcb_setup_roots_iterator(xcb_get_setup(c));
- for (; iter.rem; --screen, xcb_screen_next(&iter)) {
- if (screen == 0) {
- return iter.data;
- }
- }
-
- return NULL;
-}