core: isolate X connection with error handling into a struct

Part of the long running effort to reduce the prevalence of `session_t`.
After this, functions that communicate with X can make use of the error
handling machinary (set_ignore_cookie, set_cant_fail_cookie) without
needing to take a `session_t` parameter.

This commit converts everything to use the new struct `x_connection`,
most of the conversions are mechanical.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2023-06-29 05:39:36 +01:00
parent 4e6dddc76e
commit 1307d9ec70
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
23 changed files with 1095 additions and 986 deletions

View File

@ -91,10 +91,10 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
return handle_device_reset(ps); return handle_device_reset(ps);
} }
if (ps->o.xrender_sync_fence) { if (ps->o.xrender_sync_fence) {
if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) { if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) {
log_error("x_fence_sync failed, xrender-sync-fence will be " log_error("x_fence_sync failed, xrender-sync-fence will be "
"disabled from now on."); "disabled from now on.");
xcb_sync_destroy_fence(ps->c, ps->sync_fence); xcb_sync_destroy_fence(ps->c.c, ps->sync_fence);
ps->sync_fence = XCB_NONE; ps->sync_fence = XCB_NONE;
ps->o.xrender_sync_fence = false; ps->o.xrender_sync_fence = false;
ps->xsync_exists = false; ps->xsync_exists = false;
@ -348,7 +348,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
} }
if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 &&
w->randr_monitor < ps->randr_nmonitors) { w->randr_monitor < ps->monitors.count) {
// There can be a window where number of monitors is // There can be a window where number of monitors is
// updated, but the monitor number attached to the window // updated, but the monitor number attached to the window
// have not. // have not.
@ -358,7 +358,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
// bounds. // bounds.
pixman_region32_intersect( pixman_region32_intersect(
&reg_shadow, &reg_shadow, &reg_shadow, &reg_shadow,
&ps->randr_monitor_regs[w->randr_monitor]); &ps->monitors.regions[w->randr_monitor]);
} }
if (ps->o.transparent_clipping) { if (ps->o.transparent_clipping) {

View File

@ -23,8 +23,7 @@ struct backend_operations;
typedef struct backend_base { typedef struct backend_base {
struct backend_operations *ops; struct backend_operations *ops;
xcb_connection_t *c; struct x_connection *c;
xcb_window_t root;
struct ev_loop *loop; struct ev_loop *loop;
/// Whether the backend can accept new render request at the moment /// Whether the backend can accept new render request at the moment

View File

@ -19,17 +19,18 @@
/** /**
* Generate a 1x1 <code>Picture</code> of a particular color. * Generate a 1x1 <code>Picture</code> of a particular color.
*/ */
xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool argb, xcb_render_picture_t
double a, double r, double g, double b) { solid_picture(struct x_connection *c, bool argb, double a, double r, double g, double b) {
xcb_pixmap_t pixmap; xcb_pixmap_t pixmap;
xcb_render_picture_t picture; xcb_render_picture_t picture;
xcb_render_create_picture_value_list_t pa; xcb_render_create_picture_value_list_t pa;
xcb_render_color_t col; xcb_render_color_t col;
xcb_rectangle_t rect; xcb_rectangle_t rect;
pixmap = x_create_pixmap(c, argb ? 32 : 8, d, 1, 1); pixmap = x_create_pixmap(c, argb ? 32 : 8, 1, 1);
if (!pixmap) if (!pixmap) {
return XCB_NONE; return XCB_NONE;
}
pa.repeat = 1; pa.repeat = 1;
picture = x_create_picture_with_standard_and_pixmap( picture = x_create_picture_with_standard_and_pixmap(
@ -37,7 +38,7 @@ xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool a
XCB_RENDER_CP_REPEAT, &pa); XCB_RENDER_CP_REPEAT, &pa);
if (!picture) { if (!picture) {
xcb_free_pixmap(c, pixmap); xcb_free_pixmap(c->c, pixmap);
return XCB_NONE; return XCB_NONE;
} }
@ -51,14 +52,14 @@ xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool a
rect.width = 1; rect.width = 1;
rect.height = 1; rect.height = 1;
xcb_render_fill_rectangles(c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect); xcb_render_fill_rectangles(c->c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect);
xcb_free_pixmap(c, pixmap); xcb_free_pixmap(c->c, pixmap);
return picture; return picture;
} }
xcb_image_t * xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity,
make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height) { int width, int height) {
/* /*
* We classify shadows into 4 kinds of regions * We classify shadows into 4 kinds of regions
* r = shadow radius * r = shadow radius
@ -84,8 +85,9 @@ make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width,
assert(d % 2 == 1); assert(d % 2 == 1);
assert(d > 0); assert(d > 0);
ximage = xcb_image_create_native(c, to_u16_checked(swidth), to_u16_checked(sheight), ximage =
XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL); xcb_image_create_native(c->c, to_u16_checked(swidth), to_u16_checked(sheight),
XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL);
if (!ximage) { if (!ximage) {
log_error("failed to create an X image"); log_error("failed to create an X image");
return 0; return 0;
@ -193,7 +195,7 @@ make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width,
/** /**
* Generate shadow <code>Picture</code> for a window. * Generate shadow <code>Picture</code> for a window.
*/ */
bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const int width, bool build_shadow(struct x_connection *c, double opacity, const int width,
const int height, const conv *kernel, xcb_render_picture_t shadow_pixel, const int height, const conv *kernel, xcb_render_picture_t shadow_pixel,
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict) { xcb_pixmap_t *pixmap, xcb_render_picture_t *pict) {
xcb_image_t *shadow_image = NULL; xcb_image_t *shadow_image = NULL;
@ -207,9 +209,9 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
return false; return false;
} }
shadow_pixmap = x_create_pixmap(c, 8, d, shadow_image->width, shadow_image->height); shadow_pixmap = x_create_pixmap(c, 8, shadow_image->width, shadow_image->height);
shadow_pixmap_argb = shadow_pixmap_argb =
x_create_pixmap(c, 32, d, shadow_image->width, shadow_image->height); x_create_pixmap(c, 32, shadow_image->width, shadow_image->height);
if (!shadow_pixmap || !shadow_pixmap_argb) { if (!shadow_pixmap || !shadow_pixmap_argb) {
log_error("Failed to create shadow pixmaps"); log_error("Failed to create shadow pixmaps");
@ -225,11 +227,11 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
} }
gc = x_new_id(c); gc = x_new_id(c);
xcb_create_gc(c, gc, shadow_pixmap, 0, NULL); xcb_create_gc(c->c, gc, shadow_pixmap, 0, NULL);
// We need to make room for protocol metadata in the request. The metadata should // We need to make room for protocol metadata in the request. The metadata should
// be 24 bytes plus padding, let's be generous and give it 1kb // be 24 bytes plus padding, let's be generous and give it 1kb
auto maximum_image_size = xcb_get_maximum_request_length(c) * 4 - 1024; auto maximum_image_size = xcb_get_maximum_request_length(c->c) * 4 - 1024;
auto maximum_row = auto maximum_row =
to_u16_checked(clamp(maximum_image_size / shadow_image->stride, 0, UINT16_MAX)); to_u16_checked(clamp(maximum_image_size / shadow_image->stride, 0, UINT16_MAX));
if (maximum_row <= 0) { if (maximum_row <= 0) {
@ -248,23 +250,23 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
} }
uint32_t offset = row * shadow_image->stride / sizeof(*shadow_image->data); uint32_t offset = row * shadow_image->stride / sizeof(*shadow_image->data);
xcb_put_image(c, (uint8_t)shadow_image->format, shadow_pixmap, gc, xcb_put_image(c->c, (uint8_t)shadow_image->format, shadow_pixmap, gc,
shadow_image->width, batch_height, 0, to_i16_checked(row), shadow_image->width, batch_height, 0, to_i16_checked(row),
0, shadow_image->depth, shadow_image->stride * batch_height, 0, shadow_image->depth, shadow_image->stride * batch_height,
shadow_image->data + offset); shadow_image->data + offset);
} }
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, shadow_pixel, shadow_picture, xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, shadow_pixel, shadow_picture,
shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width, shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width,
shadow_image->height); shadow_image->height);
*pixmap = shadow_pixmap_argb; *pixmap = shadow_pixmap_argb;
*pict = shadow_picture_argb; *pict = shadow_picture_argb;
xcb_free_gc(c, gc); xcb_free_gc(c->c, gc);
xcb_image_destroy(shadow_image); xcb_image_destroy(shadow_image);
xcb_free_pixmap(c, shadow_pixmap); xcb_free_pixmap(c->c, shadow_pixmap);
xcb_render_free_picture(c, shadow_picture); x_free_picture(c, shadow_picture);
return true; return true;
@ -273,19 +275,19 @@ shadow_picture_err:
xcb_image_destroy(shadow_image); xcb_image_destroy(shadow_image);
} }
if (shadow_pixmap) { if (shadow_pixmap) {
xcb_free_pixmap(c, shadow_pixmap); xcb_free_pixmap(c->c, shadow_pixmap);
} }
if (shadow_pixmap_argb) { if (shadow_pixmap_argb) {
xcb_free_pixmap(c, shadow_pixmap_argb); xcb_free_pixmap(c->c, shadow_pixmap_argb);
} }
if (shadow_picture) { if (shadow_picture) {
xcb_render_free_picture(c, shadow_picture); x_free_picture(c, shadow_picture);
} }
if (shadow_picture_argb) { if (shadow_picture_argb) {
xcb_render_free_picture(c, shadow_picture_argb); x_free_picture(c, shadow_picture_argb);
} }
if (gc) { if (gc) {
xcb_free_gc(c, gc); xcb_free_gc(c->c, gc);
} }
return false; return false;
@ -294,22 +296,22 @@ shadow_picture_err:
void *default_backend_render_shadow(backend_t *backend_data, int width, int height, void *default_backend_render_shadow(backend_t *backend_data, int width, int height,
struct backend_shadow_context *sctx, struct color color) { struct backend_shadow_context *sctx, struct color color) {
const conv *kernel = (void *)sctx; const conv *kernel = (void *)sctx;
xcb_render_picture_t shadow_pixel = solid_picture( xcb_render_picture_t shadow_pixel =
backend_data->c, backend_data->root, true, 1, color.red, color.green, color.blue); solid_picture(backend_data->c, true, 1, color.red, color.green, color.blue);
xcb_pixmap_t shadow = XCB_NONE; xcb_pixmap_t shadow = XCB_NONE;
xcb_render_picture_t pict = XCB_NONE; xcb_render_picture_t pict = XCB_NONE;
if (!build_shadow(backend_data->c, backend_data->root, color.alpha, width, height, if (!build_shadow(backend_data->c, color.alpha, width, height, kernel,
kernel, shadow_pixel, &shadow, &pict)) { shadow_pixel, &shadow, &pict)) {
xcb_render_free_picture(backend_data->c, shadow_pixel); x_free_picture(backend_data->c, shadow_pixel);
return NULL; return NULL;
} }
auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32); auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32);
void *ret = backend_data->ops->bind_pixmap( void *ret = backend_data->ops->bind_pixmap(
backend_data, shadow, x_get_visual_info(backend_data->c, visual), true); backend_data, shadow, x_get_visual_info(backend_data->c, visual), true);
xcb_render_free_picture(backend_data->c, pict); x_free_picture(backend_data->c, pict);
xcb_render_free_picture(backend_data->c, shadow_pixel); x_free_picture(backend_data->c, shadow_pixel);
return ret; return ret;
} }
@ -506,9 +508,8 @@ struct backend_image *default_new_backend_image(int w, int h) {
} }
void init_backend_base(struct backend_base *base, session_t *ps) { void init_backend_base(struct backend_base *base, session_t *ps) {
base->c = ps->c; base->c = &ps->c;
base->loop = ps->loop; base->loop = ps->loop;
base->root = ps->root;
base->busy = false; base->busy = false;
base->ops = NULL; base->ops = NULL;
} }

View File

@ -44,15 +44,15 @@ struct backend_image {
int border_width; int border_width;
}; };
bool build_shadow(xcb_connection_t *, xcb_drawable_t, double opacity, int width, bool build_shadow(struct x_connection *, double opacity, int width, int height,
int height, const conv *kernel, xcb_render_picture_t shadow_pixel, const conv *kernel, xcb_render_picture_t shadow_pixel,
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict); xcb_pixmap_t *pixmap, xcb_render_picture_t *pict);
xcb_render_picture_t solid_picture(xcb_connection_t *, xcb_drawable_t, bool argb, xcb_render_picture_t
double a, double r, double g, double b); solid_picture(struct x_connection *, bool argb, double a, double r, double g, double b);
xcb_image_t * xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity,
make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height); int width, int height);
/// The default implementation of `is_win_transparent`, it simply looks at win::mode. So /// The default implementation of `is_win_transparent`, it simply looks at win::mode. So
/// this is not suitable for backends that alter the content of windows /// this is not suitable for backends that alter the content of windows

View File

@ -30,9 +30,8 @@ struct dummy_data {
struct backend_base *dummy_init(struct session *ps attr_unused) { struct backend_base *dummy_init(struct session *ps attr_unused) {
auto ret = (struct backend_base *)ccalloc(1, struct dummy_data); auto ret = (struct backend_base *)ccalloc(1, struct dummy_data);
ret->c = ps->c; ret->c = &ps->c;
ret->loop = ps->loop; ret->loop = ps->loop;
ret->root = ps->root;
ret->busy = false; ret->busy = false;
return ret; return ret;
} }
@ -44,7 +43,7 @@ void dummy_deinit(struct backend_base *data) {
HASH_DEL(dummy->images, img); HASH_DEL(dummy->images, img);
free(img->refcount); free(img->refcount);
if (img->owned) { if (img->owned) {
xcb_free_pixmap(data->c, img->pixmap); xcb_free_pixmap(data->c->c, img->pixmap);
} }
free(img); free(img);
} }
@ -118,7 +117,7 @@ void dummy_release_image(backend_t *base, void *image) {
HASH_DEL(dummy->images, img); HASH_DEL(dummy->images, img);
free(img->refcount); free(img->refcount);
if (img->owned) { if (img->owned) {
xcb_free_pixmap(base->c, img->pixmap); xcb_free_pixmap(base->c->c, img->pixmap);
} }
free(img); free(img);
} }

View File

@ -79,7 +79,7 @@ static void egl_release_image(backend_t *base, struct gl_texture *tex) {
} }
if (p->owned) { if (p->owned) {
xcb_free_pixmap(base->c, p->pixmap); xcb_free_pixmap(base->c->c, p->pixmap);
p->pixmap = XCB_NONE; p->pixmap = XCB_NONE;
} }
@ -154,10 +154,10 @@ static backend_t *egl_init(session_t *ps) {
} }
gd = ccalloc(1, struct egl_data); gd = ccalloc(1, struct egl_data);
gd->display = eglGetPlatformDisplayProc(EGL_PLATFORM_X11_EXT, ps->dpy, gd->display = eglGetPlatformDisplayProc(EGL_PLATFORM_X11_EXT, ps->c.dpy,
(EGLAttrib[]){ (EGLAttrib[]){
EGL_PLATFORM_X11_SCREEN_EXT, EGL_PLATFORM_X11_SCREEN_EXT,
ps->scr, ps->c.screen,
EGL_NONE, EGL_NONE,
}); });
if (gd->display == EGL_NO_DISPLAY) { if (gd->display == EGL_NO_DISPLAY) {
@ -190,7 +190,7 @@ static backend_t *egl_init(session_t *ps) {
goto end; goto end;
} }
auto visual_info = x_get_visual_info(ps->c, ps->vis); auto visual_info = x_get_visual_info(&ps->c, ps->c.screen_info->root_visual);
EGLConfig config = NULL; EGLConfig config = NULL;
int nconfigs = 1; int nconfigs = 1;
// clang-format off // clang-format off
@ -280,7 +280,8 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
struct egl_data *gd = (void *)base; struct egl_data *gd = (void *)base;
struct egl_pixmap *eglpixmap = NULL; struct egl_pixmap *eglpixmap = NULL;
auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), NULL); auto r =
xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), NULL);
if (!r) { if (!r) {
log_error("Invalid pixmap %#010x", pixmap); log_error("Invalid pixmap %#010x", pixmap);
return NULL; return NULL;
@ -335,7 +336,7 @@ err:
free(eglpixmap); free(eglpixmap);
if (owned) { if (owned) {
xcb_free_pixmap(base->c, pixmap); xcb_free_pixmap(base->c->c, pixmap);
} }
free(wd); free(wd);
return NULL; return NULL;

View File

@ -42,8 +42,6 @@ struct _glx_pixmap {
struct _glx_data { struct _glx_data {
struct gl_data gl; struct gl_data gl;
Display *display;
int screen;
xcb_window_t target_win; xcb_window_t target_win;
GLXContext ctx; GLXContext ctx;
}; };
@ -52,18 +50,18 @@ struct _glx_data {
do { \ do { \
if (glXGetFBConfigAttrib(a, b, attr, c)) { \ if (glXGetFBConfigAttrib(a, b, attr, c)) { \
log_info("Cannot get FBConfig attribute " #attr); \ log_info("Cannot get FBConfig attribute " #attr); \
continue; \ break; \
} \ } \
} while (0) } while (0)
struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvisual_info m) { struct glx_fbconfig_info *glx_find_fbconfig(struct x_connection *c, struct xvisual_info m) {
log_debug("Looking for FBConfig for RGBA%d%d%d%d, depth %d", m.red_size, log_debug("Looking for FBConfig for RGBA%d%d%d%d, depth %d", m.red_size,
m.blue_size, m.green_size, m.alpha_size, m.visual_depth); m.blue_size, m.green_size, m.alpha_size, m.visual_depth);
int ncfg; int ncfg;
// clang-format off // clang-format off
GLXFBConfig *cfg = GLXFBConfig *cfg =
glXChooseFBConfig(dpy, screen, (int[]){ glXChooseFBConfig(c->dpy, c->screen, (int[]){
GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
@ -87,25 +85,26 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
GLXFBConfig ret; GLXFBConfig ret;
for (int i = 0; i < ncfg; i++) { for (int i = 0; i < ncfg; i++) {
int depthbuf, stencil, doublebuf, bufsize; int depthbuf, stencil, doublebuf, bufsize;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BUFFER_SIZE, &bufsize); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BUFFER_SIZE, &bufsize);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_DEPTH_SIZE, &depthbuf); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_DEPTH_SIZE, &depthbuf);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_STENCIL_SIZE, &stencil); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_STENCIL_SIZE, &stencil);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_DOUBLEBUFFER, &doublebuf); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_DOUBLEBUFFER, &doublebuf);
if (depthbuf + stencil + bufsize * (doublebuf + 1) >= min_cost) { if (depthbuf + stencil + bufsize * (doublebuf + 1) >= min_cost) {
continue; continue;
} }
int red, green, blue; int red, green, blue;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_RED_SIZE, &red); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_RED_SIZE, &red);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BLUE_SIZE, &blue); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BLUE_SIZE, &blue);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_GREEN_SIZE, &green); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_GREEN_SIZE, &green);
if (red != m.red_size || green != m.green_size || blue != m.blue_size) { if (red != m.red_size || green != m.green_size || blue != m.blue_size) {
// Color size doesn't match, this cannot work // Color size doesn't match, this cannot work
continue; continue;
} }
int rgb, rgba; int rgb, rgba;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &rgb); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &rgb);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &rgba); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGBA_EXT,
&rgba);
if (!rgb && !rgba) { if (!rgb && !rgba) {
log_info("FBConfig is neither RGBA nor RGB, we cannot " log_info("FBConfig is neither RGBA nor RGB, we cannot "
"handle this setup."); "handle this setup.");
@ -113,10 +112,9 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
} }
int visual; int visual;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_VISUAL_ID, &visual); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_VISUAL_ID, &visual);
if (m.visual_depth != -1 && if (m.visual_depth != -1 &&
x_get_visual_depth(XGetXCBConnection(dpy), (xcb_visualid_t)visual) != x_get_visual_depth(c, (xcb_visualid_t)visual) != m.visual_depth) {
m.visual_depth) {
// FBConfig and the correspondent X Visual might not have the same // FBConfig and the correspondent X Visual might not have the same
// depth. (e.g. 32 bit FBConfig with a 24 bit Visual). This is // depth. (e.g. 32 bit FBConfig with a 24 bit Visual). This is
// quite common, seen in both open source and proprietary drivers. // quite common, seen in both open source and proprietary drivers.
@ -129,9 +127,9 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
// All check passed, we are using this one. // All check passed, we are using this one.
found = true; found = true;
ret = cfg[i]; ret = cfg[i];
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, glXGetFBConfigAttribChecked(
&texture_tgts); c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &texture_tgts);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_Y_INVERTED_EXT, &y_inverted); glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_Y_INVERTED_EXT, &y_inverted);
// Prefer the texture format with matching alpha, with the other one as // Prefer the texture format with matching alpha, with the other one as
// fallback // fallback
@ -161,24 +159,22 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
* Free a glx_texture_t. * Free a glx_texture_t.
*/ */
static void glx_release_image(backend_t *base, struct gl_texture *tex) { static void glx_release_image(backend_t *base, struct gl_texture *tex) {
struct _glx_data *gd = (void *)base;
struct _glx_pixmap *p = tex->user_data; struct _glx_pixmap *p = tex->user_data;
// Release binding // Release binding
if (p->glpixmap && tex->texture) { if (p->glpixmap && tex->texture) {
glBindTexture(GL_TEXTURE_2D, tex->texture); glBindTexture(GL_TEXTURE_2D, tex->texture);
glXReleaseTexImageEXT(gd->display, p->glpixmap, GLX_FRONT_LEFT_EXT); glXReleaseTexImageEXT(base->c->dpy, p->glpixmap, GLX_FRONT_LEFT_EXT);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
// Free GLX Pixmap // Free GLX Pixmap
if (p->glpixmap) { if (p->glpixmap) {
glXDestroyPixmap(gd->display, p->glpixmap); glXDestroyPixmap(base->c->dpy, p->glpixmap);
p->glpixmap = 0; p->glpixmap = 0;
} }
if (p->owned) { if (p->owned) {
xcb_free_pixmap(base->c, p->pixmap); xcb_free_pixmap(base->c->c, p->pixmap);
p->pixmap = XCB_NONE; p->pixmap = XCB_NONE;
} }
@ -196,8 +192,8 @@ void glx_deinit(backend_t *base) {
// Destroy GLX context // Destroy GLX context
if (gd->ctx) { if (gd->ctx) {
glXMakeCurrent(gd->display, None, NULL); glXMakeCurrent(base->c->dpy, None, NULL);
glXDestroyContext(gd->display, gd->ctx); glXDestroyContext(base->c->dpy, gd->ctx);
gd->ctx = 0; gd->ctx = 0;
} }
@ -233,12 +229,10 @@ static bool glx_set_swap_interval(int interval, Display *dpy, GLXDrawable drawab
*/ */
static backend_t *glx_init(session_t *ps) { static backend_t *glx_init(session_t *ps) {
bool success = false; bool success = false;
glxext_init(ps->dpy, ps->scr); glxext_init(ps->c.dpy, ps->c.screen);
auto gd = ccalloc(1, struct _glx_data); auto gd = ccalloc(1, struct _glx_data);
init_backend_base(&gd->gl.base, ps); init_backend_base(&gd->gl.base, ps);
gd->display = ps->dpy;
gd->screen = ps->scr;
gd->target_win = session_get_target_window(ps); gd->target_win = session_get_target_window(ps);
XVisualInfo *pvis = NULL; XVisualInfo *pvis = NULL;
@ -251,8 +245,8 @@ static backend_t *glx_init(session_t *ps) {
// Get XVisualInfo // Get XVisualInfo
int nitems = 0; int nitems = 0;
XVisualInfo vreq = {.visualid = ps->vis}; XVisualInfo vreq = {.visualid = ps->c.screen_info->root_visual};
pvis = XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems); pvis = XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
if (!pvis) { if (!pvis) {
log_error("Failed to acquire XVisualInfo for current visual."); log_error("Failed to acquire XVisualInfo for current visual.");
goto end; goto end;
@ -260,22 +254,22 @@ static backend_t *glx_init(session_t *ps) {
// Ensure the visual is double-buffered // Ensure the visual is double-buffered
int value = 0; int value = 0;
if (glXGetConfig(ps->dpy, pvis, GLX_USE_GL, &value) || !value) { if (glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) {
log_error("Root visual is not a GL visual."); log_error("Root visual is not a GL visual.");
goto end; goto end;
} }
if (glXGetConfig(ps->dpy, pvis, GLX_STENCIL_SIZE, &value) || !value) { if (glXGetConfig(ps->c.dpy, pvis, GLX_STENCIL_SIZE, &value) || !value) {
log_error("Root visual lacks stencil buffer."); log_error("Root visual lacks stencil buffer.");
goto end; goto end;
} }
if (glXGetConfig(ps->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) { if (glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) {
log_error("Root visual is not a double buffered GL visual."); log_error("Root visual is not a double buffered GL visual.");
goto end; goto end;
} }
if (glXGetConfig(ps->dpy, pvis, GLX_RGBA, &value) || !value) { if (glXGetConfig(ps->c.dpy, pvis, GLX_RGBA, &value) || !value) {
log_error("Root visual is a color index visual, not supported"); log_error("Root visual is a color index visual, not supported");
goto end; goto end;
} }
@ -293,11 +287,11 @@ static backend_t *glx_init(session_t *ps) {
// Find a fbconfig with visualid matching the one from the target win, so we can // Find a fbconfig with visualid matching the one from the target win, so we can
// be sure that the fbconfig is compatible with our target window. // be sure that the fbconfig is compatible with our target window.
int ncfgs; int ncfgs;
GLXFBConfig *cfg = glXGetFBConfigs(gd->display, gd->screen, &ncfgs); GLXFBConfig *cfg = glXGetFBConfigs(ps->c.dpy, ps->c.screen, &ncfgs);
bool found = false; bool found = false;
for (int i = 0; i < ncfgs; i++) { for (int i = 0; i < ncfgs; i++) {
int visualid; int visualid;
glXGetFBConfigAttribChecked(gd->display, cfg[i], GLX_VISUAL_ID, &visualid); glXGetFBConfigAttribChecked(ps->c.dpy, cfg[i], GLX_VISUAL_ID, &visualid);
if ((VisualID)visualid != pvis->visualid) { if ((VisualID)visualid != pvis->visualid) {
continue; continue;
} }
@ -316,7 +310,7 @@ static backend_t *glx_init(session_t *ps) {
attributes[7] = GLX_LOSE_CONTEXT_ON_RESET_ARB; attributes[7] = GLX_LOSE_CONTEXT_ON_RESET_ARB;
} }
gd->ctx = glXCreateContextAttribsARB(ps->dpy, cfg[i], 0, true, attributes); gd->ctx = glXCreateContextAttribsARB(ps->c.dpy, cfg[i], 0, true, attributes);
free(cfg); free(cfg);
if (!gd->ctx) { if (!gd->ctx) {
@ -334,7 +328,7 @@ static backend_t *glx_init(session_t *ps) {
// Attach GLX context // Attach GLX context
GLXDrawable tgt = gd->target_win; GLXDrawable tgt = gd->target_win;
if (!glXMakeCurrent(ps->dpy, tgt, gd->ctx)) { if (!glXMakeCurrent(ps->c.dpy, tgt, gd->ctx)) {
log_error("Failed to attach GLX context."); log_error("Failed to attach GLX context.");
goto end; goto end;
} }
@ -348,11 +342,11 @@ static backend_t *glx_init(session_t *ps) {
gd->gl.release_user_data = glx_release_image; gd->gl.release_user_data = glx_release_image;
if (ps->o.vsync) { if (ps->o.vsync) {
if (!glx_set_swap_interval(1, ps->dpy, tgt)) { if (!glx_set_swap_interval(1, ps->c.dpy, tgt)) {
log_error("Failed to enable vsync."); log_error("Failed to enable vsync.");
} }
} else { } else {
glx_set_swap_interval(0, ps->dpy, tgt); glx_set_swap_interval(0, ps->c.dpy, tgt);
} }
success = true; success = true;
@ -372,7 +366,6 @@ end:
static void * static void *
glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) { glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
struct _glx_data *gd = (void *)base;
struct _glx_pixmap *glxpixmap = NULL; struct _glx_pixmap *glxpixmap = NULL;
// Retrieve pixmap parameters, if they aren't provided // Retrieve pixmap parameters, if they aren't provided
if (fmt.visual_depth > OPENGL_MAX_DEPTH) { if (fmt.visual_depth > OPENGL_MAX_DEPTH) {
@ -386,7 +379,8 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
return false; return false;
} }
auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), NULL); auto r =
xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), NULL);
if (!r) { if (!r) {
log_error("Invalid pixmap %#010x", pixmap); log_error("Invalid pixmap %#010x", pixmap);
return NULL; return NULL;
@ -400,7 +394,7 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
wd->inner = (struct backend_image_inner_base *)inner; wd->inner = (struct backend_image_inner_base *)inner;
free(r); free(r);
auto fbcfg = glx_find_fbconfig(gd->display, gd->screen, fmt); auto fbcfg = glx_find_fbconfig(base->c, fmt);
if (!fbcfg) { if (!fbcfg) {
log_error("Couldn't find FBConfig with requested visual %x", fmt.visual); log_error("Couldn't find FBConfig with requested visual %x", fmt.visual);
goto err; goto err;
@ -429,7 +423,7 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
glxpixmap = cmalloc(struct _glx_pixmap); glxpixmap = cmalloc(struct _glx_pixmap);
glxpixmap->pixmap = pixmap; glxpixmap->pixmap = pixmap;
glxpixmap->glpixmap = glXCreatePixmap(gd->display, fbcfg->cfg, pixmap, attrs); glxpixmap->glpixmap = glXCreatePixmap(base->c->dpy, fbcfg->cfg, pixmap, attrs);
glxpixmap->owned = owned; glxpixmap->owned = owned;
free(fbcfg); free(fbcfg);
@ -446,19 +440,19 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b
inner->has_alpha = fmt.alpha_size != 0; inner->has_alpha = fmt.alpha_size != 0;
wd->inner->refcount = 1; wd->inner->refcount = 1;
glBindTexture(GL_TEXTURE_2D, inner->texture); glBindTexture(GL_TEXTURE_2D, inner->texture);
glXBindTexImageEXT(gd->display, glxpixmap->glpixmap, GLX_FRONT_LEFT_EXT, NULL); glXBindTexImageEXT(base->c->dpy, glxpixmap->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
gl_check_err(); gl_check_err();
return wd; return wd;
err: err:
if (glxpixmap && glxpixmap->glpixmap) { if (glxpixmap && glxpixmap->glpixmap) {
glXDestroyPixmap(gd->display, glxpixmap->glpixmap); glXDestroyPixmap(base->c->dpy, glxpixmap->glpixmap);
} }
free(glxpixmap); free(glxpixmap);
if (owned) { if (owned) {
xcb_free_pixmap(base->c, pixmap); xcb_free_pixmap(base->c->c, pixmap);
} }
free(wd); free(wd);
return NULL; return NULL;
@ -467,7 +461,7 @@ err:
static void glx_present(backend_t *base, const region_t *region attr_unused) { static void glx_present(backend_t *base, const region_t *region attr_unused) {
struct _glx_data *gd = (void *)base; struct _glx_data *gd = (void *)base;
gl_present(base, region); gl_present(base, region);
glXSwapBuffers(gd->display, gd->target_win); glXSwapBuffers(base->c->dpy, gd->target_win);
} }
static int glx_buffer_age(backend_t *base) { static int glx_buffer_age(backend_t *base) {
@ -477,15 +471,14 @@ static int glx_buffer_age(backend_t *base) {
struct _glx_data *gd = (void *)base; struct _glx_data *gd = (void *)base;
unsigned int val; unsigned int val;
glXQueryDrawable(gd->display, gd->target_win, GLX_BACK_BUFFER_AGE_EXT, &val); glXQueryDrawable(base->c->dpy, gd->target_win, GLX_BACK_BUFFER_AGE_EXT, &val);
return (int)val ?: -1; return (int)val ?: -1;
} }
static void glx_diagnostics(backend_t *base) { static void glx_diagnostics(backend_t *base) {
struct _glx_data *gd = (void *)base;
bool warn_software_rendering = false; bool warn_software_rendering = false;
const char *software_renderer_names[] = {"llvmpipe", "SWR", "softpipe"}; const char *software_renderer_names[] = {"llvmpipe", "SWR", "softpipe"};
auto glx_vendor = glXGetClientString(gd->display, GLX_VENDOR); auto glx_vendor = glXGetClientString(base->c->dpy, GLX_VENDOR);
printf("* Driver vendors:\n"); printf("* Driver vendors:\n");
printf(" * GLX: %s\n", glx_vendor); printf(" * GLX: %s\n", glx_vendor);
printf(" * GL: %s\n", glGetString(GL_VENDOR)); printf(" * GL: %s\n", glGetString(GL_VENDOR));

View File

@ -41,8 +41,7 @@ struct glx_fbconfig_criteria {
int visual_depth; int visual_depth;
}; };
struct glx_fbconfig_info *glx_find_fbconfig(Display *, int screen, struct xvisual_info); struct glx_fbconfig_info *glx_find_fbconfig(struct x_connection *, struct xvisual_info);
struct glxext_info { struct glxext_info {
bool initialized; bool initialized;

View File

@ -28,7 +28,6 @@ typedef struct _xrender_data {
backend_t base; backend_t base;
/// If vsync is enabled and supported by the current system /// If vsync is enabled and supported by the current system
bool vsync; bool vsync;
xcb_visualid_t default_visual;
/// Target window /// Target window
xcb_window_t target_win; xcb_window_t target_win;
/// Painting target, it is either the root or the overlay /// Painting target, it is either the root or the overlay
@ -104,9 +103,9 @@ struct xrender_image {
/// Make a picture of size width x height, which has a rounded rectangle of corner_radius /// Make a picture of size width x height, which has a rounded rectangle of corner_radius
/// rendered in it. /// rendered in it.
struct xrender_rounded_rectangle_cache * struct xrender_rounded_rectangle_cache *
make_rounded_corner_cache(xcb_connection_t *c, xcb_render_picture_t src, make_rounded_corner_cache(struct x_connection *c, xcb_render_picture_t src, int width,
xcb_drawable_t root, int width, int height, int corner_radius) { int height, int corner_radius) {
auto picture = x_create_picture_with_standard(c, root, width, height, auto picture = x_create_picture_with_standard(c, width, height,
XCB_PICT_STANDARD_ARGB_32, 0, NULL); XCB_PICT_STANDARD_ARGB_32, 0, NULL);
if (picture == XCB_NONE) { if (picture == XCB_NONE) {
return NULL; return NULL;
@ -160,7 +159,7 @@ make_rounded_corner_cache(xcb_connection_t *c, xcb_render_picture_t src,
} }
#undef ADD_POINT #undef ADD_POINT
XCB_AWAIT_VOID(xcb_render_tri_strip, c, XCB_RENDER_PICT_OP_SRC, src, picture, XCB_AWAIT_VOID(xcb_render_tri_strip, c->c, XCB_RENDER_PICT_OP_SRC, src, picture,
x_get_pictfmt_for_standard(c, XCB_PICT_STANDARD_A_8), 0, 0, x_get_pictfmt_for_standard(c, XCB_PICT_STANDARD_A_8), 0, 0,
(uint32_t)point_count, points); (uint32_t)point_count, points);
free(points); free(points);
@ -182,30 +181,29 @@ static xcb_render_picture_t process_mask(struct _xrender_data *xd, struct xrende
*allocated = true; *allocated = true;
x_clear_picture_clip_region(xd->base.c, inner->pict); x_clear_picture_clip_region(xd->base.c, inner->pict);
auto ret = x_create_picture_with_visual( auto ret = x_create_picture_with_visual(
xd->base.c, xd->base.root, inner->width, inner->height, inner->visual, xd->base.c, inner->width, inner->height, inner->visual, XCB_RENDER_CP_REPEAT,
XCB_RENDER_CP_REPEAT,
(xcb_render_create_picture_value_list_t[]){XCB_RENDER_REPEAT_PAD}); (xcb_render_create_picture_value_list_t[]){XCB_RENDER_REPEAT_PAD});
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE,
ret, 0, 0, 0, 0, 0, 0, tmpw, tmph); ret, 0, 0, 0, 0, 0, 0, tmpw, tmph);
// Remember: the mask has a 1-pixel border // Remember: the mask has a 1-pixel border
if (mask->base.corner_radius != 0) { if (mask->base.corner_radius != 0) {
if (mask->rounded_rectangle == NULL) { if (mask->rounded_rectangle == NULL) {
mask->rounded_rectangle = make_rounded_corner_cache( mask->rounded_rectangle = make_rounded_corner_cache(
xd->base.c, xd->white_pixel, xd->base.root, inner->width - 2, xd->base.c, xd->white_pixel, inner->width - 2,
inner->height - 2, (int)mask->base.corner_radius); inner->height - 2, (int)mask->base.corner_radius);
} }
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_IN_REVERSE, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_IN_REVERSE,
mask->rounded_rectangle->p, XCB_NONE, ret, 0, 0, 0, mask->rounded_rectangle->p, XCB_NONE, ret, 0, 0, 0,
0, 1, 1, (uint16_t)(tmpw - 2), (uint16_t)(tmph - 2)); 0, 1, 1, (uint16_t)(tmpw - 2), (uint16_t)(tmph - 2));
} }
if (mask->base.color_inverted) { if (mask->base.color_inverted) {
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_XOR, xd->white_pixel, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_XOR, xd->white_pixel,
XCB_NONE, ret, 0, 0, 0, 0, 0, 0, tmpw, tmph); XCB_NONE, ret, 0, 0, 0, 0, 0, 0, tmpw, tmph);
} }
if (alpha_pict != XCB_NONE) { if (alpha_pict != XCB_NONE) {
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, ret, alpha_pict, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, ret, alpha_pict,
ret, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width), ret, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width),
to_u16_checked(inner->height)); to_u16_checked(inner->height));
} }
@ -246,43 +244,43 @@ compose_impl(struct _xrender_data *xd, struct xrender_image *xrimg, coord_t dst,
pixman_region32_intersect(&reg, (region_t *)reg_paint, (region_t *)reg_visible); pixman_region32_intersect(&reg, (region_t *)reg_paint, (region_t *)reg_visible);
x_set_picture_clip_region(xd->base.c, result, 0, 0, &reg); x_set_picture_clip_region(xd->base.c, result, 0, 0, &reg);
if (img->corner_radius != 0 && xrimg->rounded_rectangle == NULL) { if (img->corner_radius != 0 && xrimg->rounded_rectangle == NULL) {
xrimg->rounded_rectangle = make_rounded_corner_cache( xrimg->rounded_rectangle =
xd->base.c, xd->white_pixel, xd->base.root, inner->width, make_rounded_corner_cache(xd->base.c, xd->white_pixel, inner->width,
inner->height, (int)img->corner_radius); inner->height, (int)img->corner_radius);
} }
if (((img->color_inverted || img->dim != 0) && has_alpha) || img->corner_radius != 0) { if (((img->color_inverted || img->dim != 0) && has_alpha) || img->corner_radius != 0) {
// Apply image properties using a temporary image, because the source // Apply image properties using a temporary image, because the source
// image is transparent. Otherwise the properties can be applied directly // image is transparent. Otherwise the properties can be applied directly
// on the target image. // on the target image.
auto tmp_pict = auto tmp_pict = x_create_picture_with_visual(
x_create_picture_with_visual(xd->base.c, xd->base.root, inner->width, xd->base.c, inner->width, inner->height, inner->visual, 0, NULL);
inner->height, inner->visual, 0, NULL);
// Set clip region translated to source coordinate // Set clip region translated to source coordinate
x_set_picture_clip_region(xd->base.c, tmp_pict, to_i16_checked(-dst.x), x_set_picture_clip_region(xd->base.c, tmp_pict, to_i16_checked(-dst.x),
to_i16_checked(-dst.y), &reg); to_i16_checked(-dst.y), &reg);
// Copy source -> tmp // Copy source -> tmp
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, inner->pict, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, inner->pict,
XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph);
if (img->color_inverted) { if (img->color_inverted) {
if (inner->has_alpha) { if (inner->has_alpha) {
auto tmp_pict2 = x_create_picture_with_visual( auto tmp_pict2 = x_create_picture_with_visual(
xd->base.c, xd->base.root, tmpw, tmph, inner->visual, xd->base.c, tmpw, tmph, inner->visual, 0, NULL);
0, NULL); xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC,
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC,
tmp_pict, XCB_NONE, tmp_pict2, 0, 0, tmp_pict, XCB_NONE, tmp_pict2, 0, 0,
0, 0, 0, 0, tmpw, tmph); 0, 0, 0, 0, tmpw, tmph);
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_DIFFERENCE, xcb_render_composite(xd->base.c->c,
XCB_RENDER_PICT_OP_DIFFERENCE,
xd->white_pixel, XCB_NONE, tmp_pict, xd->white_pixel, XCB_NONE, tmp_pict,
0, 0, 0, 0, 0, 0, tmpw, tmph); 0, 0, 0, 0, 0, 0, tmpw, tmph);
xcb_render_composite( xcb_render_composite(
xd->base.c, XCB_RENDER_PICT_OP_IN_REVERSE, tmp_pict2, xd->base.c->c, XCB_RENDER_PICT_OP_IN_REVERSE, tmp_pict2,
XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph);
xcb_render_free_picture(xd->base.c, tmp_pict2); x_free_picture(xd->base.c, tmp_pict2);
} else { } else {
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_DIFFERENCE, xcb_render_composite(xd->base.c->c,
XCB_RENDER_PICT_OP_DIFFERENCE,
xd->white_pixel, XCB_NONE, tmp_pict, xd->white_pixel, XCB_NONE, tmp_pict,
0, 0, 0, 0, 0, 0, tmpw, tmph); 0, 0, 0, 0, 0, 0, tmpw, tmph);
} }
@ -297,33 +295,34 @@ compose_impl(struct _xrender_data *xd, struct xrender_image *xrimg, coord_t dst,
.height = tmph, .height = tmph,
}; };
xcb_render_fill_rectangles(xd->base.c, XCB_RENDER_PICT_OP_OVER, xcb_render_fill_rectangles(xd->base.c->c, XCB_RENDER_PICT_OP_OVER,
tmp_pict, dim_color, 1, &rect); tmp_pict, dim_color, 1, &rect);
} }
if (img->corner_radius != 0 && xrimg->rounded_rectangle != NULL) { if (img->corner_radius != 0 && xrimg->rounded_rectangle != NULL) {
// Clip tmp_pict with a rounded rectangle // Clip tmp_pict with a rounded rectangle
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_IN_REVERSE, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_IN_REVERSE,
xrimg->rounded_rectangle->p, XCB_NONE, xrimg->rounded_rectangle->p, XCB_NONE,
tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph);
} }
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_OVER, tmp_pict, xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_OVER, tmp_pict,
mask_pict, result, 0, 0, mask_dst_x, mask_dst_y, mask_pict, result, 0, 0, mask_dst_x, mask_dst_y,
to_i16_checked(dst.x), to_i16_checked(dst.y), tmpew, to_i16_checked(dst.x), to_i16_checked(dst.y), tmpew,
tmpeh); tmpeh);
xcb_render_free_picture(xd->base.c, tmp_pict); xcb_render_free_picture(xd->base.c->c, tmp_pict);
} else { } else {
uint8_t op = (has_alpha ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC); uint8_t op = (has_alpha ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC);
xcb_render_composite(xd->base.c, op, inner->pict, mask_pict, result, 0, 0, xcb_render_composite(xd->base.c->c, op, inner->pict, mask_pict, result, 0,
mask_dst_x, mask_dst_y, to_i16_checked(dst.x), 0, mask_dst_x, mask_dst_y, to_i16_checked(dst.x),
to_i16_checked(dst.y), tmpew, tmpeh); to_i16_checked(dst.y), tmpew, tmpeh);
if (img->dim != 0 || img->color_inverted) { if (img->dim != 0 || img->color_inverted) {
// Apply properties, if we reach here, then has_alpha == false // Apply properties, if we reach here, then has_alpha == false
assert(!has_alpha); assert(!has_alpha);
if (img->color_inverted) { if (img->color_inverted) {
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_DIFFERENCE, xcb_render_composite(xd->base.c->c,
XCB_RENDER_PICT_OP_DIFFERENCE,
xd->white_pixel, XCB_NONE, result, 0, xd->white_pixel, XCB_NONE, result, 0,
0, 0, 0, to_i16_checked(dst.x), 0, 0, 0, to_i16_checked(dst.x),
to_i16_checked(dst.y), tmpew, tmpeh); to_i16_checked(dst.y), tmpew, tmpeh);
@ -338,13 +337,14 @@ compose_impl(struct _xrender_data *xd, struct xrender_image *xrimg, coord_t dst,
.height = tmpeh, .height = tmpeh,
}; };
xcb_render_fill_rectangles(xd->base.c, XCB_RENDER_PICT_OP_OVER, xcb_render_fill_rectangles(xd->base.c->c,
XCB_RENDER_PICT_OP_OVER,
result, dim_color, 1, &rect); result, dim_color, 1, &rect);
} }
} }
} }
if (mask_allocated) { if (mask_allocated) {
xcb_render_free_picture(xd->base.c, mask_pict); x_free_picture(xd->base.c, mask_pict);
} }
pixman_region32_fini(&reg); pixman_region32_fini(&reg);
} }
@ -362,7 +362,7 @@ static void fill(backend_t *base, struct color c, const region_t *clip) {
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, clip); x_set_picture_clip_region(base->c, xd->back[2], 0, 0, clip);
// color is in X fixed point representation // color is in X fixed point representation
xcb_render_fill_rectangles( xcb_render_fill_rectangles(
base->c, XCB_RENDER_PICT_OP_OVER, xd->back[2], base->c->c, XCB_RENDER_PICT_OP_OVER, xd->back[2],
(xcb_render_color_t){.red = (uint16_t)(c.red * 0xffff), (xcb_render_color_t){.red = (uint16_t)(c.red * 0xffff),
.green = (uint16_t)(c.green * 0xffff), .green = (uint16_t)(c.green * 0xffff),
.blue = (uint16_t)(c.blue * 0xffff), .blue = (uint16_t)(c.blue * 0xffff),
@ -382,7 +382,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
} }
struct _xrender_data *xd = (void *)backend_data; struct _xrender_data *xd = (void *)backend_data;
xcb_connection_t *c = xd->base.c; auto c = xd->base.c;
region_t reg_op; region_t reg_op;
pixman_region32_init(&reg_op); pixman_region32_init(&reg_op);
pixman_region32_intersect(&reg_op, (region_t *)reg_blur, (region_t *)reg_visible); pixman_region32_intersect(&reg_op, (region_t *)reg_blur, (region_t *)reg_visible);
@ -405,10 +405,12 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT; const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
const xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_PAD}; const xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_PAD};
xcb_render_picture_t tmp_picture[2] = { xcb_render_picture_t tmp_picture[2] = {
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized, x_create_picture_with_visual(xd->base.c, width_resized, height_resized,
xd->default_visual, pic_attrs_mask, &pic_attrs), xd->base.c->screen_info->root_visual,
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized, pic_attrs_mask, &pic_attrs),
xd->default_visual, pic_attrs_mask, &pic_attrs)}; x_create_picture_with_visual(xd->base.c, width_resized, height_resized,
xd->base.c->screen_info->root_visual,
pic_attrs_mask, &pic_attrs)};
if (!tmp_picture[0] || !tmp_picture[1]) { if (!tmp_picture[0] || !tmp_picture[1]) {
log_error("Failed to build intermediate Picture."); log_error("Failed to build intermediate Picture.");
@ -445,8 +447,8 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
// Copy from source picture to destination. The filter must // Copy from source picture to destination. The filter must
// be applied on source picture, to get the nearby pixels outside the // be applied on source picture, to get the nearby pixels outside the
// window. // window.
xcb_render_set_picture_filter(c, src_pict, to_u16_checked(strlen(filter)), xcb_render_set_picture_filter(c->c, src_pict,
filter, to_u16_checked(strlen(filter)), filter,
to_u32_checked(bctx->x_blur_kernel[i]->size), to_u32_checked(bctx->x_blur_kernel[i]->size),
bctx->x_blur_kernel[i]->kernel); bctx->x_blur_kernel[i]->kernel);
@ -454,21 +456,21 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
// First pass, back buffer -> tmp picture // First pass, back buffer -> tmp picture
// (we do this even if this is also the last pass, because we // (we do this even if this is also the last pass, because we
// cannot do back buffer -> back buffer) // cannot do back buffer -> back buffer)
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
dst_pict, to_i16_checked(extent_resized->x1), dst_pict, to_i16_checked(extent_resized->x1),
to_i16_checked(extent_resized->y1), 0, 0, 0, to_i16_checked(extent_resized->y1), 0, 0, 0,
0, width_resized, height_resized); 0, width_resized, height_resized);
} else if (i < bctx->x_blur_kernel_count - 1) { } else if (i < bctx->x_blur_kernel_count - 1) {
// This is not the last pass or the first pass, // This is not the last pass or the first pass,
// tmp picture 1 -> tmp picture 2 // tmp picture 1 -> tmp picture 2
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, src_pict,
XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0, XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0,
width_resized, height_resized); width_resized, height_resized);
} else { } else {
x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_op); x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_op);
// This is the last pass, and we are doing more than 1 pass // This is the last pass, and we are doing more than 1 pass
xcb_render_composite( xcb_render_composite(
c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], c->c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2],
0, 0, to_i16_checked(extent_resized->x1 - mask_dst.x + 1), 0, 0, to_i16_checked(extent_resized->x1 - mask_dst.x + 1),
to_i16_checked(extent_resized->y1 - mask_dst.y + 1), to_i16_checked(extent_resized->y1 - mask_dst.y + 1),
to_i16_checked(extent_resized->x1), to_i16_checked(extent_resized->x1),
@ -477,7 +479,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
// reset filter // reset filter
xcb_render_set_picture_filter( xcb_render_set_picture_filter(
c, src_pict, to_u16_checked(strlen(filter0)), filter0, 0, NULL); c->c, src_pict, to_u16_checked(strlen(filter0)), filter0, 0, NULL);
src_pict = tmp_picture[current]; src_pict = tmp_picture[current];
dst_pict = tmp_picture[!current]; dst_pict = tmp_picture[!current];
@ -488,15 +490,15 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
if (i == 1) { if (i == 1) {
x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_op); x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_op);
xcb_render_composite( xcb_render_composite(
c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], 0, 0, c->c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], 0, 0,
to_i16_checked(extent_resized->x1 - mask_dst.x + 1), to_i16_checked(extent_resized->x1 - mask_dst.x + 1),
to_i16_checked(extent_resized->y1 - mask_dst.y + 1), to_i16_checked(extent_resized->y1 - mask_dst.y + 1),
to_i16_checked(extent_resized->x1), to_i16_checked(extent_resized->x1),
to_i16_checked(extent_resized->y1), width_resized, height_resized); to_i16_checked(extent_resized->y1), width_resized, height_resized);
} }
xcb_render_free_picture(c, tmp_picture[0]); x_free_picture(c, tmp_picture[0]);
xcb_render_free_picture(c, tmp_picture[1]); x_free_picture(c, tmp_picture[1]);
pixman_region32_fini(&reg_op); pixman_region32_fini(&reg_op);
pixman_region32_fini(&reg_op_resized); pixman_region32_fini(&reg_op_resized);
return true; return true;
@ -505,7 +507,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
static void * static void *
bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) { bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
xcb_generic_error_t *e; xcb_generic_error_t *e;
auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), &e); auto r = xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), &e);
if (!r) { if (!r) {
log_error("Invalid pixmap: %#010x", pixmap); log_error("Invalid pixmap: %#010x", pixmap);
x_print_error(e->full_sequence, e->major_code, e->minor_code, e->error_code); x_print_error(e->full_sequence, e->major_code, e->minor_code, e->error_code);
@ -540,9 +542,9 @@ bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool
return img; return img;
} }
static void release_image_inner(backend_t *base, struct _xrender_image_data_inner *inner) { static void release_image_inner(backend_t *base, struct _xrender_image_data_inner *inner) {
xcb_render_free_picture(base->c, inner->pict); x_free_picture(base->c, inner->pict);
if (inner->owned) { if (inner->owned) {
xcb_free_pixmap(base->c, inner->pixmap); xcb_free_pixmap(base->c->c, inner->pixmap);
} }
free(inner); free(inner);
} }
@ -556,7 +558,7 @@ release_rounded_corner_cache(backend_t *base, struct xrender_rounded_rectangle_c
assert(cache->refcount > 0); assert(cache->refcount > 0);
cache->refcount--; cache->refcount--;
if (cache->refcount == 0) { if (cache->refcount == 0) {
xcb_render_free_picture(base->c, cache->p); x_free_picture(base->c, cache->p);
free(cache); free(cache);
} }
} }
@ -575,22 +577,22 @@ static void release_image(backend_t *base, void *image) {
static void deinit(backend_t *backend_data) { static void deinit(backend_t *backend_data) {
struct _xrender_data *xd = (void *)backend_data; struct _xrender_data *xd = (void *)backend_data;
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
xcb_render_free_picture(xd->base.c, xd->alpha_pict[i]); x_free_picture(xd->base.c, xd->alpha_pict[i]);
} }
xcb_render_free_picture(xd->base.c, xd->target); x_free_picture(xd->base.c, xd->target);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (xd->back[i] != XCB_NONE) { if (xd->back[i] != XCB_NONE) {
xcb_render_free_picture(xd->base.c, xd->back[i]); x_free_picture(xd->base.c, xd->back[i]);
} }
if (xd->back_pixmap[i] != XCB_NONE) { if (xd->back_pixmap[i] != XCB_NONE) {
xcb_free_pixmap(xd->base.c, xd->back_pixmap[i]); xcb_free_pixmap(xd->base.c->c, xd->back_pixmap[i]);
} }
} }
if (xd->present_event) { if (xd->present_event) {
xcb_unregister_for_special_event(xd->base.c, xd->present_event); xcb_unregister_for_special_event(xd->base.c->c, xd->present_event);
} }
xcb_render_free_picture(xd->base.c, xd->white_pixel); x_free_picture(xd->base.c, xd->white_pixel);
xcb_render_free_picture(xd->base.c, xd->black_pixel); x_free_picture(xd->base.c, xd->black_pixel);
free(xd); free(xd);
} }
@ -609,7 +611,7 @@ static void present(backend_t *base, const region_t *region) {
x_clear_picture_clip_region(base->c, xd->back[xd->curr_back]); x_clear_picture_clip_region(base->c, xd->back[xd->curr_back]);
// Update the back buffer first, then present // Update the back buffer first, then present
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2], xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_SRC, xd->back[2],
XCB_NONE, xd->back[xd->curr_back], orig_x, orig_y, 0, XCB_NONE, xd->back[xd->curr_back], orig_x, orig_y, 0,
0, orig_x, orig_y, region_width, region_height); 0, orig_x, orig_y, region_width, region_height);
@ -618,10 +620,10 @@ static void present(backend_t *base, const region_t *region) {
// Make sure we got reply from PresentPixmap before waiting for events, // Make sure we got reply from PresentPixmap before waiting for events,
// to avoid deadlock // to avoid deadlock
auto e = xcb_request_check( auto e = xcb_request_check(
base->c, xcb_present_pixmap_checked( base->c->c, xcb_present_pixmap_checked(
xd->base.c, xd->target_win, xd->base.c->c, xd->target_win,
xd->back_pixmap[xd->curr_back], 0, XCB_NONE, xregion, 0, xd->back_pixmap[xd->curr_back], 0, XCB_NONE, xregion, 0,
0, XCB_NONE, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, NULL)); 0, XCB_NONE, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, NULL));
x_destroy_region(base->c, xregion); x_destroy_region(base->c, xregion);
if (e) { if (e) {
log_error("Failed to present pixmap"); log_error("Failed to present pixmap");
@ -630,7 +632,7 @@ static void present(backend_t *base, const region_t *region) {
} }
// TODO(yshui) don't block wait for present completion // TODO(yshui) don't block wait for present completion
xcb_present_generic_event_t *pev = xcb_present_generic_event_t *pev =
(void *)xcb_wait_for_special_event(base->c, xd->present_event); (void *)xcb_wait_for_special_event(base->c->c, xd->present_event);
if (!pev) { if (!pev) {
// We don't know what happened, maybe X died // We don't know what happened, maybe X died
// But reset buffer age, so in case we do recover, we will // But reset buffer age, so in case we do recover, we will
@ -654,7 +656,7 @@ static void present(backend_t *base, const region_t *region) {
free(pev); free(pev);
} else { } else {
// No vsync needed, draw into the target picture directly // No vsync needed, draw into the target picture directly
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2], xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_SRC, xd->back[2],
XCB_NONE, xd->target, orig_x, orig_y, 0, 0, orig_x, XCB_NONE, xd->target, orig_x, orig_y, 0, 0, orig_x,
orig_y, region_width, region_height); orig_y, region_width, region_height);
} }
@ -673,7 +675,7 @@ static int buffer_age(backend_t *backend_data) {
static struct _xrender_image_data_inner * static struct _xrender_image_data_inner *
new_inner(backend_t *base, int w, int h, xcb_visualid_t visual, uint8_t depth) { new_inner(backend_t *base, int w, int h, xcb_visualid_t visual, uint8_t depth) {
auto new_inner = ccalloc(1, struct _xrender_image_data_inner); auto new_inner = ccalloc(1, struct _xrender_image_data_inner);
new_inner->pixmap = x_create_pixmap(base->c, depth, base->root, w, h); new_inner->pixmap = x_create_pixmap(base->c, depth, w, h);
if (new_inner->pixmap == XCB_NONE) { if (new_inner->pixmap == XCB_NONE) {
log_error("Failed to create pixmap for copy"); log_error("Failed to create pixmap for copy");
free(new_inner); free(new_inner);
@ -683,7 +685,7 @@ new_inner(backend_t *base, int w, int h, xcb_visualid_t visual, uint8_t depth) {
base->c, visual, new_inner->pixmap, 0, NULL); base->c, visual, new_inner->pixmap, 0, NULL);
if (new_inner->pict == XCB_NONE) { if (new_inner->pict == XCB_NONE) {
log_error("Failed to create picture for copy"); log_error("Failed to create picture for copy");
xcb_free_pixmap(base->c, new_inner->pixmap); xcb_free_pixmap(base->c->c, new_inner->pixmap);
free(new_inner); free(new_inner);
return NULL; return NULL;
} }
@ -705,12 +707,12 @@ static void *make_mask(backend_t *base, geometry_t size, const region_t *reg) {
auto inner = auto inner =
new_inner(base, size.width + 2, size.height + 2, new_inner(base, size.width + 2, size.height + 2,
x_get_visual_for_standard(base->c, XCB_PICT_STANDARD_ARGB_32), 32); x_get_visual_for_standard(base->c, XCB_PICT_STANDARD_ARGB_32), 32);
xcb_render_change_picture(base->c, inner->pict, XCB_RENDER_CP_REPEAT, xcb_render_change_picture(base->c->c, inner->pict, XCB_RENDER_CP_REPEAT,
(uint32_t[]){XCB_RENDER_REPEAT_PAD}); (uint32_t[]){XCB_RENDER_REPEAT_PAD});
const rect_t *extent = pixman_region32_extents((region_t *)reg); const rect_t *extent = pixman_region32_extents((region_t *)reg);
x_set_picture_clip_region(base->c, xd->back[2], 1, 1, reg); x_set_picture_clip_region(base->c, xd->back[2], 1, 1, reg);
xcb_render_fill_rectangles( xcb_render_fill_rectangles(
base->c, XCB_RENDER_PICT_OP_SRC, inner->pict, base->c->c, XCB_RENDER_PICT_OP_SRC, inner->pict,
(xcb_render_color_t){.red = 0, .green = 0, .blue = 0, .alpha = 0xffff}, 1, (xcb_render_color_t){.red = 0, .green = 0, .blue = 0, .alpha = 0xffff}, 1,
(xcb_rectangle_t[]){{.x = to_i16_checked(extent->x1 + 1), (xcb_rectangle_t[]){{.x = to_i16_checked(extent->x1 + 1),
.y = to_i16_checked(extent->y1 + 1), .y = to_i16_checked(extent->y1 + 1),
@ -720,7 +722,7 @@ static void *make_mask(backend_t *base, geometry_t size, const region_t *reg) {
// Paint the border transparent // Paint the border transparent
xcb_render_fill_rectangles( xcb_render_fill_rectangles(
base->c, XCB_RENDER_PICT_OP_SRC, inner->pict, base->c->c, XCB_RENDER_PICT_OP_SRC, inner->pict,
(xcb_render_color_t){.red = 0, .green = 0, .blue = 0, .alpha = 0}, 4, (xcb_render_color_t){.red = 0, .green = 0, .blue = 0, .alpha = 0}, 4,
(xcb_rectangle_t[]){{.x = 0, .y = 0, .width = w16, .height = 1}, (xcb_rectangle_t[]){{.x = 0, .y = 0, .width = w16, .height = 1},
{.x = 0, .y = 0, .width = 1, .height = h16}, {.x = 0, .y = 0, .width = 1, .height = h16},
@ -758,7 +760,7 @@ static bool decouple_image(backend_t *base, struct backend_image *img, const reg
} }
x_set_picture_clip_region(base->c, inner->pict, 0, 0, reg); x_set_picture_clip_region(base->c, inner->pict, 0, 0, reg);
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE,
inner2->pict, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width), inner2->pict, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width),
to_u16_checked(inner->height)); to_u16_checked(inner->height));
@ -797,8 +799,8 @@ static bool image_op(backend_t *base, enum image_operations op, void *image,
auto inner = (struct _xrender_image_data_inner *)img->inner; auto inner = (struct _xrender_image_data_inner *)img->inner;
auto alpha_pict = xd->alpha_pict[(int)((1 - dargs[0]) * MAX_ALPHA)]; auto alpha_pict = xd->alpha_pict[(int)((1 - dargs[0]) * MAX_ALPHA)];
x_set_picture_clip_region(base->c, inner->pict, 0, 0, &reg); x_set_picture_clip_region(base->c, inner->pict, 0, 0, &reg);
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_OUT_REVERSE, alpha_pict, xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_OUT_REVERSE,
XCB_NONE, inner->pict, 0, 0, 0, 0, 0, 0, alpha_pict, XCB_NONE, inner->pict, 0, 0, 0, 0, 0, 0,
to_u16_checked(inner->width), to_u16_checked(inner->width),
to_u16_checked(inner->height)); to_u16_checked(inner->height));
inner->has_alpha = true; inner->has_alpha = true;
@ -877,24 +879,24 @@ static backend_t *backend_xrender_init(session_t *ps) {
for (int i = 0; i <= MAX_ALPHA; ++i) { for (int i = 0; i <= MAX_ALPHA; ++i) {
double o = (double)i / (double)MAX_ALPHA; double o = (double)i / (double)MAX_ALPHA;
xd->alpha_pict[i] = solid_picture(ps->c, ps->root, false, o, 0, 0, 0); xd->alpha_pict[i] = solid_picture(&ps->c, false, o, 0, 0, 0);
assert(xd->alpha_pict[i] != XCB_NONE); assert(xd->alpha_pict[i] != XCB_NONE);
} }
xd->target_width = ps->root_width; xd->target_width = ps->root_width;
xd->target_height = ps->root_height; xd->target_height = ps->root_height;
xd->default_visual = ps->vis; xd->black_pixel = solid_picture(&ps->c, true, 1, 0, 0, 0);
xd->black_pixel = solid_picture(ps->c, ps->root, true, 1, 0, 0, 0); xd->white_pixel = solid_picture(&ps->c, true, 1, 1, 1, 1);
xd->white_pixel = solid_picture(ps->c, ps->root, true, 1, 1, 1, 1);
xd->target_win = session_get_target_window(ps); xd->target_win = session_get_target_window(ps);
xcb_render_create_picture_value_list_t pa = { xcb_render_create_picture_value_list_t pa = {
.subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS, .subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS,
}; };
xd->target = x_create_picture_with_visual_and_pixmap( xd->target = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, xd->target_win, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); &ps->c, ps->c.screen_info->root_visual, xd->target_win,
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
auto pictfmt = x_get_pictform_for_visual(ps->c, ps->vis); auto pictfmt = x_get_pictform_for_visual(&ps->c, ps->c.screen_info->root_visual);
if (!pictfmt) { if (!pictfmt) {
log_fatal("Default visual is invalid"); log_fatal("Default visual is invalid");
abort(); abort();
@ -902,11 +904,11 @@ static backend_t *backend_xrender_init(session_t *ps) {
xd->vsync = ps->o.vsync; xd->vsync = ps->o.vsync;
if (ps->present_exists) { if (ps->present_exists) {
auto eid = x_new_id(ps->c); auto eid = x_new_id(&ps->c);
auto e = auto e =
xcb_request_check(ps->c, xcb_present_select_input_checked( xcb_request_check(ps->c.c, xcb_present_select_input_checked(
ps->c, eid, xd->target_win, ps->c.c, eid, xd->target_win,
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY)); XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
if (e) { if (e) {
log_error("Cannot select present input, vsync will be disabled"); log_error("Cannot select present input, vsync will be disabled");
xd->vsync = false; xd->vsync = false;
@ -914,7 +916,7 @@ static backend_t *backend_xrender_init(session_t *ps) {
} }
xd->present_event = xd->present_event =
xcb_register_for_special_xge(ps->c, &xcb_present_id, eid, NULL); xcb_register_for_special_xge(ps->c.c, &xcb_present_id, eid, NULL);
if (!xd->present_event) { if (!xd->present_event) {
log_error("Cannot register for special XGE, vsync will be " log_error("Cannot register for special XGE, vsync will be "
"disabled"); "disabled");
@ -928,14 +930,14 @@ static backend_t *backend_xrender_init(session_t *ps) {
// double buffering. // double buffering.
int first_buffer_index = xd->vsync ? 0 : 2; int first_buffer_index = xd->vsync ? 0 : 2;
for (int i = first_buffer_index; i < 3; i++) { for (int i = first_buffer_index; i < 3; i++) {
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root, xd->back_pixmap[i] =
to_u16_checked(ps->root_width), x_create_pixmap(&ps->c, pictfmt->depth, to_u16_checked(ps->root_width),
to_u16_checked(ps->root_height)); to_u16_checked(ps->root_height));
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT; const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
const xcb_render_create_picture_value_list_t pic_attrs = { const xcb_render_create_picture_value_list_t pic_attrs = {
.repeat = XCB_RENDER_REPEAT_PAD}; .repeat = XCB_RENDER_REPEAT_PAD};
xd->back[i] = x_create_picture_with_pictfmt_and_pixmap( xd->back[i] = x_create_picture_with_pictfmt_and_pixmap(
ps->c, pictfmt, xd->back_pixmap[i], pic_attrs_mask, &pic_attrs); &ps->c, pictfmt, xd->back_pixmap[i], pic_attrs_mask, &pic_attrs);
xd->buffer_age[i] = -1; xd->buffer_age[i] = -1;
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) { if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
log_error("Cannot create pixmap for rendering"); log_error("Cannot create pixmap for rendering");

116
src/c2.c
View File

@ -336,17 +336,19 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
* Parse a condition string. * Parse a condition string.
*/ */
c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data) { c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data) {
if (!pattern) if (!pattern) {
return NULL; return NULL;
}
// Parse the pattern // Parse the pattern
c2_ptr_t result = C2_PTR_INIT; c2_ptr_t result = C2_PTR_INIT;
int offset = -1; int offset = -1;
if (strlen(pattern) >= 2 && ':' == pattern[1]) if (strlen(pattern) >= 2 && ':' == pattern[1]) {
offset = c2_parse_legacy(pattern, 0, &result); offset = c2_parse_legacy(pattern, 0, &result);
else } else {
offset = c2_parse_grp(pattern, 0, &result, 0); offset = c2_parse_grp(pattern, 0, &result, 0);
}
if (offset < 0) { if (offset < 0) {
c2_freep(&result); c2_freep(&result);
@ -395,11 +397,13 @@ c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data) {
*/ */
static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int level) { static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int level) {
// Check for recursion levels // Check for recursion levels
if (level > C2_MAX_LEVELS) if (level > C2_MAX_LEVELS) {
c2_error("Exceeded maximum recursion levels."); c2_error("Exceeded maximum recursion levels.");
}
if (!pattern) if (!pattern) {
return -1; return -1;
}
// Expected end character // Expected end character
const char endchar = (offset ? ')' : '\0'); const char endchar = (offset ? ')' : '\0');
@ -428,17 +432,20 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
assert(elei <= 2); assert(elei <= 2);
// Jump over spaces // Jump over spaces
if (isspace((unsigned char)pattern[offset])) if (isspace((unsigned char)pattern[offset])) {
continue; continue;
}
// Handle end of group // Handle end of group
if (')' == pattern[offset]) if (')' == pattern[offset]) {
break; break;
}
// Handle "!" // Handle "!"
if ('!' == pattern[offset]) { if ('!' == pattern[offset]) {
if (!next_expected) if (!next_expected) {
c2_error("Unexpected \"!\"."); c2_error("Unexpected \"!\".");
}
neg = !neg; neg = !neg;
continue; continue;
@ -446,8 +453,9 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
// Handle AND and OR // Handle AND and OR
if ('&' == pattern[offset] || '|' == pattern[offset]) { if ('&' == pattern[offset] || '|' == pattern[offset]) {
if (next_expected) if (next_expected) {
c2_error("Unexpected logical operator."); c2_error("Unexpected logical operator.");
}
next_expected = true; next_expected = true;
if (!mstrncmp("&&", pattern + offset)) { if (!mstrncmp("&&", pattern + offset)) {
@ -456,15 +464,17 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
} else if (!mstrncmp("||", pattern + offset)) { } else if (!mstrncmp("||", pattern + offset)) {
ops[elei] = C2_B_OOR; ops[elei] = C2_B_OOR;
++offset; ++offset;
} else } else {
c2_error("Illegal logical operator."); c2_error("Illegal logical operator.");
}
continue; continue;
} }
// Parsing an element // Parsing an element
if (!next_expected) if (!next_expected) {
c2_error("Unexpected expression."); c2_error("Unexpected expression.");
}
assert(!elei || ops[elei]); assert(!elei || ops[elei]);
@ -491,21 +501,25 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
// It's a subgroup if it starts with '(' // It's a subgroup if it starts with '('
if ('(' == pattern[offset]) { if ('(' == pattern[offset]) {
if ((offset = c2_parse_grp(pattern, offset + 1, pele, level + 1)) < 0) if ((offset = c2_parse_grp(pattern, offset + 1, pele, level + 1)) < 0) {
goto fail; goto fail;
}
} }
// Otherwise it's a leaf // Otherwise it's a leaf
else { else {
if ((offset = c2_parse_target(pattern, offset, pele)) < 0) if ((offset = c2_parse_target(pattern, offset, pele)) < 0) {
goto fail; goto fail;
}
assert(!pele->isbranch && !c2_ptr_isempty(*pele)); assert(!pele->isbranch && !c2_ptr_isempty(*pele));
if ((offset = c2_parse_op(pattern, offset, pele)) < 0) if ((offset = c2_parse_op(pattern, offset, pele)) < 0) {
goto fail; goto fail;
}
if ((offset = c2_parse_pattern(pattern, offset, pele)) < 0) if ((offset = c2_parse_pattern(pattern, offset, pele)) < 0) {
goto fail; goto fail;
}
} }
// Decrement offset -- we will increment it in loop update // Decrement offset -- we will increment it in loop update
--offset; --offset;
@ -513,10 +527,11 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
// Apply negation // Apply negation
if (neg) { if (neg) {
neg = false; neg = false;
if (pele->isbranch) if (pele->isbranch) {
pele->b->neg = !pele->b->neg; pele->b->neg = !pele->b->neg;
else } else {
pele->l->neg = !pele->l->neg; pele->l->neg = !pele->l->neg;
}
} }
next_expected = false; next_expected = false;
@ -525,10 +540,12 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
} }
// Wrong end character? // Wrong end character?
if (pattern[offset] && !endchar) if (pattern[offset] && !endchar) {
c2_error("Expected end of string but found '%c'.", pattern[offset]); c2_error("Expected end of string but found '%c'.", pattern[offset]);
if (!pattern[offset] && endchar) }
if (!pattern[offset] && endchar) {
c2_error("Expected '%c' but found end of string.", endchar); c2_error("Expected '%c' but found end of string.", endchar);
}
// Handle end of group // Handle end of group
if (!elei) { if (!elei) {
@ -544,8 +561,9 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
*presult = eles[0]; *presult = eles[0];
if (')' == pattern[offset]) if (')' == pattern[offset]) {
++offset; ++offset;
}
return offset; return offset;
@ -778,11 +796,11 @@ static int c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult) {
// Parse operator // Parse operator
while ('=' == pattern[offset] || '>' == pattern[offset] || '<' == pattern[offset]) { while ('=' == pattern[offset] || '>' == pattern[offset] || '<' == pattern[offset]) {
if ('=' == pattern[offset] && C2_L_OGT == pleaf->op) if ('=' == pattern[offset] && C2_L_OGT == pleaf->op) {
pleaf->op = C2_L_OGTEQ; pleaf->op = C2_L_OGTEQ;
else if ('=' == pattern[offset] && C2_L_OLT == pleaf->op) } else if ('=' == pattern[offset] && C2_L_OLT == pleaf->op) {
pleaf->op = C2_L_OLTEQ; pleaf->op = C2_L_OLTEQ;
else if (pleaf->op) { } else if (pleaf->op) {
c2_error("Duplicate operator."); c2_error("Duplicate operator.");
} else { } else {
switch (pattern[offset]) { switch (pattern[offset]) {
@ -797,9 +815,10 @@ static int c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult) {
} }
// Check for problems // Check for problems
if (C2_L_OEQ != pleaf->op && (pleaf->match || pleaf->match_ignorecase)) if (C2_L_OEQ != pleaf->op && (pleaf->match || pleaf->match_ignorecase)) {
c2_error("Exists/greater-than/less-than operators cannot have a " c2_error("Exists/greater-than/less-than operators cannot have a "
"qualifier."); "qualifier.");
}
return offset; return offset;
@ -891,9 +910,10 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult)
char *pstr = NULL; char *pstr = NULL;
long val = strtol( long val = strtol(
tstr, &pstr, ('o' == pattern[offset] ? 8 : 16)); tstr, &pstr, ('o' == pattern[offset] ? 8 : 16));
if (pstr != &tstr[2] || val <= 0) if (pstr != &tstr[2] || val <= 0) {
c2_error("Invalid octal/hex escape " c2_error("Invalid octal/hex escape "
"sequence."); "sequence.");
}
*(ptptnstr++) = to_char_checked(val); *(ptptnstr++) = to_char_checked(val);
offset += 2; offset += 2;
break; break;
@ -904,8 +924,9 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult)
*(ptptnstr++) = pattern[offset]; *(ptptnstr++) = pattern[offset];
} }
} }
if (!pattern[offset]) if (!pattern[offset]) {
c2_error("Premature end of pattern string."); c2_error("Premature end of pattern string.");
}
++offset; ++offset;
*ptptnstr = '\0'; *ptptnstr = '\0';
pleaf->ptnstr = strdup(tptnstr); pleaf->ptnstr = strdup(tptnstr);
@ -914,27 +935,32 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult)
C2H_SKIP_SPACES(); C2H_SKIP_SPACES();
if (!pleaf->ptntype) if (!pleaf->ptntype) {
c2_error("Invalid pattern type."); c2_error("Invalid pattern type.");
}
// Check if the type is correct // Check if the type is correct
if (!(((C2_L_TSTRING == pleaf->type || C2_L_TATOM == pleaf->type) && if (!(((C2_L_TSTRING == pleaf->type || C2_L_TATOM == pleaf->type) &&
C2_L_PTSTRING == pleaf->ptntype) || C2_L_PTSTRING == pleaf->ptntype) ||
((C2_L_TCARDINAL == pleaf->type || C2_L_TWINDOW == pleaf->type || ((C2_L_TCARDINAL == pleaf->type || C2_L_TWINDOW == pleaf->type ||
C2_L_TDRAWABLE == pleaf->type) && C2_L_TDRAWABLE == pleaf->type) &&
C2_L_PTINT == pleaf->ptntype))) C2_L_PTINT == pleaf->ptntype))) {
c2_error("Pattern type incompatible with target type."); c2_error("Pattern type incompatible with target type.");
}
if (C2_L_PTINT == pleaf->ptntype && pleaf->match) if (C2_L_PTINT == pleaf->ptntype && pleaf->match) {
c2_error("Integer/boolean pattern cannot have operator qualifiers."); c2_error("Integer/boolean pattern cannot have operator qualifiers.");
}
if (C2_L_PTINT == pleaf->ptntype && pleaf->match_ignorecase) if (C2_L_PTINT == pleaf->ptntype && pleaf->match_ignorecase) {
c2_error("Integer/boolean pattern cannot have flags."); c2_error("Integer/boolean pattern cannot have flags.");
}
if (C2_L_PTSTRING == pleaf->ptntype && if (C2_L_PTSTRING == pleaf->ptntype &&
(C2_L_OGT == pleaf->op || C2_L_OGTEQ == pleaf->op || C2_L_OLT == pleaf->op || (C2_L_OGT == pleaf->op || C2_L_OGTEQ == pleaf->op || C2_L_OLT == pleaf->op ||
C2_L_OLTEQ == pleaf->op)) C2_L_OLTEQ == pleaf->op)) {
c2_error("String pattern cannot have an arithmetic operator."); c2_error("String pattern cannot have an arithmetic operator.");
}
return offset; return offset;
@ -1173,9 +1199,8 @@ c2_lptr_t *c2_free_lptr(c2_lptr_t *lp, c2_userdata_free f) {
static const char *c2h_dump_str_tgt(const c2_l_t *pleaf) { static const char *c2h_dump_str_tgt(const c2_l_t *pleaf) {
if (pleaf->predef != C2_L_PUNDEFINED) { if (pleaf->predef != C2_L_PUNDEFINED) {
return C2_PREDEFS[pleaf->predef].name; return C2_PREDEFS[pleaf->predef].name;
} else {
return pleaf->tgt;
} }
return pleaf->tgt;
} }
/** /**
@ -1378,11 +1403,11 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
int word_count = 1; int word_count = 1;
if (pleaf->index < 0) { if (pleaf->index < 0) {
// Get length of property in 32-bit multiples // Get length of property in 32-bit multiples
auto prop_info = x_get_prop_info(ps->c, wid, pleaf->tgtatom); auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom);
word_count = to_int_checked((prop_info.length + 4 - 1) / 4); word_count = to_int_checked((prop_info.length + 4 - 1) / 4);
} }
winprop_t prop = x_get_prop_with_offset( winprop_t prop = x_get_prop_with_offset(
ps->c, wid, pleaf->tgtatom, idx, word_count, &ps->c, wid, pleaf->tgtatom, idx, word_count,
c2_get_atom_type(pleaf), pleaf->format); c2_get_atom_type(pleaf), pleaf->format);
ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1)); ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1));
@ -1455,11 +1480,11 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
int word_count = 1; int word_count = 1;
if (pleaf->index < 0) { if (pleaf->index < 0) {
// Get length of property in 32-bit multiples // Get length of property in 32-bit multiples
auto prop_info = x_get_prop_info(ps->c, wid, pleaf->tgtatom); auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom);
word_count = to_int_checked((prop_info.length + 4 - 1) / 4); word_count = to_int_checked((prop_info.length + 4 - 1) / 4);
} }
winprop_t prop = x_get_prop_with_offset( winprop_t prop = x_get_prop_with_offset(
ps->c, wid, pleaf->tgtatom, idx, word_count, &ps->c, wid, pleaf->tgtatom, idx, word_count,
c2_get_atom_type(pleaf), pleaf->format); c2_get_atom_type(pleaf), pleaf->format);
ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1)); ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1));
@ -1470,7 +1495,7 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
xcb_atom_t atom = (xcb_atom_t)winprop_get_int(prop, i); xcb_atom_t atom = (xcb_atom_t)winprop_get_int(prop, i);
if (atom) { if (atom) {
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply( xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
ps->c, xcb_get_atom_name(ps->c, atom), NULL); ps->c.c, xcb_get_atom_name(ps->c.c, atom), NULL);
if (reply) { if (reply) {
targets[i] = targets_free_inner[i] = strndup( targets[i] = targets_free_inner[i] = strndup(
xcb_get_atom_name_name(reply), xcb_get_atom_name_name(reply),
@ -1599,8 +1624,9 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
if (cond.isbranch) { if (cond.isbranch) {
const c2_b_t *pb = cond.b; const c2_b_t *pb = cond.b;
if (!pb) if (!pb) {
return false; return false;
}
error = false; error = false;
@ -1630,8 +1656,9 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
else { else {
const c2_l_t *pleaf = cond.l; const c2_l_t *pleaf = cond.l;
if (!pleaf) if (!pleaf) {
return false; return false;
}
c2_match_once_leaf(ps, w, pleaf, &result, &error); c2_match_once_leaf(ps, w, pleaf, &result, &error);
@ -1651,11 +1678,13 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
} }
// Postprocess the result // Postprocess the result
if (error) if (error) {
result = false; result = false;
}
if (cond.isbranch ? cond.b->neg : cond.l->neg) if (cond.isbranch ? cond.b->neg : cond.l->neg) {
result = !result; result = !result;
}
return result; return result;
} }
@ -1673,8 +1702,9 @@ bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condl
// Then go through the whole linked list // Then go through the whole linked list
for (; condlst; condlst = condlst->next) { for (; condlst; condlst = condlst->next) {
if (c2_match_once(ps, w, condlst->ptr)) { if (c2_match_once(ps, w, condlst->ptr)) {
if (pdata) if (pdata) {
*pdata = condlst->data; *pdata = condlst->data;
}
return true; return true;
} }
} }

View File

@ -84,18 +84,6 @@ struct glx_session;
struct atom; struct atom;
struct conv; struct conv;
enum pending_reply_action {
PENDING_REPLY_ACTION_IGNORE,
PENDING_REPLY_ACTION_ABORT,
PENDING_REPLY_ACTION_DEBUG_ABORT,
};
typedef struct pending_reply {
struct pending_reply *next;
unsigned long sequence;
enum pending_reply_action action;
} pending_reply_t;
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
#ifdef DEBUG_GLX_DEBUG_CONTEXT #ifdef DEBUG_GLX_DEBUG_CONTEXT
typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config,
@ -183,28 +171,14 @@ typedef struct session {
struct shader_info *shaders; struct shader_info *shaders;
// === Display related === // === Display related ===
/// X connection
struct x_connection c;
/// Whether the X server is grabbed by us /// Whether the X server is grabbed by us
bool server_grabbed; bool server_grabbed;
/// Display in use.
Display *dpy;
/// Previous handler of X errors
XErrorHandler previous_xerror_handler;
/// Default screen.
int scr;
/// XCB connection.
xcb_connection_t *c;
/// Default visual.
xcb_visualid_t vis;
/// Default depth.
int depth;
/// Root window.
xcb_window_t root;
/// Height of root window.
int root_height;
/// Width of root window. /// Width of root window.
int root_width; int root_width;
// Damage of root window. /// Height of root window.
// Damage root_damage; int root_height;
/// X Composite overlay window. /// X Composite overlay window.
xcb_window_t overlay; xcb_window_t overlay;
/// The target window for debug mode /// The target window for debug mode
@ -289,11 +263,6 @@ typedef struct session {
xcb_render_picture_t *alpha_picts; xcb_render_picture_t *alpha_picts;
/// Time of last fading. In milliseconds. /// Time of last fading. In milliseconds.
long long fade_time; long long fade_time;
/// Head pointer of the error ignore linked list.
pending_reply_t *pending_reply_head;
/// Pointer to the <code>next</code> member of tail element of the error
/// ignore linked list.
pending_reply_t **pending_reply_tail;
// Cached blur convolution kernels. // Cached blur convolution kernels.
struct x_convolution_kernel **blur_kerns_cache; struct x_convolution_kernel **blur_kerns_cache;
/// If we should quit /// If we should quit
@ -391,10 +360,8 @@ typedef struct session {
int glx_event; int glx_event;
/// Error base number for X GLX extension. /// Error base number for X GLX extension.
int glx_error; int glx_error;
/// Number of X RandR monitors. /// Information about monitors.
int randr_nmonitors; struct x_monitors monitors;
/// X RandR monitor regions.
region_t *randr_monitor_regs;
/// Whether X Sync extension exists. /// Whether X Sync extension exists.
bool xsync_exists; bool xsync_exists;
/// Event base number for X Sync extension. /// Event base number for X Sync extension.
@ -492,7 +459,7 @@ static inline struct timespec get_time_timespec(void) {
* Return the painting target window. * Return the painting target window.
*/ */
static inline xcb_window_t get_tgt_window(session_t *ps) { static inline xcb_window_t get_tgt_window(session_t *ps) {
return ps->overlay != XCB_NONE ? ps->overlay : ps->root; return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root;
} }
/** /**
@ -502,35 +469,6 @@ static inline bool bkend_use_glx(session_t *ps) {
return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend; return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend;
} }
static void
set_reply_action(session_t *ps, uint32_t sequence, enum pending_reply_action action) {
auto i = cmalloc(pending_reply_t);
if (!i) {
abort();
}
i->sequence = sequence;
i->next = 0;
i->action = action;
*ps->pending_reply_tail = i;
ps->pending_reply_tail = &i->next;
}
/**
* Ignore X errors caused by given X request.
*/
static inline void set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) {
if (ps->o.show_all_xerrors) {
return;
}
set_reply_action(ps, cookie.sequence, PENDING_REPLY_ACTION_IGNORE);
}
static inline void set_cant_fail_cookie(session_t *ps, xcb_void_cookie_t cookie) {
set_reply_action(ps, cookie.sequence, PENDING_REPLY_ACTION_ABORT);
}
/** /**
* Determine if a window has a specific property. * Determine if a window has a specific property.
* *
@ -541,7 +479,8 @@ static inline void set_cant_fail_cookie(session_t *ps, xcb_void_cookie_t cookie)
*/ */
static inline bool wid_has_prop(const session_t *ps, xcb_window_t w, xcb_atom_t atom) { static inline bool wid_has_prop(const session_t *ps, xcb_window_t w, xcb_atom_t atom) {
auto r = xcb_get_property_reply( auto r = xcb_get_property_reply(
ps->c, xcb_get_property(ps->c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL); ps->c.c,
xcb_get_property(ps->c.c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL);
if (!r) { if (!r) {
return false; return false;
} }

View File

@ -1165,7 +1165,7 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
// display // display
if (!strcmp("display", target)) { if (!strcmp("display", target)) {
cdbus_reply_string(ps, msg, DisplayString(ps->dpy)); cdbus_reply_string(ps, msg, DisplayString(ps->c.dpy));
return true; return true;
} }

View File

@ -57,7 +57,7 @@ static inline const char *ev_window_name(session_t *ps, xcb_window_t wid) {
char *name = ""; char *name = "";
if (wid) { if (wid) {
name = "(Failed to get title)"; name = "(Failed to get title)";
if (ps->root == wid) { if (ps->c.screen_info->root == wid) {
name = "(Root window)"; name = "(Root window)";
} else if (ps->overlay == wid) { } else if (ps->overlay == wid) {
name = "(Overlay)"; name = "(Overlay)";
@ -184,7 +184,7 @@ static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) {
} }
static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) { static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) {
if (ev->parent == ps->root) { if (ev->parent == ps->c.screen_info->root) {
add_win_top(ps, ev->window); add_win_top(ps, ev->window);
} }
} }
@ -239,7 +239,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
} }
// Recalculate which monitor this window is on // Recalculate which monitor this window is on
win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, mw); win_update_monitor(&ps->monitors, mw);
} }
// override_redirect flag cannot be changed after window creation, as far // override_redirect flag cannot be changed after window creation, as far
@ -250,7 +250,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) { static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) {
log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }", log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }",
ev->event, ev->window, ev->above_sibling, ev->override_redirect); ev->event, ev->window, ev->above_sibling, ev->override_redirect);
if (ev->window == ps->root) { if (ev->window == ps->c.screen_info->root) {
set_root_flags(ps, ROOT_FLAGS_CONFIGURED); set_root_flags(ps, ROOT_FLAGS_CONFIGURED);
} else { } else {
configure_win(ps, ev); configure_win(ps, ev);
@ -284,8 +284,8 @@ static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
// in redirected state. // in redirected state.
if (ps->overlay && ev->window == ps->overlay && !ps->redirected) { if (ps->overlay && ev->window == ps->overlay && !ps->redirected) {
log_debug("Overlay is mapped while we are not redirected"); log_debug("Overlay is mapped while we are not redirected");
auto e = auto e = xcb_request_check(
xcb_request_check(ps->c, xcb_unmap_window_checked(ps->c, ps->overlay)); ps->c.c, xcb_unmap_window_checked(ps->c.c, ps->overlay));
if (e) { if (e) {
log_error("Failed to unmap the overlay window"); log_error("Failed to unmap the overlay window");
free(e); free(e);
@ -323,7 +323,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
ps->pending_updates = true; ps->pending_updates = true;
} }
if (ev->parent == ps->root) { if (ev->parent == ps->c.screen_info->root) {
// X will generate reparent notifiy even if the parent didn't actually // X will generate reparent notifiy even if the parent didn't actually
// change (i.e. reparent again to current parent). So we check if that's // change (i.e. reparent again to current parent). So we check if that's
// the case // the case
@ -351,7 +351,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
// Reset event mask in case something wrong happens // Reset event mask in case something wrong happens
xcb_change_window_attributes( xcb_change_window_attributes(
ps->c, ev->window, XCB_CW_EVENT_MASK, ps->c.c, ev->window, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)}); (const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)});
if (!wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) { if (!wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
@ -360,7 +360,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
"property change in case it gains one.", "property change in case it gains one.",
ev->window); ev->window);
xcb_change_window_attributes( xcb_change_window_attributes(
ps->c, ev->window, XCB_CW_EVENT_MASK, ps->c.c, ev->window, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) | (const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) |
XCB_EVENT_MASK_PROPERTY_CHANGE}); XCB_EVENT_MASK_PROPERTY_CHANGE});
} else { } else {
@ -373,9 +373,9 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE); win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
ps->pending_updates = true; ps->pending_updates = true;
} else { } else {
if (!w_real_top) if (!w_real_top) {
log_debug("parent %#010x not found", ev->parent); log_debug("parent %#010x not found", ev->parent);
else { } else {
// Window is not currently mapped, unmark its // Window is not currently mapped, unmark its
// client to trigger a client recheck when it is // client to trigger a client recheck when it is
// mapped later. // mapped later.
@ -392,8 +392,9 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
static inline void ev_circulate_notify(session_t *ps, xcb_circulate_notify_event_t *ev) { static inline void ev_circulate_notify(session_t *ps, xcb_circulate_notify_event_t *ev) {
auto w = find_win(ps, ev->window); auto w = find_win(ps, ev->window);
if (!w) if (!w) {
return; return;
}
if (ev->place == PlaceOnTop) { if (ev->place == PlaceOnTop) {
restack_top(ps, w); restack_top(ps, w);
@ -410,7 +411,8 @@ static inline void expose_root(session_t *ps, const rect_t *rects, int nrects) {
} }
static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) { static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) {
if (ev->window == ps->root || (ps->overlay && ev->window == ps->overlay)) { if (ev->window == ps->c.screen_info->root ||
(ps->overlay && ev->window == ps->overlay)) {
int more = ev->count + 1; int more = ev->count + 1;
if (ps->n_expose == ps->size_expose) { if (ps->n_expose == ps->size_expose) {
if (ps->expose_rects) { if (ps->expose_rects) {
@ -439,8 +441,8 @@ static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) {
static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t *ev) { static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t *ev) {
if (unlikely(log_get_level_tls() <= LOG_LEVEL_TRACE)) { if (unlikely(log_get_level_tls() <= LOG_LEVEL_TRACE)) {
// Print out changed atom // Print out changed atom
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
xcb_get_atom_name_reply(ps->c, xcb_get_atom_name(ps->c, ev->atom), NULL); ps->c.c, xcb_get_atom_name(ps->c.c, ev->atom), NULL);
const char *name = "?"; const char *name = "?";
int name_len = 1; int name_len = 1;
if (reply) { if (reply) {
@ -452,7 +454,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
free(reply); free(reply);
} }
if (ps->root == ev->window) { if (ps->c.screen_info->root == ev->window) {
if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) { if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
// to update focus // to update focus
ps->pending_updates = true; ps->pending_updates = true;
@ -473,7 +475,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// Check whether it could be a client window // Check whether it could be a client window
if (!find_toplevel(ps, ev->window)) { if (!find_toplevel(ps, ev->window)) {
// Reset event mask anyway // Reset event mask anyway
xcb_change_window_attributes(ps->c, ev->window, XCB_CW_EVENT_MASK, xcb_change_window_attributes(ps->c.c, ev->window, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask( (const uint32_t[]){determine_evmask(
ps, ev->window, WIN_EVMODE_UNKNOWN)}); ps, ev->window, WIN_EVMODE_UNKNOWN)});
@ -586,12 +588,16 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
if (!w->ever_damaged) { if (!w->ever_damaged) {
win_extents(w, &parts); win_extents(w, &parts);
set_ignore_cookie( if (!ps->o.show_all_xerrors) {
ps, xcb_damage_subtract(ps->c, w->damage, XCB_NONE, XCB_NONE)); set_ignore_cookie(&ps->c, xcb_damage_subtract(ps->c.c, w->damage,
XCB_NONE, XCB_NONE));
}
} else { } else {
set_ignore_cookie( if (!ps->o.show_all_xerrors) {
ps, xcb_damage_subtract(ps->c, w->damage, XCB_NONE, ps->damaged_region)); set_ignore_cookie(&ps->c, xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
x_fetch_region(ps->c, ps->damaged_region, &parts); ps->damaged_region));
}
x_fetch_region(&ps->c, ps->damaged_region, &parts);
pixman_region32_translate(&parts, w->g.x + w->g.border_width, pixman_region32_translate(&parts, w->g.x + w->g.border_width,
w->g.y + w->g.border_width); w->g.y + w->g.border_width);
} }
@ -667,7 +673,7 @@ ev_selection_clear(session_t *ps, xcb_selection_clear_event_t attr_unused *ev) {
void ev_handle(session_t *ps, xcb_generic_event_t *ev) { void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
if (XCB_EVENT_RESPONSE_TYPE(ev) != KeymapNotify) { if (XCB_EVENT_RESPONSE_TYPE(ev) != KeymapNotify) {
discard_pending(ps, ev->full_sequence); x_discard_pending(&ps->c, ev->full_sequence);
} }
xcb_window_t wid = ev_window(ps, ev); xcb_window_t wid = ev_window(ps, ev);
@ -689,9 +695,9 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
// https://bugs.freedesktop.org/show_bug.cgi?id=35945 // https://bugs.freedesktop.org/show_bug.cgi?id=35945
// https://lists.freedesktop.org/archives/xcb/2011-November/007337.html // https://lists.freedesktop.org/archives/xcb/2011-November/007337.html
auto response_type = XCB_EVENT_RESPONSE_TYPE(ev); auto response_type = XCB_EVENT_RESPONSE_TYPE(ev);
auto proc = XESetWireToEvent(ps->dpy, response_type, 0); auto proc = XESetWireToEvent(ps->c.dpy, response_type, 0);
if (proc) { if (proc) {
XESetWireToEvent(ps->dpy, response_type, proc); XESetWireToEvent(ps->c.dpy, response_type, proc);
XEvent dummy; XEvent dummy;
// Stop Xlib from complaining about lost sequence numbers. // Stop Xlib from complaining about lost sequence numbers.
@ -701,8 +707,8 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
// //
// We only need the low 16 bits // We only need the low 16 bits
uint16_t seq = ev->sequence; uint16_t seq = ev->sequence;
ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->dpy) & 0xffff); ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->c.dpy) & 0xffff);
proc(ps->dpy, &dummy, (xEvent *)ev); proc(ps->c.dpy, &dummy, (xEvent *)ev);
// Restore the sequence number // Restore the sequence number
ev->sequence = seq; ev->sequence = seq;
} }
@ -736,7 +742,7 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
case SelectionClear: case SelectionClear:
ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev); ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev);
break; break;
case 0: ev_xcb_error(ps, (xcb_generic_error_t *)ev); break; case 0: x_handle_error(&ps->c, (xcb_generic_error_t *)ev); break;
default: default:
if (ps->shape_exists && ev->response_type == ps->shape_event) { if (ps->shape_exists && ev->response_type == ps->shape_event) {
ev_shape_notify(ps, (xcb_shape_notify_event_t *)ev); ev_shape_notify(ps, (xcb_shape_notify_event_t *)ev);

View File

@ -39,7 +39,7 @@ static inline XVisualInfo *get_visualinfo_from_visual(session_t *ps, xcb_visuali
XVisualInfo vreq = {.visualid = visual}; XVisualInfo vreq = {.visualid = visual};
int nitems = 0; int nitems = 0;
return XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems); return XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
} }
/** /**
@ -56,7 +56,7 @@ bool glx_init(session_t *ps, bool need_render) {
} }
// Get XVisualInfo // Get XVisualInfo
pvis = get_visualinfo_from_visual(ps, ps->vis); pvis = get_visualinfo_from_visual(ps, ps->c.screen_info->root_visual);
if (!pvis) { if (!pvis) {
log_error("Failed to acquire XVisualInfo for current visual."); log_error("Failed to acquire XVisualInfo for current visual.");
goto glx_init_end; goto glx_init_end;
@ -65,12 +65,13 @@ bool glx_init(session_t *ps, bool need_render) {
// Ensure the visual is double-buffered // Ensure the visual is double-buffered
if (need_render) { if (need_render) {
int value = 0; int value = 0;
if (Success != glXGetConfig(ps->dpy, pvis, GLX_USE_GL, &value) || !value) { if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) {
log_error("Root visual is not a GL visual."); log_error("Root visual is not a GL visual.");
goto glx_init_end; goto glx_init_end;
} }
if (Success != glXGetConfig(ps->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) { if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) ||
!value) {
log_error("Root visual is not a double buffered GL visual."); log_error("Root visual is not a double buffered GL visual.");
goto glx_init_end; goto glx_init_end;
} }
@ -112,7 +113,7 @@ bool glx_init(session_t *ps, bool need_render) {
if (!psglx->context) { if (!psglx->context) {
// Get GLX context // Get GLX context
#ifndef DEBUG_GLX_DEBUG_CONTEXT #ifndef DEBUG_GLX_DEBUG_CONTEXT
psglx->context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE); psglx->context = glXCreateContext(ps->c.dpy, pvis, None, GL_TRUE);
#else #else
{ {
GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis); GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis);
@ -134,7 +135,7 @@ bool glx_init(session_t *ps, bool need_render) {
static const int attrib_list[] = { static const int attrib_list[] = {
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None}; GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None};
psglx->context = p_glXCreateContextAttribsARB( psglx->context = p_glXCreateContextAttribsARB(
ps->dpy, fbconfig, NULL, GL_TRUE, attrib_list); ps->c.dpy, fbconfig, NULL, GL_TRUE, attrib_list);
} }
#endif #endif
@ -144,7 +145,7 @@ bool glx_init(session_t *ps, bool need_render) {
} }
// Attach GLX context // Attach GLX context
if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), psglx->context)) { if (!glXMakeCurrent(ps->c.dpy, get_tgt_window(ps), psglx->context)) {
log_error("Failed to attach GLX context."); log_error("Failed to attach GLX context.");
goto glx_init_end; goto glx_init_end;
} }
@ -201,7 +202,7 @@ bool glx_init(session_t *ps, bool need_render) {
// Clear screen // Clear screen
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// glXSwapBuffers(ps->dpy, get_tgt_window(ps)); // glXSwapBuffers(ps->c.dpy, get_tgt_window(ps));
} }
success = true; success = true;
@ -266,8 +267,8 @@ void glx_destroy(session_t *ps) {
// Destroy GLX context // Destroy GLX context
if (ps->psglx->context) { if (ps->psglx->context) {
glXMakeCurrent(ps->dpy, None, NULL); glXMakeCurrent(ps->c.dpy, None, NULL);
glXDestroyContext(ps->dpy, ps->psglx->context); glXDestroyContext(ps->c.dpy, ps->psglx->context);
ps->psglx->context = NULL; ps->psglx->context = NULL;
} }
@ -732,7 +733,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
// Retrieve pixmap parameters, if they aren't provided // Retrieve pixmap parameters, if they aren't provided
if (!width || !height) { if (!width || !height) {
auto r = xcb_get_geometry_reply( auto r = xcb_get_geometry_reply(
ps->c, xcb_get_geometry(ps->c, pixmap), NULL); ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL);
if (!r) { if (!r) {
log_error("Failed to query info of pixmap %#010x.", pixmap); log_error("Failed to query info of pixmap %#010x.", pixmap);
return false; return false;
@ -773,7 +774,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
0, 0,
}; };
ptex->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, pixmap, attrs); ptex->glpixmap = glXCreatePixmap(ps->c.dpy, fbcfg->cfg, pixmap, attrs);
ptex->pixmap = pixmap; ptex->pixmap = pixmap;
ptex->target = ptex->target =
(GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE); (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
@ -820,9 +821,9 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
// The specification requires rebinding whenever the content changes... // The specification requires rebinding whenever the content changes...
// We can't follow this, too slow. // We can't follow this, too slow.
if (need_release) if (need_release)
glXReleaseTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
glXBindTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); glXBindTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
// Cleanup // Cleanup
glBindTexture(ptex->target, 0); glBindTexture(ptex->target, 0);
@ -840,13 +841,13 @@ void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
// Release binding // Release binding
if (ptex->glpixmap && ptex->texture) { if (ptex->glpixmap && ptex->texture) {
glBindTexture(ptex->target, ptex->texture); glBindTexture(ptex->target, ptex->texture);
glXReleaseTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
glBindTexture(ptex->target, 0); glBindTexture(ptex->target, 0);
} }
// Free GLX Pixmap // Free GLX Pixmap
if (ptex->glpixmap) { if (ptex->glpixmap) {
glXDestroyPixmap(ps->dpy, ptex->glpixmap); glXDestroyPixmap(ps->c.dpy, ptex->glpixmap);
ptex->glpixmap = 0; ptex->glpixmap = 0;
} }

View File

@ -129,7 +129,7 @@ static inline bool dpms_screen_is_off(xcb_dpms_info_reply_t *info) {
void check_dpms_status(EV_P attr_unused, ev_timer *w, int revents attr_unused) { void check_dpms_status(EV_P attr_unused, ev_timer *w, int revents attr_unused) {
auto ps = session_ptr(w, dpms_check_timer); auto ps = session_ptr(w, dpms_check_timer);
auto r = xcb_dpms_info_reply(ps->c, xcb_dpms_info(ps->c), NULL); auto r = xcb_dpms_info_reply(ps->c.c, xcb_dpms_info(ps->c.c), NULL);
if (!r) { if (!r) {
log_fatal("Failed to query DPMS status."); log_fatal("Failed to query DPMS status.");
abort(); abort();
@ -149,7 +149,7 @@ void check_dpms_status(EV_P attr_unused, ev_timer *w, int revents attr_unused) {
* XXX move to win.c * XXX move to win.c
*/ */
static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t wid) { static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t wid) {
if (!wid || PointerRoot == wid || wid == ps->root || wid == ps->overlay) { if (!wid || PointerRoot == wid || wid == ps->c.screen_info->root || wid == ps->overlay) {
return NULL; return NULL;
} }
@ -352,8 +352,9 @@ void add_damage(session_t *ps, const region_t *damage) {
*/ */
static double fade_timeout(session_t *ps) { static double fade_timeout(session_t *ps) {
auto now = get_time_ms(); auto now = get_time_ms();
if (ps->o.fade_delta + ps->fade_time < now) if (ps->o.fade_delta + ps->fade_time < now) {
return 0; return 0;
}
auto diff = ps->o.fade_delta + ps->fade_time - now; auto diff = ps->o.fade_delta + ps->fade_time - now;
@ -406,47 +407,6 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long long steps) {
return true; return true;
} }
// === Error handling ===
void discard_pending(session_t *ps, uint32_t sequence) {
while (ps->pending_reply_head) {
if (sequence > ps->pending_reply_head->sequence) {
auto next = ps->pending_reply_head->next;
free(ps->pending_reply_head);
ps->pending_reply_head = next;
if (!ps->pending_reply_head) {
ps->pending_reply_tail = &ps->pending_reply_head;
}
} else {
break;
}
}
}
static void handle_error(session_t *ps, xcb_generic_error_t *ev) {
if (ps == NULL) {
// Do not ignore errors until the session has been initialized
return;
}
discard_pending(ps, ev->full_sequence);
if (ps->pending_reply_head && ps->pending_reply_head->sequence == ev->full_sequence) {
if (ps->pending_reply_head->action != PENDING_REPLY_ACTION_IGNORE) {
x_log_error(LOG_LEVEL_ERROR, ev->full_sequence, ev->major_code,
ev->minor_code, ev->error_code);
}
switch (ps->pending_reply_head->action) {
case PENDING_REPLY_ACTION_ABORT:
log_fatal("An unrecoverable X error occurred, aborting...");
abort();
case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break;
case PENDING_REPLY_ACTION_IGNORE: break;
}
return;
}
x_log_error(LOG_LEVEL_WARN, ev->full_sequence, ev->major_code, ev->minor_code,
ev->error_code);
}
// === Windows === // === Windows ===
/** /**
@ -482,8 +442,8 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
*/ */
void update_ewmh_active_win(session_t *ps) { void update_ewmh_active_win(session_t *ps) {
// Search for the window // Search for the window
xcb_window_t wid = xcb_window_t wid = wid_get_prop_window(&ps->c, ps->c.screen_info->root,
wid_get_prop_window(ps->c, ps->root, ps->atoms->a_NET_ACTIVE_WINDOW); ps->atoms->a_NET_ACTIVE_WINDOW);
auto w = find_win_all(ps, wid); auto w = find_win_all(ps, wid);
// Mark the window focused. No need to unfocus the previous one. // Mark the window focused. No need to unfocus the previous one.
@ -510,7 +470,7 @@ static void recheck_focus(session_t *ps) {
// opacity on it // opacity on it
xcb_window_t wid = XCB_NONE; xcb_window_t wid = XCB_NONE;
xcb_get_input_focus_reply_t *reply = xcb_get_input_focus_reply_t *reply =
xcb_get_input_focus_reply(ps->c, xcb_get_input_focus(ps->c), NULL); xcb_get_input_focus_reply(ps->c.c, xcb_get_input_focus(ps->c.c), NULL);
if (reply) { if (reply) {
wid = reply->focus; wid = reply->focus;
@ -719,7 +679,7 @@ err:
/// Handle configure event of the root window /// Handle configure event of the root window
static void configure_root(session_t *ps) { static void configure_root(session_t *ps) {
auto r = XCB_AWAIT(xcb_get_geometry, ps->c, ps->root); auto r = XCB_AWAIT(xcb_get_geometry, ps->c.c, ps->c.screen_info->root);
if (!r) { if (!r) {
log_fatal("Failed to fetch root geometry"); log_fatal("Failed to fetch root geometry");
abort(); abort();
@ -795,8 +755,8 @@ static void configure_root(session_t *ps) {
static void handle_root_flags(session_t *ps) { static void handle_root_flags(session_t *ps) {
if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) { if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) {
if (ps->o.crop_shadow_to_monitor) { if (ps->o.crop_shadow_to_monitor && ps->randr_exists) {
x_update_randr_monitors(ps); x_update_monitors(&ps->c, &ps->monitors);
} }
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE; ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE;
} }
@ -1096,10 +1056,11 @@ void root_damaged(session_t *ps) {
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image); ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
ps->root_image = NULL; ps->root_image = NULL;
} }
auto pixmap = x_get_root_back_pixmap(ps->c, ps->root, ps->atoms); auto pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms);
if (pixmap != XCB_NONE) { if (pixmap != XCB_NONE) {
ps->root_image = ps->backend_data->ops->bind_pixmap( ps->root_image = ps->backend_data->ops->bind_pixmap(
ps->backend_data, pixmap, x_get_visual_info(ps->c, ps->vis), false); ps->backend_data, pixmap,
x_get_visual_info(&ps->c, ps->c.screen_info->root_visual), false);
if (ps->root_image) { if (ps->root_image) {
ps->backend_data->ops->set_image_property( ps->backend_data->ops->set_image_property(
ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE, ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE,
@ -1114,27 +1075,6 @@ void root_damaged(session_t *ps) {
force_repaint(ps); force_repaint(ps);
} }
/**
* Xlib error handler function.
*/
static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
// Fake a xcb error, fill in just enough information
xcb_generic_error_t xcb_err;
xcb_err.full_sequence = (uint32_t)ev->serial;
xcb_err.major_code = ev->request_code;
xcb_err.minor_code = ev->minor_code;
xcb_err.error_code = ev->error_code;
handle_error(ps_g, &xcb_err);
return 0;
}
/**
* XCB error handler function.
*/
void ev_xcb_error(session_t *ps, xcb_generic_error_t *err) {
handle_error(ps, err);
}
/** /**
* Force a full-screen repaint. * Force a full-screen repaint.
*/ */
@ -1169,10 +1109,11 @@ void opts_set_no_fading_openclose(session_t *ps, bool newval) {
static int register_cm(session_t *ps) { static int register_cm(session_t *ps) {
assert(!ps->reg_win); assert(!ps->reg_win);
ps->reg_win = x_new_id(ps->c); ps->reg_win = x_new_id(&ps->c);
auto e = xcb_request_check( auto e = xcb_request_check(
ps->c, xcb_create_window_checked(ps->c, XCB_COPY_FROM_PARENT, ps->reg_win, ps->root, ps->c.c, xcb_create_window_checked(ps->c.c, XCB_COPY_FROM_PARENT, ps->reg_win,
0, 0, 1, 1, 0, XCB_NONE, ps->vis, 0, NULL)); ps->c.screen_info->root, 0, 0, 1, 1, 0, XCB_NONE,
ps->c.screen_info->root_visual, 0, NULL));
if (e) { if (e) {
log_fatal("Failed to create window."); log_fatal("Failed to create window.");
@ -1191,10 +1132,10 @@ static int register_cm(session_t *ps) {
// Set names and classes // Set names and classes
for (size_t i = 0; i < ARR_SIZE(prop_atoms); i++) { for (size_t i = 0; i < ARR_SIZE(prop_atoms); i++) {
e = xcb_request_check( e = xcb_request_check(
ps->c, xcb_change_property_checked( ps->c.c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i], ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i],
prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING, prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING,
8, strlen("picom"), "picom")); 8, strlen("picom"), "picom"));
if (e) { if (e) {
log_error_x_error(e, "Failed to set window property %d", log_error_x_error(e, "Failed to set window property %d",
prop_atoms[i]); prop_atoms[i]);
@ -1204,9 +1145,9 @@ static int register_cm(session_t *ps) {
const char picom_class[] = "picom\0picom"; const char picom_class[] = "picom\0picom";
e = xcb_request_check( e = xcb_request_check(
ps->c, xcb_change_property_checked(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, ps->c.c, xcb_change_property_checked(ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8, ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8,
ARR_SIZE(picom_class), picom_class)); ARR_SIZE(picom_class), picom_class));
if (e) { if (e) {
log_error_x_error(e, "Failed to set the WM_CLASS property"); log_error_x_error(e, "Failed to set the WM_CLASS property");
free(e); free(e);
@ -1220,10 +1161,10 @@ static int register_cm(session_t *ps) {
if (gethostname(hostname, hostname_max) == 0) { if (gethostname(hostname, hostname_max) == 0) {
e = xcb_request_check( e = xcb_request_check(
ps->c, xcb_change_property_checked( ps->c.c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING, 8, ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING,
(uint32_t)strlen(hostname), hostname)); 8, (uint32_t)strlen(hostname), hostname));
if (e) { if (e) {
log_error_x_error(e, "Failed to set the WM_CLIENT_MACHINE" log_error_x_error(e, "Failed to set the WM_CLIENT_MACHINE"
" property"); " property");
@ -1239,16 +1180,16 @@ static int register_cm(session_t *ps) {
// Set _NET_WM_PID // Set _NET_WM_PID
{ {
auto pid = getpid(); auto pid = getpid();
xcb_change_property(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, xcb_change_property(ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->a_NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid); ps->atoms->a_NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
} }
// Set COMPTON_VERSION // Set COMPTON_VERSION
e = xcb_request_check( e = xcb_request_check(
ps->c, xcb_change_property_checked( ps->c.c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win,
get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8, get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8,
(uint32_t)strlen(PICOM_VERSION), PICOM_VERSION)); (uint32_t)strlen(PICOM_VERSION), PICOM_VERSION));
if (e) { if (e) {
log_error_x_error(e, "Failed to set COMPTON_VERSION."); log_error_x_error(e, "Failed to set COMPTON_VERSION.");
free(e); free(e);
@ -1260,7 +1201,7 @@ static int register_cm(session_t *ps) {
xcb_atom_t atom; xcb_atom_t atom;
char *buf = NULL; char *buf = NULL;
if (asprintf(&buf, "%s%d", register_prop, ps->scr) < 0) { if (asprintf(&buf, "%s%d", register_prop, ps->c.screen) < 0) {
log_fatal("Failed to allocate memory"); log_fatal("Failed to allocate memory");
return -1; return -1;
} }
@ -1268,7 +1209,7 @@ static int register_cm(session_t *ps) {
free(buf); free(buf);
xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply( xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(
ps->c, xcb_get_selection_owner(ps->c, atom), NULL); ps->c.c, xcb_get_selection_owner(ps->c.c, atom), NULL);
if (reply && reply->owner != XCB_NONE) { if (reply && reply->owner != XCB_NONE) {
// Another compositor already running // Another compositor already running
@ -1276,7 +1217,7 @@ static int register_cm(session_t *ps) {
return 1; return 1;
} }
free(reply); free(reply);
xcb_set_selection_owner(ps->c, ps->reg_win, atom, 0); xcb_set_selection_owner(ps->c.c, ps->reg_win, atom, 0);
} }
return 0; return 0;
@ -1306,9 +1247,8 @@ static inline bool write_pid(session_t *ps) {
* Initialize X composite overlay window. * Initialize X composite overlay window.
*/ */
static bool init_overlay(session_t *ps) { static bool init_overlay(session_t *ps) {
xcb_composite_get_overlay_window_reply_t *reply = xcb_composite_get_overlay_window_reply_t *reply = xcb_composite_get_overlay_window_reply(
xcb_composite_get_overlay_window_reply( ps->c.c, xcb_composite_get_overlay_window(ps->c.c, ps->c.screen_info->root), NULL);
ps->c, xcb_composite_get_overlay_window(ps->c, ps->root), NULL);
if (reply) { if (reply) {
ps->overlay = reply->overlay_win; ps->overlay = reply->overlay_win;
free(reply); free(reply);
@ -1318,13 +1258,13 @@ static bool init_overlay(session_t *ps) {
if (ps->overlay != XCB_NONE) { if (ps->overlay != XCB_NONE) {
// Set window region of the overlay window, code stolen from // Set window region of the overlay window, code stolen from
// compiz-0.8.8 // compiz-0.8.8
if (!XCB_AWAIT_VOID(xcb_shape_mask, ps->c, XCB_SHAPE_SO_SET, if (!XCB_AWAIT_VOID(xcb_shape_mask, ps->c.c, XCB_SHAPE_SO_SET,
XCB_SHAPE_SK_BOUNDING, ps->overlay, 0, 0, 0)) { XCB_SHAPE_SK_BOUNDING, ps->overlay, 0, 0, 0)) {
log_fatal("Failed to set the bounding shape of overlay, giving " log_fatal("Failed to set the bounding shape of overlay, giving "
"up."); "up.");
return false; return false;
} }
if (!XCB_AWAIT_VOID(xcb_shape_rectangles, ps->c, XCB_SHAPE_SO_SET, if (!XCB_AWAIT_VOID(xcb_shape_rectangles, ps->c.c, XCB_SHAPE_SO_SET,
XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED,
ps->overlay, 0, 0, 0, NULL)) { ps->overlay, 0, 0, 0, NULL)) {
log_fatal("Failed to set the input shape of overlay, giving up."); log_fatal("Failed to set the input shape of overlay, giving up.");
@ -1332,7 +1272,7 @@ static bool init_overlay(session_t *ps) {
} }
// Listen to Expose events on the overlay // Listen to Expose events on the overlay
xcb_change_window_attributes(ps->c, ps->overlay, XCB_CW_EVENT_MASK, xcb_change_window_attributes(ps->c.c, ps->overlay, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_EXPOSURE}); (const uint32_t[]){XCB_EVENT_MASK_EXPOSURE});
// Retrieve DamageNotify on root window if we are painting on an // Retrieve DamageNotify on root window if we are painting on an
@ -1340,7 +1280,7 @@ static bool init_overlay(session_t *ps) {
// root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty); // root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty);
// Unmap the overlay, we will map it when needed in redirect_start // Unmap the overlay, we will map it when needed in redirect_start
XCB_AWAIT_VOID(xcb_unmap_window, ps->c, ps->overlay); XCB_AWAIT_VOID(xcb_unmap_window, ps->c.c, ps->overlay);
} else { } else {
log_error("Cannot get X Composite overlay window. Falling " log_error("Cannot get X Composite overlay window. Falling "
"back to painting on root window."); "back to painting on root window.");
@ -1351,27 +1291,29 @@ static bool init_overlay(session_t *ps) {
} }
static bool init_debug_window(session_t *ps) { static bool init_debug_window(session_t *ps) {
xcb_colormap_t colormap = x_new_id(ps->c); xcb_colormap_t colormap = x_new_id(&ps->c);
ps->debug_window = x_new_id(ps->c); ps->debug_window = x_new_id(&ps->c);
auto err = xcb_request_check( auto err = xcb_request_check(
ps->c, xcb_create_colormap_checked(ps->c, XCB_COLORMAP_ALLOC_NONE, colormap, ps->c.c, xcb_create_colormap_checked(ps->c.c, XCB_COLORMAP_ALLOC_NONE,
ps->root, ps->vis)); colormap, ps->c.screen_info->root,
ps->c.screen_info->root_visual));
if (err) { if (err) {
goto err_out; goto err_out;
} }
err = xcb_request_check( err = xcb_request_check(
ps->c, xcb_create_window_checked(ps->c, (uint8_t)ps->depth, ps->debug_window, ps->c.c, xcb_create_window_checked(
ps->root, 0, 0, to_u16_checked(ps->root_width), ps->c.c, (uint8_t)ps->c.screen_info->root_depth,
to_u16_checked(ps->root_height), 0, ps->debug_window, ps->c.screen_info->root, 0, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->vis, to_u16_checked(ps->root_width), to_u16_checked(ps->root_height),
XCB_CW_COLORMAP, (uint32_t[]){colormap, 0})); 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->c.screen_info->root_visual,
XCB_CW_COLORMAP, (uint32_t[]){colormap, 0}));
if (err) { if (err) {
goto err_out; goto err_out;
} }
err = xcb_request_check(ps->c, xcb_map_window_checked(ps->c, ps->debug_window)); err = xcb_request_check(ps->c.c, xcb_map_window_checked(ps->c.c, ps->debug_window));
if (err) { if (err) {
goto err_out; goto err_out;
} }
@ -1386,7 +1328,7 @@ xcb_window_t session_get_target_window(session_t *ps) {
if (ps->o.debug_mode) { if (ps->o.debug_mode) {
return ps->debug_window; return ps->debug_window;
} }
return ps->overlay != XCB_NONE ? ps->overlay : ps->root; return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root;
} }
uint8_t session_redirection_mode(session_t *ps) { uint8_t session_redirection_mode(session_t *ps) {
@ -1416,18 +1358,18 @@ static bool redirect_start(session_t *ps) {
// Map overlay window. Done firstly according to this: // Map overlay window. Done firstly according to this:
// https://bugzilla.gnome.org/show_bug.cgi?id=597014 // https://bugzilla.gnome.org/show_bug.cgi?id=597014
if (ps->overlay != XCB_NONE) { if (ps->overlay != XCB_NONE) {
xcb_map_window(ps->c, ps->overlay); xcb_map_window(ps->c.c, ps->overlay);
} }
bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c, ps->root, bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c.c,
session_redirection_mode(ps)); ps->c.screen_info->root, session_redirection_mode(ps));
if (!success) { if (!success) {
log_fatal("Another composite manager is already running " log_fatal("Another composite manager is already running "
"(and does not handle _NET_WM_CM_Sn correctly)"); "(and does not handle _NET_WM_CM_Sn correctly)");
return false; return false;
} }
x_sync(ps->c); x_sync(&ps->c);
if (!initialize_backend(ps)) { if (!initialize_backend(ps)) {
return false; return false;
@ -1456,16 +1398,16 @@ static bool redirect_start(session_t *ps) {
} }
if (ps->present_exists && ps->frame_pacing) { if (ps->present_exists && ps->frame_pacing) {
ps->present_event_id = x_new_id(ps->c); ps->present_event_id = x_new_id(&ps->c);
auto select_input = xcb_present_select_input( auto select_input = xcb_present_select_input(
ps->c, ps->present_event_id, session_get_target_window(ps), ps->c.c, ps->present_event_id, session_get_target_window(ps),
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
auto notify_msc = auto notify_msc = xcb_present_notify_msc(
xcb_present_notify_msc(ps->c, session_get_target_window(ps), 0, 0, 1, 0); ps->c.c, session_get_target_window(ps), 0, 0, 1, 0);
set_cant_fail_cookie(ps, select_input); set_cant_fail_cookie(&ps->c, select_input);
set_cant_fail_cookie(ps, notify_msc); set_cant_fail_cookie(&ps->c, notify_msc);
ps->present_event = xcb_register_for_special_xge( ps->present_event = xcb_register_for_special_xge(
ps->c, &xcb_present_id, ps->present_event_id, NULL); ps->c.c, &xcb_present_id, ps->present_event_id, NULL);
// Initialize rendering and frame timing statistics, and frame pacing // Initialize rendering and frame timing statistics, and frame pacing
// states. // states.
@ -1480,13 +1422,13 @@ static bool redirect_start(session_t *ps) {
} }
// Must call XSync() here // Must call XSync() here
x_sync(ps->c); x_sync(&ps->c);
ps->redirected = true; ps->redirected = true;
ps->first_frame = true; ps->first_frame = true;
// Re-detect driver since we now have a backend // Re-detect driver since we now have a backend
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root); ps->drivers = detect_driver(ps->c.c, ps->backend_data, ps->c.screen_info->root);
apply_driver_workarounds(ps, ps->drivers); apply_driver_workarounds(ps, ps->drivers);
root_damaged(ps); root_damaged(ps);
@ -1506,10 +1448,11 @@ static void unredirect(session_t *ps) {
destroy_backend(ps); destroy_backend(ps);
xcb_composite_unredirect_subwindows(ps->c, ps->root, session_redirection_mode(ps)); xcb_composite_unredirect_subwindows(ps->c.c, ps->c.screen_info->root,
session_redirection_mode(ps));
// Unmap overlay window // Unmap overlay window
if (ps->overlay != XCB_NONE) { if (ps->overlay != XCB_NONE) {
xcb_unmap_window(ps->c, ps->overlay); xcb_unmap_window(ps->c.c, ps->overlay);
} }
// Free the damage ring // Free the damage ring
@ -1521,15 +1464,15 @@ static void unredirect(session_t *ps) {
ps->damage_ring = ps->damage = NULL; ps->damage_ring = ps->damage = NULL;
if (ps->present_event_id) { if (ps->present_event_id) {
xcb_present_select_input(ps->c, ps->present_event_id, xcb_present_select_input(ps->c.c, ps->present_event_id,
session_get_target_window(ps), 0); session_get_target_window(ps), 0);
ps->present_event_id = XCB_NONE; ps->present_event_id = XCB_NONE;
xcb_unregister_for_special_event(ps->c, ps->present_event); xcb_unregister_for_special_event(ps->c.c, ps->present_event);
ps->present_event = NULL; ps->present_event = NULL;
} }
// Must call XSync() here // Must call XSync() here
x_sync(ps->c); x_sync(&ps->c);
ps->redirected = false; ps->redirected = false;
log_debug("Screen unredirected."); log_debug("Screen unredirected.");
@ -1553,9 +1496,9 @@ handle_present_complete_notify(session_t *ps, xcb_present_complete_notify_event_
next_msc = ps->last_msc + 1; next_msc = ps->last_msc + 1;
event_is_invalid = true; event_is_invalid = true;
} }
auto cookie = xcb_present_notify_msc(ps->c, session_get_target_window(ps), auto cookie = xcb_present_notify_msc(
0, next_msc, 0, 0); ps->c.c, session_get_target_window(ps), 0, next_msc, 0, 0);
set_cant_fail_cookie(ps, cookie); set_cant_fail_cookie(&ps->c, cookie);
} }
if (event_is_invalid) { if (event_is_invalid) {
return; return;
@ -1602,7 +1545,7 @@ static void handle_present_events(session_t *ps) {
return; return;
} }
xcb_present_generic_event_t *ev; xcb_present_generic_event_t *ev;
while ((ev = (void *)xcb_poll_for_special_event(ps->c, ps->present_event))) { while ((ev = (void *)xcb_poll_for_special_event(ps->c.c, ps->present_event))) {
if (ev->event != ps->present_event_id) { if (ev->event != ps->present_event_id) {
// This event doesn't have the right event context, it's not meant // This event doesn't have the right event context, it's not meant
// for us. // for us.
@ -1623,7 +1566,7 @@ static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents
handle_present_events(ps); handle_present_events(ps);
xcb_generic_event_t *ev; xcb_generic_event_t *ev;
while ((ev = xcb_poll_for_queued_event(ps->c))) { while ((ev = xcb_poll_for_queued_event(ps->c.c))) {
ev_handle(ps, ev); ev_handle(ps, ev);
free(ev); free(ev);
}; };
@ -1632,9 +1575,9 @@ static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents
// for an indefinite amount of time. // for an indefinite amount of time.
// Use XFlush here too, we might still use some Xlib functions // Use XFlush here too, we might still use some Xlib functions
// because OpenGL. // because OpenGL.
XFlush(ps->dpy); XFlush(ps->c.dpy);
xcb_flush(ps->c); xcb_flush(ps->c.c);
int err = xcb_connection_has_error(ps->c); int err = xcb_connection_has_error(ps->c.c);
if (err) { if (err) {
log_fatal("X11 server connection broke (error %d)", err); log_fatal("X11 server connection broke (error %d)", err);
exit(1); exit(1);
@ -1692,7 +1635,7 @@ static void fade_timer_callback(EV_P attr_unused, ev_timer *w, int revents attr_
static void handle_pending_updates(EV_P_ struct session *ps) { static void handle_pending_updates(EV_P_ struct session *ps) {
if (ps->pending_updates) { if (ps->pending_updates) {
log_debug("Delayed handling of events, entering critical section"); log_debug("Delayed handling of events, entering critical section");
auto e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c)); auto e = xcb_request_check(ps->c.c, xcb_grab_server_checked(ps->c.c));
if (e) { if (e) {
log_fatal_x_error(e, "failed to grab x server"); log_fatal_x_error(e, "failed to grab x server");
free(e); free(e);
@ -1718,7 +1661,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
{ {
auto r = xcb_get_input_focus_reply( auto r = xcb_get_input_focus_reply(
ps->c, xcb_get_input_focus(ps->c), NULL); ps->c.c, xcb_get_input_focus(ps->c.c), NULL);
if (!ps->active_win || (r && r->focus != ps->active_win->base.id)) { if (!ps->active_win || (r && r->focus != ps->active_win->base.id)) {
recheck_focus(ps); recheck_focus(ps);
} }
@ -1728,7 +1671,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
// Process window flags (stale images) // Process window flags (stale images)
refresh_images(ps); refresh_images(ps);
e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c)); e = xcb_request_check(ps->c.c, xcb_ungrab_server_checked(ps->c.c));
if (e) { if (e) {
log_fatal_x_error(e, "failed to ungrab x server"); log_fatal_x_error(e, "failed to ungrab x server");
free(e); free(e);
@ -1868,7 +1811,7 @@ static void draw_callback(EV_P_ ev_timer *w, int revents) {
static void x_event_callback(EV_P attr_unused, ev_io *w, int revents attr_unused) { static void x_event_callback(EV_P attr_unused, ev_io *w, int revents attr_unused) {
session_t *ps = (session_t *)w; session_t *ps = (session_t *)w;
xcb_generic_event_t *ev = xcb_poll_for_event(ps->c); xcb_generic_event_t *ev = xcb_poll_for_event(ps->c.c);
if (ev) { if (ev) {
ev_handle(ps, ev); ev_handle(ps, ev);
free(ev); free(ev);
@ -1966,12 +1909,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
const char *config_file, bool all_xerrors, bool fork) { const char *config_file, bool all_xerrors, bool fork) {
static const session_t s_def = { static const session_t s_def = {
.backend_data = NULL, .backend_data = NULL,
.dpy = NULL,
.scr = 0,
.c = NULL,
.vis = 0,
.depth = 0,
.root = XCB_NONE,
.root_height = 0, .root_height = 0,
.root_width = 0, .root_width = 0,
// .root_damage = XCB_NONE, // .root_damage = XCB_NONE,
@ -1987,8 +1924,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.redirected = false, .redirected = false,
.alpha_picts = NULL, .alpha_picts = NULL,
.fade_time = 0L, .fade_time = 0L,
.pending_reply_head = NULL,
.pending_reply_tail = NULL,
.quit = false, .quit = false,
.expose_rects = NULL, .expose_rects = NULL,
@ -2056,52 +1991,42 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// TODO(yshui) investigate what's the best window size // TODO(yshui) investigate what's the best window size
render_statistics_init(&ps->render_stats, 128); render_statistics_init(&ps->render_stats, 128);
ps->pending_reply_tail = &ps->pending_reply_head;
ps->o.show_all_xerrors = all_xerrors; ps->o.show_all_xerrors = all_xerrors;
// Use the same Display across reset, primarily for resource leak checking // Use the same Display across reset, primarily for resource leak checking
ps->dpy = dpy; x_connection_init(&ps->c, dpy);
ps->c = XGetXCBConnection(ps->dpy); // We store width/height from screen_info instead using them directly because they
// can change, see configure_root().
ps->root_width = ps->c.screen_info->width_in_pixels;
ps->root_height = ps->c.screen_info->height_in_pixels;
const xcb_query_extension_reply_t *ext_info; const xcb_query_extension_reply_t *ext_info;
ps->previous_xerror_handler = XSetErrorHandler(xerror);
ps->scr = DefaultScreen(ps->dpy);
auto screen = x_screen_of_display(ps->c, ps->scr);
ps->vis = screen->root_visual;
ps->depth = screen->root_depth;
ps->root = screen->root;
ps->root_width = screen->width_in_pixels;
ps->root_height = screen->height_in_pixels;
// Start listening to events on root earlier to catch all possible // Start listening to events on root earlier to catch all possible
// root geometry changes // root geometry changes
auto e = xcb_request_check( auto e = xcb_request_check(
ps->c, xcb_change_window_attributes_checked( ps->c.c, xcb_change_window_attributes_checked(
ps->c, ps->root, XCB_CW_EVENT_MASK, ps->c.c, ps->c.screen_info->root, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | (const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_PROPERTY_CHANGE})); XCB_EVENT_MASK_PROPERTY_CHANGE}));
if (e) { if (e) {
log_error_x_error(e, "Failed to setup root window event mask"); log_error_x_error(e, "Failed to setup root window event mask");
free(e); free(e);
} }
xcb_prefetch_extension_data(ps->c, &xcb_render_id); xcb_prefetch_extension_data(ps->c.c, &xcb_render_id);
xcb_prefetch_extension_data(ps->c, &xcb_composite_id); xcb_prefetch_extension_data(ps->c.c, &xcb_composite_id);
xcb_prefetch_extension_data(ps->c, &xcb_damage_id); xcb_prefetch_extension_data(ps->c.c, &xcb_damage_id);
xcb_prefetch_extension_data(ps->c, &xcb_shape_id); xcb_prefetch_extension_data(ps->c.c, &xcb_shape_id);
xcb_prefetch_extension_data(ps->c, &xcb_xfixes_id); xcb_prefetch_extension_data(ps->c.c, &xcb_xfixes_id);
xcb_prefetch_extension_data(ps->c, &xcb_randr_id); xcb_prefetch_extension_data(ps->c.c, &xcb_randr_id);
xcb_prefetch_extension_data(ps->c, &xcb_present_id); xcb_prefetch_extension_data(ps->c.c, &xcb_present_id);
xcb_prefetch_extension_data(ps->c, &xcb_sync_id); xcb_prefetch_extension_data(ps->c.c, &xcb_sync_id);
xcb_prefetch_extension_data(ps->c, &xcb_glx_id); xcb_prefetch_extension_data(ps->c.c, &xcb_glx_id);
xcb_prefetch_extension_data(ps->c, &xcb_dpms_id); xcb_prefetch_extension_data(ps->c.c, &xcb_dpms_id);
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_render_id);
if (!ext_info || !ext_info->present) { if (!ext_info || !ext_info->present) {
log_fatal("No render extension"); log_fatal("No render extension");
exit(1); exit(1);
@ -2109,7 +2034,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
ps->render_event = ext_info->first_event; ps->render_event = ext_info->first_event;
ps->render_error = ext_info->first_error; ps->render_error = ext_info->first_error;
ext_info = xcb_get_extension_data(ps->c, &xcb_composite_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_composite_id);
if (!ext_info || !ext_info->present) { if (!ext_info || !ext_info->present) {
log_fatal("No composite extension"); log_fatal("No composite extension");
exit(1); exit(1);
@ -2120,8 +2045,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
{ {
xcb_composite_query_version_reply_t *reply = xcb_composite_query_version_reply( xcb_composite_query_version_reply_t *reply = xcb_composite_query_version_reply(
ps->c, ps->c.c,
xcb_composite_query_version(ps->c, XCB_COMPOSITE_MAJOR_VERSION, xcb_composite_query_version(ps->c.c, XCB_COMPOSITE_MAJOR_VERSION,
XCB_COMPOSITE_MINOR_VERSION), XCB_COMPOSITE_MINOR_VERSION),
NULL); NULL);
@ -2133,45 +2058,45 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
free(reply); free(reply);
} }
ext_info = xcb_get_extension_data(ps->c, &xcb_damage_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_damage_id);
if (!ext_info || !ext_info->present) { if (!ext_info || !ext_info->present) {
log_fatal("No damage extension"); log_fatal("No damage extension");
exit(1); exit(1);
} }
ps->damage_event = ext_info->first_event; ps->damage_event = ext_info->first_event;
ps->damage_error = ext_info->first_error; ps->damage_error = ext_info->first_error;
xcb_discard_reply(ps->c, xcb_damage_query_version(ps->c, XCB_DAMAGE_MAJOR_VERSION, xcb_discard_reply(ps->c.c, xcb_damage_query_version(ps->c.c, XCB_DAMAGE_MAJOR_VERSION,
XCB_DAMAGE_MINOR_VERSION) XCB_DAMAGE_MINOR_VERSION)
.sequence); .sequence);
ext_info = xcb_get_extension_data(ps->c, &xcb_xfixes_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_xfixes_id);
if (!ext_info || !ext_info->present) { if (!ext_info || !ext_info->present) {
log_fatal("No XFixes extension"); log_fatal("No XFixes extension");
exit(1); exit(1);
} }
ps->xfixes_event = ext_info->first_event; ps->xfixes_event = ext_info->first_event;
ps->xfixes_error = ext_info->first_error; ps->xfixes_error = ext_info->first_error;
xcb_discard_reply(ps->c, xcb_xfixes_query_version(ps->c, XCB_XFIXES_MAJOR_VERSION, xcb_discard_reply(ps->c.c, xcb_xfixes_query_version(ps->c.c, XCB_XFIXES_MAJOR_VERSION,
XCB_XFIXES_MINOR_VERSION) XCB_XFIXES_MINOR_VERSION)
.sequence); .sequence);
ps->damaged_region = x_new_id(ps->c); ps->damaged_region = x_new_id(&ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c, ps->damaged_region, 0, NULL)) { if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->damaged_region, 0, NULL)) {
log_fatal("Failed to create a XFixes region"); log_fatal("Failed to create a XFixes region");
goto err; goto err;
} }
ext_info = xcb_get_extension_data(ps->c, &xcb_glx_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_glx_id);
if (ext_info && ext_info->present) { if (ext_info && ext_info->present) {
ps->glx_exists = true; ps->glx_exists = true;
ps->glx_error = ext_info->first_error; ps->glx_error = ext_info->first_error;
ps->glx_event = ext_info->first_event; ps->glx_event = ext_info->first_event;
} }
ext_info = xcb_get_extension_data(ps->c, &xcb_dpms_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_dpms_id);
ps->dpms_exists = ext_info && ext_info->present; ps->dpms_exists = ext_info && ext_info->present;
if (ps->dpms_exists) { if (ps->dpms_exists) {
auto r = xcb_dpms_info_reply(ps->c, xcb_dpms_info(ps->c), NULL); auto r = xcb_dpms_info_reply(ps->c.c, xcb_dpms_info(ps->c.c), NULL);
if (!r) { if (!r) {
log_fatal("Failed to query DPMS info"); log_fatal("Failed to query DPMS info");
goto err; goto err;
@ -2226,7 +2151,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
"binary will not be installed in the future."); "binary will not be installed in the future.");
} }
ps->atoms = init_atoms(ps->c); ps->atoms = init_atoms(ps->c.c);
ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0; ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0;
#define SET_WM_TYPE_ATOM(x) \ #define SET_WM_TYPE_ATOM(x) \
ps->atoms_wintypes[WINTYPE_##x] = ps->atoms->a_NET_WM_WINDOW_TYPE_##x ps->atoms_wintypes[WINTYPE_##x] = ps->atoms->a_NET_WM_WINDOW_TYPE_##x
@ -2287,25 +2212,25 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
rebuild_shadow_exclude_reg(ps); rebuild_shadow_exclude_reg(ps);
// Query X Shape // Query X Shape
ext_info = xcb_get_extension_data(ps->c, &xcb_shape_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_shape_id);
if (ext_info && ext_info->present) { if (ext_info && ext_info->present) {
ps->shape_event = ext_info->first_event; ps->shape_event = ext_info->first_event;
ps->shape_error = ext_info->first_error; ps->shape_error = ext_info->first_error;
ps->shape_exists = true; ps->shape_exists = true;
} }
ext_info = xcb_get_extension_data(ps->c, &xcb_randr_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_randr_id);
if (ext_info && ext_info->present) { if (ext_info && ext_info->present) {
ps->randr_exists = true; ps->randr_exists = true;
ps->randr_event = ext_info->first_event; ps->randr_event = ext_info->first_event;
ps->randr_error = ext_info->first_error; ps->randr_error = ext_info->first_error;
} }
ext_info = xcb_get_extension_data(ps->c, &xcb_present_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_present_id);
if (ext_info && ext_info->present) { if (ext_info && ext_info->present) {
auto r = xcb_present_query_version_reply( auto r = xcb_present_query_version_reply(
ps->c, ps->c.c,
xcb_present_query_version(ps->c, XCB_PRESENT_MAJOR_VERSION, xcb_present_query_version(ps->c.c, XCB_PRESENT_MAJOR_VERSION,
XCB_PRESENT_MINOR_VERSION), XCB_PRESENT_MINOR_VERSION),
NULL); NULL);
if (r) { if (r) {
@ -2315,14 +2240,14 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
} }
// Query X Sync // Query X Sync
ext_info = xcb_get_extension_data(ps->c, &xcb_sync_id); ext_info = xcb_get_extension_data(ps->c.c, &xcb_sync_id);
if (ext_info && ext_info->present) { if (ext_info && ext_info->present) {
ps->xsync_error = ext_info->first_error; ps->xsync_error = ext_info->first_error;
ps->xsync_event = ext_info->first_event; ps->xsync_event = ext_info->first_event;
// Need X Sync 3.1 for fences // Need X Sync 3.1 for fences
auto r = xcb_sync_initialize_reply( auto r = xcb_sync_initialize_reply(
ps->c, ps->c.c,
xcb_sync_initialize(ps->c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION), xcb_sync_initialize(ps->c.c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION),
NULL); NULL);
if (r && (r->major_version > 3 || if (r && (r->major_version > 3 ||
(r->major_version == 3 && r->minor_version >= 1))) { (r->major_version == 3 && r->minor_version >= 1))) {
@ -2333,9 +2258,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
ps->sync_fence = XCB_NONE; ps->sync_fence = XCB_NONE;
if (ps->xsync_exists) { if (ps->xsync_exists) {
ps->sync_fence = x_new_id(ps->c); ps->sync_fence = x_new_id(&ps->c);
e = xcb_request_check(ps->c, xcb_sync_create_fence_checked( e = xcb_request_check(
ps->c, ps->root, ps->sync_fence, 0)); ps->c.c, xcb_sync_create_fence_checked(
ps->c.c, ps->c.screen_info->root, ps->sync_fence, 0));
if (e) { if (e) {
if (ps->o.xrender_sync_fence) { if (ps->o.xrender_sync_fence) {
log_error_x_error(e, "Failed to create a XSync fence. " log_error_x_error(e, "Failed to create a XSync fence. "
@ -2412,7 +2338,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
} }
} }
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root); ps->drivers = detect_driver(ps->c.c, ps->backend_data, ps->c.screen_info->root);
apply_driver_workarounds(ps, ps->drivers); apply_driver_workarounds(ps, ps->drivers);
// Initialize filters, must be preceded by OpenGL context creation // Initialize filters, must be preceded by OpenGL context creation
@ -2453,26 +2379,29 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// Monitor screen changes if vsync_sw is enabled and we are using // Monitor screen changes if vsync_sw is enabled and we are using
// an auto-detected refresh rate, or when X RandR features are enabled // an auto-detected refresh rate, or when X RandR features are enabled
if (ps->randr_exists && ps->o.crop_shadow_to_monitor) { if (ps->randr_exists && ps->o.crop_shadow_to_monitor) {
xcb_randr_select_input(ps->c, ps->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); xcb_randr_select_input(ps->c.c, ps->c.screen_info->root,
XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
x_update_monitors(&ps->c, &ps->monitors);
} }
x_update_randr_monitors(ps);
{ {
xcb_render_create_picture_value_list_t pa = { xcb_render_create_picture_value_list_t pa = {
.subwindowmode = IncludeInferiors, .subwindowmode = IncludeInferiors,
}; };
ps->root_picture = x_create_picture_with_visual_and_pixmap( ps->root_picture = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, ps->root, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); &ps->c, ps->c.screen_info->root_visual, ps->c.screen_info->root,
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
if (ps->overlay != XCB_NONE) { if (ps->overlay != XCB_NONE) {
ps->tgt_picture = x_create_picture_with_visual_and_pixmap( ps->tgt_picture = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, ps->overlay, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); &ps->c, ps->c.screen_info->root_visual, ps->overlay,
} else XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
} else {
ps->tgt_picture = ps->root_picture; ps->tgt_picture = ps->root_picture;
}
} }
ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->dpy), EV_READ); ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->c.dpy), EV_READ);
ev_io_start(ps->loop, &ps->xiow); ev_io_start(ps->loop, &ps->xiow);
ev_init(&ps->unredir_timer, tmout_unredir_callback); ev_init(&ps->unredir_timer, tmout_unredir_callback);
ev_init(&ps->draw_timer, draw_callback); ev_init(&ps->draw_timer, draw_callback);
@ -2509,7 +2438,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// functions // functions
if (ps->o.dbus) { if (ps->o.dbus) {
#ifdef CONFIG_DBUS #ifdef CONFIG_DBUS
cdbus_init(ps, DisplayString(ps->dpy)); cdbus_init(ps, DisplayString(ps->c.dpy));
if (!ps->dbus_data) { if (!ps->dbus_data) {
ps->o.dbus = false; ps->o.dbus = false;
} }
@ -2519,7 +2448,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
#endif #endif
} }
e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c)); e = xcb_request_check(ps->c.c, xcb_grab_server_checked(ps->c.c));
if (e) { if (e) {
log_fatal_x_error(e, "Failed to grab X server"); log_fatal_x_error(e, "Failed to grab X server");
free(e); free(e);
@ -2532,12 +2461,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// earlier is irrelavant at this point. // earlier is irrelavant at this point.
// A better solution is probably grabbing the server from the very start. But I // A better solution is probably grabbing the server from the very start. But I
// think there still could be race condition that mandates discarding the events. // think there still could be race condition that mandates discarding the events.
x_discard_events(ps->c); x_discard_events(&ps->c);
xcb_query_tree_reply_t *query_tree_reply = xcb_query_tree_reply_t *query_tree_reply = xcb_query_tree_reply(
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, ps->root), NULL); ps->c.c, xcb_query_tree(ps->c.c, ps->c.screen_info->root), NULL);
e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c)); e = xcb_request_check(ps->c.c, xcb_ungrab_server_checked(ps->c.c));
if (e) { if (e) {
log_fatal_x_error(e, "Failed to ungrab server"); log_fatal_x_error(e, "Failed to ungrab server");
free(e); free(e);
@ -2630,7 +2559,7 @@ static void session_destroy(session_t *ps) {
ps->file_watch_handle = NULL; ps->file_watch_handle = NULL;
// Stop listening to events on root window // Stop listening to events on root window
xcb_change_window_attributes(ps->c, ps->root, XCB_CW_EVENT_MASK, xcb_change_window_attributes(ps->c.c, ps->c.screen_info->root, XCB_CW_EVENT_MASK,
(const uint32_t[]){0}); (const uint32_t[]){0});
#ifdef CONFIG_DBUS #ifdef CONFIG_DBUS
@ -2681,32 +2610,17 @@ static void session_destroy(session_t *ps) {
ps->track_atom_lst = NULL; ps->track_atom_lst = NULL;
} }
// Free ignore linked list
{
pending_reply_t *next = NULL;
for (auto ign = ps->pending_reply_head; ign; ign = next) {
next = ign->next;
free(ign);
}
// Reset head and tail
ps->pending_reply_head = NULL;
ps->pending_reply_tail = &ps->pending_reply_head;
}
// Free tgt_{buffer,picture} and root_picture // Free tgt_{buffer,picture} and root_picture
if (ps->tgt_buffer.pict == ps->tgt_picture) { if (ps->tgt_buffer.pict == ps->tgt_picture) {
ps->tgt_buffer.pict = XCB_NONE; ps->tgt_buffer.pict = XCB_NONE;
} }
if (ps->tgt_picture == ps->root_picture) { if (ps->tgt_picture != ps->root_picture) {
ps->tgt_picture = XCB_NONE; x_free_picture(&ps->c, ps->tgt_picture);
} else {
free_picture(ps->c, &ps->tgt_picture);
} }
x_free_picture(&ps->c, ps->root_picture);
ps->tgt_picture = ps->root_picture = XCB_NONE;
free_picture(ps->c, &ps->root_picture);
free_paint(ps, &ps->tgt_buffer); free_paint(ps, &ps->tgt_buffer);
pixman_region32_fini(&ps->screen_reg); pixman_region32_fini(&ps->screen_reg);
@ -2719,7 +2633,7 @@ static void session_destroy(session_t *ps) {
} }
free(ps->o.blur_kerns); free(ps->o.blur_kerns);
free(ps->o.glx_fshader_win_str); free(ps->o.glx_fshader_win_str);
x_free_randr_info(ps); x_free_monitor_info(&ps->monitors);
render_statistics_destroy(&ps->render_stats); render_statistics_destroy(&ps->render_stats);
@ -2744,28 +2658,28 @@ static void session_destroy(session_t *ps) {
// Release overlay window // Release overlay window
if (ps->overlay) { if (ps->overlay) {
xcb_composite_release_overlay_window(ps->c, ps->overlay); xcb_composite_release_overlay_window(ps->c.c, ps->overlay);
ps->overlay = XCB_NONE; ps->overlay = XCB_NONE;
} }
if (ps->sync_fence != XCB_NONE) { if (ps->sync_fence != XCB_NONE) {
xcb_sync_destroy_fence(ps->c, ps->sync_fence); xcb_sync_destroy_fence(ps->c.c, ps->sync_fence);
ps->sync_fence = XCB_NONE; ps->sync_fence = XCB_NONE;
} }
// Free reg_win // Free reg_win
if (ps->reg_win != XCB_NONE) { if (ps->reg_win != XCB_NONE) {
xcb_destroy_window(ps->c, ps->reg_win); xcb_destroy_window(ps->c.c, ps->reg_win);
ps->reg_win = XCB_NONE; ps->reg_win = XCB_NONE;
} }
if (ps->debug_window != XCB_NONE) { if (ps->debug_window != XCB_NONE) {
xcb_destroy_window(ps->c, ps->debug_window); xcb_destroy_window(ps->c.c, ps->debug_window);
ps->debug_window = XCB_NONE; ps->debug_window = XCB_NONE;
} }
if (ps->damaged_region != XCB_NONE) { if (ps->damaged_region != XCB_NONE) {
xcb_xfixes_destroy_region(ps->c, ps->damaged_region); xcb_xfixes_destroy_region(ps->c.c, ps->damaged_region);
ps->damaged_region = XCB_NONE; ps->damaged_region = XCB_NONE;
} }
@ -2784,7 +2698,7 @@ static void session_destroy(session_t *ps) {
#endif #endif
// Flush all events // Flush all events
x_sync(ps->c); x_sync(&ps->c);
ev_io_stop(ps->loop, &ps->xiow); ev_io_stop(ps->loop, &ps->xiow);
if (ps->o.legacy_backends) { if (ps->o.legacy_backends) {
free_conv((conv *)ps->shadow_context); free_conv((conv *)ps->shadow_context);
@ -2796,8 +2710,6 @@ static void session_destroy(session_t *ps) {
xrc_report_xid(); xrc_report_xid();
#endif #endif
XSetErrorHandler(ps->previous_xerror_handler);
// Stop libev event handlers // Stop libev event handlers
ev_timer_stop(ps->loop, &ps->unredir_timer); ev_timer_stop(ps->loop, &ps->unredir_timer);
ev_timer_stop(ps->loop, &ps->fade_timer); ev_timer_stop(ps->loop, &ps->fade_timer);
@ -2806,6 +2718,8 @@ static void session_destroy(session_t *ps) {
ev_prepare_stop(ps->loop, &ps->event_check); ev_prepare_stop(ps->loop, &ps->event_check);
ev_signal_stop(ps->loop, &ps->usr1_signal); ev_signal_stop(ps->loop, &ps->usr1_signal);
ev_signal_stop(ps->loop, &ps->int_signal); ev_signal_stop(ps->loop, &ps->int_signal);
free_x_connection(&ps->c);
} }
/** /**
@ -2872,10 +2786,9 @@ int main(int argc, char **argv) {
// Failed to read, the child has most likely died // Failed to read, the child has most likely died
// We can probably waitpid() here. // We can probably waitpid() here.
return 1; return 1;
} else {
// We are done
return 0;
} }
// We are done
return 0;
} }
// We are the child // We are the child
close(pfds[0]); close(pfds[0]);

View File

@ -94,7 +94,7 @@ free_win_res_glx(session_t *ps attr_unused, struct managed_win *w attr_unused) {
* Dump an drawable's info. * Dump an drawable's info.
*/ */
static inline void dump_drawable(session_t *ps, xcb_drawable_t drawable) { static inline void dump_drawable(session_t *ps, xcb_drawable_t drawable) {
auto r = xcb_get_geometry_reply(ps->c, xcb_get_geometry(ps->c, drawable), NULL); auto r = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, drawable), NULL);
if (!r) { if (!r) {
log_trace("Drawable %#010x: Failed", drawable); log_trace("Drawable %#010x: Failed", drawable);
return; return;

View File

@ -48,20 +48,20 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
bool repeat, int depth, xcb_visualid_t visual, bool force) { bool repeat, int depth, xcb_visualid_t visual, bool force) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
// XXX This is a mess. But this will go away after the backend refactor. // XXX This is a mess. But this will go away after the backend refactor.
if (!ppaint->pixmap) if (!ppaint->pixmap) {
return false; return false;
}
struct glx_fbconfig_info *fbcfg; struct glx_fbconfig_info *fbcfg;
if (!visual) { if (!visual) {
assert(depth == 32); assert(depth == 32);
if (!ps->argb_fbconfig) { if (!ps->argb_fbconfig) {
ps->argb_fbconfig = ps->argb_fbconfig = glx_find_fbconfig(
glx_find_fbconfig(ps->dpy, ps->scr, &ps->c, (struct xvisual_info){.red_size = 8,
(struct xvisual_info){.red_size = 8, .green_size = 8,
.green_size = 8, .blue_size = 8,
.blue_size = 8, .alpha_size = 8,
.alpha_size = 8, .visual_depth = 32});
.visual_depth = 32});
} }
if (!ps->argb_fbconfig) { if (!ps->argb_fbconfig) {
log_error("Failed to find appropriate FBConfig for 32 bit depth"); log_error("Failed to find appropriate FBConfig for 32 bit depth");
@ -69,7 +69,7 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
} }
fbcfg = ps->argb_fbconfig; fbcfg = ps->argb_fbconfig;
} else { } else {
auto m = x_get_visual_info(ps->c, visual); auto m = x_get_visual_info(&ps->c, visual);
if (m.visual_depth < 0) { if (m.visual_depth < 0) {
return false; return false;
} }
@ -80,7 +80,7 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
} }
if (!ppaint->fbcfg) { if (!ppaint->fbcfg) {
ppaint->fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, m); ppaint->fbcfg = glx_find_fbconfig(&ps->c, m);
} }
if (!ppaint->fbcfg) { if (!ppaint->fbcfg) {
log_error("Failed to find appropriate FBConfig for X pixmap"); log_error("Failed to find appropriate FBConfig for X pixmap");
@ -89,9 +89,10 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
fbcfg = ppaint->fbcfg; fbcfg = ppaint->fbcfg;
} }
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap)) if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap)) {
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei,
repeat, fbcfg); repeat, fbcfg);
}
#else #else
(void)ps; (void)ps;
(void)ppaint; (void)ppaint;
@ -129,7 +130,7 @@ static int get_buffer_age(session_t *ps) {
} }
if (ps->o.use_damage) { if (ps->o.use_damage) {
unsigned int val; unsigned int val;
glXQueryDrawable(ps->dpy, get_tgt_window(ps), glXQueryDrawable(ps->c.dpy, get_tgt_window(ps),
GLX_BACK_BUFFER_AGE_EXT, &val); GLX_BACK_BUFFER_AGE_EXT, &val);
return (int)val ?: -1; return (int)val ?: -1;
} }
@ -144,7 +145,7 @@ static int get_buffer_age(session_t *ps) {
*/ */
static inline void xrfilter_reset(session_t *ps, xcb_render_picture_t p) { static inline void xrfilter_reset(session_t *ps, xcb_render_picture_t p) {
#define FILTER "Nearest" #define FILTER "Nearest"
xcb_render_set_picture_filter(ps->c, p, strlen(FILTER), FILTER, 0, NULL); xcb_render_set_picture_filter(ps->c.c, p, strlen(FILTER), FILTER, 0, NULL);
#undef FILTER #undef FILTER
} }
@ -153,7 +154,7 @@ static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg)
switch (ps->o.backend) { switch (ps->o.backend) {
case BKEND_XRENDER: case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID: case BKEND_XR_GLX_HYBRID:
x_set_picture_clip_region(ps->c, ps->tgt_buffer.pict, 0, 0, reg); x_set_picture_clip_region(&ps->c, ps->tgt_buffer.pict, 0, 0, reg);
break; break;
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
case BKEND_GLX: glx_set_clip(ps, reg); break; case BKEND_GLX: glx_set_clip(ps, reg); break;
@ -162,16 +163,6 @@ static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg)
} }
} }
/**
* Destroy a <code>Picture</code>.
*/
void free_picture(xcb_connection_t *c, xcb_render_picture_t *p) {
if (*p) {
xcb_render_free_picture(c, *p);
*p = XCB_NONE;
}
}
/** /**
* Free paint_t. * Free paint_t.
*/ */
@ -179,10 +170,14 @@ void free_paint(session_t *ps, paint_t *ppaint) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
free_paint_glx(ps, ppaint); free_paint_glx(ps, ppaint);
#endif #endif
free_picture(ps->c, &ppaint->pict); if (ppaint->pict != XCB_NONE) {
if (ppaint->pixmap) x_free_picture(&ps->c, ppaint->pict);
xcb_free_pixmap(ps->c, ppaint->pixmap); ppaint->pict = XCB_NONE;
ppaint->pixmap = XCB_NONE; }
if (ppaint->pixmap) {
xcb_free_pixmap(ps->c.c, ppaint->pixmap);
ppaint->pixmap = XCB_NONE;
}
} }
uint32_t uint32_t
@ -253,8 +248,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
if (alpha_step != 0) { if (alpha_step != 0) {
if (cr) { if (cr) {
xcb_render_picture_t p_tmp = x_create_picture_with_standard( xcb_render_picture_t p_tmp = x_create_picture_with_standard(
ps->c, ps->root, fullwid, fullhei, &ps->c, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = { xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0}; .red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = { const xcb_rectangle_t rect = {
@ -262,7 +256,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
.y = 0, .y = 0,
.width = to_u16_checked(fullwid), .width = to_u16_checked(fullwid),
.height = to_u16_checked(fullhei)}; .height = to_u16_checked(fullhei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC,
p_tmp, trans, 1, &rect); p_tmp, trans, 1, &rect);
uint32_t max_ntraps = to_u32_checked(cr); uint32_t max_ntraps = to_u32_checked(cr);
@ -272,25 +266,24 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
traps, max_ntraps, cr, fullwid, fullhei); traps, max_ntraps, cr, fullwid, fullhei);
xcb_render_trapezoids( xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, ps->c.c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8),
0, 0, n, traps); 0, 0, n, traps);
xcb_render_composite( xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, ps->c.c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp,
ps->tgt_buffer.pict, to_i16_checked(x), ps->tgt_buffer.pict, to_i16_checked(x),
to_i16_checked(y), to_i16_checked(x), to_i16_checked(y), to_i16_checked(y), to_i16_checked(x), to_i16_checked(y),
to_i16_checked(dx), to_i16_checked(dy), to_i16_checked(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei)); to_u16_checked(wid), to_u16_checked(hei));
xcb_render_free_picture(ps->c, p_tmp); x_free_picture(&ps->c, p_tmp);
} else { } else {
xcb_render_picture_t p_tmp = alpha_pict; xcb_render_picture_t p_tmp = alpha_pict;
if (clip) { if (clip) {
p_tmp = x_create_picture_with_standard( p_tmp = x_create_picture_with_standard(
ps->c, ps->root, wid, hei, &ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t black = { xcb_render_color_t black = {
.red = 255, .blue = 255, .green = 255, .alpha = 255}; .red = 255, .blue = 255, .green = 255, .alpha = 255};
@ -299,17 +292,18 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
.y = 0, .y = 0,
.width = to_u16_checked(wid), .width = to_u16_checked(wid),
.height = to_u16_checked(hei)}; .height = to_u16_checked(hei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, xcb_render_fill_rectangles(ps->c.c,
XCB_RENDER_PICT_OP_SRC,
p_tmp, black, 1, &rect); p_tmp, black, 1, &rect);
if (alpha_pict) { if (alpha_pict) {
xcb_render_composite( xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_SRC, ps->c.c, XCB_RENDER_PICT_OP_SRC,
alpha_pict, XCB_NONE, p_tmp, 0, 0, 0, alpha_pict, XCB_NONE, p_tmp, 0, 0, 0,
0, 0, 0, to_u16_checked(wid), 0, 0, 0, to_u16_checked(wid),
to_u16_checked(hei)); to_u16_checked(hei));
} }
xcb_render_composite( xcb_render_composite(
ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE, ps->c.c, XCB_RENDER_PICT_OP_OUT_REVERSE,
clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0, clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0,
to_i16_checked(clip->x), to_i16_checked(clip->y), to_i16_checked(clip->x), to_i16_checked(clip->y),
to_u16_checked(wid), to_u16_checked(hei)); to_u16_checked(wid), to_u16_checked(hei));
@ -319,12 +313,12 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
: XCB_RENDER_PICT_OP_OVER); : XCB_RENDER_PICT_OP_OVER);
xcb_render_composite( xcb_render_composite(
ps->c, op, pict, p_tmp, ps->tgt_buffer.pict, ps->c.c, op, pict, p_tmp, ps->tgt_buffer.pict,
to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(x), to_i16_checked(y), 0, 0,
to_i16_checked(dx), to_i16_checked(dy), to_i16_checked(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei)); to_u16_checked(wid), to_u16_checked(hei));
if (clip) { if (clip) {
xcb_render_free_picture(ps->c, p_tmp); x_free_picture(&ps->c, p_tmp);
} }
} }
} }
@ -375,15 +369,18 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid,
static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
// Don't check for presence of Pixmap here, because older X Composite doesn't // Don't check for presence of Pixmap here, because older X Composite doesn't
// provide it // provide it
if (!ppaint) if (!ppaint) {
return false; return false;
}
if (bkend_use_xrender(ps) && !ppaint->pict) if (bkend_use_xrender(ps) && !ppaint->pict) {
return false; return false;
}
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE)) if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE)) {
return false; return false;
}
#endif #endif
return true; return true;
@ -395,9 +392,9 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) { void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) {
// Fetch Pixmap // Fetch Pixmap
if (!w->paint.pixmap) { if (!w->paint.pixmap) {
w->paint.pixmap = x_new_id(ps->c); w->paint.pixmap = x_new_id(&ps->c);
set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->base.id, set_ignore_cookie(&ps->c, xcb_composite_name_window_pixmap(
w->paint.pixmap)); ps->c.c, w->base.id, w->paint.pixmap));
} }
xcb_drawable_t draw = w->paint.pixmap; xcb_drawable_t draw = w->paint.pixmap;
@ -415,7 +412,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
}; };
w->paint.pict = x_create_picture_with_pictfmt_and_pixmap( w->paint.pict = x_create_picture_with_pictfmt_and_pixmap(
ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); &ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
} }
// GLX: Build texture // GLX: Build texture
@ -442,8 +439,8 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
// Invert window color, if required // Invert window color, if required
if (bkend_use_xrender(ps) && w->invert_color) { if (bkend_use_xrender(ps) && w->invert_color) {
xcb_render_picture_t newpict = x_create_picture_with_pictfmt( xcb_render_picture_t newpict =
ps->c, ps->root, wid, hei, w->pictfmt, 0, NULL); x_create_picture_with_pictfmt(&ps->c, wid, hei, w->pictfmt, 0, NULL);
if (newpict) { if (newpict) {
// Apply clipping region to save some CPU // Apply clipping region to save some CPU
if (reg_paint) { if (reg_paint) {
@ -456,17 +453,18 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
pixman_region32_fini(&reg); pixman_region32_fini(&reg);
} }
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, pict, XCB_NONE, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, pict,
newpict, 0, 0, 0, 0, 0, 0, wid, hei); XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_DIFFERENCE, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_DIFFERENCE,
ps->white_picture, XCB_NONE, newpict, 0, 0, ps->white_picture, XCB_NONE, newpict, 0, 0,
0, 0, 0, 0, wid, hei); 0, 0, 0, 0, wid, hei);
// We use an extra PictOpInReverse operation to get correct // We use an extra PictOpInReverse operation to get correct
// pixel alpha. There could be a better solution. // pixel alpha. There could be a better solution.
if (win_has_alpha(w)) if (win_has_alpha(w)) {
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_IN_REVERSE, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_IN_REVERSE,
pict, XCB_NONE, newpict, 0, 0, 0, 0, pict, XCB_NONE, newpict, 0, 0, 0, 0,
0, 0, wid, hei); 0, 0, wid, hei);
}
pict = newpict; pict = newpict;
} }
} }
@ -494,43 +492,51 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
// ctop = checked top // ctop = checked top
// Make sure top margin is smaller than height // Make sure top margin is smaller than height
int ctop = min2(body_height, t); int ctop = min2(body_height, t);
if (ctop > 0) if (ctop > 0) {
COMP_BDR(0, 0, wid, ctop); COMP_BDR(0, 0, wid, ctop);
}
body_height -= ctop; body_height -= ctop;
if (body_height <= 0) if (body_height <= 0) {
break; break;
}
// bottom // bottom
// cbot = checked bottom // cbot = checked bottom
// Make sure bottom margin is not too large // Make sure bottom margin is not too large
int cbot = min2(body_height, b); int cbot = min2(body_height, b);
if (cbot > 0) if (cbot > 0) {
COMP_BDR(0, hei - cbot, wid, cbot); COMP_BDR(0, hei - cbot, wid, cbot);
}
// Height of window exclude the margin // Height of window exclude the margin
body_height -= cbot; body_height -= cbot;
if (body_height <= 0) if (body_height <= 0) {
break; break;
}
// left // left
int body_width = wid; int body_width = wid;
int cleft = min2(body_width, l); int cleft = min2(body_width, l);
if (cleft > 0) if (cleft > 0) {
COMP_BDR(0, ctop, cleft, body_height); COMP_BDR(0, ctop, cleft, body_height);
}
body_width -= cleft; body_width -= cleft;
if (body_width <= 0) if (body_width <= 0) {
break; break;
}
// right // right
int cright = min2(body_width, r); int cright = min2(body_width, r);
if (cright > 0) if (cright > 0) {
COMP_BDR(wid - cright, ctop, cright, body_height); COMP_BDR(wid - cright, ctop, cright, body_height);
}
body_width -= cright; body_width -= cright;
if (body_width <= 0) if (body_width <= 0) {
break; break;
}
// body // body
paint_region(ps, w, cleft, ctop, body_width, body_height, paint_region(ps, w, cleft, ctop, body_width, body_height,
@ -540,14 +546,17 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
#undef COMP_BDR #undef COMP_BDR
if (pict != w->paint.pict) if (pict != w->paint.pict) {
free_picture(ps->c, &pict); x_free_picture(&ps->c, pict);
pict = XCB_NONE;
}
// Dimming the window if needed // Dimming the window if needed
if (w->dim) { if (w->dim) {
double dim_opacity = ps->o.inactive_dim; double dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed) if (!ps->o.inactive_dim_fixed) {
dim_opacity *= w->opacity; dim_opacity *= w->opacity;
}
switch (ps->o.backend) { switch (ps->o.backend) {
case BKEND_XRENDER: case BKEND_XRENDER:
@ -569,7 +578,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
.height = hei, .height = hei,
}; };
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_OVER, xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_OVER,
ps->tgt_buffer.pict, color, 1, &rect); ps->tgt_buffer.pict, color, 1, &rect);
} break; } break;
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
@ -593,15 +602,17 @@ static bool get_root_tile(session_t *ps) {
ps->root_tile_fill = false; ps->root_tile_fill = false;
bool fill = false; bool fill = false;
xcb_pixmap_t pixmap = x_get_root_back_pixmap(ps->c, ps->root, ps->atoms); xcb_pixmap_t pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms);
// Make sure the pixmap we got is valid // Make sure the pixmap we got is valid
if (pixmap && !x_validate_pixmap(ps->c, pixmap)) if (pixmap && !x_validate_pixmap(&ps->c, pixmap)) {
pixmap = XCB_NONE; pixmap = XCB_NONE;
}
// Create a pixmap if there isn't any // Create a pixmap if there isn't any
if (!pixmap) { if (!pixmap) {
pixmap = x_create_pixmap(ps->c, (uint8_t)ps->depth, ps->root, 1, 1); pixmap =
x_create_pixmap(&ps->c, (uint8_t)ps->c.screen_info->root_depth, 1, 1);
if (pixmap == XCB_NONE) { if (pixmap == XCB_NONE) {
log_error("Failed to create pixmaps for root tile."); log_error("Failed to create pixmaps for root tile.");
return false; return false;
@ -614,7 +625,7 @@ static bool get_root_tile(session_t *ps) {
.repeat = true, .repeat = true,
}; };
ps->root_tile_paint.pict = x_create_picture_with_visual_and_pixmap( ps->root_tile_paint.pict = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, pixmap, XCB_RENDER_CP_REPEAT, &pa); &ps->c, ps->c.screen_info->root_visual, pixmap, XCB_RENDER_CP_REPEAT, &pa);
// Fill pixmap if needed // Fill pixmap if needed
if (fill) { if (fill) {
@ -627,15 +638,17 @@ static bool get_root_tile(session_t *ps) {
rect.x = rect.y = 0; rect.x = rect.y = 0;
rect.width = rect.height = 1; rect.width = rect.height = 1;
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC,
ps->root_tile_paint.pict, col, 1, &rect); ps->root_tile_paint.pict, col, 1, &rect);
} }
ps->root_tile_fill = fill; ps->root_tile_fill = fill;
ps->root_tile_paint.pixmap = pixmap; ps->root_tile_paint.pixmap = pixmap;
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (BKEND_GLX == ps->o.backend) if (BKEND_GLX == ps->o.backend) {
return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, ps->vis, false); return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0,
ps->c.screen_info->root_visual, false);
}
#endif #endif
return true; return true;
@ -668,16 +681,16 @@ static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacit
xcb_render_picture_t shadow_picture = XCB_NONE, shadow_picture_argb = XCB_NONE; xcb_render_picture_t shadow_picture = XCB_NONE, shadow_picture_argb = XCB_NONE;
xcb_gcontext_t gc = XCB_NONE; xcb_gcontext_t gc = XCB_NONE;
shadow_image = make_shadow(ps->c, (conv *)ps->shadow_context, opacity, width, height); shadow_image =
make_shadow(&ps->c, (conv *)ps->shadow_context, opacity, width, height);
if (!shadow_image) { if (!shadow_image) {
log_error("failed to make shadow"); log_error("failed to make shadow");
return XCB_NONE; return XCB_NONE;
} }
shadow_pixmap = shadow_pixmap = x_create_pixmap(&ps->c, 8, shadow_image->width, shadow_image->height);
x_create_pixmap(ps->c, 8, ps->root, shadow_image->width, shadow_image->height);
shadow_pixmap_argb = shadow_pixmap_argb =
x_create_pixmap(ps->c, 32, ps->root, shadow_image->width, shadow_image->height); x_create_pixmap(&ps->c, 32, shadow_image->width, shadow_image->height);
if (!shadow_pixmap || !shadow_pixmap_argb) { if (!shadow_pixmap || !shadow_pixmap_argb) {
log_error("failed to create shadow pixmaps"); log_error("failed to create shadow pixmaps");
@ -685,18 +698,18 @@ static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacit
} }
shadow_picture = x_create_picture_with_standard_and_pixmap( shadow_picture = x_create_picture_with_standard_and_pixmap(
ps->c, XCB_PICT_STANDARD_A_8, shadow_pixmap, 0, NULL); &ps->c, XCB_PICT_STANDARD_A_8, shadow_pixmap, 0, NULL);
shadow_picture_argb = x_create_picture_with_standard_and_pixmap( shadow_picture_argb = x_create_picture_with_standard_and_pixmap(
ps->c, XCB_PICT_STANDARD_ARGB_32, shadow_pixmap_argb, 0, NULL); &ps->c, XCB_PICT_STANDARD_ARGB_32, shadow_pixmap_argb, 0, NULL);
if (!shadow_picture || !shadow_picture_argb) { if (!shadow_picture || !shadow_picture_argb) {
goto shadow_picture_err; goto shadow_picture_err;
} }
gc = x_new_id(ps->c); gc = x_new_id(&ps->c);
xcb_create_gc(ps->c, gc, shadow_pixmap, 0, NULL); xcb_create_gc(ps->c.c, gc, shadow_pixmap, 0, NULL);
xcb_image_put(ps->c, shadow_pixmap, gc, shadow_image, 0, 0, 0); xcb_image_put(ps->c.c, shadow_pixmap, gc, shadow_image, 0, 0, 0);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, ps->cshadow_picture, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, ps->cshadow_picture,
shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0,
shadow_image->width, shadow_image->height); shadow_image->width, shadow_image->height);
@ -705,26 +718,32 @@ static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacit
assert(!w->shadow_paint.pict); assert(!w->shadow_paint.pict);
w->shadow_paint.pict = shadow_picture_argb; w->shadow_paint.pict = shadow_picture_argb;
xcb_free_gc(ps->c, gc); xcb_free_gc(ps->c.c, gc);
xcb_image_destroy(shadow_image); xcb_image_destroy(shadow_image);
xcb_free_pixmap(ps->c, shadow_pixmap); xcb_free_pixmap(ps->c.c, shadow_pixmap);
xcb_render_free_picture(ps->c, shadow_picture); x_free_picture(&ps->c, shadow_picture);
return true; return true;
shadow_picture_err: shadow_picture_err:
if (shadow_image) if (shadow_image) {
xcb_image_destroy(shadow_image); xcb_image_destroy(shadow_image);
if (shadow_pixmap) }
xcb_free_pixmap(ps->c, shadow_pixmap); if (shadow_pixmap) {
if (shadow_pixmap_argb) xcb_free_pixmap(ps->c.c, shadow_pixmap);
xcb_free_pixmap(ps->c, shadow_pixmap_argb); }
if (shadow_picture) if (shadow_pixmap_argb) {
xcb_render_free_picture(ps->c, shadow_picture); xcb_free_pixmap(ps->c.c, shadow_pixmap_argb);
if (shadow_picture_argb) }
xcb_render_free_picture(ps->c, shadow_picture_argb); if (shadow_picture) {
if (gc) x_free_picture(&ps->c, shadow_picture);
xcb_free_gc(ps->c, gc); }
if (shadow_picture_argb) {
x_free_picture(&ps->c, shadow_picture_argb);
}
if (gc) {
xcb_free_gc(ps->c.c, gc);
}
return false; return false;
} }
@ -753,23 +772,22 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
traps, max_ntraps, w->corner_radius, w->widthb, w->heightb); traps, max_ntraps, w->corner_radius, w->widthb, w->heightb);
td = x_create_picture_with_standard( td = x_create_picture_with_standard(
ps->c, ps->root, w->widthb, w->heightb, &ps->c, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0);
XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = { xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0}; .red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0, const xcb_rectangle_t rect = {.x = 0,
.y = 0, .y = 0,
.width = to_u16_checked(w->widthb), .width = to_u16_checked(w->widthb),
.height = to_u16_checked(w->heightb)}; .height = to_u16_checked(w->heightb)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, td,
trans, 1, &rect); trans, 1, &rect);
auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0); auto solid = solid_picture(&ps->c, false, 1, 0, 0, 0);
xcb_render_trapezoids( xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, solid, td, ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0,
0, n, traps); 0, n, traps);
xcb_render_free_picture(ps->c, solid); x_free_picture(&ps->c, solid);
} else { } else {
// Not implemented // Not implemented
} }
@ -785,7 +803,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL, w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL,
should_clip ? &clip : NULL); should_clip ? &clip : NULL);
if (td) { if (td) {
xcb_render_free_picture(ps->c, td); x_free_picture(&ps->c, td);
} }
} }
@ -813,16 +831,17 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y
// Directly copying from tgt_buffer to it does not work, so we create a // Directly copying from tgt_buffer to it does not work, so we create a
// Picture in the middle. // Picture in the middle.
xcb_render_picture_t tmp_picture = xcb_render_picture_t tmp_picture = x_create_picture_with_visual(
x_create_picture_with_visual(ps->c, ps->root, wid, hei, ps->vis, 0, NULL); &ps->c, wid, hei, ps->c.screen_info->root_visual, 0, NULL);
if (!tmp_picture) { if (!tmp_picture) {
log_error("Failed to build intermediate Picture."); log_error("Failed to build intermediate Picture.");
return false; return false;
} }
if (reg_clip && tmp_picture) if (reg_clip && tmp_picture) {
x_set_picture_clip_region(ps->c, tmp_picture, 0, 0, reg_clip); x_set_picture_clip_region(&ps->c, tmp_picture, 0, 0, reg_clip);
}
xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture; xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture;
for (int i = 0; i < nkernels; ++i) { for (int i = 0; i < nkernels; ++i) {
@ -836,9 +855,9 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y
// be applied on source picture, to get the nearby pixels outside the // be applied on source picture, to get the nearby pixels outside the
// window. // window.
xcb_render_set_picture_filter( xcb_render_set_picture_filter(
ps->c, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION, ps->c.c, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION,
(uint32_t)(kwid * khei + 2), convolution_blur); (uint32_t)(kwid * khei + 2), convolution_blur);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
dst_pict, (rd_from_tgt ? x : 0), dst_pict, (rd_from_tgt ? x : 0),
(rd_from_tgt ? y : 0), 0, 0, (rd_from_tgt ? 0 : x), (rd_from_tgt ? y : 0), 0, 0, (rd_from_tgt ? 0 : x),
(rd_from_tgt ? 0 : y), wid, hei); (rd_from_tgt ? 0 : y), wid, hei);
@ -851,11 +870,12 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y
} }
} }
if (src_pict != tgt_buffer) if (src_pict != tgt_buffer) {
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded,
tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
}
free_picture(ps->c, &tmp_picture); x_free_picture(&ps->c, tmp_picture);
return true; return true;
} }
@ -910,23 +930,23 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
make_rounded_window_shape(traps, max_ntraps, cr, wid, hei); make_rounded_window_shape(traps, max_ntraps, cr, wid, hei);
td = x_create_picture_with_standard( td = x_create_picture_with_standard(
ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); &ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = { xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0}; .red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0, const xcb_rectangle_t rect = {.x = 0,
.y = 0, .y = 0,
.width = to_u16_checked(wid), .width = to_u16_checked(wid),
.height = to_u16_checked(hei)}; .height = to_u16_checked(hei)};
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, td,
trans, 1, &rect); trans, 1, &rect);
auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0); auto solid = solid_picture(&ps->c, false, 1, 0, 0, 0);
xcb_render_trapezoids( xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, solid, td, ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0,
0, n, traps); 0, n, traps);
xcb_render_free_picture(ps->c, solid); x_free_picture(&ps->c, solid);
} }
// Minimize the region we try to blur, if the window itself is not // Minimize the region we try to blur, if the window itself is not
@ -946,7 +966,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache,
ps->o.blur_kernel_count, &reg_blur, td); ps->o.blur_kernel_count, &reg_blur, td);
if (td) { if (td) {
xcb_render_free_picture(ps->c, td); x_free_picture(&ps->c, td);
} }
pixman_region32_clear(&reg_blur); pixman_region32_clear(&reg_blur);
} break; } break;
@ -969,10 +989,10 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
/// region_real = the damage region /// region_real = the damage region
void paint_all(session_t *ps, struct managed_win *t) { void paint_all(session_t *ps, struct managed_win *t) {
if (ps->o.xrender_sync_fence || (ps->drivers & DRIVER_NVIDIA)) { if (ps->o.xrender_sync_fence || (ps->drivers & DRIVER_NVIDIA)) {
if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) { if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) {
log_error("x_fence_sync failed, xrender-sync-fence will be " log_error("x_fence_sync failed, xrender-sync-fence will be "
"disabled from now on."); "disabled from now on.");
xcb_sync_destroy_fence(ps->c, ps->sync_fence); xcb_sync_destroy_fence(ps->c.c, ps->sync_fence);
ps->sync_fence = XCB_NONE; ps->sync_fence = XCB_NONE;
ps->o.xrender_sync_fence = false; ps->o.xrender_sync_fence = false;
ps->xsync_exists = false; ps->xsync_exists = false;
@ -1010,7 +1030,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
if (!ps->tgt_buffer.pixmap) { if (!ps->tgt_buffer.pixmap) {
free_paint(ps, &ps->tgt_buffer); free_paint(ps, &ps->tgt_buffer);
ps->tgt_buffer.pixmap = ps->tgt_buffer.pixmap =
x_create_pixmap(ps->c, (uint8_t)ps->depth, ps->root, x_create_pixmap(&ps->c, ps->c.screen_info->root_depth,
ps->root_width, ps->root_height); ps->root_width, ps->root_height);
if (ps->tgt_buffer.pixmap == XCB_NONE) { if (ps->tgt_buffer.pixmap == XCB_NONE) {
log_fatal("Failed to allocate a screen-sized pixmap for" log_fatal("Failed to allocate a screen-sized pixmap for"
@ -1019,18 +1039,20 @@ void paint_all(session_t *ps, struct managed_win *t) {
} }
} }
if (BKEND_GLX != ps->o.backend) if (BKEND_GLX != ps->o.backend) {
ps->tgt_buffer.pict = x_create_picture_with_visual_and_pixmap( ps->tgt_buffer.pict = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, ps->tgt_buffer.pixmap, 0, 0); &ps->c, ps->c.screen_info->root_visual, ps->tgt_buffer.pixmap,
0, 0);
}
} }
if (BKEND_XRENDER == ps->o.backend) { if (BKEND_XRENDER == ps->o.backend) {
x_set_picture_clip_region(ps->c, ps->tgt_picture, 0, 0, &region); x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, &region);
} }
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (bkend_use_glx(ps)) { if (bkend_use_glx(ps)) {
ps->psglx->z = 0.0; ps->psglx->z = 0;
} }
#endif #endif
@ -1066,18 +1088,21 @@ void paint_all(session_t *ps, struct managed_win *t) {
// Painting shadow // Painting shadow
if (w->shadow) { if (w->shadow) {
// Lazy shadow building // Lazy shadow building
if (!w->shadow_paint.pixmap) if (!w->shadow_paint.pixmap) {
if (!win_build_shadow(ps, w, 1)) if (!win_build_shadow(ps, w, 1)) {
log_error("build shadow failed"); log_error("build shadow failed");
}
}
// Shadow doesn't need to be painted underneath the body // Shadow doesn't need to be painted underneath the body
// of the windows above. Because no one can see it // of the windows above. Because no one can see it
pixman_region32_subtract(&reg_tmp, &region, w->reg_ignore); pixman_region32_subtract(&reg_tmp, &region, w->reg_ignore);
// Mask out the region we don't want shadow on // Mask out the region we don't want shadow on
if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) {
pixman_region32_subtract(&reg_tmp, &reg_tmp, pixman_region32_subtract(&reg_tmp, &reg_tmp,
&ps->shadow_exclude_reg); &ps->shadow_exclude_reg);
}
if (pixman_region32_not_empty(&reg_shadow_clip)) { if (pixman_region32_not_empty(&reg_shadow_clip)) {
pixman_region32_subtract(&reg_tmp, &reg_tmp, &reg_shadow_clip); pixman_region32_subtract(&reg_tmp, &reg_tmp, &reg_shadow_clip);
} }
@ -1093,11 +1118,12 @@ void paint_all(session_t *ps, struct managed_win *t) {
// needed Doing it here instead of in make_shadow() for // needed Doing it here instead of in make_shadow() for
// saving GPU power and handling shaped windows (XXX // saving GPU power and handling shaped windows (XXX
// unconfirmed) // unconfirmed)
if (!ps->o.wintype_option[w->window_type].full_shadow) if (!ps->o.wintype_option[w->window_type].full_shadow) {
pixman_region32_subtract(&reg_tmp, &reg_tmp, &bshape_no_corners); pixman_region32_subtract(&reg_tmp, &reg_tmp, &bshape_no_corners);
}
if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 &&
w->randr_monitor < ps->randr_nmonitors) { w->randr_monitor < ps->monitors.count) {
// There can be a window where number of monitors is // There can be a window where number of monitors is
// updated, but the monitor number attached to the window // updated, but the monitor number attached to the window
// have not. // have not.
@ -1107,7 +1133,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
// bounds. // bounds.
pixman_region32_intersect( pixman_region32_intersect(
&reg_tmp, &reg_tmp, &reg_tmp, &reg_tmp,
&ps->randr_monitor_regs[w->randr_monitor]); &ps->monitors.regions[w->randr_monitor]);
} }
// Detect if the region is empty before painting // Detect if the region is empty before painting
@ -1197,13 +1223,14 @@ void paint_all(session_t *ps, struct managed_win *t) {
if (ps->o.vsync) { if (ps->o.vsync) {
// Make sure all previous requests are processed to achieve best // Make sure all previous requests are processed to achieve best
// effect // effect
x_sync(ps->c); x_sync(&ps->c);
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (glx_has_context(ps)) { if (glx_has_context(ps)) {
if (ps->o.vsync_use_glfinish) if (ps->o.vsync_use_glfinish) {
glFinish(); glFinish();
else } else {
glFlush(); glFlush();
}
glXWaitX(); glXWaitX();
} }
#endif #endif
@ -1224,57 +1251,63 @@ void paint_all(session_t *ps, struct managed_win *t) {
// First we create a new picture, and copy content from the buffer // First we create a new picture, and copy content from the buffer
// to it // to it
auto pictfmt = x_get_pictform_for_visual(ps->c, ps->vis); auto pictfmt = x_get_pictform_for_visual(
&ps->c, ps->c.screen_info->root_visual);
xcb_render_picture_t new_pict = x_create_picture_with_pictfmt( xcb_render_picture_t new_pict = x_create_picture_with_pictfmt(
ps->c, ps->root, rwidth, rheight, pictfmt, 0, NULL); &ps->c, rwidth, rheight, pictfmt, 0, NULL);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC,
ps->tgt_buffer.pict, XCB_NONE, new_pict, 0, ps->tgt_buffer.pict, XCB_NONE, new_pict, 0,
0, 0, 0, 0, 0, rwidth, rheight); 0, 0, 0, 0, 0, rwidth, rheight);
// Next, we set the region of paint and highlight it // Next, we set the region of paint and highlight it
x_set_picture_clip_region(ps->c, new_pict, 0, 0, &region); x_set_picture_clip_region(&ps->c, new_pict, 0, 0, &region);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, ps->white_picture, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, ps->white_picture,
ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0, ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0,
0, 0, 0, 0, 0, rwidth, rheight); 0, 0, 0, 0, 0, rwidth, rheight);
// Finally, clear clip regions of new_pict and the screen, and put // Finally, clear clip regions of new_pict and the screen, and put
// the whole thing on screen // the whole thing on screen
x_set_picture_clip_region(ps->c, new_pict, 0, 0, &ps->screen_reg); x_set_picture_clip_region(&ps->c, new_pict, 0, 0, &ps->screen_reg);
x_set_picture_clip_region(ps->c, ps->tgt_picture, 0, 0, &ps->screen_reg); x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0,
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, new_pict, &ps->screen_reg);
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, new_pict,
XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0, XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0,
rwidth, rheight); rwidth, rheight);
xcb_render_free_picture(ps->c, new_pict); x_free_picture(&ps->c, new_pict);
} else } else {
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC,
ps->tgt_buffer.pict, XCB_NONE, ps->tgt_picture, ps->tgt_buffer.pict, XCB_NONE, ps->tgt_picture,
0, 0, 0, 0, 0, 0, rwidth, rheight); 0, 0, 0, 0, 0, 0, rwidth, rheight);
}
break; break;
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
case BKEND_XR_GLX_HYBRID: case BKEND_XR_GLX_HYBRID:
x_sync(ps->c); x_sync(&ps->c);
if (ps->o.vsync_use_glfinish) if (ps->o.vsync_use_glfinish) {
glFinish(); glFinish();
else } else {
glFlush(); glFlush();
}
glXWaitX(); glXWaitX();
assert(ps->tgt_buffer.pixmap); assert(ps->tgt_buffer.pixmap);
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height,
false, ps->depth, ps->vis, !ps->o.glx_no_rebind_pixmap); false, ps->c.screen_info->root_depth,
if (ps->o.vsync_use_glfinish) ps->c.screen_info->root_visual, !ps->o.glx_no_rebind_pixmap);
if (ps->o.vsync_use_glfinish) {
glFinish(); glFinish();
else } else {
glFlush(); glFlush();
}
glXWaitX(); glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width, glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
ps->root_height, 0, 1.0, false, false, &region, NULL); ps->root_height, 0, 1.0, false, false, &region, NULL);
fallthrough(); fallthrough();
case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break; case BKEND_GLX: glXSwapBuffers(ps->c.dpy, get_tgt_window(ps)); break;
#endif #endif
default: assert(0); default: assert(0);
} }
x_sync(ps->c); x_sync(&ps->c);
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (glx_has_context(ps)) { if (glx_has_context(ps)) {
@ -1304,7 +1337,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
static bool xr_init_blur(session_t *ps) { static bool xr_init_blur(session_t *ps) {
// Query filters // Query filters
xcb_render_query_filters_reply_t *pf = xcb_render_query_filters_reply( xcb_render_query_filters_reply_t *pf = xcb_render_query_filters_reply(
ps->c, xcb_render_query_filters(ps->c, get_tgt_window(ps)), NULL); ps->c.c, xcb_render_query_filters(ps->c.c, get_tgt_window(ps)), NULL);
if (pf) { if (pf) {
xcb_str_iterator_t iter = xcb_render_query_filters_filters_iterator(pf); xcb_str_iterator_t iter = xcb_render_query_filters_filters_iterator(pf);
for (; iter.rem; xcb_str_next(&iter)) { for (; iter.rem; xcb_str_next(&iter)) {
@ -1312,8 +1345,9 @@ static bool xr_init_blur(session_t *ps) {
char *name = xcb_str_name(iter.data); char *name = xcb_str_name(iter.data);
// Check for the convolution filter // Check for the convolution filter
if (strlen(XRFILTER_CONVOLUTION) == len && if (strlen(XRFILTER_CONVOLUTION) == len &&
!memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) !memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) {
ps->xrfilter_convolution_exists = true; ps->xrfilter_convolution_exists = true;
}
} }
free(pf); free(pf);
} }
@ -1337,9 +1371,10 @@ static bool init_alpha_picts(session_t *ps) {
for (int i = 0; i <= MAX_ALPHA; ++i) { for (int i = 0; i <= MAX_ALPHA; ++i) {
double o = (double)i / MAX_ALPHA; double o = (double)i / MAX_ALPHA;
ps->alpha_picts[i] = solid_picture(ps->c, ps->root, false, o, 0, 0, 0); ps->alpha_picts[i] = solid_picture(&ps->c, false, o, 0, 0, 0);
if (ps->alpha_picts[i] == XCB_NONE) if (ps->alpha_picts[i] == XCB_NONE) {
return false; return false;
}
} }
return true; return true;
} }
@ -1351,12 +1386,13 @@ bool init_render(session_t *ps) {
// Initialize OpenGL as early as possible // Initialize OpenGL as early as possible
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
glxext_init(ps->dpy, ps->scr); glxext_init(ps->c.dpy, ps->c.screen);
#endif #endif
if (bkend_use_glx(ps)) { if (bkend_use_glx(ps)) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (!glx_init(ps, true)) if (!glx_init(ps, true)) {
return false; return false;
}
#else #else
log_error("GLX backend support not compiled in."); log_error("GLX backend support not compiled in.");
return false; return false;
@ -1371,8 +1407,9 @@ bool init_render(session_t *ps) {
// Initialize window GL shader // Initialize window GL shader
if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) { if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (!glx_load_prog_main(NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) if (!glx_load_prog_main(NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) {
return false; return false;
}
#else #else
log_error("GLSL supported not compiled in, can't load " log_error("GLSL supported not compiled in, can't load "
"shader."); "shader.");
@ -1411,8 +1448,8 @@ bool init_render(session_t *ps) {
} }
} }
ps->black_picture = solid_picture(ps->c, ps->root, true, 1, 0, 0, 0); ps->black_picture = solid_picture(&ps->c, true, 1, 0, 0, 0);
ps->white_picture = solid_picture(ps->c, ps->root, true, 1, 1, 1, 1); ps->white_picture = solid_picture(&ps->c, true, 1, 1, 1, 1);
if (ps->black_picture == XCB_NONE || ps->white_picture == XCB_NONE) { if (ps->black_picture == XCB_NONE || ps->white_picture == XCB_NONE) {
log_error("Failed to create solid xrender pictures."); log_error("Failed to create solid xrender pictures.");
@ -1424,7 +1461,7 @@ bool init_render(session_t *ps) {
if (ps->o.shadow_red == 0 && ps->o.shadow_green == 0 && ps->o.shadow_blue == 0) { if (ps->o.shadow_red == 0 && ps->o.shadow_green == 0 && ps->o.shadow_blue == 0) {
ps->cshadow_picture = ps->black_picture; ps->cshadow_picture = ps->black_picture;
} else { } else {
ps->cshadow_picture = solid_picture(ps->c, ps->root, true, 1, ps->o.shadow_red, ps->cshadow_picture = solid_picture(&ps->c, true, 1, ps->o.shadow_red,
ps->o.shadow_green, ps->o.shadow_blue); ps->o.shadow_green, ps->o.shadow_blue);
if (ps->cshadow_picture == XCB_NONE) { if (ps->cshadow_picture == XCB_NONE) {
log_error("Failed to create shadow picture."); log_error("Failed to create shadow picture.");
@ -1450,14 +1487,14 @@ bool init_render(session_t *ps) {
* Free root tile related things. * Free root tile related things.
*/ */
void free_root_tile(session_t *ps) { void free_root_tile(session_t *ps) {
free_picture(ps->c, &ps->root_tile_paint.pict); x_free_picture(&ps->c, ps->root_tile_paint.pict);
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
free_texture(ps, &ps->root_tile_paint.ptex); free_texture(ps, &ps->root_tile_paint.ptex);
#else #else
assert(!ps->root_tile_paint.ptex); assert(!ps->root_tile_paint.ptex);
#endif #endif
if (ps->root_tile_fill) { if (ps->root_tile_fill) {
xcb_free_pixmap(ps->c, ps->root_tile_paint.pixmap); xcb_free_pixmap(ps->c.c, ps->root_tile_paint.pixmap);
ps->root_tile_paint.pixmap = XCB_NONE; ps->root_tile_paint.pixmap = XCB_NONE;
} }
ps->root_tile_paint.pixmap = XCB_NONE; ps->root_tile_paint.pixmap = XCB_NONE;
@ -1466,19 +1503,20 @@ void free_root_tile(session_t *ps) {
void deinit_render(session_t *ps) { void deinit_render(session_t *ps) {
// Free alpha_picts // Free alpha_picts
for (int i = 0; i <= MAX_ALPHA; ++i) for (int i = 0; i <= MAX_ALPHA; ++i) {
free_picture(ps->c, &ps->alpha_picts[i]); x_free_picture(&ps->c, ps->alpha_picts[i]);
}
free(ps->alpha_picts); free(ps->alpha_picts);
ps->alpha_picts = NULL; ps->alpha_picts = NULL;
// Free cshadow_picture and black_picture // Free cshadow_picture and black_picture
if (ps->cshadow_picture == ps->black_picture) if (ps->cshadow_picture != ps->black_picture) {
ps->cshadow_picture = XCB_NONE; x_free_picture(&ps->c, ps->cshadow_picture);
else }
free_picture(ps->c, &ps->cshadow_picture);
free_picture(ps->c, &ps->black_picture); x_free_picture(&ps->c, ps->black_picture);
free_picture(ps->c, &ps->white_picture); x_free_picture(&ps->c, ps->white_picture);
ps->cshadow_picture = ps->black_picture = ps->white_picture = XCB_NONE;
// Free other X resources // Free other X resources
free_root_tile(ps); free_root_tile(ps);

View File

@ -39,8 +39,6 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint);
void paint_all(session_t *ps, struct managed_win *const t); void paint_all(session_t *ps, struct managed_win *const t);
void free_picture(xcb_connection_t *c, xcb_render_picture_t *p);
void free_paint(session_t *ps, paint_t *ppaint); void free_paint(session_t *ps, paint_t *ppaint);
void free_root_tile(session_t *ps); void free_root_tile(session_t *ps);

View File

@ -77,31 +77,35 @@ static bool vsync_drm_init(session_t *ps) {
* @return true for success, false otherwise * @return true for success, false otherwise
*/ */
static bool vsync_opengl_init(session_t *ps) { static bool vsync_opengl_init(session_t *ps) {
if (!ensure_glx_context(ps)) if (!ensure_glx_context(ps)) {
return false; return false;
}
return glxext.has_GLX_SGI_video_sync; return glxext.has_GLX_SGI_video_sync;
} }
static bool vsync_opengl_oml_init(session_t *ps) { static bool vsync_opengl_oml_init(session_t *ps) {
if (!ensure_glx_context(ps)) if (!ensure_glx_context(ps)) {
return false; return false;
}
return glxext.has_GLX_OML_sync_control; return glxext.has_GLX_OML_sync_control;
} }
static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) { static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) {
if (glxext.has_GLX_MESA_swap_control) if (glxext.has_GLX_MESA_swap_control) {
return glXSwapIntervalMESA((uint)interval) == 0; return glXSwapIntervalMESA((uint)interval) == 0;
else if (glxext.has_GLX_SGI_swap_control) }
if (glxext.has_GLX_SGI_swap_control) {
return glXSwapIntervalSGI(interval) == 0; return glXSwapIntervalSGI(interval) == 0;
else if (glxext.has_GLX_EXT_swap_control) { }
if (glxext.has_GLX_EXT_swap_control) {
GLXDrawable d = glXGetCurrentDrawable(); GLXDrawable d = glXGetCurrentDrawable();
if (d == None) { if (d == None) {
// We don't have a context?? // We don't have a context??
return false; return false;
} }
glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval); glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval);
return true; return true;
} }
return false; return false;
@ -140,8 +144,8 @@ static int vsync_opengl_wait(session_t *ps attr_unused) {
static int vsync_opengl_oml_wait(session_t *ps) { static int vsync_opengl_oml_wait(session_t *ps) {
int64_t ust = 0, msc = 0, sbc = 0; int64_t ust = 0, msc = 0, sbc = 0;
glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); glXGetSyncValuesOML(ps->c.dpy, ps->reg_win, &ust, &msc, &sbc);
glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
return 0; return 0;
} }
#endif #endif

112
src/win.c
View File

@ -324,7 +324,7 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
assert(!w->win_image); assert(!w->win_image);
auto pixmap = x_new_id(b->c); auto pixmap = x_new_id(b->c);
auto e = xcb_request_check( auto e = xcb_request_check(
b->c, xcb_composite_name_window_pixmap_checked(b->c, w->base.id, pixmap)); b->c->c, xcb_composite_name_window_pixmap_checked(b->c->c, w->base.id, pixmap));
if (e) { if (e) {
log_error("Failed to get named pixmap for window %#010x(%s)", w->base.id, log_error("Failed to get named pixmap for window %#010x(%s)", w->base.id,
w->name); w->name);
@ -519,7 +519,7 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
win_clear_flags(w, WIN_FLAGS_POSITION_STALE); win_clear_flags(w, WIN_FLAGS_POSITION_STALE);
} }
win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, w); win_update_monitor(&ps->monitors, w);
} }
if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) { if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) {
@ -702,7 +702,7 @@ static inline bool win_bounding_shaped(const session_t *ps, xcb_window_t wid) {
Bool bounding_shaped; Bool bounding_shaped;
reply = xcb_shape_query_extents_reply( reply = xcb_shape_query_extents_reply(
ps->c, xcb_shape_query_extents(ps->c, wid), NULL); ps->c.c, xcb_shape_query_extents(ps->c.c, wid), NULL);
bounding_shaped = reply && reply->bounding_shaped; bounding_shaped = reply && reply->bounding_shaped;
free(reply); free(reply);
@ -714,7 +714,7 @@ static inline bool win_bounding_shaped(const session_t *ps, xcb_window_t wid) {
static wintype_t wid_get_prop_wintype(session_t *ps, xcb_window_t wid) { static wintype_t wid_get_prop_wintype(session_t *ps, xcb_window_t wid) {
winprop_t prop = winprop_t prop =
x_get_prop(ps->c, wid, ps->atoms->a_NET_WM_WINDOW_TYPE, 32L, XCB_ATOM_ATOM, 32); x_get_prop(&ps->c, wid, ps->atoms->a_NET_WM_WINDOW_TYPE, 32L, XCB_ATOM_ATOM, 32);
for (unsigned i = 0; i < prop.nitems; ++i) { for (unsigned i = 0; i < prop.nitems; ++i) {
for (wintype_t j = 1; j < NUM_WINTYPES; ++j) { for (wintype_t j = 1; j < NUM_WINTYPES; ++j) {
@ -735,7 +735,7 @@ wid_get_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t def, opacity_t *
bool ret = false; bool ret = false;
*out = def; *out = def;
winprop_t prop = x_get_prop(ps->c, wid, ps->atoms->a_NET_WM_WINDOW_OPACITY, 1L, winprop_t prop = x_get_prop(&ps->c, wid, ps->atoms->a_NET_WM_WINDOW_OPACITY, 1L,
XCB_ATOM_CARDINAL, 32); XCB_ATOM_CARDINAL, 32);
if (prop.nitems) { if (prop.nitems) {
@ -827,11 +827,12 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
} else { } else {
// Respect active_opacity only when the window is physically // Respect active_opacity only when the window is physically
// focused // focused
if (win_is_focused_raw(ps, w)) if (win_is_focused_raw(ps, w)) {
opacity = ps->o.active_opacity; opacity = ps->o.active_opacity;
else if (!w->focused) } else if (!w->focused) {
// Respect inactive_opacity in some cases // Respect inactive_opacity in some cases
opacity = ps->o.inactive_opacity; opacity = ps->o.inactive_opacity;
}
} }
// respect inactive override // respect inactive override
@ -853,9 +854,8 @@ bool win_should_dim(session_t *ps, const struct managed_win *w) {
if (ps->o.inactive_dim > 0 && !(w->focused)) { if (ps->o.inactive_dim > 0 && !(w->focused)) {
return true; return true;
} else {
return false;
} }
return false;
} }
/** /**
@ -887,7 +887,7 @@ bool win_should_fade(session_t *ps, const struct managed_win *w) {
* The property must be set on the outermost window, usually the WM frame. * The property must be set on the outermost window, usually the WM frame.
*/ */
void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w) { void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w) {
winprop_t prop = x_get_prop(ps->c, w->base.id, ps->atoms->a_COMPTON_SHADOW, 1, winprop_t prop = x_get_prop(&ps->c, w->base.id, ps->atoms->a_COMPTON_SHADOW, 1,
XCB_ATOM_CARDINAL, 32); XCB_ATOM_CARDINAL, 32);
if (!prop.nitems) { if (!prop.nitems) {
@ -1085,8 +1085,9 @@ void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val) {
static void static void
win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new) { win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new) {
if (w->blur_background == blur_background_new) if (w->blur_background == blur_background_new) {
return; return;
}
w->blur_background = blur_background_new; w->blur_background = blur_background_new;
@ -1284,10 +1285,11 @@ void win_update_wintype(session_t *ps, struct managed_win *w) {
// _NET_WM_WINDOW_TYPE_NORMAL, otherwise as _NET_WM_WINDOW_TYPE_DIALOG. // _NET_WM_WINDOW_TYPE_NORMAL, otherwise as _NET_WM_WINDOW_TYPE_DIALOG.
if (WINTYPE_UNKNOWN == w->window_type) { if (WINTYPE_UNKNOWN == w->window_type) {
if (w->a.override_redirect || if (w->a.override_redirect ||
!wid_has_prop(ps, w->client_win, ps->atoms->aWM_TRANSIENT_FOR)) !wid_has_prop(ps, w->client_win, ps->atoms->aWM_TRANSIENT_FOR)) {
w->window_type = WINTYPE_NORMAL; w->window_type = WINTYPE_NORMAL;
else } else {
w->window_type = WINTYPE_DIALOG; w->window_type = WINTYPE_DIALOG;
}
} }
if (w->window_type != wtype_old) { if (w->window_type != wtype_old) {
@ -1312,9 +1314,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
} }
auto e = xcb_request_check( auto e = xcb_request_check(
ps->c, xcb_change_window_attributes_checked( ps->c.c, xcb_change_window_attributes_checked(
ps->c, client, XCB_CW_EVENT_MASK, ps->c.c, client, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_CLIENT)})); (const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_CLIENT)}));
if (e) { if (e) {
log_error("Failed to change event mask of window %#010x", client); log_error("Failed to change event mask of window %#010x", client);
free(e); free(e);
@ -1339,13 +1341,13 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
win_on_factor_change(ps, w); win_on_factor_change(ps, w);
auto r = xcb_get_window_attributes_reply( auto r = xcb_get_window_attributes_reply(
ps->c, xcb_get_window_attributes(ps->c, w->client_win), &e); ps->c.c, xcb_get_window_attributes(ps->c.c, w->client_win), &e);
if (!r) { if (!r) {
log_error_x_error(e, "Failed to get client window attributes"); log_error_x_error(e, "Failed to get client window attributes");
return; return;
} }
w->client_pictfmt = x_get_pictform_for_visual(ps->c, r->visual); w->client_pictfmt = x_get_pictform_for_visual(&ps->c, r->visual);
free(r); free(r);
} }
@ -1364,7 +1366,7 @@ void win_unmark_client(session_t *ps, struct managed_win *w) {
// Recheck event mask // Recheck event mask
xcb_change_window_attributes( xcb_change_window_attributes(
ps->c, client, XCB_CW_EVENT_MASK, ps->c.c, client, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_UNKNOWN)}); (const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_UNKNOWN)});
} }
@ -1377,7 +1379,7 @@ static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
} }
xcb_query_tree_reply_t *reply = xcb_query_tree_reply_t *reply =
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL); xcb_query_tree_reply(ps->c.c, xcb_query_tree(ps->c.c, w), NULL);
if (!reply) { if (!reply) {
return 0; return 0;
} }
@ -1451,7 +1453,7 @@ void free_win_res(session_t *ps, struct managed_win *w) {
pixman_region32_fini(&w->bounding_shape); pixman_region32_fini(&w->bounding_shape);
// BadDamage may be thrown if the window is destroyed // BadDamage may be thrown if the window is destroyed
set_ignore_cookie(ps, xcb_damage_destroy(ps->c, w->damage)); set_ignore_cookie(&ps->c, xcb_damage_destroy(ps->c.c, w->damage));
rc_region_unref(&w->reg_ignore); rc_region_unref(&w->reg_ignore);
free(w->name); free(w->name);
free(w->class_instance); free(w->class_instance);
@ -1619,9 +1621,10 @@ struct win *fill_win(session_t *ps, struct win *w) {
} }
log_debug("Managing window %#010x", w->id); log_debug("Managing window %#010x", w->id);
xcb_get_window_attributes_cookie_t acookie = xcb_get_window_attributes(ps->c, w->id); xcb_get_window_attributes_cookie_t acookie =
xcb_get_window_attributes(ps->c.c, w->id);
xcb_get_window_attributes_reply_t *a = xcb_get_window_attributes_reply_t *a =
xcb_get_window_attributes_reply(ps->c, acookie, NULL); xcb_get_window_attributes_reply(ps->c.c, acookie, NULL);
if (!a || a->map_state == XCB_MAP_STATE_UNVIEWABLE) { if (!a || a->map_state == XCB_MAP_STATE_UNVIEWABLE) {
// Failed to get window attributes or geometry probably means // Failed to get window attributes or geometry probably means
// the window is gone already. Unviewable means the window is // the window is gone already. Unviewable means the window is
@ -1656,7 +1659,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
free(a); free(a);
xcb_generic_error_t *e; xcb_generic_error_t *e;
auto g = xcb_get_geometry_reply(ps->c, xcb_get_geometry(ps->c, w->id), &e); auto g = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, w->id), &e);
if (!g) { if (!g) {
log_error_x_error(e, "Failed to get geometry of window %#010x", w->id); log_error_x_error(e, "Failed to get geometry of window %#010x", w->id);
free(e); free(e);
@ -1674,10 +1677,10 @@ struct win *fill_win(session_t *ps, struct win *w) {
free(g); free(g);
// Create Damage for window (if not Input Only) // Create Damage for window (if not Input Only)
new->damage = x_new_id(ps->c); new->damage = x_new_id(&ps->c);
e = xcb_request_check( e = xcb_request_check(
ps->c, xcb_damage_create_checked(ps->c, new->damage, w->id, ps->c.c, xcb_damage_create_checked(ps->c.c, new->damage, w->id,
XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY)); XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY));
if (e) { if (e) {
log_error_x_error(e, "Failed to create damage"); log_error_x_error(e, "Failed to create damage");
free(e); free(e);
@ -1687,15 +1690,15 @@ struct win *fill_win(session_t *ps, struct win *w) {
// Set window event mask // Set window event mask
xcb_change_window_attributes( xcb_change_window_attributes(
ps->c, new->base.id, XCB_CW_EVENT_MASK, ps->c.c, new->base.id, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, new->base.id, WIN_EVMODE_FRAME)}); (const uint32_t[]){determine_evmask(ps, new->base.id, WIN_EVMODE_FRAME)});
// Get notification when the shape of a window changes // Get notification when the shape of a window changes
if (ps->shape_exists) { if (ps->shape_exists) {
xcb_shape_select_input(ps->c, new->base.id, 1); xcb_shape_select_input(ps->c.c, new->base.id, 1);
} }
new->pictfmt = x_get_pictform_for_visual(ps->c, new->a.visual); new->pictfmt = x_get_pictform_for_visual(&ps->c, new->a.visual);
new->client_pictfmt = NULL; new->client_pictfmt = NULL;
list_replace(&w->stack_neighbour, &new->base.stack_neighbour); list_replace(&w->stack_neighbour, &new->base.stack_neighbour);
@ -1765,12 +1768,12 @@ void win_update_leader(session_t *ps, struct managed_win *w) {
// Read the leader properties // Read the leader properties
if (ps->o.detect_transient && !leader) { if (ps->o.detect_transient && !leader) {
leader = leader =
wid_get_prop_window(ps->c, w->client_win, ps->atoms->aWM_TRANSIENT_FOR); wid_get_prop_window(&ps->c, w->client_win, ps->atoms->aWM_TRANSIENT_FOR);
} }
if (ps->o.detect_client_leader && !leader) { if (ps->o.detect_client_leader && !leader) {
leader = leader =
wid_get_prop_window(ps->c, w->client_win, ps->atoms->aWM_CLIENT_LEADER); wid_get_prop_window(&ps->c, w->client_win, ps->atoms->aWM_CLIENT_LEADER);
} }
win_set_leader(ps, w, leader); win_set_leader(ps, w, leader);
@ -1786,8 +1789,9 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int
// Rebuild the cache if needed // Rebuild the cache if needed
if (!w->cache_leader && (w->client_win || w->leader)) { if (!w->cache_leader && (w->client_win || w->leader)) {
// Leader defaults to client window // Leader defaults to client window
if (!(w->cache_leader = w->leader)) if (!(w->cache_leader = w->leader)) {
w->cache_leader = w->client_win; w->cache_leader = w->client_win;
}
// If the leader of this window isn't itself, look for its // If the leader of this window isn't itself, look for its
// ancestors // ancestors
@ -1795,8 +1799,9 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int
auto wp = find_toplevel(ps, w->cache_leader); auto wp = find_toplevel(ps, w->cache_leader);
if (wp) { if (wp) {
// Dead loop? // Dead loop?
if (recursions > WIN_GET_LEADER_MAX_RECURSION) if (recursions > WIN_GET_LEADER_MAX_RECURSION) {
return XCB_NONE; return XCB_NONE;
}
w->cache_leader = win_get_leader_raw(ps, wp, recursions + 1); w->cache_leader = win_get_leader_raw(ps, wp, recursions + 1);
} }
@ -1815,8 +1820,9 @@ bool win_update_class(session_t *ps, struct managed_win *w) {
int nstr = 0; int nstr = 0;
// Can't do anything if there's no client window // Can't do anything if there's no client window
if (!w->client_win) if (!w->client_win) {
return false; return false;
}
// Free and reset old strings // Free and reset old strings
free(w->class_instance); free(w->class_instance);
@ -1956,8 +1962,9 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
*/ */
xcb_shape_get_rectangles_reply_t *r = xcb_shape_get_rectangles_reply( xcb_shape_get_rectangles_reply_t *r = xcb_shape_get_rectangles_reply(
ps->c, ps->c.c,
xcb_shape_get_rectangles(ps->c, w->base.id, XCB_SHAPE_SK_BOUNDING), NULL); xcb_shape_get_rectangles(ps->c.c, w->base.id, XCB_SHAPE_SK_BOUNDING),
NULL);
if (!r) { if (!r) {
break; break;
@ -2030,7 +2037,7 @@ void win_update_opacity_prop(session_t *ps, struct managed_win *w) {
* Retrieve frame extents from a window. * Retrieve frame extents from a window.
*/ */
void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client) { void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client) {
winprop_t prop = x_get_prop(ps->c, client, ps->atoms->a_NET_FRAME_EXTENTS, 4L, winprop_t prop = x_get_prop(&ps->c, client, ps->atoms->a_NET_FRAME_EXTENTS, 4L,
XCB_ATOM_CARDINAL, 32); XCB_ATOM_CARDINAL, 32);
if (prop.nitems == 4) { if (prop.nitems == 4) {
@ -2085,7 +2092,7 @@ bool win_is_region_ignore_valid(session_t *ps, const struct managed_win *w) {
* Stop listening for events on a particular window. * Stop listening for events on a particular window.
*/ */
void win_ev_stop(session_t *ps, const struct win *w) { void win_ev_stop(session_t *ps, const struct win *w) {
xcb_change_window_attributes(ps->c, w->id, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); xcb_change_window_attributes(ps->c.c, w->id, XCB_CW_EVENT_MASK, (const uint32_t[]){0});
if (!w->managed) { if (!w->managed) {
return; return;
@ -2093,12 +2100,12 @@ void win_ev_stop(session_t *ps, const struct win *w) {
auto mw = (struct managed_win *)w; auto mw = (struct managed_win *)w;
if (mw->client_win) { if (mw->client_win) {
xcb_change_window_attributes(ps->c, mw->client_win, XCB_CW_EVENT_MASK, xcb_change_window_attributes(ps->c.c, mw->client_win, XCB_CW_EVENT_MASK,
(const uint32_t[]){0}); (const uint32_t[]){0});
} }
if (ps->shape_exists) { if (ps->shape_exists) {
xcb_shape_select_input(ps->c, w->id, 0); xcb_shape_select_input(ps->c.c, w->id, 0);
} }
} }
@ -2449,10 +2456,10 @@ bool win_skip_fading(session_t *ps, struct managed_win *w) {
// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to // TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to
// the x.c. // the x.c.
void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw) { void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw) {
mw->randr_monitor = -1; mw->randr_monitor = -1;
for (int i = 0; i < nmons; i++) { for (int i = 0; i < monitors->count; i++) {
auto e = pixman_region32_extents(&mons[i]); auto e = pixman_region32_extents(&monitors->regions[i]);
if (e->x1 <= mw->g.x && e->y1 <= mw->g.y && if (e->x1 <= mw->g.x && e->y1 <= mw->g.y &&
e->x2 >= mw->g.x + mw->widthb && e->y2 >= mw->g.y + mw->heightb) { e->x2 >= mw->g.x + mw->widthb && e->y2 >= mw->g.y + mw->heightb) {
mw->randr_monitor = i; mw->randr_monitor = i;
@ -2670,11 +2677,12 @@ struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wi
// We traverse through its ancestors to find out the frame // We traverse through its ancestors to find out the frame
// Using find_win here because if we found a unmanaged window we know // Using find_win here because if we found a unmanaged window we know
// about, we can stop early. // about, we can stop early.
while (wid && wid != ps->root && !(w = find_win(ps, wid))) { while (wid && wid != ps->c.screen_info->root && !(w = find_win(ps, wid))) {
// xcb_query_tree probably fails if you run picom when X is // xcb_query_tree probably fails if you run picom when X is
// somehow initializing (like add it in .xinitrc). In this case // somehow initializing (like add it in .xinitrc). In this case
// just leave it alone. // just leave it alone.
auto reply = xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, wid), NULL); auto reply =
xcb_query_tree_reply(ps->c.c, xcb_query_tree(ps->c.c, wid), NULL);
if (reply == NULL) { if (reply == NULL) {
break; break;
} }
@ -2811,7 +2819,7 @@ bool win_check_flags_all(struct managed_win *w, uint64_t flags) {
*/ */
bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) { bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) {
if (!ps->o.no_ewmh_fullscreen && if (!ps->o.no_ewmh_fullscreen &&
win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win)) { win_is_fullscreen_xcb(ps->c.c, ps->atoms, w->client_win)) {
return true; return true;
} }
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) && return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
@ -2826,7 +2834,7 @@ bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) {
bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *w) { bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *w) {
bool ret = false; bool ret = false;
auto prop = x_get_prop(ps->c, w->client_win, ps->atoms->a_NET_WM_BYPASS_COMPOSITOR, auto prop = x_get_prop(&ps->c, w->client_win, ps->atoms->a_NET_WM_BYPASS_COMPOSITOR,
1L, XCB_ATOM_CARDINAL, 32); 1L, XCB_ATOM_CARDINAL, 32);
if (prop.nitems && *prop.c32 == 1) { if (prop.nitems && *prop.c32 == 1) {
@ -2847,13 +2855,13 @@ bool win_is_focused_raw(const session_t *ps, const struct managed_win *w) {
// Find the managed window immediately below `i` in the window stack // Find the managed window immediately below `i` in the window stack
struct managed_win * struct managed_win *
win_stack_find_next_managed(const session_t *ps, const struct list_node *i) { win_stack_find_next_managed(const session_t *ps, const struct list_node *w) {
while (!list_node_is_last(&ps->window_stack, i)) { while (!list_node_is_last(&ps->window_stack, w)) {
auto next = list_entry(i->next, struct win, stack_neighbour); auto next = list_entry(w->next, struct win, stack_neighbour);
if (next->managed) { if (next->managed) {
return (struct managed_win *)next; return (struct managed_win *)next;
} }
i = &next->stack_neighbour; w = &next->stack_neighbour;
} }
return NULL; return NULL;
} }

View File

@ -341,9 +341,7 @@ void win_recheck_client(session_t *ps, struct managed_win *w);
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w); double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w); bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw);
// the x.h.
void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw);
/** /**
* Retrieve the bounding shape of a window. * Retrieve the bounding shape of a window.

230
src/x.c
View File

@ -4,6 +4,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <pixman.h> #include <pixman.h>
#include <xcb/composite.h> #include <xcb/composite.h>
@ -28,6 +29,72 @@
#include "utils.h" #include "utils.h"
#include "x.h" #include "x.h"
// === Error handling ===
/**
* Xlib error handler function.
*/
static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
if (!ps_g) {
// Do not ignore errors until the session has been initialized
return 0;
}
// Fake a xcb error, fill in just enough information
xcb_generic_error_t xcb_err;
xcb_err.full_sequence = (uint32_t)ev->serial;
xcb_err.major_code = ev->request_code;
xcb_err.minor_code = ev->minor_code;
xcb_err.error_code = ev->error_code;
x_handle_error(&ps_g->c, &xcb_err);
return 0;
}
void x_discard_pending(struct x_connection *c, uint32_t sequence) {
while (c->pending_reply_head && sequence > c->pending_reply_head->sequence) {
auto next = c->pending_reply_head->next;
free(c->pending_reply_head);
c->pending_reply_head = next;
}
if (!c->pending_reply_head) {
c->pending_reply_tail = &c->pending_reply_head;
}
}
void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev) {
x_discard_pending(c, ev->full_sequence);
if (c->pending_reply_head && c->pending_reply_head->sequence == ev->full_sequence) {
if (c->pending_reply_head->action != PENDING_REPLY_ACTION_IGNORE) {
x_log_error(LOG_LEVEL_ERROR, ev->full_sequence, ev->major_code,
ev->minor_code, ev->error_code);
}
switch (c->pending_reply_head->action) {
case PENDING_REPLY_ACTION_ABORT:
log_fatal("An unrecoverable X error occurred, aborting...");
abort();
case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break;
case PENDING_REPLY_ACTION_IGNORE: break;
}
return;
}
x_log_error(LOG_LEVEL_WARN, ev->full_sequence, ev->major_code, ev->minor_code,
ev->error_code);
}
/// Initialize x_connection struct from an Xlib Display.
///
/// Note this function doesn't take ownership of the Display, the caller is still
/// responsible for closing it after `free_x_connection` is called.
void x_connection_init(struct x_connection *c, Display *dpy) {
c->dpy = dpy;
c->c = XGetXCBConnection(dpy);
c->pending_reply_tail = &c->pending_reply_head;
c->previous_xerror_handler = XSetErrorHandler(xerror);
c->screen = DefaultScreen(dpy);
c->screen_info = x_screen_of_display(c, c->screen);
}
/** /**
* Get a specific attribute of a window. * Get a specific attribute of a window.
* *
@ -43,11 +110,11 @@
* @return a <code>winprop_t</code> structure containing the attribute * @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure. * 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, winprop_t x_get_prop_with_offset(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom,
int offset, int length, xcb_atom_t rtype, int rformat) { int offset, int length, xcb_atom_t rtype, int rformat) {
xcb_get_property_reply_t *r = xcb_get_property_reply( xcb_get_property_reply_t *r = xcb_get_property_reply(
c, c->c,
xcb_get_property(c, 0, w, atom, rtype, to_u32_checked(offset), xcb_get_property(c->c, 0, w, atom, rtype, to_u32_checked(offset),
to_u32_checked(length)), to_u32_checked(length)),
NULL); NULL);
@ -71,10 +138,10 @@ winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t
} }
/// Get the type, format and size in bytes of a window's specific attribute. /// 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) { winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom) {
xcb_generic_error_t *e = NULL; xcb_generic_error_t *e = NULL;
auto r = xcb_get_property_reply( auto r = xcb_get_property_reply(
c, xcb_get_property(c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e); c->c, xcb_get_property(c->c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e);
if (!r) { if (!r) {
log_debug_x_error(e, "Failed to get property info for window %#010x", w); log_debug_x_error(e, "Failed to get property info for window %#010x", w);
free(e); free(e);
@ -94,7 +161,7 @@ winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t a
* *
* @return the value if successful, 0 otherwise * @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) { xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop) {
// Get the attribute // Get the attribute
xcb_window_t p = XCB_NONE; xcb_window_t p = XCB_NONE;
winprop_t prop = x_get_prop(c, wid, aprop, 1L, XCB_ATOM_WINDOW, 32); winprop_t prop = x_get_prop(c, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);
@ -115,7 +182,7 @@ xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst, bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
int *pnstr) { int *pnstr) {
assert(ps->server_grabbed); assert(ps->server_grabbed);
auto prop_info = x_get_prop_info(ps->c, wid, prop); auto prop_info = x_get_prop_info(&ps->c, wid, prop);
auto type = prop_info.type; auto type = prop_info.type;
auto format = prop_info.format; auto format = prop_info.format;
auto length = prop_info.length; auto length = prop_info.length;
@ -140,7 +207,7 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
xcb_generic_error_t *e = NULL; xcb_generic_error_t *e = NULL;
auto word_count = (length + 4 - 1) / 4; auto word_count = (length + 4 - 1) / 4;
auto r = xcb_get_property_reply( auto r = xcb_get_property_reply(
ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, word_count), &e); ps->c.c, xcb_get_property(ps->c.c, 0, wid, prop, type, 0, word_count), &e);
if (!r) { if (!r) {
log_debug_x_error(e, "Failed to get window property for %#010x", wid); log_debug_x_error(e, "Failed to get window property for %#010x", wid);
free(e); free(e);
@ -198,14 +265,14 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
// of this program // of this program
static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL; static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL;
static inline void x_get_server_pictfmts(xcb_connection_t *c) { static inline void x_get_server_pictfmts(struct x_connection *c) {
if (g_pictfmts) { if (g_pictfmts) {
return; return;
} }
xcb_generic_error_t *e = NULL; xcb_generic_error_t *e = NULL;
// Get window picture format // Get window picture format
g_pictfmts = g_pictfmts = xcb_render_query_pict_formats_reply(
xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), &e); c->c, xcb_render_query_pict_formats(c->c), &e);
if (e || !g_pictfmts) { if (e || !g_pictfmts) {
log_fatal("failed to get pict formats\n"); log_fatal("failed to get pict formats\n");
abort(); abort();
@ -213,7 +280,7 @@ static inline void x_get_server_pictfmts(xcb_connection_t *c) {
} }
const xcb_render_pictforminfo_t * const xcb_render_pictforminfo_t *
x_get_pictform_for_visual(xcb_connection_t *c, xcb_visualid_t visual) { x_get_pictform_for_visual(struct x_connection *c, xcb_visualid_t visual) {
x_get_server_pictfmts(c); x_get_server_pictfmts(c);
xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual); xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual);
@ -244,7 +311,7 @@ static xcb_visualid_t attr_pure x_get_visual_for_pictfmt(xcb_render_query_pict_f
return XCB_NONE; return XCB_NONE;
} }
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std) {
x_get_server_pictfmts(c); x_get_server_pictfmts(c);
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std); auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
@ -253,7 +320,7 @@ xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_
} }
xcb_render_pictformat_t xcb_render_pictformat_t
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std) {
x_get_server_pictfmts(c); x_get_server_pictfmts(c);
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std); auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
@ -261,8 +328,8 @@ x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
return pictfmt->id; return pictfmt->id;
} }
int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) { int x_get_visual_depth(struct x_connection *c, xcb_visualid_t visual) {
auto setup = xcb_get_setup(c); auto setup = xcb_get_setup(c->c);
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem; for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
xcb_screen_next(&screen)) { xcb_screen_next(&screen)) {
for (auto depth = xcb_screen_allowed_depths_iterator(screen.data); for (auto depth = xcb_screen_allowed_depths_iterator(screen.data);
@ -280,7 +347,7 @@ int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c, x_create_picture_with_pictfmt_and_pixmap(struct x_connection *c,
const xcb_render_pictforminfo_t *pictfmt, const xcb_render_pictforminfo_t *pictfmt,
xcb_pixmap_t pixmap, uint32_t valuemask, xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) { const xcb_render_create_picture_value_list_t *attr) {
@ -294,9 +361,9 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
} }
xcb_render_picture_t tmp_picture = x_new_id(c); xcb_render_picture_t tmp_picture = x_new_id(c);
xcb_generic_error_t *e = xcb_generic_error_t *e = xcb_request_check(
xcb_request_check(c, xcb_render_create_picture_checked( c->c, xcb_render_create_picture_checked(c->c, tmp_picture, pixmap,
c, tmp_picture, pixmap, pictfmt->id, valuemask, buf)); pictfmt->id, valuemask, buf));
free(buf); free(buf);
if (e) { if (e) {
log_error_x_error(e, "failed to create picture"); log_error_x_error(e, "failed to create picture");
@ -307,7 +374,7 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visual, x_create_picture_with_visual_and_pixmap(struct x_connection *c, xcb_visualid_t visual,
xcb_pixmap_t pixmap, uint32_t valuemask, xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) { const xcb_render_create_picture_value_list_t *attr) {
const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual); const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual);
@ -315,7 +382,7 @@ x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visu
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard_t standard, x_create_picture_with_standard_and_pixmap(struct x_connection *c, xcb_pict_standard_t standard,
xcb_pixmap_t pixmap, uint32_t valuemask, xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) { const xcb_render_create_picture_value_list_t *attr) {
x_get_server_pictfmts(c); x_get_server_pictfmts(c);
@ -326,26 +393,26 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h, x_create_picture_with_standard(struct x_connection *c, int w, int h,
xcb_pict_standard_t standard, uint32_t valuemask, xcb_pict_standard_t standard, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) { const xcb_render_create_picture_value_list_t *attr) {
x_get_server_pictfmts(c); x_get_server_pictfmts(c);
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard); auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
assert(pictfmt); assert(pictfmt);
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr); return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr);
} }
/** /**
* Create an picture. * Create an picture.
*/ */
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int h, x_create_picture_with_pictfmt(struct x_connection *c, int w, int h,
const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask, const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) { const xcb_render_create_picture_value_list_t *attr) {
uint8_t depth = pictfmt->depth; uint8_t depth = pictfmt->depth;
xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, w, h); xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, w, h);
if (!tmp_pixmap) { if (!tmp_pixmap) {
return XCB_NONE; return XCB_NONE;
} }
@ -353,23 +420,23 @@ x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int
xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap( xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap(
c, pictfmt, tmp_pixmap, valuemask, attr); c, pictfmt, tmp_pixmap, valuemask, attr);
xcb_free_pixmap(c, tmp_pixmap); set_cant_fail_cookie(c, xcb_free_pixmap(c->c, tmp_pixmap));
return picture; return picture;
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h, x_create_picture_with_visual(struct x_connection *c, int w, int h, xcb_visualid_t visual,
xcb_visualid_t visual, uint32_t valuemask, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) { const xcb_render_create_picture_value_list_t *attr) {
auto pictfmt = x_get_pictform_for_visual(c, visual); auto pictfmt = x_get_pictform_for_visual(c, visual);
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr); return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr);
} }
bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_t *res) { bool x_fetch_region(struct x_connection *c, xcb_xfixes_region_t r, pixman_region32_t *res) {
xcb_generic_error_t *e = NULL; xcb_generic_error_t *e = NULL;
xcb_xfixes_fetch_region_reply_t *xr = xcb_xfixes_fetch_region_reply_t *xr =
xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region(c, r), &e); xcb_xfixes_fetch_region_reply(c->c, xcb_xfixes_fetch_region(c->c, r), &e);
if (!xr) { if (!xr) {
log_error_x_error(e, "Failed to fetch rectangles"); log_error_x_error(e, "Failed to fetch rectangles");
return false; return false;
@ -390,7 +457,7 @@ bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_
return ret; return ret;
} }
uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) { uint32_t x_create_region(struct x_connection *c, const region_t *reg) {
if (!reg) { if (!reg) {
return XCB_NONE; return XCB_NONE;
} }
@ -410,8 +477,8 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) {
} }
xcb_xfixes_region_t ret = x_new_id(c); xcb_xfixes_region_t ret = x_new_id(c);
bool success = bool success = XCB_AWAIT_VOID(xcb_xfixes_create_region, c->c, ret,
XCB_AWAIT_VOID(xcb_xfixes_create_region, c, ret, to_u32_checked(nrects), xrects); to_u32_checked(nrects), xrects);
free(xrects); free(xrects);
if (!success) { if (!success) {
return XCB_NONE; return XCB_NONE;
@ -419,13 +486,13 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) {
return ret; return ret;
} }
void x_destroy_region(xcb_connection_t *c, xcb_xfixes_region_t r) { void x_destroy_region(struct x_connection *c, xcb_xfixes_region_t r) {
if (r != XCB_NONE) { if (r != XCB_NONE) {
xcb_xfixes_destroy_region(c, r); set_debug_cant_fail_cookie(c, xcb_xfixes_destroy_region(c->c, r));
} }
} }
void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict, void x_set_picture_clip_region(struct x_connection *c, xcb_render_picture_t pict,
int16_t clip_x_origin, int16_t clip_y_origin, int16_t clip_x_origin, int16_t clip_y_origin,
const region_t *reg) { const region_t *reg) {
int nrects; int nrects;
@ -440,9 +507,10 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
}; };
} }
xcb_generic_error_t *e = xcb_request_check( xcb_generic_error_t *e =
c, xcb_render_set_picture_clip_rectangles_checked( xcb_request_check(c->c, xcb_render_set_picture_clip_rectangles_checked(
c, pict, clip_x_origin, clip_y_origin, to_u32_checked(nrects), xrects)); c->c, pict, clip_x_origin, clip_y_origin,
to_u32_checked(nrects), xrects));
if (e) { if (e) {
log_error_x_error(e, "Failed to set clip region"); log_error_x_error(e, "Failed to set clip region");
free(e); free(e);
@ -450,17 +518,28 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
free(xrects); free(xrects);
} }
void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) { void x_clear_picture_clip_region(struct x_connection *c, xcb_render_picture_t pict) {
assert(pict != XCB_NONE); assert(pict != XCB_NONE);
xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE}; xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE};
xcb_generic_error_t *e = xcb_request_check( xcb_generic_error_t *e = xcb_request_check(
c, xcb_render_change_picture_checked(c, pict, XCB_RENDER_CP_CLIP_MASK, &v)); c->c, xcb_render_change_picture_checked(c->c, pict, XCB_RENDER_CP_CLIP_MASK, &v));
if (e) { if (e) {
log_error_x_error(e, "failed to clear clip region"); log_error_x_error(e, "failed to clear clip region");
free(e); free(e);
} }
} }
/**
* Destroy a <code>Picture</code>.
*
* Picture must be valid.
*/
void x_free_picture(struct x_connection *c, xcb_render_picture_t p) {
assert(p != XCB_NONE);
auto cookie = xcb_render_free_picture(c->c, p);
set_cant_fail_cookie(c, cookie);
}
enum { enum {
XSyncBadCounter = 0, XSyncBadCounter = 0,
XSyncBadAlarm = 1, XSyncBadAlarm = 1,
@ -593,12 +672,12 @@ const char *x_strerror(xcb_generic_error_t *e) {
/** /**
* Create a pixmap and check that creation succeeded. * 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, xcb_pixmap_t x_create_pixmap(struct x_connection *c, uint8_t depth, int width, int height) {
int width, int height) {
xcb_pixmap_t pix = x_new_id(c); xcb_pixmap_t pix = x_new_id(c);
xcb_void_cookie_t cookie = xcb_create_pixmap_checked( xcb_void_cookie_t cookie =
c, depth, pix, drawable, to_u16_checked(width), to_u16_checked(height)); xcb_create_pixmap_checked(c->c, depth, pix, c->screen_info->root,
xcb_generic_error_t *err = xcb_request_check(c, cookie); to_u16_checked(width), to_u16_checked(height));
xcb_generic_error_t *err = xcb_request_check(c->c, cookie);
if (err == NULL) { if (err == NULL) {
return pix; return pix;
} }
@ -614,12 +693,12 @@ xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t
* Detect whether the pixmap is valid with XGetGeometry. Well, maybe there * Detect whether the pixmap is valid with XGetGeometry. Well, maybe there
* are better ways. * are better ways.
*/ */
bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) { bool x_validate_pixmap(struct x_connection *c, xcb_pixmap_t pixmap) {
if (pixmap == XCB_NONE) { if (pixmap == XCB_NONE) {
return false; return false;
} }
auto r = xcb_get_geometry_reply(c, xcb_get_geometry(c, pixmap), NULL); auto r = xcb_get_geometry_reply(c->c, xcb_get_geometry(c->c, pixmap), NULL);
if (!r) { if (!r) {
return false; return false;
} }
@ -641,14 +720,14 @@ bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) {
/// https://github.com/ImageMagick/ImageMagick/blob/d04a47227637dbb3af9231b0107ccf9677bf985e/MagickCore/xwindow.c#L1853-L1922 /// https://github.com/ImageMagick/ImageMagick/blob/d04a47227637dbb3af9231b0107ccf9677bf985e/MagickCore/xwindow.c#L1853-L1922
/// https://www.fvwm.org/Archive/Manpages/fvwm-root.html /// https://www.fvwm.org/Archive/Manpages/fvwm-root.html
xcb_pixmap_t xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms) {
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms) {
xcb_pixmap_t pixmap = XCB_NONE; xcb_pixmap_t pixmap = XCB_NONE;
xcb_atom_t root_back_pixmap_atoms[] = {atoms->a_XROOTPMAP_ID, atoms->aESETROOT_PMAP_ID}; xcb_atom_t root_back_pixmap_atoms[] = {atoms->a_XROOTPMAP_ID, atoms->aESETROOT_PMAP_ID};
for (size_t i = 0; i < ARR_SIZE(root_back_pixmap_atoms); i++) { for (size_t i = 0; i < ARR_SIZE(root_back_pixmap_atoms); i++) {
winprop_t prop = winprop_t prop =
x_get_prop(c, root, root_back_pixmap_atoms[i], 1, XCB_ATOM_PIXMAP, 32); x_get_prop(c, c->screen_info->root, root_back_pixmap_atoms[i], 1,
XCB_ATOM_PIXMAP, 32);
if (prop.nitems) { if (prop.nitems) {
pixmap = (xcb_pixmap_t)*prop.p32; pixmap = (xcb_pixmap_t)*prop.p32;
free_winprop(&prop); free_winprop(&prop);
@ -669,24 +748,24 @@ bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom) {
* Synchronizes a X Render drawable to ensure all pending painting requests * Synchronizes a X Render drawable to ensure all pending painting requests
* are completed. * are completed.
*/ */
bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) { bool x_fence_sync(struct x_connection *c, xcb_sync_fence_t f) {
// TODO(richardgv): If everybody just follows the rules stated in X Sync // 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 // prototype, we need only one fence per screen, but let's stay a bit
// cautious right now // cautious right now
auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f)); auto e = xcb_request_check(c->c, xcb_sync_trigger_fence_checked(c->c, f));
if (e) { if (e) {
log_error_x_error(e, "Failed to trigger the fence"); log_error_x_error(e, "Failed to trigger the fence");
goto err; goto err;
} }
e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f)); e = xcb_request_check(c->c, xcb_sync_await_fence_checked(c->c, 1, &f));
if (e) { if (e) {
log_error_x_error(e, "Failed to await on a fence"); log_error_x_error(e, "Failed to await on a fence");
goto err; goto err;
} }
e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f)); e = xcb_request_check(c->c, xcb_sync_reset_fence_checked(c->c, f));
if (e) { if (e) {
log_error_x_error(e, "Failed to reset the fence"); log_error_x_error(e, "Failed to reset the fence");
goto err; goto err;
@ -748,7 +827,7 @@ void x_create_convolution_kernel(const conv *kernel, double center,
/// Generate a search criteria for fbconfig from a X visual. /// Generate a search criteria for fbconfig from a X visual.
/// Returns {-1, -1, -1, -1, -1, 0} on failure /// Returns {-1, -1, -1, -1, -1, 0} on failure
struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual) { struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t visual) {
auto pictfmt = x_get_pictform_for_visual(c, visual); auto pictfmt = x_get_pictform_for_visual(c, visual);
auto depth = x_get_visual_depth(c, visual); auto depth = x_get_visual_depth(c, visual);
if (!pictfmt || depth == -1) { if (!pictfmt || depth == -1) {
@ -776,10 +855,10 @@ struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual
}; };
} }
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) { xcb_screen_t *x_screen_of_display(struct x_connection *c, int screen) {
xcb_screen_iterator_t iter; xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator(xcb_get_setup(c)); iter = xcb_setup_roots_iterator(xcb_get_setup(c->c));
for (; iter.rem; --screen, xcb_screen_next(&iter)) { for (; iter.rem; --screen, xcb_screen_next(&iter)) {
if (screen == 0) { if (screen == 0) {
return iter.data; return iter.data;
@ -789,39 +868,34 @@ xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) {
return NULL; return NULL;
} }
void x_update_randr_monitors(session_t *ps) { void x_update_monitors(struct x_connection *c, struct x_monitors *m) {
x_free_randr_info(ps); x_free_monitor_info(m);
if (!ps->o.crop_shadow_to_monitor || !ps->randr_exists) {
return;
}
xcb_randr_get_monitors_reply_t *r = xcb_randr_get_monitors_reply( xcb_randr_get_monitors_reply_t *r = xcb_randr_get_monitors_reply(
ps->c, xcb_randr_get_monitors(ps->c, ps->root, true), NULL); c->c, xcb_randr_get_monitors(c->c, c->screen_info->root, true), NULL);
if (!r) { if (!r) {
return; return;
} }
ps->randr_nmonitors = xcb_randr_get_monitors_monitors_length(r); m->count = xcb_randr_get_monitors_monitors_length(r);
ps->randr_monitor_regs = ccalloc(ps->randr_nmonitors, region_t); m->regions = ccalloc(m->count, region_t);
xcb_randr_monitor_info_iterator_t monitor_info_it = xcb_randr_monitor_info_iterator_t monitor_info_it =
xcb_randr_get_monitors_monitors_iterator(r); xcb_randr_get_monitors_monitors_iterator(r);
for (int i = 0; monitor_info_it.rem; xcb_randr_monitor_info_next(&monitor_info_it)) { for (int i = 0; monitor_info_it.rem; xcb_randr_monitor_info_next(&monitor_info_it)) {
xcb_randr_monitor_info_t *mi = monitor_info_it.data; xcb_randr_monitor_info_t *mi = monitor_info_it.data;
pixman_region32_init_rect(&ps->randr_monitor_regs[i++], mi->x, mi->y, pixman_region32_init_rect(&m->regions[i++], mi->x, mi->y, mi->width, mi->height);
mi->width, mi->height);
} }
free(r); free(r);
} }
void x_free_randr_info(session_t *ps) { void x_free_monitor_info(struct x_monitors *m) {
if (ps->randr_monitor_regs) { if (m->regions) {
for (int i = 0; i < ps->randr_nmonitors; i++) { for (int i = 0; i < m->count; i++) {
pixman_region32_fini(&ps->randr_monitor_regs[i]); pixman_region32_fini(&m->regions[i]);
} }
free(ps->randr_monitor_regs); free(m->regions);
ps->randr_monitor_regs = NULL; m->regions = NULL;
} }
ps->randr_nmonitors = 0; m->count = 0;
} }

200
src/x.h
View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com> // Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
#pragma once #pragma once
#include <X11/Xlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -55,6 +56,42 @@ struct xvisual_info {
xcb_visualid_t visual; xcb_visualid_t visual;
}; };
enum pending_reply_action {
PENDING_REPLY_ACTION_IGNORE,
PENDING_REPLY_ACTION_ABORT,
PENDING_REPLY_ACTION_DEBUG_ABORT,
};
typedef struct pending_reply {
struct pending_reply *next;
unsigned long sequence;
enum pending_reply_action action;
} pending_reply_t;
struct x_connection {
/// XCB connection.
xcb_connection_t *c;
/// Display in use.
Display *dpy;
/// Head pointer of the error ignore linked list.
pending_reply_t *pending_reply_head;
/// Pointer to the <code>next</code> member of tail element of the error
/// ignore linked list.
pending_reply_t **pending_reply_tail;
/// Previous handler of X errors
XErrorHandler previous_xerror_handler;
/// Default screen
int screen;
/// Information about the default screen
xcb_screen_t *screen_info;
};
/// Monitor info
struct x_monitors {
int count;
region_t *regions;
};
#define XCB_AWAIT_VOID(func, c, ...) \ #define XCB_AWAIT_VOID(func, c, ...) \
({ \ ({ \
bool __success = true; \ bool __success = true; \
@ -92,8 +129,8 @@ struct xvisual_info {
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536)) #define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536))
/// Wraps x_new_id. abort the program if x_new_id returns error /// Wraps x_new_id. abort the program if x_new_id returns error
static inline uint32_t x_new_id(xcb_connection_t *c) { static inline uint32_t x_new_id(struct x_connection *c) {
auto ret = xcb_generate_id(c); auto ret = xcb_generate_id(c->c);
if (ret == (uint32_t)-1) { if (ret == (uint32_t)-1) {
log_fatal("We seems to have run of XIDs. This is either a bug in the X " log_fatal("We seems to have run of XIDs. This is either a bug in the X "
"server, or a resource leakage in the compositor. Please open " "server, or a resource leakage in the compositor. Please open "
@ -103,6 +140,73 @@ static inline uint32_t x_new_id(xcb_connection_t *c) {
return ret; return ret;
} }
static void set_reply_action(struct x_connection *c, uint32_t sequence,
enum pending_reply_action action) {
auto i = cmalloc(pending_reply_t);
i->sequence = sequence;
i->next = 0;
i->action = action;
*c->pending_reply_tail = i;
c->pending_reply_tail = &i->next;
}
/**
* Ignore X errors caused by given X request.
*/
static inline void attr_unused set_ignore_cookie(struct x_connection *c,
xcb_void_cookie_t cookie) {
set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_IGNORE);
}
static inline void attr_unused set_cant_fail_cookie(struct x_connection *c,
xcb_void_cookie_t cookie) {
set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_ABORT);
}
static inline void attr_unused set_debug_cant_fail_cookie(struct x_connection *c,
xcb_void_cookie_t cookie) {
#ifndef NDEBUG
set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_DEBUG_ABORT);
#else
(void)c;
(void)cookie;
#endif
}
static inline void attr_unused free_x_connection(struct x_connection *c) {
pending_reply_t *next = NULL;
for (auto ign = c->pending_reply_head; ign; ign = next) {
next = ign->next;
free(ign);
}
// Reset head and tail
c->pending_reply_head = NULL;
c->pending_reply_tail = &c->pending_reply_head;
XSetErrorHandler(c->previous_xerror_handler);
}
/// Initialize x_connection struct from an Xlib Display.
///
/// Note this function doesn't take ownership of the Display, the caller is still
/// responsible for closing it after `free_x_connection` is called.
void x_connection_init(struct x_connection *c, Display *dpy);
/// Discard queued pending replies.
///
/// We have received reply with sequence number `sequence`, which means all pending
/// replies with sequence number less than `sequence` will never be received. So discard
/// them.
void x_discard_pending(struct x_connection *c, uint32_t sequence);
/// Handle X errors.
///
/// This function logs X errors, or aborts the program based on severity of the error.
void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev);
/** /**
* Send a request to X server and get the reply to make sure all previous * Send a request to X server and get the reply to make sure all previous
* requests are processed, and their replies received * requests are processed, and their replies received
@ -110,8 +214,8 @@ static inline uint32_t x_new_id(xcb_connection_t *c) {
* xcb_get_input_focus is used here because it is the same request used by * xcb_get_input_focus is used here because it is the same request used by
* libX11 * libX11
*/ */
static inline void x_sync(xcb_connection_t *c) { static inline void x_sync(struct x_connection *c) {
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL)); free(xcb_get_input_focus_reply(c->c, xcb_get_input_focus(c->c), NULL));
} }
/** /**
@ -129,25 +233,26 @@ static inline void x_sync(xcb_connection_t *c) {
* @return a <code>winprop_t</code> structure containing the attribute * @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure. * 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, winprop_t x_get_prop_with_offset(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom,
int offset, int length, xcb_atom_t rtype, int rformat); int offset, int length, xcb_atom_t rtype, int rformat);
/** /**
* Wrapper of wid_get_prop_adv(). * Wrapper of wid_get_prop_adv().
*/ */
static inline winprop_t x_get_prop(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t atom, static inline winprop_t
int length, xcb_atom_t rtype, int rformat) { x_get_prop(const struct x_connection *c, xcb_window_t wid, xcb_atom_t atom, int length,
xcb_atom_t rtype, int rformat) {
return x_get_prop_with_offset(c, wid, atom, 0L, length, rtype, rformat); return x_get_prop_with_offset(c, wid, atom, 0L, length, rtype, rformat);
} }
/// Get the type, format and size in bytes of a window's specific attribute. /// 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); winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom);
/// Discard all X events in queue or in flight. Should only be used when the server is /// Discard all X events in queue or in flight. Should only be used when the server is
/// grabbed /// grabbed
static inline void x_discard_events(xcb_connection_t *c) { static inline void x_discard_events(struct x_connection *c) {
xcb_generic_event_t *e; xcb_generic_event_t *e;
while ((e = xcb_poll_for_event(c))) { while ((e = xcb_poll_for_event(c->c))) {
free(e); free(e);
} }
} }
@ -157,7 +262,7 @@ static inline void x_discard_events(xcb_connection_t *c) {
* *
* @return the value if successful, 0 otherwise * @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); xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop);
/** /**
* Get the value of a text property of a window. * Get the value of a text property of a window.
@ -170,30 +275,30 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
int *pnstr); int *pnstr);
const xcb_render_pictforminfo_t * const xcb_render_pictforminfo_t *
x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t); x_get_pictform_for_visual(struct x_connection *, xcb_visualid_t);
int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t); int x_get_visual_depth(struct x_connection *, xcb_visualid_t);
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *, x_create_picture_with_pictfmt_and_pixmap(struct x_connection *,
const xcb_render_pictforminfo_t *pictfmt, const xcb_render_pictforminfo_t *pictfmt,
xcb_pixmap_t pixmap, uint32_t valuemask, xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1, 2); attr_nonnull(1, 2);
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_visual_and_pixmap(xcb_connection_t *, xcb_visualid_t visual, x_create_picture_with_visual_and_pixmap(struct x_connection *, xcb_visualid_t visual,
xcb_pixmap_t pixmap, uint32_t valuemask, xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1); attr_nonnull(1);
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_t standard, x_create_picture_with_standard_and_pixmap(struct x_connection *, xcb_pict_standard_t standard,
xcb_pixmap_t pixmap, uint32_t valuemask, xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1); attr_nonnull(1);
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h, x_create_picture_with_standard(struct x_connection *c, int w, int h,
xcb_pict_standard_t standard, uint32_t valuemask, xcb_pict_standard_t standard, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1); attr_nonnull(1);
@ -202,30 +307,37 @@ x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int
* Create an picture. * Create an picture.
*/ */
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int w, int h, x_create_picture_with_pictfmt(struct x_connection *, int w, int h,
const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask, const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1, 5); attr_nonnull(1, 4);
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h, x_create_picture_with_visual(struct x_connection *, int w, int h, xcb_visualid_t visual,
xcb_visualid_t visual, uint32_t valuemask, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1); attr_nonnull(1);
/// Fetch a X region and store it in a pixman region /// Fetch a X region and store it in a pixman region
bool x_fetch_region(xcb_connection_t *, xcb_xfixes_region_t r, region_t *res); bool x_fetch_region(struct x_connection *, xcb_xfixes_region_t r, region_t *res);
/// Create a X region from a pixman region /// Create a X region from a pixman region
uint32_t x_create_region(xcb_connection_t *c, const region_t *reg); uint32_t x_create_region(struct x_connection *c, const region_t *reg);
/// Destroy a X region /// Destroy a X region
void x_destroy_region(xcb_connection_t *c, uint32_t region); void x_destroy_region(struct x_connection *c, uint32_t region);
void x_set_picture_clip_region(xcb_connection_t *, xcb_render_picture_t, int16_t clip_x_origin, void x_set_picture_clip_region(struct x_connection *, xcb_render_picture_t,
int16_t clip_y_origin, const region_t *); int16_t clip_x_origin, int16_t clip_y_origin, const region_t *);
void x_clear_picture_clip_region(xcb_connection_t *, xcb_render_picture_t pict); void x_clear_picture_clip_region(struct x_connection *, xcb_render_picture_t pict);
/**
* Destroy a <code>Picture</code>.
*
* Picture must be valid.
*/
void x_free_picture(struct x_connection *c, xcb_render_picture_t p);
/** /**
* Log a X11 error * Log a X11 error
@ -242,10 +354,9 @@ void x_log_error(enum log_level level, unsigned long serial, uint8_t major,
*/ */
const char *x_strerror(xcb_generic_error_t *e); const char *x_strerror(xcb_generic_error_t *e);
xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable, xcb_pixmap_t x_create_pixmap(struct x_connection *, uint8_t depth, int width, int height);
int width, int height);
bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap); bool x_validate_pixmap(struct x_connection *, xcb_pixmap_t pxmap);
/** /**
* Free a <code>winprop_t</code>. * Free a <code>winprop_t</code>.
@ -254,22 +365,22 @@ bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap);
*/ */
static inline void free_winprop(winprop_t *pprop) { static inline void free_winprop(winprop_t *pprop) {
// Empty the whole structure to avoid possible issues // Empty the whole structure to avoid possible issues
if (pprop->r) if (pprop->r) {
free(pprop->r); free(pprop->r);
}
pprop->ptr = NULL; pprop->ptr = NULL;
pprop->r = NULL; pprop->r = NULL;
pprop->nitems = 0; pprop->nitems = 0;
} }
/// Get the back pixmap of the root window /// Get the back pixmap of the root window
xcb_pixmap_t xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms);
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms);
/// Return true if the atom refers to a property name that is used for the /// Return true if the atom refers to a property name that is used for the
/// root window background pixmap /// root window background pixmap
bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom); bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom);
bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t); bool x_fence_sync(struct x_connection *, xcb_sync_fence_t);
struct x_convolution_kernel { struct x_convolution_kernel {
int size; int size;
@ -293,23 +404,18 @@ void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double c
/// Generate a search criteria for fbconfig from a X visual. /// Generate a search criteria for fbconfig from a X visual.
/// Returns {-1, -1, -1, -1, -1, -1} on failure /// Returns {-1, -1, -1, -1, -1, -1} on failure
struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual); struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t visual);
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std);
xcb_render_pictformat_t xcb_render_pictformat_t
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std);
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen); xcb_screen_t *x_screen_of_display(struct x_connection *c, int screen);
/** /// Populates a `struct x_monitors` with the current monitor configuration.
* X RandR-related functions. void x_update_monitors(struct x_connection *, struct x_monitors *);
* /// Free memory allocated for a `struct x_monitors`.
* The x_update_randr_monitors function populates ps->randr_nmonitors and void x_free_monitor_info(struct x_monitors *);
* ps->randr_monitor_regs with the data X RandR provided and the
* x_free_randr_info function frees them.
*/
void x_update_randr_monitors(session_t *ps);
void x_free_randr_info(session_t *ps);
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c); uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);