Merge pull request #516 from yshui/no-xlib

x: remove the last bit of Xlib dependency
This commit is contained in:
yshui 2020-10-23 14:19:00 +01:00 committed by GitHub
commit 6c6b1afeb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 186 additions and 60 deletions

View File

@ -14,3 +14,6 @@ Checks: >
-readability-magic-numbers
AnalyzeTemporaryDtors: false
FormatStyle: file
CheckOptions:
- key: readability-magic-numbers.IgnoredIntegerValues
value: 4;8;16;24;32;1;2;3;4096

View File

@ -30,7 +30,8 @@ struct atom *init_atoms(xcb_connection_t *c) {
auto atoms = ccalloc(1, struct atom);
atoms->c = new_cache((void *)c, atom_getter, NULL);
#define ATOM_GET(x) atoms->a##x = (xcb_atom_t)(intptr_t)cache_get(atoms->c, #x, NULL)
LIST_APPLY(ATOM_GET, SEP_COLON, ATOM_LIST);
LIST_APPLY(ATOM_GET, SEP_COLON, ATOM_LIST1);
LIST_APPLY(ATOM_GET, SEP_COLON, ATOM_LIST2);
#undef ATOM_GET
return atoms;
}

View File

@ -8,7 +8,7 @@
// clang-format off
// Splitted into 2 lists because of the limitation of our macros
#define ATOM_LIST \
#define ATOM_LIST1 \
_NET_WM_WINDOW_OPACITY, \
_NET_FRAME_EXTENTS, \
WM_STATE, \
@ -16,12 +16,16 @@
_NET_WM_PID, \
WM_NAME, \
WM_CLASS, \
WM_ICON_NAME, \
WM_TRANSIENT_FOR, \
WM_WINDOW_ROLE, \
WM_CLIENT_LEADER, \
WM_CLIENT_MACHINE, \
_NET_ACTIVE_WINDOW, \
_COMPTON_SHADOW, \
_NET_WM_WINDOW_TYPE, \
_NET_WM_WINDOW_TYPE
#define ATOM_LIST2 \
_NET_WM_WINDOW_TYPE_DESKTOP, \
_NET_WM_WINDOW_TYPE_DOCK, \
_NET_WM_WINDOW_TYPE_TOOLBAR, \
@ -38,14 +42,17 @@
_NET_WM_WINDOW_TYPE_DND, \
_NET_WM_STATE, \
_NET_WM_STATE_FULLSCREEN, \
_NET_WM_BYPASS_COMPOSITOR
_NET_WM_BYPASS_COMPOSITOR, \
UTF8_STRING, \
C_STRING
// clang-format on
#define ATOM_DEF(x) xcb_atom_t a##x
struct atom {
struct cache *c;
LIST_APPLY(ATOM_DEF, SEP_COLON, ATOM_LIST);
LIST_APPLY(ATOM_DEF, SEP_COLON, ATOM_LIST1);
LIST_APPLY(ATOM_DEF, SEP_COLON, ATOM_LIST2);
};
struct atom *init_atoms(xcb_connection_t *);

View File

@ -1406,8 +1406,9 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
tgt_free = strdup(strlst[idx]);
tgt = tgt_free;
}
if (strlst)
XFreeStringList(strlst);
if (strlst) {
free(strlst);
}
}
if (tgt) {
@ -1464,10 +1465,7 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
// Free the string after usage, if necessary
if (tgt_free) {
if (C2_L_TATOM == pleaf->type)
XFree(tgt_free);
else
free(tgt_free);
free(tgt_free);
}
} break;
default: assert(0); break;
@ -1557,6 +1555,7 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
*/
bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condlst,
void **pdata) {
assert(ps->server_grabbed);
// Then go through the whole linked list
for (; condlst; condlst = condlst->next) {
if (c2_match_once(ps, w, condlst->ptr)) {

View File

@ -6,6 +6,7 @@
#include <stdc-predef.h>
#endif
// clang-format off
#define auto __auto_type
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
@ -78,6 +79,12 @@
# define attr_malloc
#endif
#if __has_attribute(fallthrough)
# define fallthrough() __attribute__((fallthrough))
#else
# define fallthrough()
#endif
#if __STDC_VERSION__ >= 201112L
# define attr_noret _Noreturn
#else
@ -107,6 +114,7 @@
#else
# define thread_local _Pragma("GCC error \"No thread local storage support\"") __error__
#endif
// clang-format on
typedef unsigned long ulong;
typedef unsigned int uint;

View File

@ -13,6 +13,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/sync.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@ -918,7 +919,7 @@ void opts_set_no_fading_openclose(session_t *ps, bool newval) {
#endif
/**
* Register us with the compositor selection (_NET_WM_CM_S)
* Setup window properties, then register us with the compositor selection (_NET_WM_CM_S)
*
* @return 0 if success, 1 if compositor already running, -1 if error.
*/
@ -936,15 +937,56 @@ static int register_cm(session_t *ps) {
return -1;
}
{
XClassHint *h = XAllocClassHint();
if (h) {
h->res_name = "picom";
h->res_class = "picom";
const xcb_atom_t prop_atoms[] = {
ps->atoms->aWM_NAME,
ps->atoms->a_NET_WM_NAME,
ps->atoms->aWM_ICON_NAME,
};
const bool prop_is_utf8[] = {false, true, false};
// Set names and classes
for (size_t i = 0; i < ARR_SIZE(prop_atoms); i++) {
e = xcb_request_check(
ps->c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i],
prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING,
8, strlen("picom"), "picom"));
if (e) {
log_error_x_error(e, "Failed to set window property %d",
prop_atoms[i]);
free(e);
}
}
const char picom_class[] = "picom\0picom";
e = xcb_request_check(
ps->c, xcb_change_property_checked(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8,
ARR_SIZE(picom_class), picom_class));
if (e) {
log_error_x_error(e, "Failed to set the WM_CLASS property");
free(e);
}
// Set WM_CLIENT_MACHINE. As per EWMH, because we set _NET_WM_PID, we must also
// set WM_CLIENT_MACHINE.
{
char hostname[HOST_NAME_MAX];
if (gethostname(hostname, sizeof(hostname)) == 0) {
e = xcb_request_check(
ps->c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING, 8,
(uint32_t)strlen(hostname), hostname));
if (e) {
log_error_x_error(e, "Failed to set the WM_CLIENT_MACHINE"
" property");
free(e);
}
} else {
log_error_errno("Failed to get hostname");
}
Xutf8SetWMProperties(ps->dpy, ps->reg_win, "picom", "picom", NULL, 0,
NULL, NULL, h);
XFree(h);
}
// Set _NET_WM_PID
@ -997,8 +1039,9 @@ static int register_cm(session_t *ps) {
* Write PID to a file.
*/
static inline bool write_pid(session_t *ps) {
if (!ps->o.write_pid_path)
if (!ps->o.write_pid_path) {
return true;
}
FILE *f = fopen(ps->o.write_pid_path, "w");
if (unlikely(!f)) {

View File

@ -1054,7 +1054,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
ps->root_height, 0, 1.0, false, false, &region, NULL);
// falls through
fallthrough();
case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break;
#endif
default: assert(0);

View File

@ -535,28 +535,20 @@ static bool attr_pure win_has_rounded_corners(const struct managed_win *w) {
}
int win_update_name(session_t *ps, struct managed_win *w) {
XTextProperty text_prop = {NULL, XCB_NONE, 0, 0};
char **strlst = NULL;
int nstr = 0;
if (!w->client_win)
if (!w->client_win) {
return 0;
}
if (!(wid_get_text_prop(ps, w->client_win, ps->atoms->a_NET_WM_NAME, &strlst, &nstr))) {
log_trace("(%#010x): _NET_WM_NAME unset, falling back to WM_NAME.",
w->client_win);
if (!(XGetWMName(ps->dpy, w->client_win, &text_prop) && text_prop.value)) {
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_NAME, &strlst, &nstr)) {
return -1;
}
if (Success != XmbTextPropertyToTextList(ps->dpy, &text_prop, &strlst, &nstr) ||
!nstr || !strlst) {
if (strlst)
XFreeStringList(strlst);
XFree(text_prop.value);
return -1;
}
XFree(text_prop.value);
}
int ret = 0;
@ -566,7 +558,7 @@ int win_update_name(session_t *ps, struct managed_win *w) {
w->name = strdup(strlst[0]);
}
XFreeStringList(strlst);
free(strlst);
log_trace("(%#010x): client = %#010x, name = \"%s\", "
"ret = %d",
@ -578,8 +570,9 @@ static int win_update_role(session_t *ps, struct managed_win *w) {
char **strlst = NULL;
int nstr = 0;
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_WINDOW_ROLE, &strlst, &nstr))
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_WINDOW_ROLE, &strlst, &nstr)) {
return -1;
}
int ret = 0;
if (!w->role || strcmp(w->role, strlst[0]) != 0) {
@ -588,7 +581,7 @@ static int win_update_role(session_t *ps, struct managed_win *w) {
w->role = strdup(strlst[0]);
}
XFreeStringList(strlst);
free(strlst);
log_trace("(%#010x): client = %#010x, role = \"%s\", "
"ret = %d",
@ -1577,16 +1570,18 @@ bool win_update_class(session_t *ps, struct managed_win *w) {
w->class_general = NULL;
// Retrieve the property string list
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_CLASS, &strlst, &nstr))
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_CLASS, &strlst, &nstr)) {
return false;
}
// Copy the strings if successful
w->class_instance = strdup(strlst[0]);
if (nstr > 1)
if (nstr > 1) {
w->class_general = strdup(strlst[1]);
}
XFreeStringList(strlst);
free(strlst);
log_trace("(%#010x): client = %#010x, "
"instance = \"%s\", general = \"%s\"",

106
src/x.c
View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
#include <stdalign.h>
#include <stdbool.h>
#include <stdlib.h>
@ -93,21 +94,79 @@ xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t apr
*/
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
int *pnstr) {
XTextProperty text_prop = {NULL, XCB_NONE, 0, 0};
if (!(XGetTextProperty(ps->dpy, wid, &text_prop, prop) && text_prop.value))
return false;
if (Success != XmbTextPropertyToTextList(ps->dpy, &text_prop, pstrlst, pnstr) ||
!*pnstr) {
*pnstr = 0;
if (*pstrlst)
XFreeStringList(*pstrlst);
XFree(text_prop.value);
assert(ps->server_grabbed);
xcb_generic_error_t *e = NULL;
auto r = xcb_get_property_reply(
ps->c, xcb_get_property(ps->c, 0, wid, prop, XCB_ATOM_ANY, 0, 0), &e);
if (!r) {
log_debug_x_error(e, "Failed to get window property for %#010x", wid);
free(e);
return false;
}
XFree(text_prop.value);
auto type = r->type;
auto format = r->format;
auto length = r->bytes_after;
free(r);
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;
}
r = xcb_get_property_reply(
ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, length), &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;
}
// 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;
}
@ -116,8 +175,9 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
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)
if (g_pictfmts) {
return;
}
xcb_generic_error_t *e = NULL;
// Get window picture format
g_pictfmts =
@ -261,8 +321,9 @@ x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int
uint8_t depth = pictfmt->depth;
xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, w, h);
if (!tmp_pixmap)
if (!tmp_pixmap) {
return XCB_NONE;
}
xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap(
c, pictfmt, tmp_pixmap, valuemask, attr);
@ -310,13 +371,14 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
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++)
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(
@ -326,7 +388,6 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
free(e);
}
free(xrects);
return;
}
void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) {
@ -337,7 +398,6 @@ void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict)
log_error_x_error(e, "failed to clear clip region");
free(e);
}
return;
}
enum { XSyncBadCounter = 0,
@ -469,8 +529,9 @@ xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t
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)
if (err == NULL) {
return pix;
}
log_error_x_error(err, "Failed to create pixmap");
free(err);
@ -526,8 +587,9 @@ xcb_pixmap_t x_get_root_back_pixmap(session_t *ps) {
bool x_is_root_back_pixmap_atom(session_t *ps, xcb_atom_t atom) {
for (int p = 0; background_props_str[p]; p++) {
xcb_atom_t prop_atom = get_atom(ps->atoms, background_props_str[p]);
if (prop_atom == atom)
if (prop_atom == atom) {
return true;
}
}
return false;
}
@ -651,9 +713,11 @@ 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)
for (; iter.rem; --screen, xcb_screen_next(&iter)) {
if (screen == 0) {
return iter.data;
}
}
return NULL;
}

View File

@ -73,6 +73,8 @@ struct xvisual_info {
__r; \
})
#define log_debug_x_error(e, fmt, ...) \
LOG(DEBUG, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
#define log_error_x_error(e, fmt, ...) \
LOG(ERROR, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
#define log_fatal_x_error(e, fmt, ...) \
@ -145,6 +147,10 @@ xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t apr
/**
* Get the value of a text property of a window.
*
* @param[out] pstrlst Out parameter for an array of strings, caller needs to free this
* array
* @param[out] pnstr Number of strings in the array
*/
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
int *pnstr);