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);
}
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 "
"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->o.xrender_sync_fence = 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 &&
w->randr_monitor < ps->randr_nmonitors) {
w->randr_monitor < ps->monitors.count) {
// There can be a window where number of monitors is
// updated, but the monitor number attached to the window
// have not.
@ -358,7 +358,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
// bounds.
pixman_region32_intersect(
&reg_shadow, &reg_shadow,
&ps->randr_monitor_regs[w->randr_monitor]);
&ps->monitors.regions[w->randr_monitor]);
}
if (ps->o.transparent_clipping) {

View File

@ -23,8 +23,7 @@ struct backend_operations;
typedef struct backend_base {
struct backend_operations *ops;
xcb_connection_t *c;
xcb_window_t root;
struct x_connection *c;
struct ev_loop *loop;
/// 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.
*/
xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool argb,
double a, double r, double g, double b) {
xcb_render_picture_t
solid_picture(struct x_connection *c, bool argb, double a, double r, double g, double b) {
xcb_pixmap_t pixmap;
xcb_render_picture_t picture;
xcb_render_create_picture_value_list_t pa;
xcb_render_color_t col;
xcb_rectangle_t rect;
pixmap = x_create_pixmap(c, argb ? 32 : 8, d, 1, 1);
if (!pixmap)
pixmap = x_create_pixmap(c, argb ? 32 : 8, 1, 1);
if (!pixmap) {
return XCB_NONE;
}
pa.repeat = 1;
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);
if (!picture) {
xcb_free_pixmap(c, pixmap);
xcb_free_pixmap(c->c, pixmap);
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.height = 1;
xcb_render_fill_rectangles(c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect);
xcb_free_pixmap(c, pixmap);
xcb_render_fill_rectangles(c->c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect);
xcb_free_pixmap(c->c, pixmap);
return picture;
}
xcb_image_t *
make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height) {
xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity,
int width, int height) {
/*
* We classify shadows into 4 kinds of regions
* 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 > 0);
ximage = xcb_image_create_native(c, to_u16_checked(swidth), to_u16_checked(sheight),
XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL);
ximage =
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) {
log_error("failed to create an X image");
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.
*/
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,
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict) {
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;
}
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 =
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) {
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);
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
// 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 =
to_u16_checked(clamp(maximum_image_size / shadow_image->stride, 0, UINT16_MAX));
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);
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),
0, shadow_image->depth, shadow_image->stride * batch_height,
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_image->height);
*pixmap = shadow_pixmap_argb;
*pict = shadow_picture_argb;
xcb_free_gc(c, gc);
xcb_free_gc(c->c, gc);
xcb_image_destroy(shadow_image);
xcb_free_pixmap(c, shadow_pixmap);
xcb_render_free_picture(c, shadow_picture);
xcb_free_pixmap(c->c, shadow_pixmap);
x_free_picture(c, shadow_picture);
return true;
@ -273,19 +275,19 @@ shadow_picture_err:
xcb_image_destroy(shadow_image);
}
if (shadow_pixmap) {
xcb_free_pixmap(c, shadow_pixmap);
xcb_free_pixmap(c->c, shadow_pixmap);
}
if (shadow_pixmap_argb) {
xcb_free_pixmap(c, shadow_pixmap_argb);
xcb_free_pixmap(c->c, shadow_pixmap_argb);
}
if (shadow_picture) {
xcb_render_free_picture(c, shadow_picture);
x_free_picture(c, shadow_picture);
}
if (shadow_picture_argb) {
xcb_render_free_picture(c, shadow_picture_argb);
x_free_picture(c, shadow_picture_argb);
}
if (gc) {
xcb_free_gc(c, gc);
xcb_free_gc(c->c, gc);
}
return false;
@ -294,22 +296,22 @@ shadow_picture_err:
void *default_backend_render_shadow(backend_t *backend_data, int width, int height,
struct backend_shadow_context *sctx, struct color color) {
const conv *kernel = (void *)sctx;
xcb_render_picture_t shadow_pixel = solid_picture(
backend_data->c, backend_data->root, true, 1, color.red, color.green, color.blue);
xcb_render_picture_t shadow_pixel =
solid_picture(backend_data->c, true, 1, color.red, color.green, color.blue);
xcb_pixmap_t shadow = XCB_NONE;
xcb_render_picture_t pict = XCB_NONE;
if (!build_shadow(backend_data->c, backend_data->root, color.alpha, width, height,
kernel, shadow_pixel, &shadow, &pict)) {
xcb_render_free_picture(backend_data->c, shadow_pixel);
if (!build_shadow(backend_data->c, color.alpha, width, height, kernel,
shadow_pixel, &shadow, &pict)) {
x_free_picture(backend_data->c, shadow_pixel);
return NULL;
}
auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32);
void *ret = backend_data->ops->bind_pixmap(
backend_data, shadow, x_get_visual_info(backend_data->c, visual), true);
xcb_render_free_picture(backend_data->c, pict);
xcb_render_free_picture(backend_data->c, shadow_pixel);
x_free_picture(backend_data->c, pict);
x_free_picture(backend_data->c, shadow_pixel);
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) {
base->c = ps->c;
base->c = &ps->c;
base->loop = ps->loop;
base->root = ps->root;
base->busy = false;
base->ops = NULL;
}

View File

@ -44,15 +44,15 @@ struct backend_image {
int border_width;
};
bool build_shadow(xcb_connection_t *, xcb_drawable_t, double opacity, int width,
int height, const conv *kernel, xcb_render_picture_t shadow_pixel,
bool build_shadow(struct x_connection *, double opacity, int width, int height,
const conv *kernel, xcb_render_picture_t shadow_pixel,
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict);
xcb_render_picture_t solid_picture(xcb_connection_t *, xcb_drawable_t, bool argb,
double a, double r, double g, double b);
xcb_render_picture_t
solid_picture(struct x_connection *, bool argb, double a, double r, double g, double b);
xcb_image_t *
make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height);
xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity,
int width, int height);
/// 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

View File

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

View File

