mirror of
https://github.com/yshui/picom.git
synced 2024-11-11 13:51:02 -05:00
x: remove the last bit of Xlib dependency
Of course, we still use GLX, so we can't completely remove Xlib yet. But this removes all Xlib uses outside of the backends. This drops support for COMPOUND_TEXT Xorg strings, so people how wants multilingual support has to use UTF8, which should be fine since most of the applications support that. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
b675e3f19d
commit
dc37370a66
10 changed files with 186 additions and 60 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
15
src/atom.h
15
src/atom.h
|
@ -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 *);
|
||||
|
|
11
src/c2.c
11
src/c2.c
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
63
src/picom.c
63
src/picom.c
|
@ -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)) {
|
||||
|
|
|
@ -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, ®ion, NULL);
|
||||
// falls through
|
||||
fallthrough();
|
||||
case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break;
|
||||
#endif
|
||||
default: assert(0);
|
||||
|
|
29
src/win.c
29
src/win.c
|
@ -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
106
src/x.c
|
@ -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;
|
||||
}
|
||||
|
|
6
src/x.h
6
src/x.h
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue