diff --git a/src/backend/backend.c b/src/backend/backend.c index da1fa429..f094555c 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -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( ®_shadow, ®_shadow, - &ps->randr_monitor_regs[w->randr_monitor]); + &ps->monitors.regions[w->randr_monitor]); } if (ps->o.transparent_clipping) { diff --git a/src/backend/backend.h b/src/backend/backend.h index 7cd64a08..3ed7a761 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -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 diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index ecdefa4c..5b24c67a 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -19,17 +19,18 @@ /** * Generate a 1x1 Picture 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 Picture 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; } diff --git a/src/backend/backend_common.h b/src/backend/backend_common.h index c72a1686..2e49cecf 100644 --- a/src/backend/backend_common.h +++ b/src/backend/backend_common.h @@ -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 diff --git a/src/backend/dummy/dummy.c b/src/backend/dummy/dummy.c index 5f5e1229..4e3d7138 100644 --- a/src/backend/dummy/dummy.c +++ b/src/backend/dummy/dummy.c @@ -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); } diff --git a/src/backend/gl/egl.c b/src/backend/gl/egl.c index 761eb635..a78c1903 100644 --- a/src/backend/gl/egl.c +++ b/src/backend/gl/egl.c @@ -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; diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 80056c67..d30dc9f2 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -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)); diff --git a/src/backend/gl/glx.h b/src/backend/gl/glx.h index 44b4da05..ce8702a9 100644 --- a/src/backend/gl/glx.h +++ b/src/backend/gl/glx.h @@ -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; diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index 0041817a..bb2acd45 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -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(®, (region_t *)reg_paint, (region_t *)reg_visible); x_set_picture_clip_region(xd->base.c, result, 0, 0, ®); 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), ®); // 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(®); } @@ -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(®_op); pixman_region32_intersect(®_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, ®_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, ®_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(®_op); pixman_region32_fini(®_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, ®); - 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"); diff --git a/src/c2.c b/src/c2.c index f8af6992..823d30ea 100644 --- a/src/c2.c +++ b/src/c2.c @@ -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; } } diff --git a/src/common.h b/src/common.h index e183a1e6..707d00e7 100644 --- a/src/common.h +++ b/src/common.h @@ -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 next 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; } diff --git a/src/dbus.c b/src/dbus.c index baff2bcc..ad98a0f2 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -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; } diff --git a/src/event.c b/src/event.c index b1400828..807cf4ed 100644 --- a/src/event.c +++ b/src/event.c @@ -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); diff --git a/src/opengl.c b/src/opengl.c index 5d2d66cb..6f4d0471 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -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; } diff --git a/src/picom.c b/src/picom.c index 126922e7..1567ab89 100644 --- a/src/picom.c +++ b/src/picom.c @@ -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]); diff --git a/src/picom.h b/src/picom.h index 6f14cd08..e68b1e04 100644 --- a/src/picom.h +++ b/src/picom.h @@ -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; diff --git a/src/render.c b/src/render.c index f4b3a979..65d02cf3 100644 --- a/src/render.c +++ b/src/render.c @@ -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 Picture. - */ -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(®); } - 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, ®_blur, td); if (td) { - xcb_render_free_picture(ps->c, td); + x_free_picture(&ps->c, td); } pixman_region32_clear(®_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, ®ion); + x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, ®ion); } #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(®_tmp, ®ion, 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(®_tmp, ®_tmp, &ps->shadow_exclude_reg); + } if (pixman_region32_not_empty(®_shadow_clip)) { pixman_region32_subtract(®_tmp, ®_tmp, ®_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(®_tmp, ®_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( ®_tmp, ®_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, ®ion); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, ps->white_picture, + x_set_picture_clip_region(&ps->c, new_pict, 0, 0, ®ion); + 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, ®ion, 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); diff --git a/src/render.h b/src/render.h index 249f7bf2..4e0c7a81 100644 --- a/src/render.h +++ b/src/render.h @@ -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); diff --git a/src/vsync.c b/src/vsync.c index 59801558..57fbb595 100644 --- a/src/vsync.c +++ b/src/vsync.c @@ -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 diff --git a/src/win.c b/src/win.c index 1aa10fd2..14e2953f 100644 --- a/src/win.c +++ b/src/win.c @@ -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; } diff --git a/src/win.h b/src/win.h index da46572b..b841ffc1 100644 --- a/src/win.h +++ b/src/win.h @@ -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. diff --git a/src/x.c b/src/x.c index a2a7153d..46af709c 100644 --- a/src/x.c +++ b/src/x.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -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 winprop_t 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 Picture. + * + * 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; } diff --git a/src/x.h b/src/x.h index fc105c78..b5bd1a59 100644 --- a/src/x.h +++ b/src/x.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2018 Yuxuan Shui #pragma once +#include #include #include #include @@ -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 next 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 winprop_t 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 Picture. + * + * 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 winprop_t. @@ -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);