@ -79,7 +79,7 @@ static void egl_release_image(backend_t *base, struct gl_texture *tex) {
}
if (p->owned) {
xcb_free_pixmap(base->c, p->pixmap);
xcb_free_pixmap(base->c->c, p->pixmap);
p->pixmap = XCB_NONE;
}
@ -154,10 +154,10 @@ static backend_t *egl_init(session_t *ps) {
}
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[]){
EGL_PLATFORM_X11_SCREEN_EXT,
ps->scr,
ps->c.screen,
EGL_NONE,
});
if (gd->display == EGL_NO_DISPLAY) {
@ -190,7 +190,7 @@ static backend_t *egl_init(session_t *ps) {
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;
int nconfigs = 1;
// 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_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) {
log_error("Invalid pixmap %#010x", pixmap);
return NULL;
@ -335,7 +336,7 @@ err:
free(eglpixmap);
if (owned) {
xcb_free_pixmap(base->c, pixmap);
xcb_free_pixmap(base->c->c, pixmap);
}
free(wd);
return NULL;

View File

@ -42,8 +42,6 @@ struct _glx_pixmap {
struct _glx_data {
struct gl_data gl;
Display *display;
int screen;
xcb_window_t target_win;
GLXContext ctx;
};
@ -52,18 +50,18 @@ struct _glx_data {
do { \
if (glXGetFBConfigAttrib(a, b, attr, c)) { \
log_info("Cannot get FBConfig attribute " #attr); \
continue; \
break; \
} \
} 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,
m.blue_size, m.green_size, m.alpha_size, m.visual_depth);
int ncfg;
// clang-format off
GLXFBConfig *cfg =
glXChooseFBConfig(dpy, screen, (int[]){
glXChooseFBConfig(c->dpy, c->screen, (int[]){
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
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;
for (int i = 0; i < ncfg; i++) {
int depthbuf, stencil, doublebuf, bufsize;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BUFFER_SIZE, &bufsize);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_DEPTH_SIZE, &depthbuf);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_STENCIL_SIZE, &stencil);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_DOUBLEBUFFER, &doublebuf);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BUFFER_SIZE, &bufsize);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_DEPTH_SIZE, &depthbuf);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_STENCIL_SIZE, &stencil);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_DOUBLEBUFFER, &doublebuf);
if (depthbuf + stencil + bufsize * (doublebuf + 1) >= min_cost) {
continue;
}
int red, green, blue;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_RED_SIZE, &red);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BLUE_SIZE, &blue);
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_GREEN_SIZE, &green);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_RED_SIZE, &red);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BLUE_SIZE, &blue);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_GREEN_SIZE, &green);
if (red != m.red_size || green != m.green_size || blue != m.blue_size) {
// Color size doesn't match, this cannot work
continue;
}
int rgb, rgba;
glXGetFBConfigAttribChecked(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_RGB_EXT, &rgb);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGBA_EXT,
&rgba);
if (!rgb && !rgba) {
log_info("FBConfig is neither RGBA nor RGB, we cannot "
"handle this setup.");
@ -113,10 +112,9 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
}
int visual;
glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_VISUAL_ID, &visual);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_VISUAL_ID, &visual);
if (m.visual_depth != -1 &&
x_get_visual_depth(XGetXCBConnection(dpy), (xcb_visualid_t)visual) !=
m.visual_depth) {
x_get_visual_depth(c, (xcb_visualid_t)visual) != m.visual_depth) {
// FBConfig and the correspondent X Visual might not have the same
// depth. (e.g. 32 bit FBConfig with a 24 bit Visual). This is
// 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.
found = true;
ret = cfg[i];
glXGetFBConfigAttribChecked(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_BIND_TO_TEXTURE_TARGETS_EXT, &texture_tgts);
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_Y_INVERTED_EXT, &y_inverted);
// Prefer the texture format with matching alpha, with the other one as
// fallback
@ -161,24 +159,22 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi
* Free a glx_texture_t.
*/
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;
// Release binding
if (p->glpixmap && 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);
}
// Free GLX Pixmap
if (p->glpixmap) {
glXDestroyPixmap(gd->display, p->glpixmap);
glXDestroyPixmap(base->c->dpy, p->glpixmap);
p->glpixmap = 0;
}
if (p->owned) {
xcb_free_pixmap(base->c, p->pixmap);
xcb_free_pixmap(base->c->c, p->pixmap);
p->pixmap = XCB_NONE;
}
@ -196,8 +192,8 @@ void glx_deinit(backend_t *base) {
// Destroy GLX context
if (gd->ctx) {
glXMakeCurrent(gd->display, None, NULL);
glXDestroyContext(gd->display, gd->ctx);
glXMakeCurrent(base->c->dpy, None, NULL);
glXDestroyContext(base->c->dpy, gd->ctx);
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) {
bool success = false;
glxext_init(ps->dpy, ps->scr);
glxext_init(ps->c.dpy, ps->c.screen);
auto gd = ccalloc(1, struct _glx_data);
init_backend_base(&gd->gl.base, ps);
gd->display = ps->dpy;
gd->screen = ps->scr;
gd->target_win = session_get_target_window(ps);
XVisualInfo *pvis = NULL;
@ -251,8 +245,8 @@ static backend_t *glx_init(session_t *ps) {
// Get XVisualInfo
int nitems = 0;
XVisualInfo vreq = {.visualid = ps->vis};
pvis = XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems);
XVisualInfo vreq = {.visualid = ps->c.screen_info->root_visual};
pvis = XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
if (!pvis) {
log_error("Failed to acquire XVisualInfo for current visual.");
goto end;
@ -260,22 +254,22 @@ static backend_t *glx_init(session_t *ps) {
// Ensure the visual is double-buffered
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.");
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.");
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.");
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");
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
// be sure that the fbconfig is compatible with our target window.
int ncfgs;
GLXFBConfig *cfg = glXGetFBConfigs(gd->display, gd->screen, &ncfgs);
GLXFBConfig *cfg = glXGetFBConfigs(ps->c.dpy, ps->c.screen, &ncfgs);
bool found = false;
for (int i = 0; i < ncfgs; i++) {
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) {
continue;
}
@ -316,7 +310,7 @@ static backend_t *glx_init(session_t *ps) {
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);
if (!gd->ctx) {
@ -334,7 +328,7 @@ static backend_t *glx_init(session_t *ps) {
// Attach GLX context
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.");
goto end;
}
@ -348,11 +342,11 @@ static backend_t *glx_init(session_t *ps) {
gd->gl.release_user_data = glx_release_image;
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.");
}
} else {
glx_set_swap_interval(0, ps->dpy, tgt);
glx_set_swap_interval(0, ps->c.dpy, tgt);
}
success = true;
@ -372,7 +366,6 @@ end:
static void *
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;
// Retrieve pixmap parameters, if they aren't provided
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;
}
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) {
log_error("Invalid pixmap %#010x", pixmap);
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;
free(r);
auto fbcfg = glx_find_fbconfig(gd->display, gd->screen, fmt);
auto fbcfg = glx_find_fbconfig(base->c, fmt);
if (!fbcfg) {
log_error("Couldn't find FBConfig with requested visual %x", fmt.visual);
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->pixmap = pixmap;
glxpixmap->glpixmap = glXCreatePixmap(gd->display, fbcfg->cfg, pixmap, attrs);
glxpixmap->glpixmap = glXCreatePixmap(base->c->dpy, fbcfg->cfg, pixmap, attrs);
glxpixmap->owned = owned;
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;
wd->inner->refcount = 1;
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);
gl_check_err();
return wd;
err:
if (glxpixmap && glxpixmap->glpixmap) {
glXDestroyPixmap(gd->display, glxpixmap->glpixmap);
glXDestroyPixmap(base->c->dpy, glxpixmap->glpixmap);
}
free(glxpixmap);
if (owned) {
xcb_free_pixmap(base->c, pixmap);
xcb_free_pixmap(base->c->c, pixmap);
}
free(wd);
return NULL;
@ -467,7 +461,7 @@ err:
static void glx_present(backend_t *base, const region_t *region attr_unused) {
struct _glx_data *gd = (void *)base;
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) {
@ -477,15 +471,14 @@ static int glx_buffer_age(backend_t *base) {
struct _glx_data *gd = (void *)base;
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;
}
static void glx_diagnostics(backend_t *base) {
struct _glx_data *gd = (void *)base;
bool warn_software_rendering = false;
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(" * GLX: %s\n", glx_vendor);
printf(" * GL: %s\n", glGetString(GL_VENDOR));

View File

@ -41,8 +41,7 @@ struct glx_fbconfig_criteria {
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 {
bool initialized;

View File

@ -28,7 +28,6 @@ typedef struct _xrender_data {
backend_t base;
/// If vsync is enabled and supported by the current system
bool vsync;
xcb_visualid_t default_visual;
/// Target window
xcb_window_t target_win;
/// 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
/// rendered in it.
struct xrender_rounded_rectangle_cache *
make_rounded_corner_cache(xcb_connection_t *c, xcb_render_picture_t src,
xcb_drawable_t root, int width, int height, int corner_radius) {
auto picture = x_create_picture_with_standard(c, root, width, height,
make_rounded_corner_cache(struct x_connection *c, xcb_render_picture_t src, int width,
int height, int corner_radius) {
auto picture = x_create_picture_with_standard(c, width, height,
XCB_PICT_STANDARD_ARGB_32, 0, NULL);
if (picture == XCB_NONE) {
return NULL;
@ -160,7 +159,7 @@ make_rounded_corner_cache(xcb_connection_t *c, xcb_render_picture_t src,
}
#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,
(uint32_t)point_count, points);
free(points);
@ -182,30 +181,29 @@ static xcb_render_picture_t process_mask(struct _xrender_data *xd, struct xrende
*allocated = true;
x_clear_picture_clip_region(xd->base.c, inner->pict);
auto ret = x_create_picture_with_visual(
xd->base.c, xd->base.root, inner->width, inner->height, inner->visual,
XCB_RENDER_CP_REPEAT,
xd->base.c, inner->width, inner->height, inner->visual, XCB_RENDER_CP_REPEAT,
(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);
// Remember: the mask has a 1-pixel border
if (mask->base.corner_radius != 0) {
if (mask->rounded_rectangle == NULL) {
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);
}
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,
0, 1, 1, (uint16_t)(tmpw - 2), (uint16_t)(tmph - 2));
}
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);
}
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),
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);
x_set_picture_clip_region(xd->base.c, result, 0, 0, &reg);
if (img->corner_radius != 0 && xrimg->rounded_rectangle == NULL) {
xrimg->rounded_rectangle = make_rounded_corner_cache(
xd->base.c, xd->white_pixel, xd->base.root, inner->width,
inner->height, (int)img->corner_radius);
xrimg->rounded_rectangle =
make_rounded_corner_cache(xd->base.c, xd->white_pixel, inner->width,
inner->height, (int)img->corner_radius);
}
if (((img->color_inverted || img->dim != 0) && has_alpha) || img->corner_radius != 0) {
// Apply image properties using a temporary image, because the source
// image is transparent. Otherwise the properties can be applied directly
// on the target image.
auto tmp_pict =
x_create_picture_with_visual(xd->base.c, xd->base.root, inner->width,
inner->height, inner->visual, 0, NULL);
auto tmp_pict = x_create_picture_with_visual(
xd->base.c, inner->width, inner->height, inner->visual, 0, NULL);
// Set clip region translated to source coordinate
x_set_picture_clip_region(xd->base.c, tmp_pict, to_i16_checked(-dst.x),
to_i16_checked(-dst.y), &reg);
// 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);
if (img->color_inverted) {
if (inner->has_alpha) {
auto tmp_pict2 = x_create_picture_with_visual(
xd->base.c, xd->base.root, tmpw, tmph, inner->visual,
0, NULL);
xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC,
xd->base.c, tmpw, tmph, inner->visual, 0, NULL);
xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC,
tmp_pict, XCB_NONE, tmp_pict2, 0, 0,
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,
0, 0, 0, 0, 0, 0, tmpw, tmph);
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_render_free_picture(xd->base.c, tmp_pict2);
x_free_picture(xd->base.c, tmp_pict2);
} 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,
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,
};
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);
}
if (img->corner_radius != 0 && xrimg->rounded_rectangle != NULL) {
// 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,
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,
to_i16_checked(dst.x), to_i16_checked(dst.y), tmpew,
tmpeh);
xcb_render_free_picture(xd->base.c, tmp_pict);
xcb_render_free_picture(xd->base.c->c, tmp_pict);
} else {
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,
mask_dst_x, mask_dst_y, to_i16_checked(dst.x),
xcb_render_composite(xd->base.c->c, op, inner->pict, mask_pict, result, 0,
0, mask_dst_x, mask_dst_y, to_i16_checked(dst.x),
to_i16_checked(dst.y), tmpew, tmpeh);
if (img->dim != 0 || img->color_inverted) {
// Apply properties, if we reach here, then has_alpha == false
assert(!has_alpha);
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,
0, 0, 0, to_i16_checked(dst.x),
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,
};
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);
}
}
}
if (mask_allocated) {
xcb_render_free_picture(xd->base.c, mask_pict);
x_free_picture(xd->base.c, mask_pict);
}
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);
// color is in X fixed point representation
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),
.green = (uint16_t)(c.green * 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;
xcb_connection_t *c = xd->base.c;
auto c = xd->base.c;
region_t reg_op;
pixman_region32_init(&reg_op);
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 xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_PAD};
xcb_render_picture_t tmp_picture[2] = {
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized,
xd->default_visual, pic_attrs_mask, &pic_attrs),
x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized,
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),
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]) {
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
// be applied on source picture, to get the nearby pixels outside the
// window.
xcb_render_set_picture_filter(c, src_pict, to_u16_checked(strlen(filter)),
filter,
xcb_render_set_picture_filter(c->c, src_pict,
to_u16_checked(strlen(filter)), filter,
to_u32_checked(bctx->x_blur_kernel[i]->size),
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
// (we do this even if this is also the last pass, because we
// 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),
to_i16_checked(extent_resized->y1), 0, 0, 0,
0, width_resized, height_resized);
} else if (i < bctx->x_blur_kernel_count - 1) {
// This is not the last pass or the first pass,
// 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,
width_resized, height_resized);
} else {
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
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),
to_i16_checked(extent_resized->y1 - mask_dst.y + 1),
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
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];
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) {
x_set_picture_clip_region(c, xd->back[2], 0, 0, &reg_op);
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->y1 - mask_dst.y + 1),
to_i16_checked(extent_resized->x1),
to_i16_checked(extent_resized->y1), width_resized, height_resized);
}
xcb_render_free_picture(c, tmp_picture[0]);
xcb_render_free_picture(c, tmp_picture[1]);
x_free_picture(c, tmp_picture[0]);
x_free_picture(c, tmp_picture[1]);
pixman_region32_fini(&reg_op);
pixman_region32_fini(&reg_op_resized);
return true;
@ -505,7 +507,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask
static void *
bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
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) {
log_error("Invalid pixmap: %#010x", pixmap);
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;
}
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) {
xcb_free_pixmap(base->c, inner->pixmap);
xcb_free_pixmap(base->c->c, inner->pixmap);
}
free(inner);
}
@ -556,7 +558,7 @@ release_rounded_corner_cache(backend_t *base, struct xrender_rounded_rectangle_c
assert(cache->refcount > 0);
cache->refcount--;
if (cache->refcount == 0) {
xcb_render_free_picture(base->c, cache->p);
x_free_picture(base->c, cache->p);
free(cache);
}
}
@ -575,22 +577,22 @@ static void release_image(backend_t *base, void *image) {
static void deinit(backend_t *backend_data) {
struct _xrender_data *xd = (void *)backend_data;
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++) {
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) {
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) {
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);
xcb_render_free_picture(xd->base.c, xd->black_pixel);
x_free_picture(xd->base.c, xd->white_pixel);
x_free_picture(xd->base.c, xd->black_pixel);
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]);
// 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,
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,
// to avoid deadlock
auto e = xcb_request_check(
base->c, xcb_present_pixmap_checked(
xd->base.c, xd->target_win,
xd->back_pixmap[xd->curr_back], 0, XCB_NONE, xregion, 0,
0, XCB_NONE, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, NULL));
base->c->c, xcb_present_pixmap_checked(
xd->base.c->c, xd->target_win,
xd->back_pixmap[xd->curr_back], 0, XCB_NONE, xregion, 0,
0, XCB_NONE, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, NULL));
x_destroy_region(base->c, xregion);
if (e) {
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
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) {
// We don't know what happened, maybe X died
// 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);
} else {
// 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,
orig_y, region_width, region_height);
}
@ -673,7 +675,7 @@ static int buffer_age(backend_t *backend_data) {
static struct _xrender_image_data_inner *
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);
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) {
log_error("Failed to create pixmap for copy");
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);
if (new_inner->pict == XCB_NONE) {
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);
return NULL;
}
@ -705,12 +707,12 @@ static void *make_mask(backend_t *base, geometry_t size, const region_t *reg) {
auto inner =
new_inner(base, size.width + 2, size.height + 2,
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});
const rect_t *extent = pixman_region32_extents((region_t *)reg);
x_set_picture_clip_region(base->c, xd->back[2], 1, 1, reg);
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_rectangle_t[]){{.x = to_i16_checked(extent->x1 + 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
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_rectangle_t[]){{.x = 0, .y = 0, .width = w16, .height = 1},
{.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);
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),
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 alpha_pict = xd->alpha_pict[(int)((1 - dargs[0]) * MAX_ALPHA)];
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_NONE, inner->pict, 0, 0, 0, 0, 0, 0,
xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_OUT_REVERSE,
alpha_pict, XCB_NONE, inner->pict, 0, 0, 0, 0, 0, 0,
to_u16_checked(inner->width),
to_u16_checked(inner->height));
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) {
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);
}
xd->target_width = ps->root_width;
xd->target_height = ps->root_height;
xd->default_visual = ps->vis;
xd->black_pixel = solid_picture(ps->c, ps->root, true, 1, 0, 0, 0);
xd->white_pixel = solid_picture(ps->c, ps->root, true, 1, 1, 1, 1);
xd->black_pixel = solid_picture(&ps->c, true, 1, 0, 0, 0);
xd->white_pixel = solid_picture(&ps->c, true, 1, 1, 1, 1);
xd->target_win = session_get_target_window(ps);
xcb_render_create_picture_value_list_t pa = {
.subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS,
};
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) {
log_fatal("Default visual is invalid");
abort();
@ -902,11 +904,11 @@ static backend_t *backend_xrender_init(session_t *ps) {
xd->vsync = ps->o.vsync;
if (ps->present_exists) {
auto eid = x_new_id(ps->c);
auto eid = x_new_id(&ps->c);
auto e =
xcb_request_check(ps->c, xcb_present_select_input_checked(
ps->c, eid, xd->target_win,
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
xcb_request_check(ps->c.c, xcb_present_select_input_checked(
ps->c.c, eid, xd->target_win,
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
if (e) {
log_error("Cannot select present input, vsync will be disabled");
xd->vsync = false;
@ -914,7 +916,7 @@ static backend_t *backend_xrender_init(session_t *ps) {
}
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) {
log_error("Cannot register for special XGE, vsync will be "
"disabled");
@ -928,14 +930,14 @@ static backend_t *backend_xrender_init(session_t *ps) {
// double buffering.
int first_buffer_index = xd->vsync ? 0 : 2;
for (int i = first_buffer_index; i < 3; i++) {
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root,
to_u16_checked(ps->root_width),
to_u16_checked(ps->root_height));
xd->back_pixmap[i] =
x_create_pixmap(&ps->c, pictfmt->depth, to_u16_checked(ps->root_width),
to_u16_checked(ps->root_height));
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};
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;
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
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.
*/
c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data) {
if (!pattern)
if (!pattern) {
return NULL;
}
// Parse the pattern
c2_ptr_t result = C2_PTR_INIT;
int offset = -1;
if (strlen(pattern) >= 2 && ':' == pattern[1])
if (strlen(pattern) >= 2 && ':' == pattern[1]) {
offset = c2_parse_legacy(pattern, 0, &result);
else
} else {
offset = c2_parse_grp(pattern, 0, &result, 0);
}
if (offset < 0) {
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) {
// Check for recursion levels
if (level > C2_MAX_LEVELS)
if (level > C2_MAX_LEVELS) {
c2_error("Exceeded maximum recursion levels.");
}
if (!pattern)
if (!pattern) {
return -1;
}
// Expected end character
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);
// Jump over spaces
if (isspace((unsigned char)pattern[offset]))
if (isspace((unsigned char)pattern[offset])) {
continue;
}
// Handle end of group
if (')' == pattern[offset])
if (')' == pattern[offset]) {
break;
}
// Handle "!"
if ('!' == pattern[offset]) {
if (!next_expected)
if (!next_expected) {
c2_error("Unexpected \"!\".");
}
neg = !neg;
continue;
@ -446,8 +453,9 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
// Handle AND and OR
if ('&' == pattern[offset] || '|' == pattern[offset]) {
if (next_expected)
if (next_expected) {
c2_error("Unexpected logical operator.");
}
next_expected = true;
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)) {
ops[elei] = C2_B_OOR;
++offset;
} else
} else {
c2_error("Illegal logical operator.");
}
continue;
}
// Parsing an element
if (!next_expected)
if (!next_expected) {
c2_error("Unexpected expression.");
}
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 '('
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;
}
}
// Otherwise it's a leaf
else {
if ((offset = c2_parse_target(pattern, offset, pele)) < 0)
if ((offset = c2_parse_target(pattern, offset, pele)) < 0) {
goto fail;
}
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;
}
if ((offset = c2_parse_pattern(pattern, offset, pele)) < 0)
if ((offset = c2_parse_pattern(pattern, offset, pele)) < 0) {
goto fail;
}
}
// Decrement offset -- we will increment it in loop update
--offset;
@ -513,10 +527,11 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
// Apply negation
if (neg) {
neg = false;
if (pele->isbranch)
if (pele->isbranch) {
pele->b->neg = !pele->b->neg;
else
} else {
pele->l->neg = !pele->l->neg;
}
}
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?
if (pattern[offset] && !endchar)
if (pattern[offset] && !endchar) {
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);
}
// Handle end of group
if (!elei) {
@ -544,8 +561,9 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int
*presult = eles[0];
if (')' == pattern[offset])
if (')' == pattern[offset]) {
++offset;
}
return offset;
@ -778,11 +796,11 @@ static int c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult) {
// Parse operator
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;
else if ('=' == pattern[offset] && C2_L_OLT == pleaf->op)
} else if ('=' == pattern[offset] && C2_L_OLT == pleaf->op) {
pleaf->op = C2_L_OLTEQ;
else if (pleaf->op) {
} else if (pleaf->op) {
c2_error("Duplicate operator.");
} else {
switch (pattern[offset]) {
@ -797,9 +815,10 @@ static int c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult) {
}
// 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 "
"qualifier.");
}
return offset;
@ -891,9 +910,10 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult)
char *pstr = NULL;
long val = strtol(
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 "
"sequence.");
}
*(ptptnstr++) = to_char_checked(val);
offset += 2;
break;
@ -904,8 +924,9 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult)
*(ptptnstr++) = pattern[offset];
}
}
if (!pattern[offset])
if (!pattern[offset]) {
c2_error("Premature end of pattern string.");
}
++offset;
*ptptnstr = '\0';
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();
if (!pleaf->ptntype)
if (!pleaf->ptntype) {
c2_error("Invalid pattern type.");
}
// Check if the type is correct
if (!(((C2_L_TSTRING == pleaf->type || C2_L_TATOM == pleaf->type) &&
C2_L_PTSTRING == pleaf->ptntype) ||
((C2_L_TCARDINAL == pleaf->type || C2_L_TWINDOW == 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.");
}
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.");
}
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.");
}
if (C2_L_PTSTRING == pleaf->ptntype &&
(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.");
}
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) {
if (pleaf->predef != C2_L_PUNDEFINED) {
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;
if (pleaf->index < 0) {
// 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);
}
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);
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;
if (pleaf->index < 0) {
// 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);
}
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);
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);
if (atom) {
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) {
targets[i] = targets_free_inner[i] = strndup(
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) {
const c2_b_t *pb = cond.b;
if (!pb)
if (!pb) {
return false;
}
error = false;
@ -1630,8 +1656,9 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
else {
const c2_l_t *pleaf = cond.l;
if (!pleaf)
if (!pleaf) {
return false;
}
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
if (error)
if (error) {
result = false;
}
if (cond.isbranch ? cond.b->neg : cond.l->neg)
if (cond.isbranch ? cond.b->neg : cond.l->neg) {
result = !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
for (; condlst; condlst = condlst->next) {
if (c2_match_once(ps, w, condlst->ptr)) {
if (pdata)
if (pdata) {
*pdata = condlst->data;
}
return true;
}
}

View File

@ -84,18 +84,6 @@ struct glx_session;
struct atom;
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 DEBUG_GLX_DEBUG_CONTEXT
typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config,
@ -183,28 +171,14 @@ typedef struct session {
struct shader_info *shaders;
// === Display related ===
/// X connection
struct x_connection c;
/// Whether the X server is grabbed by us
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.
int root_width;
// Damage of root window.
// Damage root_damage;
/// Height of root window.
int root_height;
/// X Composite overlay window.
xcb_window_t overlay;
/// The target window for debug mode
@ -289,11 +263,6 @@ typedef struct session {
xcb_render_picture_t *alpha_picts;
/// Time of last fading. In milliseconds.
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.
struct x_convolution_kernel **blur_kerns_cache;
/// If we should quit
@ -391,10 +360,8 @@ typedef struct session {
int glx_event;
/// Error base number for X GLX extension.
int glx_error;
/// Number of X RandR monitors.
int randr_nmonitors;
/// X RandR monitor regions.
region_t *randr_monitor_regs;
/// Information about monitors.
struct x_monitors monitors;
/// Whether X Sync extension exists.
bool xsync_exists;
/// Event base number for X Sync extension.
@ -492,7 +459,7 @@ static inline struct timespec get_time_timespec(void) {
* Return the painting target window.
*/
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;
}
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.
*
@ -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) {
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) {
return false;
}

View File

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

View File

@ -57,7 +57,7 @@ static inline const char *ev_window_name(session_t *ps, xcb_window_t wid) {
char *name = "";
if (wid) {
name = "(Failed to get title)";
if (ps->root == wid) {
if (ps->c.screen_info->root == wid) {
name = "(Root window)";
} else if (ps->overlay == wid) {
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) {
if (ev->parent == ps->root) {
if (ev->parent == ps->c.screen_info->root) {
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
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
@ -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) {
log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }",
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);
} else {
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.
if (ps->overlay && ev->window == ps->overlay && !ps->redirected) {
log_debug("Overlay is mapped while we are not redirected");
auto e =
xcb_request_check(ps->c, xcb_unmap_window_checked(ps->c, ps->overlay));
auto e = xcb_request_check(
ps->c.c, xcb_unmap_window_checked(ps->c.c, ps->overlay));
if (e) {
log_error("Failed to unmap the overlay window");
free(e);
@ -323,7 +323,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
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
// change (i.e. reparent again to current parent). So we check if that's
// 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
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)});
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.",
ev->window);
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) |
XCB_EVENT_MASK_PROPERTY_CHANGE});
} 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);
ps->pending_updates = true;
} else {
if (!w_real_top)
if (!w_real_top) {
log_debug("parent %#010x not found", ev->parent);
else {
} else {
// Window is not currently mapped, unmark its
// client to trigger a client recheck when it is
// 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) {
auto w = find_win(ps, ev->window);
if (!w)
if (!w) {
return;
}
if (ev->place == PlaceOnTop) {
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) {
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;
if (ps->n_expose == ps->size_expose) {
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) {
if (unlikely(log_get_level_tls() <= LOG_LEVEL_TRACE)) {
// Print out changed atom
xcb_get_atom_name_reply_t *reply =
xcb_get_atom_name_reply(ps->c, xcb_get_atom_name(ps->c, ev->atom), NULL);
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
ps->c.c, xcb_get_atom_name(ps->c.c, ev->atom), NULL);
const char *name = "?";
int name_len = 1;
if (reply) {
@ -452,7 +454,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
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) {
// to update focus
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
if (!find_toplevel(ps, ev->window)) {
// 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(
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) {
win_extents(w, &parts);
set_ignore_cookie(
ps, xcb_damage_subtract(ps->c, w->damage, XCB_NONE, XCB_NONE));
if (!ps->o.show_all_xerrors) {
set_ignore_cookie(&ps->c, xcb_damage_subtract(ps->c.c, w->damage,
XCB_NONE, XCB_NONE));
}
} else {
set_ignore_cookie(
ps, xcb_damage_subtract(ps->c, w->damage, XCB_NONE, ps->damaged_region));
x_fetch_region(ps->c, ps->damaged_region, &parts);
if (!ps->o.show_all_xerrors) {
set_ignore_cookie(&ps->c, xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
ps->damaged_region));
}
x_fetch_region(&ps->c, ps->damaged_region, &parts);
pixman_region32_translate(&parts, w->g.x + 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) {
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);
@ -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://lists.freedesktop.org/archives/xcb/2011-November/007337.html
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) {
XESetWireToEvent(ps->dpy, response_type, proc);
XESetWireToEvent(ps->c.dpy, response_type, proc);
XEvent dummy;
// 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
uint16_t seq = ev->sequence;
ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->dpy) & 0xffff);
proc(ps->dpy, &dummy, (xEvent *)ev);
ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->c.dpy) & 0xffff);
proc(ps->c.dpy, &dummy, (xEvent *)ev);
// Restore the sequence number
ev->sequence = seq;
}
@ -736,7 +742,7 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
case SelectionClear:
ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev);
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:
if (ps->shape_exists && ev->response_type == ps->shape_event) {
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};
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
pvis = get_visualinfo_from_visual(ps, ps->vis);
pvis = get_visualinfo_from_visual(ps, ps->c.screen_info->root_visual);
if (!pvis) {
log_error("Failed to acquire XVisualInfo for current visual.");
goto glx_init_end;
@ -65,12 +65,13 @@ bool glx_init(session_t *ps, bool need_render) {
// Ensure the visual is double-buffered
if (need_render) {
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.");
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.");
goto glx_init_end;
}
@ -112,7 +113,7 @@ bool glx_init(session_t *ps, bool need_render) {
if (!psglx->context) {
// Get GLX 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
{
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[] = {
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None};
psglx->context = p_glXCreateContextAttribsARB(
ps->dpy, fbconfig, NULL, GL_TRUE, attrib_list);
ps->c.dpy, fbconfig, NULL, GL_TRUE, attrib_list);
}
#endif
@ -144,7 +145,7 @@ bool glx_init(session_t *ps, bool need_render) {
}
// 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.");
goto glx_init_end;
}
@ -201,7 +202,7 @@ bool glx_init(session_t *ps, bool need_render) {
// Clear screen
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 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;
@ -266,8 +267,8 @@ void glx_destroy(session_t *ps) {
// Destroy GLX context
if (ps->psglx->context) {
glXMakeCurrent(ps->dpy, None, NULL);
glXDestroyContext(ps->dpy, ps->psglx->context);
glXMakeCurrent(ps->c.dpy, None, NULL);
glXDestroyContext(ps->c.dpy, ps->psglx->context);
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
if (!width || !height) {
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) {
log_error("Failed to query info of pixmap %#010x.", pixmap);
return false;
@ -773,7 +774,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
0,
};
ptex->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, pixmap, attrs);
ptex->glpixmap = glXCreatePixmap(ps->c.dpy, fbcfg->cfg, pixmap, attrs);
ptex->pixmap = pixmap;
ptex->target =
(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...
// We can't follow this, too slow.
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
glBindTexture(ptex->target, 0);
@ -840,13 +841,13 @@ void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
// Release binding
if (ptex->glpixmap && 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);
}
// Free GLX Pixmap
if (ptex->glpixmap) {
glXDestroyPixmap(ps->dpy, ptex->glpixmap);
glXDestroyPixmap(ps->c.dpy, ptex->glpixmap);
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) {
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) {
log_fatal("Failed to query DPMS status.");
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
*/
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;
}
@ -352,8 +352,9 @@ void add_damage(session_t *ps, const region_t *damage) {
*/
static double fade_timeout(session_t *ps) {
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;
}
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;
}
// === 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 ===
/**
@ -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) {
// Search for the window
xcb_window_t wid =
wid_get_prop_window(ps->c, ps->root, ps->atoms->a_NET_ACTIVE_WINDOW);
xcb_window_t wid = wid_get_prop_window(&ps->c, ps->c.screen_info->root,
ps->atoms->a_NET_ACTIVE_WINDOW);
auto w = find_win_all(ps, wid);
// 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
xcb_window_t wid = XCB_NONE;
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) {
wid = reply->focus;
@ -719,7 +679,7 @@ err:
/// Handle configure event of the root window
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) {
log_fatal("Failed to fetch root geometry");
abort();
@ -795,8 +755,8 @@ static void configure_root(session_t *ps) {
static void handle_root_flags(session_t *ps) {
if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) {
if (ps->o.crop_shadow_to_monitor) {
x_update_randr_monitors(ps);
if (ps->o.crop_shadow_to_monitor && ps->randr_exists) {
x_update_monitors(&ps->c, &ps->monitors);
}
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->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) {
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) {
ps->backend_data->ops->set_image_property(
ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE,
@ -1114,27 +1075,6 @@ void root_damaged(session_t *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.
*/
@ -1169,10 +1109,11 @@ void opts_set_no_fading_openclose(session_t *ps, bool newval) {
static int register_cm(session_t *ps) {
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(
ps->c, xcb_create_window_checked(ps->c, XCB_COPY_FROM_PARENT, ps->reg_win, ps->root,
0, 0, 1, 1, 0, XCB_NONE, ps->vis, 0, NULL));
ps->c.c, xcb_create_window_checked(ps->c.c, XCB_COPY_FROM_PARENT, ps->reg_win,
ps->c.screen_info->root, 0, 0, 1, 1, 0, XCB_NONE,
ps->c.screen_info->root_visual, 0, NULL));
if (e) {
log_fatal("Failed to create window.");
@ -1191,10 +1132,10 @@ static int register_cm(session_t *ps) {
// Set names and classes
for (size_t i = 0; i < ARR_SIZE(prop_atoms); i++) {
e = xcb_request_check(
ps->c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i],
prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING,
8, strlen("picom"), "picom"));
ps->c.c, xcb_change_property_checked(
ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i],
prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING,
8, strlen("picom"), "picom"));
if (e) {
log_error_x_error(e, "Failed to set window property %d",
prop_atoms[i]);
@ -1204,9 +1145,9 @@ static int register_cm(session_t *ps) {
const char picom_class[] = "picom\0picom";
e = xcb_request_check(
ps->c, xcb_change_property_checked(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8,
ARR_SIZE(picom_class), picom_class));
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,
ARR_SIZE(picom_class), picom_class));
if (e) {
log_error_x_error(e, "Failed to set the WM_CLASS property");
free(e);
@ -1220,10 +1161,10 @@ static int register_cm(session_t *ps) {
if (gethostname(hostname, hostname_max) == 0) {
e = xcb_request_check(
ps->c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING, 8,
(uint32_t)strlen(hostname), hostname));
ps->c.c, xcb_change_property_checked(
ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win,
ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING,
8, (uint32_t)strlen(hostname), hostname));
if (e) {
log_error_x_error(e, "Failed to set the WM_CLIENT_MACHINE"
" property");
@ -1239,16 +1180,16 @@ static int register_cm(session_t *ps) {
// Set _NET_WM_PID
{
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);
}
// Set COMPTON_VERSION
e = xcb_request_check(
ps->c, xcb_change_property_checked(
ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win,
get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8,
(uint32_t)strlen(PICOM_VERSION), PICOM_VERSION));
ps->c.c, xcb_change_property_checked(
ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win,
get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8,
(uint32_t)strlen(PICOM_VERSION), PICOM_VERSION));
if (e) {
log_error_x_error(e, "Failed to set COMPTON_VERSION.");
free(e);
@ -1260,7 +1201,7 @@ static int register_cm(session_t *ps) {
xcb_atom_t atom;
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");
return -1;
}
@ -1268,7 +1209,7 @@ static int register_cm(session_t *ps) {
free(buf);
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) {
// Another compositor already running
@ -1276,7 +1217,7 @@ static int register_cm(session_t *ps) {
return 1;
}
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;
@ -1306,9 +1247,8 @@ static inline bool write_pid(session_t *ps) {
* Initialize X composite overlay window.
*/
static bool init_overlay(session_t *ps) {
xcb_composite_get_overlay_window_reply_t *reply =
xcb_composite_get_overlay_window_reply(
ps->c, xcb_composite_get_overlay_window(ps->c, ps->root), NULL);
xcb_composite_get_overlay_window_reply_t *reply = xcb_composite_get_overlay_window_reply(
ps->c.c, xcb_composite_get_overlay_window(ps->c.c, ps->c.screen_info->root), NULL);
if (reply) {
ps->overlay = reply->overlay_win;
free(reply);
@ -1318,13 +1258,13 @@ static bool init_overlay(session_t *ps) {
if (ps->overlay != XCB_NONE) {
// Set window region of the overlay window, code stolen from
// 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)) {
log_fatal("Failed to set the bounding shape of overlay, giving "
"up.");
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,
ps->overlay, 0, 0, 0, NULL)) {
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
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});
// 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);
// 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 {
log_error("Cannot get X Composite overlay window. Falling "
"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) {
xcb_colormap_t colormap = x_new_id(ps->c);
ps->debug_window = x_new_id(ps->c);
xcb_colormap_t colormap = x_new_id(&ps->c);
ps->debug_window = x_new_id(&ps->c);
auto err = xcb_request_check(
ps->c, xcb_create_colormap_checked(ps->c, XCB_COLORMAP_ALLOC_NONE, colormap,
ps->root, ps->vis));
ps->c.c, xcb_create_colormap_checked(ps->c.c, XCB_COLORMAP_ALLOC_NONE,
colormap, ps->c.screen_info->root,
ps->c.screen_info->root_visual));
if (err) {
goto err_out;
}
err = xcb_request_check(
ps->c, xcb_create_window_checked(ps->c, (uint8_t)ps->depth, ps->debug_window,
ps->root, 0, 0, to_u16_checked(ps->root_width),
to_u16_checked(ps->root_height), 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->vis,
XCB_CW_COLORMAP, (uint32_t[]){colormap, 0}));
ps->c.c, xcb_create_window_checked(
ps->c.c, (uint8_t)ps->c.screen_info->root_depth,
ps->debug_window, ps->c.screen_info->root, 0, 0,
to_u16_checked(ps->root_width), to_u16_checked(ps->root_height),
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->c.screen_info->root_visual,
XCB_CW_COLORMAP, (uint32_t[]){colormap, 0}));
if (err) {
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) {
goto err_out;
}
@ -1386,7 +1328,7 @@ xcb_window_t session_get_target_window(session_t *ps) {
if (ps->o.debug_mode) {
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) {
@ -1416,18 +1358,18 @@ static bool redirect_start(session_t *ps) {
// Map overlay window. Done firstly according to this:
// https://bugzilla.gnome.org/show_bug.cgi?id=597014
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,
session_redirection_mode(ps));
bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c.c,
ps->c.screen_info->root, session_redirection_mode(ps));
if (!success) {
log_fatal("Another composite manager is already running "
"(and does not handle _NET_WM_CM_Sn correctly)");
return false;
}
x_sync(ps->c);
x_sync(&ps->c);
if (!initialize_backend(ps)) {
return false;
@ -1456,16 +1398,16 @@ static bool redirect_start(session_t *ps) {
}
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(
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);
auto notify_msc =
xcb_present_notify_msc(ps->c, session_get_target_window(ps), 0, 0, 1, 0);
set_cant_fail_cookie(ps, select_input);
set_cant_fail_cookie(ps, notify_msc);
auto notify_msc = xcb_present_notify_msc(
ps->c.c, session_get_target_window(ps), 0, 0, 1, 0);
set_cant_fail_cookie(&ps->c, select_input);
set_cant_fail_cookie(&ps->c, notify_msc);
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
// states.
@ -1480,13 +1422,13 @@ static bool redirect_start(session_t *ps) {
}
// Must call XSync() here
x_sync(ps->c);
x_sync(&ps->c);
ps->redirected = true;
ps->first_frame = true;
// 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);
root_damaged(ps);
@ -1506,10 +1448,11 @@ static void unredirect(session_t *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
if (ps->overlay != XCB_NONE) {
xcb_unmap_window(ps->c, ps->overlay);
xcb_unmap_window(ps->c.c, ps->overlay);
}
// Free the damage ring
@ -1521,15 +1464,15 @@ static void unredirect(session_t *ps) {
ps->damage_ring = ps->damage = NULL;
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);
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;
}
// Must call XSync() here
x_sync(ps->c);
x_sync(&ps->c);
ps->redirected = false;
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;
event_is_invalid = true;
}
auto cookie = xcb_present_notify_msc(ps->c, session_get_target_window(ps),
0, next_msc, 0, 0);
set_cant_fail_cookie(ps, cookie);
auto cookie = xcb_present_notify_msc(
ps->c.c, session_get_target_window(ps), 0, next_msc, 0, 0);
set_cant_fail_cookie(&ps->c, cookie);
}
if (event_is_invalid) {
return;
@ -1602,7 +1545,7 @@ static void handle_present_events(session_t *ps) {
return;
}
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) {
// This event doesn't have the right event context, it's not meant
// 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);
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);
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.
// Use XFlush here too, we might still use some Xlib functions
// because OpenGL.
XFlush(ps->dpy);
xcb_flush(ps->c);
int err = xcb_connection_has_error(ps->c);
XFlush(ps->c.dpy);
xcb_flush(ps->c.c);
int err = xcb_connection_has_error(ps->c.c);
if (err) {
log_fatal("X11 server connection broke (error %d)", err);
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) {
if (ps->pending_updates) {
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) {
log_fatal_x_error(e, "failed to grab x server");
free(e);
@ -1718,7 +1661,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
{
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)) {
recheck_focus(ps);
}
@ -1728,7 +1671,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
// Process window flags (stale images)
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) {
log_fatal_x_error(e, "failed to ungrab x server");
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) {
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) {
ev_handle(ps, 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) {
static const session_t s_def = {
.backend_data = NULL,
.dpy = NULL,
.scr = 0,
.c = NULL,
.vis = 0,
.depth = 0,
.root = XCB_NONE,
.root_height = 0,
.root_width = 0,
// .root_damage = XCB_NONE,
@ -1987,8 +1924,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
.redirected = false,
.alpha_picts = NULL,
.fade_time = 0L,
.pending_reply_head = NULL,
.pending_reply_tail = NULL,
.quit = false,
.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
render_statistics_init(&ps->render_stats, 128);
ps->pending_reply_tail = &ps->pending_reply_head;
ps->o.show_all_xerrors = all_xerrors;
// Use the same Display across reset, primarily for resource leak checking
ps->dpy = dpy;
ps->c = XGetXCBConnection(ps->dpy);
x_connection_init(&ps->c, 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;
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
// root geometry changes
auto e = xcb_request_check(
ps->c, xcb_change_window_attributes_checked(
ps->c, ps->root, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_PROPERTY_CHANGE}));
ps->c.c, xcb_change_window_attributes_checked(
ps->c.c, ps->c.screen_info->root, XCB_CW_EVENT_MASK,
(const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_PROPERTY_CHANGE}));
if (e) {
log_error_x_error(e, "Failed to setup root window event mask");
free(e);
}
xcb_prefetch_extension_data(ps->c, &xcb_render_id);
xcb_prefetch_extension_data(ps->c, &xcb_composite_id);
xcb_prefetch_extension_data(ps->c, &xcb_damage_id);
xcb_prefetch_extension_data(ps->c, &xcb_shape_id);
xcb_prefetch_extension_data(ps->c, &xcb_xfixes_id);
xcb_prefetch_extension_data(ps->c, &xcb_randr_id);
xcb_prefetch_extension_data(ps->c, &xcb_present_id);
xcb_prefetch_extension_data(ps->c, &xcb_sync_id);
xcb_prefetch_extension_data(ps->c, &xcb_glx_id);
xcb_prefetch_extension_data(ps->c, &xcb_dpms_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_render_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_composite_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_damage_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_shape_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_xfixes_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_randr_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_present_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_sync_id);
xcb_prefetch_extension_data(ps->c.c, &xcb_glx_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) {
log_fatal("No render extension");
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_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) {
log_fatal("No composite extension");
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(
ps->c,
xcb_composite_query_version(ps->c, XCB_COMPOSITE_MAJOR_VERSION,
ps->c.c,
xcb_composite_query_version(ps->c.c, XCB_COMPOSITE_MAJOR_VERSION,
XCB_COMPOSITE_MINOR_VERSION),
NULL);
@ -2133,45 +2058,45 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
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) {
log_fatal("No damage extension");
exit(1);
}
ps->damage_event = ext_info->first_event;
ps->damage_error = ext_info->first_error;
xcb_discard_reply(ps->c, xcb_damage_query_version(ps->c, XCB_DAMAGE_MAJOR_VERSION,
XCB_DAMAGE_MINOR_VERSION)
.sequence);
xcb_discard_reply(ps->c.c, xcb_damage_query_version(ps->c.c, XCB_DAMAGE_MAJOR_VERSION,
XCB_DAMAGE_MINOR_VERSION)
.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) {
log_fatal("No XFixes extension");
exit(1);
}
ps->xfixes_event = ext_info->first_event;
ps->xfixes_error = ext_info->first_error;
xcb_discard_reply(ps->c, xcb_xfixes_query_version(ps->c, XCB_XFIXES_MAJOR_VERSION,
XCB_XFIXES_MINOR_VERSION)
.sequence);
xcb_discard_reply(ps->c.c, xcb_xfixes_query_version(ps->c.c, XCB_XFIXES_MAJOR_VERSION,
XCB_XFIXES_MINOR_VERSION)
.sequence);
ps->damaged_region = x_new_id(ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c, ps->damaged_region, 0, NULL)) {
ps->damaged_region = x_new_id(&ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->damaged_region, 0, NULL)) {
log_fatal("Failed to create a XFixes region");
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) {
ps->glx_exists = true;
ps->glx_error = ext_info->first_error;
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;
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) {
log_fatal("Failed to query DPMS info");
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.");
}
ps->atoms = init_atoms(ps->c);
ps->atoms = init_atoms(ps->c.c);
ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0;
#define SET_WM_TYPE_ATOM(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);
// 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) {
ps->shape_event = ext_info->first_event;
ps->shape_error = ext_info->first_error;
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) {
ps->randr_exists = true;
ps->randr_event = ext_info->first_event;
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) {
auto r = xcb_present_query_version_reply(
ps->c,
xcb_present_query_version(ps->c, XCB_PRESENT_MAJOR_VERSION,
ps->c.c,
xcb_present_query_version(ps->c.c, XCB_PRESENT_MAJOR_VERSION,
XCB_PRESENT_MINOR_VERSION),
NULL);
if (r) {
@ -2315,14 +2240,14 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
}
// 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) {
ps->xsync_error = ext_info->first_error;
ps->xsync_event = ext_info->first_event;
// Need X Sync 3.1 for fences
auto r = xcb_sync_initialize_reply(
ps->c,
xcb_sync_initialize(ps->c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION),
ps->c.c,
xcb_sync_initialize(ps->c.c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION),
NULL);
if (r && (r->major_version > 3 ||
(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;
if (ps->xsync_exists) {
ps->sync_fence = x_new_id(ps->c);
e = xcb_request_check(ps->c, xcb_sync_create_fence_checked(
ps->c, ps->root, ps->sync_fence, 0));
ps->sync_fence = x_new_id(&ps->c);
e = xcb_request_check(
ps->c.c, xcb_sync_create_fence_checked(
ps->c.c, ps->c.screen_info->root, ps->sync_fence, 0));
if (e) {
if (ps->o.xrender_sync_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);
// 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
// an auto-detected refresh rate, or when X RandR features are enabled
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 = {
.subwindowmode = IncludeInferiors,
};
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) {
ps->tgt_picture = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, ps->overlay, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
} else
&ps->c, ps->c.screen_info->root_visual, ps->overlay,
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
} else {
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_init(&ps->unredir_timer, tmout_unredir_callback);
ev_init(&ps->draw_timer, draw_callback);
@ -2509,7 +2438,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// functions
if (ps->o.dbus) {
#ifdef CONFIG_DBUS
cdbus_init(ps, DisplayString(ps->dpy));
cdbus_init(ps, DisplayString(ps->c.dpy));
if (!ps->dbus_data) {
ps->o.dbus = false;
}
@ -2519,7 +2448,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
#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) {
log_fatal_x_error(e, "Failed to grab X server");
free(e);
@ -2532,12 +2461,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// earlier is irrelavant at this point.
// 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.
x_discard_events(ps->c);
x_discard_events(&ps->c);
xcb_query_tree_reply_t *query_tree_reply =
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, ps->root), NULL);
xcb_query_tree_reply_t *query_tree_reply = xcb_query_tree_reply(
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) {
log_fatal_x_error(e, "Failed to ungrab server");
free(e);
@ -2630,7 +2559,7 @@ static void session_destroy(session_t *ps) {
ps->file_watch_handle = NULL;
// 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});
#ifdef CONFIG_DBUS
@ -2681,32 +2610,17 @@ static void session_destroy(session_t *ps) {
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
if (ps->tgt_buffer.pict == ps->tgt_picture) {
ps->tgt_buffer.pict = XCB_NONE;
}
if (ps->tgt_picture == ps->root_picture) {
ps->tgt_picture = XCB_NONE;
} else {
free_picture(ps->c, &ps->tgt_picture);
if (ps->tgt_picture != ps->root_picture) {
x_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);
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.glx_fshader_win_str);
x_free_randr_info(ps);
x_free_monitor_info(&ps->monitors);
render_statistics_destroy(&ps->render_stats);
@ -2744,28 +2658,28 @@ static void session_destroy(session_t *ps) {
// Release overlay window
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;
}
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;
}
// Free reg_win
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;
}
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;
}
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;
}
@ -2784,7 +2698,7 @@ static void session_destroy(session_t *ps) {
#endif
// Flush all events
x_sync(ps->c);
x_sync(&ps->c);
ev_io_stop(ps->loop, &ps->xiow);
if (ps->o.legacy_backends) {
free_conv((conv *)ps->shadow_context);
@ -2796,8 +2710,6 @@ static void session_destroy(session_t *ps) {
xrc_report_xid();
#endif
XSetErrorHandler(ps->previous_xerror_handler);
// Stop libev event handlers
ev_timer_stop(ps->loop, &ps->unredir_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_signal_stop(ps->loop, &ps->usr1_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
// We can probably waitpid() here.
return 1;
} else {
// We are done
return 0;
}
// We are done
return 0;
}
// We are the child
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.
*/
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) {
log_trace("Drawable %#010x: Failed", drawable);
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) {
#ifdef CONFIG_OPENGL
// XXX This is a mess. But this will go away after the backend refactor.
if (!ppaint->pixmap)
if (!ppaint->pixmap) {
return false;
}
struct glx_fbconfig_info *fbcfg;
if (!visual) {
assert(depth == 32);
if (!ps->argb_fbconfig) {
ps->argb_fbconfig =
glx_find_fbconfig(ps->dpy, ps->scr,
(struct xvisual_info){.red_size = 8,
.green_size = 8,
.blue_size = 8,
.alpha_size = 8,
.visual_depth = 32});
ps->argb_fbconfig = glx_find_fbconfig(
&ps->c, (struct xvisual_info){.red_size = 8,
.green_size = 8,
.blue_size = 8,
.alpha_size = 8,
.visual_depth = 32});
}
if (!ps->argb_fbconfig) {
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;
} else {
auto m = x_get_visual_info(ps->c, visual);
auto m = x_get_visual_info(&ps->c, visual);
if (m.visual_depth < 0) {
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) {
ppaint->fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, m);
ppaint->fbcfg = glx_find_fbconfig(&ps->c, m);
}
if (!ppaint->fbcfg) {
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;
}
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,
repeat, fbcfg);
}
#else
(void)ps;
(void)ppaint;
@ -129,7 +130,7 @@ static int get_buffer_age(session_t *ps) {
}
if (ps->o.use_damage) {
unsigned int val;
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
glXQueryDrawable(ps->c.dpy, get_tgt_window(ps),
GLX_BACK_BUFFER_AGE_EXT, &val);
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) {
#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
}
@ -153,7 +154,7 @@ static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg)
switch (ps->o.backend) {
case BKEND_XRENDER:
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;
#ifdef CONFIG_OPENGL
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.
*/
@ -179,10 +170,14 @@ void free_paint(session_t *ps, paint_t *ppaint) {
#ifdef CONFIG_OPENGL
free_paint_glx(ps, ppaint);
#endif
free_picture(ps->c, &ppaint->pict);
if (ppaint->pixmap)
xcb_free_pixmap(ps->c, ppaint->pixmap);
ppaint->pixmap = XCB_NONE;
if (ppaint->pict != XCB_NONE) {
x_free_picture(&ps->c, ppaint->pict);
ppaint->pict = XCB_NONE;
}
if (ppaint->pixmap) {
xcb_free_pixmap(ps->c.c, ppaint->pixmap);
ppaint->pixmap = XCB_NONE;
}
}
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 (cr) {
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
ps->c, ps->root, fullwid, fullhei,
XCB_PICT_STANDARD_ARGB_32, 0, 0);
&ps->c, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
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,
.width = to_u16_checked(fullwid),
.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);
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);
xcb_render_trapezoids(
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
ps->c.c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8),
0, 0, n, traps);
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),
to_i16_checked(y), to_i16_checked(x), to_i16_checked(y),
to_i16_checked(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei));
xcb_render_free_picture(ps->c, p_tmp);
x_free_picture(&ps->c, p_tmp);
} else {
xcb_render_picture_t p_tmp = alpha_pict;
if (clip) {
p_tmp = 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 black = {
.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,
.width = to_u16_checked(wid),
.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);
if (alpha_pict) {
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,
0, 0, 0, to_u16_checked(wid),
to_u16_checked(hei));
}
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,
to_i16_checked(clip->x), to_i16_checked(clip->y),
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_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(dx), to_i16_checked(dy),
to_u16_checked(wid), to_u16_checked(hei));
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) {
// Don't check for presence of Pixmap here, because older X Composite doesn't
// provide it
if (!ppaint)
if (!ppaint) {
return false;
}
if (bkend_use_xrender(ps) && !ppaint->pict)
if (bkend_use_xrender(ps) && !ppaint->pict) {
return false;
}
#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;
}
#endif
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) {
// Fetch Pixmap
if (!w->paint.pixmap) {
w->paint.pixmap = x_new_id(ps->c);
set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->base.id,
w->paint.pixmap));
w->paint.pixmap = x_new_id(&ps->c);
set_ignore_cookie(&ps->c, xcb_composite_name_window_pixmap(
ps->c.c, w->base.id, 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(
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
@ -442,8 +439,8 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
// Invert window color, if required
if (bkend_use_xrender(ps) && w->invert_color) {
xcb_render_picture_t newpict = x_create_picture_with_pictfmt(
ps->c, ps->root, wid, hei, w->pictfmt, 0, NULL);
xcb_render_picture_t newpict =
x_create_picture_with_pictfmt(&ps->c, wid, hei, w->pictfmt, 0, NULL);
if (newpict) {
// Apply clipping region to save some CPU
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);
}
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, pict, 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_SRC, pict,
XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei);
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_DIFFERENCE,
ps->white_picture, XCB_NONE, newpict, 0, 0,
0, 0, 0, 0, wid, hei);
// We use an extra PictOpInReverse operation to get correct
// pixel alpha. There could be a better solution.
if (win_has_alpha(w))
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_IN_REVERSE,
if (win_has_alpha(w)) {
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_IN_REVERSE,
pict, XCB_NONE, newpict, 0, 0, 0, 0,
0, 0, wid, hei);
}
pict = newpict;
}
}
@ -494,43 +492,51 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
// ctop = checked top
// Make sure top margin is smaller than height
int ctop = min2(body_height, t);
if (ctop > 0)
if (ctop > 0) {
COMP_BDR(0, 0, wid, ctop);
}
body_height -= ctop;
if (body_height <= 0)
if (body_height <= 0) {
break;
}
// bottom
// cbot = checked bottom
// Make sure bottom margin is not too large
int cbot = min2(body_height, b);
if (cbot > 0)
if (cbot > 0) {
COMP_BDR(0, hei - cbot, wid, cbot);
}
// Height of window exclude the margin
body_height -= cbot;
if (body_height <= 0)
if (body_height <= 0) {
break;
}
// left
int body_width = wid;
int cleft = min2(body_width, l);
if (cleft > 0)
if (cleft > 0) {
COMP_BDR(0, ctop, cleft, body_height);
}
body_width -= cleft;
if (body_width <= 0)
if (body_width <= 0) {
break;
}
// right
int cright = min2(body_width, r);
if (cright > 0)
if (cright > 0) {
COMP_BDR(wid - cright, ctop, cright, body_height);
}
body_width -= cright;
if (body_width <= 0)
if (body_width <= 0) {
break;
}
// body
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
if (pict != w->paint.pict)
free_picture(ps->c, &pict);
if (pict != w->paint.pict) {
x_free_picture(&ps->c, pict);
pict = XCB_NONE;
}
// Dimming the window if needed
if (w->dim) {
double dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed)
if (!ps->o.inactive_dim_fixed) {
dim_opacity *= w->opacity;
}
switch (ps->o.backend) {
case BKEND_XRENDER:
@ -569,7 +578,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
.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);
} break;
#ifdef CONFIG_OPENGL
@ -593,15 +602,17 @@ static bool get_root_tile(session_t *ps) {
ps->root_tile_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
if (pixmap && !x_validate_pixmap(ps->c, pixmap))
if (pixmap && !x_validate_pixmap(&ps->c, pixmap)) {
pixmap = XCB_NONE;
}
// Create a pixmap if there isn't any
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) {
log_error("Failed to create pixmaps for root tile.");
return false;
@ -614,7 +625,7 @@ static bool get_root_tile(session_t *ps) {
.repeat = true,
};
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
if (fill) {
@ -627,15 +638,17 @@ static bool get_root_tile(session_t *ps) {
rect.x = rect.y = 0;
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_fill = fill;
ps->root_tile_paint.pixmap = pixmap;
#ifdef CONFIG_OPENGL
if (BKEND_GLX == ps->o.backend)
return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, ps->vis, false);
if (BKEND_GLX == ps->o.backend) {
return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0,
ps->c.screen_info->root_visual, false);
}
#endif
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_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) {
log_error("failed to make shadow");
return XCB_NONE;
}
shadow_pixmap =
x_create_pixmap(ps->c, 8, ps->root, shadow_image->width, shadow_image->height);
shadow_pixmap = x_create_pixmap(&ps->c, 8, shadow_image->width, shadow_image->height);
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) {
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(
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(
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) {
goto shadow_picture_err;
}
gc = x_new_id(ps->c);
xcb_create_gc(ps->c, gc, shadow_pixmap, 0, NULL);
gc = x_new_id(&ps->c);
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_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, ps->cshadow_picture,
xcb_image_put(ps->c.c, shadow_pixmap, gc, shadow_image, 0, 0, 0);
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_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);
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_free_pixmap(ps->c, shadow_pixmap);
xcb_render_free_picture(ps->c, shadow_picture);
xcb_free_pixmap(ps->c.c, shadow_pixmap);
x_free_picture(&ps->c, shadow_picture);
return true;
shadow_picture_err:
if (shadow_image)
if (shadow_image) {
xcb_image_destroy(shadow_image);
if (shadow_pixmap)
xcb_free_pixmap(ps->c, shadow_pixmap);
if (shadow_pixmap_argb)
xcb_free_pixmap(ps->c, shadow_pixmap_argb);
if (shadow_picture)
xcb_render_free_picture(ps->c, shadow_picture);
if (shadow_picture_argb)
xcb_render_free_picture(ps->c, shadow_picture_argb);
if (gc)
xcb_free_gc(ps->c, gc);
}
if (shadow_pixmap) {
xcb_free_pixmap(ps->c.c, shadow_pixmap);
}
if (shadow_pixmap_argb) {
xcb_free_pixmap(ps->c.c, shadow_pixmap_argb);
}
if (shadow_picture) {
x_free_picture(&ps->c, shadow_picture);
}
if (shadow_picture_argb) {
x_free_picture(&ps->c, shadow_picture_argb);
}
if (gc) {
xcb_free_gc(ps->c.c, gc);
}
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);
td = x_create_picture_with_standard(
ps->c, ps->root, w->widthb, w->heightb,
XCB_PICT_STANDARD_ARGB_32, 0, 0);
&ps->c, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0);
xcb_render_color_t trans = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0,
.y = 0,
.width = to_u16_checked(w->widthb),
.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);
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(
ps->c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0,
ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0,
0, n, traps);
xcb_render_free_picture(ps->c, solid);
x_free_picture(&ps->c, solid);
} else {
// 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,
should_clip ? &clip : NULL);
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
// Picture in the middle.
xcb_render_picture_t tmp_picture =
x_create_picture_with_visual(ps->c, ps->root, wid, hei, ps->vis, 0, NULL);
xcb_render_picture_t tmp_picture = x_create_picture_with_visual(
&ps->c, wid, hei, ps->c.screen_info->root_visual, 0, NULL);
if (!tmp_picture) {
log_error("Failed to build intermediate Picture.");
return false;
}
if (reg_clip && tmp_picture)
x_set_picture_clip_region(ps->c, tmp_picture, 0, 0, reg_clip);
if (reg_clip && tmp_picture) {
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;
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
// window.
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);
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),
(rd_from_tgt ? y : 0), 0, 0, (rd_from_tgt ? 0 : x),
(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)
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded,
if (src_pict != tgt_buffer) {
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded,
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;
}
@ -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);
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 = {
.red = 0, .blue = 0, .green = 0, .alpha = 0};
const xcb_rectangle_t rect = {.x = 0,
.y = 0,
.width = to_u16_checked(wid),
.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);
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(
ps->c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0,
ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td,
x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0,
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
@ -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,
ps->o.blur_kernel_count, &reg_blur, td);
if (td) {
xcb_render_free_picture(ps->c, td);
x_free_picture(&ps->c, td);
}
pixman_region32_clear(&reg_blur);
} 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
void paint_all(session_t *ps, struct managed_win *t) {
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 "
"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->o.xrender_sync_fence = false;
ps->xsync_exists = false;
@ -1010,7 +1030,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
if (!ps->tgt_buffer.pixmap) {
free_paint(ps, &ps->tgt_buffer);
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);
if (ps->tgt_buffer.pixmap == XCB_NONE) {
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->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) {
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
if (bkend_use_glx(ps)) {
ps->psglx->z = 0.0;
ps->psglx->z = 0;
}
#endif
@ -1066,18 +1088,21 @@ void paint_all(session_t *ps, struct managed_win *t) {
// Painting shadow
if (w->shadow) {
// Lazy shadow building
if (!w->shadow_paint.pixmap)
if (!win_build_shadow(ps, w, 1))
if (!w->shadow_paint.pixmap) {
if (!win_build_shadow(ps, w, 1)) {
log_error("build shadow failed");
}
}
// Shadow doesn't need to be painted underneath the body
// of the windows above. Because no one can see it
pixman_region32_subtract(&reg_tmp, &region, w->reg_ignore);
// 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,
&ps->shadow_exclude_reg);
}
if (pixman_region32_not_empty(&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
// saving GPU power and handling shaped windows (XXX
// 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);
}
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
// updated, but the monitor number attached to the window
// have not.
@ -1107,7 +1133,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
// bounds.
pixman_region32_intersect(
&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
@ -1197,13 +1223,14 @@ void paint_all(session_t *ps, struct managed_win *t) {
if (ps->o.vsync) {
// Make sure all previous requests are processed to achieve best
// effect
x_sync(ps->c);
x_sync(&ps->c);
#ifdef CONFIG_OPENGL
if (glx_has_context(ps)) {
if (ps->o.vsync_use_glfinish)
if (ps->o.vsync_use_glfinish) {
glFinish();
else
} else {
glFlush();
}
glXWaitX();
}
#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
// 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(
ps->c, ps->root, rwidth, rheight, pictfmt, 0, NULL);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC,
&ps->c, rwidth, rheight, pictfmt, 0, NULL);
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC,
ps->tgt_buffer.pict, XCB_NONE, new_pict, 0,
0, 0, 0, 0, 0, rwidth, rheight);
// Next, we set the region of paint and highlight it
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,
x_set_picture_clip_region(&ps->c, new_pict, 0, 0, &region);
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, ps->white_picture,
ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0,
0, 0, 0, 0, 0, rwidth, rheight);
// Finally, clear clip regions of new_pict and the screen, and put
// 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, ps->tgt_picture, 0, 0, &ps->screen_reg);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, new_pict,
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);
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, new_pict,
XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0,
rwidth, rheight);
xcb_render_free_picture(ps->c, new_pict);
} else
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC,
x_free_picture(&ps->c, new_pict);
} else {
xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC,
ps->tgt_buffer.pict, XCB_NONE, ps->tgt_picture,
0, 0, 0, 0, 0, 0, rwidth, rheight);
}
break;
#ifdef CONFIG_OPENGL
case BKEND_XR_GLX_HYBRID:
x_sync(ps->c);
if (ps->o.vsync_use_glfinish)
x_sync(&ps->c);
if (ps->o.vsync_use_glfinish) {
glFinish();
else
} else {
glFlush();
}
glXWaitX();
assert(ps->tgt_buffer.pixmap);
paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height,
false, ps->depth, ps->vis, !ps->o.glx_no_rebind_pixmap);
if (ps->o.vsync_use_glfinish)
false, ps->c.screen_info->root_depth,
ps->c.screen_info->root_visual, !ps->o.glx_no_rebind_pixmap);
if (ps->o.vsync_use_glfinish) {
glFinish();
else
} else {
glFlush();
}
glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
ps->root_height, 0, 1.0, false, false, &region, NULL);
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
default: assert(0);
}
x_sync(ps->c);
x_sync(&ps->c);
#ifdef CONFIG_OPENGL
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) {
// Query filters
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) {
xcb_str_iterator_t iter = xcb_render_query_filters_filters_iterator(pf);
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);
// Check for the convolution filter
if (strlen(XRFILTER_CONVOLUTION) == len &&
!memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION)))
!memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) {
ps->xrfilter_convolution_exists = true;
}
}
free(pf);
}
@ -1337,9 +1371,10 @@ static bool init_alpha_picts(session_t *ps) {
for (int i = 0; i <= MAX_ALPHA; ++i) {
double o = (double)i / MAX_ALPHA;
ps->alpha_picts[i] = solid_picture(ps->c, ps->root, false, o, 0, 0, 0);
if (ps->alpha_picts[i] == XCB_NONE)
ps->alpha_picts[i] = solid_picture(&ps->c, false, o, 0, 0, 0);
if (ps->alpha_picts[i] == XCB_NONE) {
return false;
}
}
return true;
}
@ -1351,12 +1386,13 @@ bool init_render(session_t *ps) {
// Initialize OpenGL as early as possible
#ifdef CONFIG_OPENGL
glxext_init(ps->dpy, ps->scr);
glxext_init(ps->c.dpy, ps->c.screen);
#endif
if (bkend_use_glx(ps)) {
#ifdef CONFIG_OPENGL
if (!glx_init(ps, true))
if (!glx_init(ps, true)) {
return false;
}
#else
log_error("GLX backend support not compiled in.");
return false;
@ -1371,8 +1407,9 @@ bool init_render(session_t *ps) {
// Initialize window GL shader
if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) {
#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;
}
#else
log_error("GLSL supported not compiled in, can't load "
"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->white_picture = solid_picture(ps->c, ps->root, true, 1, 1, 1, 1);
ps->black_picture = solid_picture(&ps->c, true, 1, 0, 0, 0);
ps->white_picture = solid_picture(&ps->c, true, 1, 1, 1, 1);
if (ps->black_picture == XCB_NONE || ps->white_picture == XCB_NONE) {
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) {
ps->cshadow_picture = ps->black_picture;
} 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);
if (ps->cshadow_picture == XCB_NONE) {
log_error("Failed to create shadow picture.");
@ -1450,14 +1487,14 @@ bool init_render(session_t *ps) {
* Free root tile related things.
*/
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
free_texture(ps, &ps->root_tile_paint.ptex);
#else
assert(!ps->root_tile_paint.ptex);
#endif
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;
@ -1466,19 +1503,20 @@ void free_root_tile(session_t *ps) {
void deinit_render(session_t *ps) {
// Free alpha_picts
for (int i = 0; i <= MAX_ALPHA; ++i)
free_picture(ps->c, &ps->alpha_picts[i]);
for (int i = 0; i <= MAX_ALPHA; ++i) {
x_free_picture(&ps->c, ps->alpha_picts[i]);
}
free(ps->alpha_picts);
ps->alpha_picts = NULL;
// Free cshadow_picture and black_picture
if (ps->cshadow_picture == ps->black_picture)
ps->cshadow_picture = XCB_NONE;
else
free_picture(ps->c, &ps->cshadow_picture);
if (ps->cshadow_picture != ps->black_picture) {
x_free_picture(&ps->c, ps->cshadow_picture);
}
free_picture(ps->c, &ps->black_picture);
free_picture(ps->c, &ps->white_picture);
x_free_picture(&ps->c, ps->black_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_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 free_picture(xcb_connection_t *c, xcb_render_picture_t *p);
void free_paint(session_t *ps, paint_t *ppaint);
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
*/
static bool vsync_opengl_init(session_t *ps) {
if (!ensure_glx_context(ps))
if (!ensure_glx_context(ps)) {
return false;
}
return glxext.has_GLX_SGI_video_sync;
}
static bool vsync_opengl_oml_init(session_t *ps) {
if (!ensure_glx_context(ps))
if (!ensure_glx_context(ps)) {
return false;
}
return glxext.has_GLX_OML_sync_control;
}
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;
else if (glxext.has_GLX_SGI_swap_control)
}
if (glxext.has_GLX_SGI_swap_control) {
return glXSwapIntervalSGI(interval) == 0;
else if (glxext.has_GLX_EXT_swap_control) {
}
if (glxext.has_GLX_EXT_swap_control) {
GLXDrawable d = glXGetCurrentDrawable();
if (d == None) {
// We don't have a context??
return false;
}
glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval);
glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval);
return true;
}
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) {
int64_t ust = 0, msc = 0, sbc = 0;
glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc);
glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
glXGetSyncValuesOML(ps->c.dpy, ps->reg_win, &ust, &msc, &sbc);
glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
return 0;
}
#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);
auto pixmap = x_new_id(b->c);
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) {
log_error("Failed to get named pixmap for window %#010x(%s)", w->base.id,
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_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)) {
@ -702,7 +702,7 @@ static inline bool win_bounding_shaped(const session_t *ps, xcb_window_t wid) {
Bool bounding_shaped;
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;
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) {
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 (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;
*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);
if (prop.nitems) {
@ -827,11 +827,12 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
} else {
// Respect active_opacity only when the window is physically
// focused
if (win_is_focused_raw(ps, w))
if (win_is_focused_raw(ps, w)) {
opacity = ps->o.active_opacity;
else if (!w->focused)
} else if (!w->focused) {
// Respect inactive_opacity in some cases
opacity = ps->o.inactive_opacity;
}
}
// 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)) {
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.
*/
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);
if (!prop.nitems) {
@ -1085,8 +1085,9 @@ void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val) {
static void
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;
}
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.
if (WINTYPE_UNKNOWN == w->window_type) {
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;
else
} else {
w->window_type = WINTYPE_DIALOG;
}
}
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(
ps->c, xcb_change_window_attributes_checked(
ps->c, client, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_CLIENT)}));
ps->c.c, xcb_change_window_attributes_checked(
ps->c.c, client, XCB_CW_EVENT_MASK,
(const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_CLIENT)}));
if (e) {
log_error("Failed to change event mask of window %#010x", client);
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);
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) {
log_error_x_error(e, "Failed to get client window attributes");
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);
}
@ -1364,7 +1366,7 @@ void win_unmark_client(session_t *ps, struct managed_win *w) {
// Recheck event mask
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)});
}
@ -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(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) {
return 0;
}
@ -1451,7 +1453,7 @@ void free_win_res(session_t *ps, struct managed_win *w) {
pixman_region32_fini(&w->bounding_shape);
// 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);
free(w->name);
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);
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(ps->c, acookie, NULL);
xcb_get_window_attributes_reply(ps->c.c, acookie, NULL);
if (!a || a->map_state == XCB_MAP_STATE_UNVIEWABLE) {
// Failed to get window attributes or geometry probably means
// 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);
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) {
log_error_x_error(e, "Failed to get geometry of window %#010x", w->id);
free(e);
@ -1674,10 +1677,10 @@ struct win *fill_win(session_t *ps, struct win *w) {
free(g);
// 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(
ps->c, xcb_damage_create_checked(ps->c, new->damage, w->id,
XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY));
ps->c.c, xcb_damage_create_checked(ps->c.c, new->damage, w->id,
XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY));
if (e) {
log_error_x_error(e, "Failed to create damage");
free(e);
@ -1687,15 +1690,15 @@ struct win *fill_win(session_t *ps, struct win *w) {
// Set window event mask
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)});
// Get notification when the shape of a window changes
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;
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
if (ps->o.detect_transient && !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) {
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);
@ -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
if (!w->cache_leader && (w->client_win || w->leader)) {
// Leader defaults to client window
if (!(w->cache_leader = w->leader))
if (!(w->cache_leader = w->leader)) {
w->cache_leader = w->client_win;
}
// If the leader of this window isn't itself, look for its
// 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);
if (wp) {
// Dead loop?
if (recursions > WIN_GET_LEADER_MAX_RECURSION)
if (recursions > WIN_GET_LEADER_MAX_RECURSION) {
return XCB_NONE;
}
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;
// Can't do anything if there's no client window
if (!w->client_win)
if (!w->client_win) {
return false;
}
// Free and reset old strings
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(
ps->c,
xcb_shape_get_rectangles(ps->c, w->base.id, XCB_SHAPE_SK_BOUNDING), NULL);
ps->c.c,
xcb_shape_get_rectangles(ps->c.c, w->base.id, XCB_SHAPE_SK_BOUNDING),
NULL);
if (!r) {
break;
@ -2030,7 +2037,7 @@ void win_update_opacity_prop(session_t *ps, struct managed_win *w) {
* Retrieve frame extents from a window.
*/
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);
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.
*/
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) {
return;
@ -2093,12 +2100,12 @@ void win_ev_stop(session_t *ps, const struct win *w) {
auto mw = (struct managed_win *)w;
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});
}
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
// 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;
for (int i = 0; i < nmons; i++) {
auto e = pixman_region32_extents(&mons[i]);
for (int i = 0; i < monitors->count; i++) {
auto e = pixman_region32_extents(&monitors->regions[i]);
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) {
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
// Using find_win here because if we found a unmanaged window we know
// 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
// somehow initializing (like add it in .xinitrc). In this case
// 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) {
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) {
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 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 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);
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
struct managed_win *
win_stack_find_next_managed(const session_t *ps, const struct list_node *i) {
while (!list_node_is_last(&ps->window_stack, i)) {
auto next = list_entry(i->next, struct win, stack_neighbour);
win_stack_find_next_managed(const session_t *ps, const struct list_node *w) {
while (!list_node_is_last(&ps->window_stack, w)) {
auto next = list_entry(w->next, struct win, stack_neighbour);
if (next->managed) {
return (struct managed_win *)next;
}
i = &next->stack_neighbour;
w = &next->stack_neighbour;
}
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);
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
// the x.h.
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);
/**
* Retrieve the bounding shape of a window.

230
src/x.c
View File

@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <pixman.h>
#include <xcb/composite.h>
@ -28,6 +29,72 @@
#include "utils.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.
*
@ -43,11 +110,11 @@
* @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure.
*/
winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom,
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) {
xcb_get_property_reply_t *r = xcb_get_property_reply(
c,
xcb_get_property(c, 0, w, atom, rtype, to_u32_checked(offset),
c->c,
xcb_get_property(c->c, 0, w, atom, rtype, to_u32_checked(offset),
to_u32_checked(length)),
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.
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;
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) {
log_debug_x_error(e, "Failed to get property info for window %#010x", w);
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
*/
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
xcb_window_t p = XCB_NONE;
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,
int *pnstr) {
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 format = prop_info.format;
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;
auto word_count = (length + 4 - 1) / 4;
auto r = xcb_get_property_reply(
ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, word_count), &e);
ps->c.c, xcb_get_property(ps->c.c, 0, wid, prop, type, 0, word_count), &e);
if (!r) {
log_debug_x_error(e, "Failed to get window property for %#010x", wid);
free(e);
@ -198,14 +265,14 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
// of this program
static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL;
static inline void x_get_server_pictfmts(xcb_connection_t *c) {
static inline void x_get_server_pictfmts(struct x_connection *c) {
if (g_pictfmts) {
return;
}
xcb_generic_error_t *e = NULL;
// Get window picture format
g_pictfmts =
xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), &e);
g_pictfmts = xcb_render_query_pict_formats_reply(
c->c, xcb_render_query_pict_formats(c->c), &e);
if (e || !g_pictfmts) {
log_fatal("failed to get pict formats\n");
abort();
@ -213,7 +280,7 @@ static inline void x_get_server_pictfmts(xcb_connection_t *c) {
}
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);
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;
}
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);
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
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);
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;
}
int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
auto setup = xcb_get_setup(c);
int x_get_visual_depth(struct x_connection *c, xcb_visualid_t visual) {
auto setup = xcb_get_setup(c->c);
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
xcb_screen_next(&screen)) {
for (auto depth = xcb_screen_allowed_depths_iterator(screen.data);
@ -280,7 +347,7 @@ int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
}
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,
xcb_pixmap_t pixmap, uint32_t valuemask,
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_generic_error_t *e =
xcb_request_check(c, xcb_render_create_picture_checked(
c, tmp_picture, pixmap, pictfmt->id, valuemask, buf));
xcb_generic_error_t *e = xcb_request_check(
c->c, xcb_render_create_picture_checked(c->c, tmp_picture, pixmap,
pictfmt->id, valuemask, buf));
free(buf);
if (e) {
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
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,
const xcb_render_create_picture_value_list_t *attr) {
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
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,
const xcb_render_create_picture_value_list_t *attr) {
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
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,
const xcb_render_create_picture_value_list_t *attr) {
x_get_server_pictfmts(c);
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
assert(pictfmt);
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr);
}
/**
* Create an picture.
*/
xcb_render_picture_t
x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
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_create_picture_value_list_t *attr) {
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) {
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(
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;
}
xcb_render_picture_t
x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
xcb_visualid_t visual, uint32_t valuemask,
x_create_picture_with_visual(struct x_connection *c, int w, int h, xcb_visualid_t visual,
uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr) {
auto pictfmt = x_get_pictform_for_visual(c, visual);
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
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_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) {
log_error_x_error(e, "Failed to fetch rectangles");
return false;
@ -390,7 +457,7 @@ bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_
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) {
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);
bool success =
XCB_AWAIT_VOID(xcb_xfixes_create_region, c, ret, to_u32_checked(nrects), xrects);
bool success = XCB_AWAIT_VOID(xcb_xfixes_create_region, c->c, ret,
to_u32_checked(nrects), xrects);
free(xrects);
if (!success) {
return XCB_NONE;
@ -419,13 +486,13 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) {
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) {
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,
const region_t *reg) {
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(
c, xcb_render_set_picture_clip_rectangles_checked(
c, pict, clip_x_origin, clip_y_origin, to_u32_checked(nrects), xrects));
xcb_generic_error_t *e =
xcb_request_check(c->c, xcb_render_set_picture_clip_rectangles_checked(
c->c, pict, clip_x_origin, clip_y_origin,
to_u32_checked(nrects), xrects));
if (e) {
log_error_x_error(e, "Failed to set clip region");
free(e);
@ -450,17 +518,28 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
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);
xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE};
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) {
log_error_x_error(e, "failed to clear clip region");
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 {
XSyncBadCounter = 0,
XSyncBadAlarm = 1,
@ -593,12 +672,12 @@ const char *x_strerror(xcb_generic_error_t *e) {
/**
* Create a pixmap and check that creation succeeded.
*/
xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable,
int width, int height) {
xcb_pixmap_t x_create_pixmap(struct x_connection *c, uint8_t depth, int width, int height) {
xcb_pixmap_t pix = x_new_id(c);
xcb_void_cookie_t cookie = xcb_create_pixmap_checked(
c, depth, pix, drawable, to_u16_checked(width), to_u16_checked(height));
xcb_generic_error_t *err = xcb_request_check(c, cookie);
xcb_void_cookie_t cookie =
xcb_create_pixmap_checked(c->c, depth, pix, c->screen_info->root,
to_u16_checked(width), to_u16_checked(height));
xcb_generic_error_t *err = xcb_request_check(c->c, cookie);
if (err == NULL) {
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
* 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) {
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) {
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://www.fvwm.org/Archive/Manpages/fvwm-root.html
xcb_pixmap_t
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms) {
xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms) {
xcb_pixmap_t pixmap = XCB_NONE;
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++) {
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) {
pixmap = (xcb_pixmap_t)*prop.p32;
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
* 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
// prototype, we need only one fence per screen, but let's stay a bit
// cautious right now
auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f));
auto e = xcb_request_check(c->c, xcb_sync_trigger_fence_checked(c->c, f));
if (e) {
log_error_x_error(e, "Failed to trigger the fence");
goto err;
}
e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f));
e = xcb_request_check(c->c, xcb_sync_await_fence_checked(c->c, 1, &f));
if (e) {
log_error_x_error(e, "Failed to await on a fence");
goto err;
}
e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f));
e = xcb_request_check(c->c, xcb_sync_reset_fence_checked(c->c, f));
if (e) {
log_error_x_error(e, "Failed to reset the fence");
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.
/// 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 depth = x_get_visual_depth(c, visual);
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;
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)) {
if (screen == 0) {
return iter.data;
@ -789,39 +868,34 @@ xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) {
return NULL;
}
void x_update_randr_monitors(session_t *ps) {
x_free_randr_info(ps);
if (!ps->o.crop_shadow_to_monitor || !ps->randr_exists) {
return;
}
void x_update_monitors(struct x_connection *c, struct x_monitors *m) {
x_free_monitor_info(m);
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) {
return;
}
ps->randr_nmonitors = xcb_randr_get_monitors_monitors_length(r);
ps->randr_monitor_regs = ccalloc(ps->randr_nmonitors, region_t);
m->count = xcb_randr_get_monitors_monitors_length(r);
m->regions = ccalloc(m->count, region_t);
xcb_randr_monitor_info_iterator_t monitor_info_it =
xcb_randr_get_monitors_monitors_iterator(r);
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;
pixman_region32_init_rect(&ps->randr_monitor_regs[i++], mi->x, mi->y,
mi->width, mi->height);
pixman_region32_init_rect(&m->regions[i++], mi->x, mi->y, mi->width, mi->height);
}
free(r);
}
void x_free_randr_info(session_t *ps) {
if (ps->randr_monitor_regs) {
for (int i = 0; i < ps->randr_nmonitors; i++) {
pixman_region32_fini(&ps->randr_monitor_regs[i]);
void x_free_monitor_info(struct x_monitors *m) {
if (m->regions) {
for (int i = 0; i < m->count; i++) {
pixman_region32_fini(&m->regions[i]);
}
free(ps->randr_monitor_regs);
ps->randr_monitor_regs = NULL;
free(m->regions);
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
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <X11/Xlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@ -55,6 +56,42 @@ struct xvisual_info {
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, ...) \
({ \
bool __success = true; \
@ -92,8 +129,8 @@ struct xvisual_info {
#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
static inline uint32_t x_new_id(xcb_connection_t *c) {
auto ret = xcb_generate_id(c);
static inline uint32_t x_new_id(struct x_connection *c) {
auto ret = xcb_generate_id(c->c);
if (ret == (uint32_t)-1) {
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 "
@ -103,6 +140,73 @@ static inline uint32_t x_new_id(xcb_connection_t *c) {
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
* 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
* libX11
*/
static inline void x_sync(xcb_connection_t *c) {
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
static inline void x_sync(struct x_connection *c) {
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
* 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);
/**
* 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,
int length, xcb_atom_t rtype, int rformat) {
static inline winprop_t
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);
}
/// 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
/// 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;
while ((e = xcb_poll_for_event(c))) {
while ((e = xcb_poll_for_event(c->c))) {
free(e);
}
}
@ -157,7 +262,7 @@ static inline void x_discard_events(xcb_connection_t *c) {
*
* @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.
@ -170,30 +275,30 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
int *pnstr);
const xcb_render_pictforminfo_t *
x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t);
int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t);
x_get_pictform_for_visual(struct x_connection *, xcb_visualid_t);
int x_get_visual_depth(struct x_connection *, xcb_visualid_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,
xcb_pixmap_t pixmap, uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1, 2);
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,
const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1);
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,
const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1);
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,
const xcb_render_create_picture_value_list_t *attr)
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.
*/
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_create_picture_value_list_t *attr)
attr_nonnull(1, 5);
attr_nonnull(1, 4);
xcb_render_picture_t
x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h,
xcb_visualid_t visual, uint32_t valuemask,
x_create_picture_with_visual(struct x_connection *, int w, int h, xcb_visualid_t visual,
uint32_t valuemask,
const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1);
/// 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
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
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,
int16_t clip_y_origin, const region_t *);
void x_set_picture_clip_region(struct x_connection *, xcb_render_picture_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
@ -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);
xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable,
int width, int height);
xcb_pixmap_t x_create_pixmap(struct x_connection *, uint8_t depth, 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>.
@ -254,22 +365,22 @@ bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap);
*/
static inline void free_winprop(winprop_t *pprop) {
// Empty the whole structure to avoid possible issues
if (pprop->r)
if (pprop->r) {
free(pprop->r);
}
pprop->ptr = NULL;
pprop->r = NULL;
pprop->nitems = 0;
}
/// Get the back pixmap of the root window
xcb_pixmap_t
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms);
xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms);
/// Return true if the atom refers to a property name that is used for the
/// root window background pixmap
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 {
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.
/// 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
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);
/**
* X RandR-related functions.
*
* The x_update_randr_monitors function populates ps->randr_nmonitors and
* 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);
/// Populates a `struct x_monitors` with the current monitor configuration.
void x_update_monitors(struct x_connection *, struct x_monitors *);
/// Free memory allocated for a `struct x_monitors`.
void x_free_monitor_info(struct x_monitors *);
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);