mirror of
https://github.com/yshui/picom.git
synced 2025-04-07 17:44:04 -04:00
core: isolate X connection with error handling into a struct
Part of the long running effort to reduce the prevalence of `session_t`. After this, functions that communicate with X can make use of the error handling machinary (set_ignore_cookie, set_cant_fail_cookie) without needing to take a `session_t` parameter. This commit converts everything to use the new struct `x_connection`, most of the conversions are mechanical. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
4e6dddc76e
commit
1307d9ec70
23 changed files with 1095 additions and 986 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,17 +19,18 @@
|
|||
/**
|
||||
* Generate a 1x1 <code>Picture</code> of a particular color.
|
||||
*/
|
||||
xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool argb,
|
||||
double a, double r, double g, double b) {
|
||||
xcb_render_picture_t
|
||||
solid_picture(struct x_connection *c, bool argb, double a, double r, double g, double b) {
|
||||
xcb_pixmap_t pixmap;
|
||||
xcb_render_picture_t picture;
|
||||
xcb_render_create_picture_value_list_t pa;
|
||||
xcb_render_color_t col;
|
||||
xcb_rectangle_t rect;
|
||||
|
||||
pixmap = x_create_pixmap(c, argb ? 32 : 8, d, 1, 1);
|
||||
if (!pixmap)
|
||||
pixmap = x_create_pixmap(c, argb ? 32 : 8, 1, 1);
|
||||
if (!pixmap) {
|
||||
return XCB_NONE;
|
||||
}
|
||||
|
||||
pa.repeat = 1;
|
||||
picture = x_create_picture_with_standard_and_pixmap(
|
||||
|
@ -37,7 +38,7 @@ xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool a
|
|||
XCB_RENDER_CP_REPEAT, &pa);
|
||||
|
||||
if (!picture) {
|
||||
xcb_free_pixmap(c, pixmap);
|
||||
xcb_free_pixmap(c->c, pixmap);
|
||||
return XCB_NONE;
|
||||
}
|
||||
|
||||
|
@ -51,14 +52,14 @@ xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool a
|
|||
rect.width = 1;
|
||||
rect.height = 1;
|
||||
|
||||
xcb_render_fill_rectangles(c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect);
|
||||
xcb_free_pixmap(c, pixmap);
|
||||
xcb_render_fill_rectangles(c->c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect);
|
||||
xcb_free_pixmap(c->c, pixmap);
|
||||
|
||||
return picture;
|
||||
}
|
||||
|
||||
xcb_image_t *
|
||||
make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height) {
|
||||
xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity,
|
||||
int width, int height) {
|
||||
/*
|
||||
* We classify shadows into 4 kinds of regions
|
||||
* r = shadow radius
|
||||
|
@ -84,8 +85,9 @@ make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width,
|
|||
assert(d % 2 == 1);
|
||||
assert(d > 0);
|
||||
|
||||
ximage = xcb_image_create_native(c, to_u16_checked(swidth), to_u16_checked(sheight),
|
||||
XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL);
|
||||
ximage =
|
||||
xcb_image_create_native(c->c, to_u16_checked(swidth), to_u16_checked(sheight),
|
||||
XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL);
|
||||
if (!ximage) {
|
||||
log_error("failed to create an X image");
|
||||
return 0;
|
||||
|
@ -193,7 +195,7 @@ make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width,
|
|||
/**
|
||||
* Generate shadow <code>Picture</code> for a window.
|
||||
*/
|
||||
bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const int width,
|
||||
bool build_shadow(struct x_connection *c, double opacity, const int width,
|
||||
const int height, const conv *kernel, xcb_render_picture_t shadow_pixel,
|
||||
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict) {
|
||||
xcb_image_t *shadow_image = NULL;
|
||||
|
@ -207,9 +209,9 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
|
|||
return false;
|
||||
}
|
||||
|
||||
shadow_pixmap = x_create_pixmap(c, 8, d, shadow_image->width, shadow_image->height);
|
||||
shadow_pixmap = x_create_pixmap(c, 8, shadow_image->width, shadow_image->height);
|
||||
shadow_pixmap_argb =
|
||||
x_create_pixmap(c, 32, d, shadow_image->width, shadow_image->height);
|
||||
x_create_pixmap(c, 32, shadow_image->width, shadow_image->height);
|
||||
|
||||
if (!shadow_pixmap || !shadow_pixmap_argb) {
|
||||
log_error("Failed to create shadow pixmaps");
|
||||
|
@ -225,11 +227,11 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
|
|||
}
|
||||
|
||||
gc = x_new_id(c);
|
||||
xcb_create_gc(c, gc, shadow_pixmap, 0, NULL);
|
||||
xcb_create_gc(c->c, gc, shadow_pixmap, 0, NULL);
|
||||
|
||||
// We need to make room for protocol metadata in the request. The metadata should
|
||||
// be 24 bytes plus padding, let's be generous and give it 1kb
|
||||
auto maximum_image_size = xcb_get_maximum_request_length(c) * 4 - 1024;
|
||||
auto maximum_image_size = xcb_get_maximum_request_length(c->c) * 4 - 1024;
|
||||
auto maximum_row =
|
||||
to_u16_checked(clamp(maximum_image_size / shadow_image->stride, 0, UINT16_MAX));
|
||||
if (maximum_row <= 0) {
|
||||
|
@ -248,23 +250,23 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i
|
|||
}
|
||||
|
||||
uint32_t offset = row * shadow_image->stride / sizeof(*shadow_image->data);
|
||||
xcb_put_image(c, (uint8_t)shadow_image->format, shadow_pixmap, gc,
|
||||
xcb_put_image(c->c, (uint8_t)shadow_image->format, shadow_pixmap, gc,
|
||||
shadow_image->width, batch_height, 0, to_i16_checked(row),
|
||||
0, shadow_image->depth, shadow_image->stride * batch_height,
|
||||
shadow_image->data + offset);
|
||||
}
|
||||
|
||||
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, shadow_pixel, shadow_picture,
|
||||
xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, shadow_pixel, shadow_picture,
|
||||
shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width,
|
||||
shadow_image->height);
|
||||
|
||||
*pixmap = shadow_pixmap_argb;
|
||||
*pict = shadow_picture_argb;
|
||||
|
||||
xcb_free_gc(c, gc);
|
||||
xcb_free_gc(c->c, gc);
|
||||
xcb_image_destroy(shadow_image);
|
||||
xcb_free_pixmap(c, shadow_pixmap);
|
||||
xcb_render_free_picture(c, shadow_picture);
|
||||
xcb_free_pixmap(c->c, shadow_pixmap);
|
||||
x_free_picture(c, shadow_picture);
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -273,19 +275,19 @@ shadow_picture_err:
|
|||
xcb_image_destroy(shadow_image);
|
||||
}
|
||||
if (shadow_pixmap) {
|
||||
xcb_free_pixmap(c, shadow_pixmap);
|
||||
xcb_free_pixmap(c->c, shadow_pixmap);
|
||||
}
|
||||
if (shadow_pixmap_argb) {
|
||||
xcb_free_pixmap(c, shadow_pixmap_argb);
|
||||
xcb_free_pixmap(c->c, shadow_pixmap_argb);
|
||||
}
|
||||
if (shadow_picture) {
|
||||
xcb_render_free_picture(c, shadow_picture);
|
||||
x_free_picture(c, shadow_picture);
|
||||
}
|
||||
if (shadow_picture_argb) {
|
||||
xcb_render_free_picture(c, shadow_picture_argb);
|
||||
x_free_picture(c, shadow_picture_argb);
|
||||
}
|
||||
if (gc) {
|
||||
xcb_free_gc(c, gc);
|
||||
xcb_free_gc(c->c, gc);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -294,22 +296,22 @@ shadow_picture_err:
|
|||
void *default_backend_render_shadow(backend_t *backend_data, int width, int height,
|
||||
struct backend_shadow_context *sctx, struct color color) {
|
||||
const conv *kernel = (void *)sctx;
|
||||
xcb_render_picture_t shadow_pixel = solid_picture(
|
||||
backend_data->c, backend_data->root, true, 1, color.red, color.green, color.blue);
|
||||
xcb_render_picture_t shadow_pixel =
|
||||
solid_picture(backend_data->c, true, 1, color.red, color.green, color.blue);
|
||||
xcb_pixmap_t shadow = XCB_NONE;
|
||||
xcb_render_picture_t pict = XCB_NONE;
|
||||
|
||||
if (!build_shadow(backend_data->c, backend_data->root, color.alpha, width, height,
|
||||
kernel, shadow_pixel, &shadow, &pict)) {
|
||||
xcb_render_free_picture(backend_data->c, shadow_pixel);
|
||||
if (!build_shadow(backend_data->c, color.alpha, width, height, kernel,
|
||||
shadow_pixel, &shadow, &pict)) {
|
||||
x_free_picture(backend_data->c, shadow_pixel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32);
|
||||
void *ret = backend_data->ops->bind_pixmap(
|
||||
backend_data, shadow, x_get_visual_info(backend_data->c, visual), true);
|
||||
xcb_render_free_picture(backend_data->c, pict);
|
||||
xcb_render_free_picture(backend_data->c, shadow_pixel);
|
||||
x_free_picture(backend_data->c, pict);
|
||||
x_free_picture(backend_data->c, shadow_pixel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -506,9 +508,8 @@ struct backend_image *default_new_backend_image(int w, int h) {
|
|||
}
|
||||
|
||||
void init_backend_base(struct backend_base *base, session_t *ps) {
|
||||
base->c = ps->c;
|
||||
base->c = &ps->c;
|
||||
base->loop = ps->loop;
|
||||
base->root = ps->root;
|
||||
base->busy = false;
|
||||
base->ops = NULL;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
116
src/c2.c
116
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;
|
||||
}
|
||||
}
|
||||
|
|
79
src/common.h
79
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 <code>next</code> member of tail element of the error
|
||||
/// ignore linked list.
|
||||
pending_reply_t **pending_reply_tail;
|
||||
// Cached blur convolution kernels.
|
||||
struct x_convolution_kernel **blur_kerns_cache;
|
||||
/// If we should quit
|
||||
|
@ -391,10 +360,8 @@ typedef struct session {
|
|||
int glx_event;
|
||||
/// Error base number for X GLX extension.
|
||||
int glx_error;
|
||||
/// Number of X RandR monitors.
|
||||
int randr_nmonitors;
|
||||
/// X RandR monitor regions.
|
||||
region_t *randr_monitor_regs;
|
||||
/// Information about monitors.
|
||||
struct x_monitors monitors;
|
||||
/// Whether X Sync extension exists.
|
||||
bool xsync_exists;
|
||||
/// Event base number for X Sync extension.
|
||||
|
@ -492,7 +459,7 @@ static inline struct timespec get_time_timespec(void) {
|
|||
* Return the painting target window.
|
||||
*/
|
||||
static inline xcb_window_t get_tgt_window(session_t *ps) {
|
||||
return ps->overlay != XCB_NONE ? ps->overlay : ps->root;
|
||||
return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -502,35 +469,6 @@ static inline bool bkend_use_glx(session_t *ps) {
|
|||
return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend;
|
||||
}
|
||||
|
||||
static void
|
||||
set_reply_action(session_t *ps, uint32_t sequence, enum pending_reply_action action) {
|
||||
auto i = cmalloc(pending_reply_t);
|
||||
if (!i) {
|
||||
abort();
|
||||
}
|
||||
|
||||
i->sequence = sequence;
|
||||
i->next = 0;
|
||||
i->action = action;
|
||||
*ps->pending_reply_tail = i;
|
||||
ps->pending_reply_tail = &i->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore X errors caused by given X request.
|
||||
*/
|
||||
static inline void set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) {
|
||||
if (ps->o.show_all_xerrors) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_reply_action(ps, cookie.sequence, PENDING_REPLY_ACTION_IGNORE);
|
||||
}
|
||||
|
||||
static inline void set_cant_fail_cookie(session_t *ps, xcb_void_cookie_t cookie) {
|
||||
set_reply_action(ps, cookie.sequence, PENDING_REPLY_ACTION_ABORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a window has a specific property.
|
||||
*
|
||||
|
@ -541,7 +479,8 @@ static inline void set_cant_fail_cookie(session_t *ps, xcb_void_cookie_t cookie)
|
|||
*/
|
||||
static inline bool wid_has_prop(const session_t *ps, xcb_window_t w, xcb_atom_t atom) {
|
||||
auto r = xcb_get_property_reply(
|
||||
ps->c, xcb_get_property(ps->c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL);
|
||||
ps->c.c,
|
||||
xcb_get_property(ps->c.c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL);
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
62
src/event.c
62
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);
|
||||
|
|
33
src/opengl.c
33
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;
|
||||
}
|
||||
|
||||
|
|
425
src/picom.c
425
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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
394
src/render.c
394
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 <code>Picture</code>.
|
||||
*/
|
||||
void free_picture(xcb_connection_t *c, xcb_render_picture_t *p) {
|
||||
if (*p) {
|
||||
xcb_render_free_picture(c, *p);
|
||||
*p = XCB_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free paint_t.
|
||||
*/
|
||||
|
@ -179,10 +170,14 @@ void free_paint(session_t *ps, paint_t *ppaint) {
|
|||
#ifdef CONFIG_OPENGL
|
||||
free_paint_glx(ps, ppaint);
|
||||
#endif
|
||||
free_picture(ps->c, &ppaint->pict);
|
||||
if (ppaint->pixmap)
|
||||
xcb_free_pixmap(ps->c, ppaint->pixmap);
|
||||
ppaint->pixmap = XCB_NONE;
|
||||
if (ppaint->pict != XCB_NONE) {
|
||||
x_free_picture(&ps->c, ppaint->pict);
|
||||
ppaint->pict = XCB_NONE;
|
||||
}
|
||||
if (ppaint->pixmap) {
|
||||
xcb_free_pixmap(ps->c.c, ppaint->pixmap);
|
||||
ppaint->pixmap = XCB_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -253,8 +248,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
if (alpha_step != 0) {
|
||||
if (cr) {
|
||||
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
|
||||
ps->c, ps->root, fullwid, fullhei,
|
||||
XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
&ps->c, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
xcb_render_color_t trans = {
|
||||
.red = 0, .blue = 0, .green = 0, .alpha = 0};
|
||||
const xcb_rectangle_t rect = {
|
||||
|
@ -262,7 +256,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
.y = 0,
|
||||
.width = to_u16_checked(fullwid),
|
||||
.height = to_u16_checked(fullhei)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
|
||||
xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC,
|
||||
p_tmp, trans, 1, &rect);
|
||||
|
||||
uint32_t max_ntraps = to_u32_checked(cr);
|
||||
|
@ -272,25 +266,24 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
traps, max_ntraps, cr, fullwid, fullhei);
|
||||
|
||||
xcb_render_trapezoids(
|
||||
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
|
||||
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
|
||||
ps->c.c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
|
||||
x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8),
|
||||
0, 0, n, traps);
|
||||
|
||||
xcb_render_composite(
|
||||
ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp,
|
||||
ps->c.c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp,
|
||||
ps->tgt_buffer.pict, to_i16_checked(x),
|
||||
to_i16_checked(y), to_i16_checked(x), to_i16_checked(y),
|
||||
to_i16_checked(dx), to_i16_checked(dy),
|
||||
to_u16_checked(wid), to_u16_checked(hei));
|
||||
|
||||
xcb_render_free_picture(ps->c, p_tmp);
|
||||
x_free_picture(&ps->c, p_tmp);
|
||||
|
||||
} else {
|
||||
xcb_render_picture_t p_tmp = alpha_pict;
|
||||
if (clip) {
|
||||
p_tmp = x_create_picture_with_standard(
|
||||
ps->c, ps->root, wid, hei,
|
||||
XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
&ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
|
||||
xcb_render_color_t black = {
|
||||
.red = 255, .blue = 255, .green = 255, .alpha = 255};
|
||||
|
@ -299,17 +292,18 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
.y = 0,
|
||||
.width = to_u16_checked(wid),
|
||||
.height = to_u16_checked(hei)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
|
||||
xcb_render_fill_rectangles(ps->c.c,
|
||||
XCB_RENDER_PICT_OP_SRC,
|
||||
p_tmp, black, 1, &rect);
|
||||
if (alpha_pict) {
|
||||
xcb_render_composite(
|
||||
ps->c, XCB_RENDER_PICT_OP_SRC,
|
||||
ps->c.c, XCB_RENDER_PICT_OP_SRC,
|
||||
alpha_pict, XCB_NONE, p_tmp, 0, 0, 0,
|
||||
0, 0, 0, to_u16_checked(wid),
|
||||
to_u16_checked(hei));
|
||||
}
|
||||
xcb_render_composite(
|
||||
ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE,
|
||||
ps->c.c, XCB_RENDER_PICT_OP_OUT_REVERSE,
|
||||
clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0,
|
||||
to_i16_checked(clip->x), to_i16_checked(clip->y),
|
||||
to_u16_checked(wid), to_u16_checked(hei));
|
||||
|
@ -319,12 +313,12 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
: XCB_RENDER_PICT_OP_OVER);
|
||||
|
||||
xcb_render_composite(
|
||||
ps->c, op, pict, p_tmp, ps->tgt_buffer.pict,
|
||||
ps->c.c, op, pict, p_tmp, ps->tgt_buffer.pict,
|
||||
to_i16_checked(x), to_i16_checked(y), 0, 0,
|
||||
to_i16_checked(dx), to_i16_checked(dy),
|
||||
to_u16_checked(wid), to_u16_checked(hei));
|
||||
if (clip) {
|
||||
xcb_render_free_picture(ps->c, p_tmp);
|
||||
x_free_picture(&ps->c, p_tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,15 +369,18 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid,
|
|||
static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
|
||||
// Don't check for presence of Pixmap here, because older X Composite doesn't
|
||||
// provide it
|
||||
if (!ppaint)
|
||||
if (!ppaint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bkend_use_xrender(ps) && !ppaint->pict)
|
||||
if (bkend_use_xrender(ps) && !ppaint->pict) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE))
|
||||
if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
@ -395,9 +392,9 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
|
|||
void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) {
|
||||
// Fetch Pixmap
|
||||
if (!w->paint.pixmap) {
|
||||
w->paint.pixmap = x_new_id(ps->c);
|
||||
set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->base.id,
|
||||
w->paint.pixmap));
|
||||
w->paint.pixmap = x_new_id(&ps->c);
|
||||
set_ignore_cookie(&ps->c, xcb_composite_name_window_pixmap(
|
||||
ps->c.c, w->base.id, w->paint.pixmap));
|
||||
}
|
||||
|
||||
xcb_drawable_t draw = w->paint.pixmap;
|
||||
|
@ -415,7 +412,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
};
|
||||
|
||||
w->paint.pict = x_create_picture_with_pictfmt_and_pixmap(
|
||||
ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
||||
&ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
||||
}
|
||||
|
||||
// GLX: Build texture
|
||||
|
@ -442,8 +439,8 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
|
||||
// Invert window color, if required
|
||||
if (bkend_use_xrender(ps) && w->invert_color) {
|
||||
xcb_render_picture_t newpict = x_create_picture_with_pictfmt(
|
||||
ps->c, ps->root, wid, hei, w->pictfmt, 0, NULL);
|
||||
xcb_render_picture_t newpict =
|
||||
x_create_picture_with_pictfmt(&ps->c, wid, hei, w->pictfmt, 0, NULL);
|
||||
if (newpict) {
|
||||
// Apply clipping region to save some CPU
|
||||
if (reg_paint) {
|
||||
|
@ -456,17 +453,18 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
pixman_region32_fini(®);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
20
src/vsync.c
20
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
|
||||
|
|
112
src/win.c
112
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;
|
||||
}
|
||||
|
|
|
@ -341,9 +341,7 @@ void win_recheck_client(session_t *ps, struct managed_win *w);
|
|||
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
|
||||
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
|
||||
|
||||
// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to
|
||||
// the x.h.
|
||||
void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw);
|
||||
void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw);
|
||||
|
||||
/**
|
||||
* Retrieve the bounding shape of a window.
|
||||
|
|
230
src/x.c
230
src/x.c
|
@ -4,6 +4,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <pixman.h>
|
||||
#include <xcb/composite.h>
|
||||
|
@ -28,6 +29,72 @@
|
|||
#include "utils.h"
|
||||
#include "x.h"
|
||||
|
||||
// === Error handling ===
|
||||
|
||||
/**
|
||||
* Xlib error handler function.
|
||||
*/
|
||||
static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
|
||||
if (!ps_g) {
|
||||
// Do not ignore errors until the session has been initialized
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fake a xcb error, fill in just enough information
|
||||
xcb_generic_error_t xcb_err;
|
||||
xcb_err.full_sequence = (uint32_t)ev->serial;
|
||||
xcb_err.major_code = ev->request_code;
|
||||
xcb_err.minor_code = ev->minor_code;
|
||||
xcb_err.error_code = ev->error_code;
|
||||
x_handle_error(&ps_g->c, &xcb_err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void x_discard_pending(struct x_connection *c, uint32_t sequence) {
|
||||
while (c->pending_reply_head && sequence > c->pending_reply_head->sequence) {
|
||||
auto next = c->pending_reply_head->next;
|
||||
free(c->pending_reply_head);
|
||||
c->pending_reply_head = next;
|
||||
}
|
||||
if (!c->pending_reply_head) {
|
||||
c->pending_reply_tail = &c->pending_reply_head;
|
||||
}
|
||||
}
|
||||
|
||||
void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev) {
|
||||
x_discard_pending(c, ev->full_sequence);
|
||||
if (c->pending_reply_head && c->pending_reply_head->sequence == ev->full_sequence) {
|
||||
if (c->pending_reply_head->action != PENDING_REPLY_ACTION_IGNORE) {
|
||||
x_log_error(LOG_LEVEL_ERROR, ev->full_sequence, ev->major_code,
|
||||
ev->minor_code, ev->error_code);
|
||||
}
|
||||
switch (c->pending_reply_head->action) {
|
||||
case PENDING_REPLY_ACTION_ABORT:
|
||||
log_fatal("An unrecoverable X error occurred, aborting...");
|
||||
abort();
|
||||
case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break;
|
||||
case PENDING_REPLY_ACTION_IGNORE: break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
x_log_error(LOG_LEVEL_WARN, ev->full_sequence, ev->major_code, ev->minor_code,
|
||||
ev->error_code);
|
||||
}
|
||||
|
||||
/// Initialize x_connection struct from an Xlib Display.
|
||||
///
|
||||
/// Note this function doesn't take ownership of the Display, the caller is still
|
||||
/// responsible for closing it after `free_x_connection` is called.
|
||||
void x_connection_init(struct x_connection *c, Display *dpy) {
|
||||
c->dpy = dpy;
|
||||
c->c = XGetXCBConnection(dpy);
|
||||
c->pending_reply_tail = &c->pending_reply_head;
|
||||
c->previous_xerror_handler = XSetErrorHandler(xerror);
|
||||
|
||||
c->screen = DefaultScreen(dpy);
|
||||
c->screen_info = x_screen_of_display(c, c->screen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific attribute of a window.
|
||||
*
|
||||
|
@ -43,11 +110,11 @@
|
|||
* @return a <code>winprop_t</code> structure containing the attribute
|
||||
* and number of items. A blank one on failure.
|
||||
*/
|
||||
winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom,
|
||||
winprop_t x_get_prop_with_offset(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom,
|
||||
int offset, int length, xcb_atom_t rtype, int rformat) {
|
||||
xcb_get_property_reply_t *r = xcb_get_property_reply(
|
||||
c,
|
||||
xcb_get_property(c, 0, w, atom, rtype, to_u32_checked(offset),
|
||||
c->c,
|
||||
xcb_get_property(c->c, 0, w, atom, rtype, to_u32_checked(offset),
|
||||
to_u32_checked(length)),
|
||||
NULL);
|
||||
|
||||
|
@ -71,10 +138,10 @@ winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t
|
|||
}
|
||||
|
||||
/// Get the type, format and size in bytes of a window's specific attribute.
|
||||
winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom) {
|
||||
winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom) {
|
||||
xcb_generic_error_t *e = NULL;
|
||||
auto r = xcb_get_property_reply(
|
||||
c, xcb_get_property(c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e);
|
||||
c->c, xcb_get_property(c->c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e);
|
||||
if (!r) {
|
||||
log_debug_x_error(e, "Failed to get property info for window %#010x", w);
|
||||
free(e);
|
||||
|
@ -94,7 +161,7 @@ winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t a
|
|||
*
|
||||
* @return the value if successful, 0 otherwise
|
||||
*/
|
||||
xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t aprop) {
|
||||
xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop) {
|
||||
// Get the attribute
|
||||
xcb_window_t p = XCB_NONE;
|
||||
winprop_t prop = x_get_prop(c, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);
|
||||
|
@ -115,7 +182,7 @@ xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom
|
|||
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
|
||||
int *pnstr) {
|
||||
assert(ps->server_grabbed);
|
||||
auto prop_info = x_get_prop_info(ps->c, wid, prop);
|
||||
auto prop_info = x_get_prop_info(&ps->c, wid, prop);
|
||||
auto type = prop_info.type;
|
||||
auto format = prop_info.format;
|
||||
auto length = prop_info.length;
|
||||
|
@ -140,7 +207,7 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
|
|||
xcb_generic_error_t *e = NULL;
|
||||
auto word_count = (length + 4 - 1) / 4;
|
||||
auto r = xcb_get_property_reply(
|
||||
ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, word_count), &e);
|
||||
ps->c.c, xcb_get_property(ps->c.c, 0, wid, prop, type, 0, word_count), &e);
|
||||
if (!r) {
|
||||
log_debug_x_error(e, "Failed to get window property for %#010x", wid);
|
||||
free(e);
|
||||
|
@ -198,14 +265,14 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
|
|||
// of this program
|
||||
static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL;
|
||||
|
||||
static inline void x_get_server_pictfmts(xcb_connection_t *c) {
|
||||
static inline void x_get_server_pictfmts(struct x_connection *c) {
|
||||
if (g_pictfmts) {
|
||||
return;
|
||||
}
|
||||
xcb_generic_error_t *e = NULL;
|
||||
// Get window picture format
|
||||
g_pictfmts =
|
||||
xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), &e);
|
||||
g_pictfmts = xcb_render_query_pict_formats_reply(
|
||||
c->c, xcb_render_query_pict_formats(c->c), &e);
|
||||
if (e || !g_pictfmts) {
|
||||
log_fatal("failed to get pict formats\n");
|
||||
abort();
|
||||
|
@ -213,7 +280,7 @@ static inline void x_get_server_pictfmts(xcb_connection_t *c) {
|
|||
}
|
||||
|
||||
const xcb_render_pictforminfo_t *
|
||||
x_get_pictform_for_visual(xcb_connection_t *c, xcb_visualid_t visual) {
|
||||
x_get_pictform_for_visual(struct x_connection *c, xcb_visualid_t visual) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
||||
xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual);
|
||||
|
@ -244,7 +311,7 @@ static xcb_visualid_t attr_pure x_get_visual_for_pictfmt(xcb_render_query_pict_f
|
|||
return XCB_NONE;
|
||||
}
|
||||
|
||||
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
|
||||
xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
||||
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
|
||||
|
@ -253,7 +320,7 @@ xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_
|
|||
}
|
||||
|
||||
xcb_render_pictformat_t
|
||||
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
|
||||
x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
||||
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
|
||||
|
@ -261,8 +328,8 @@ x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
|
|||
return pictfmt->id;
|
||||
}
|
||||
|
||||
int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
|
||||
auto setup = xcb_get_setup(c);
|
||||
int x_get_visual_depth(struct x_connection *c, xcb_visualid_t visual) {
|
||||
auto setup = xcb_get_setup(c->c);
|
||||
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
|
||||
xcb_screen_next(&screen)) {
|
||||
for (auto depth = xcb_screen_allowed_depths_iterator(screen.data);
|
||||
|
@ -280,7 +347,7 @@ int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
|
|||
}
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
|
||||
x_create_picture_with_pictfmt_and_pixmap(struct x_connection *c,
|
||||
const xcb_render_pictforminfo_t *pictfmt,
|
||||
xcb_pixmap_t pixmap, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
|
@ -294,9 +361,9 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
|
|||
}
|
||||
|
||||
xcb_render_picture_t tmp_picture = x_new_id(c);
|
||||
xcb_generic_error_t *e =
|
||||
xcb_request_check(c, xcb_render_create_picture_checked(
|
||||
c, tmp_picture, pixmap, pictfmt->id, valuemask, buf));
|
||||
xcb_generic_error_t *e = xcb_request_check(
|
||||
c->c, xcb_render_create_picture_checked(c->c, tmp_picture, pixmap,
|
||||
pictfmt->id, valuemask, buf));
|
||||
free(buf);
|
||||
if (e) {
|
||||
log_error_x_error(e, "failed to create picture");
|
||||
|
@ -307,7 +374,7 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
|
|||
}
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visual,
|
||||
x_create_picture_with_visual_and_pixmap(struct x_connection *c, xcb_visualid_t visual,
|
||||
xcb_pixmap_t pixmap, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual);
|
||||
|
@ -315,7 +382,7 @@ x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visu
|
|||
}
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard_t standard,
|
||||
x_create_picture_with_standard_and_pixmap(struct x_connection *c, xcb_pict_standard_t standard,
|
||||
xcb_pixmap_t pixmap, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
@ -326,26 +393,26 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard
|
|||
}
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
||||
x_create_picture_with_standard(struct x_connection *c, int w, int h,
|
||||
xcb_pict_standard_t standard, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
||||
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
|
||||
assert(pictfmt);
|
||||
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
|
||||
return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an picture.
|
||||
*/
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
||||
x_create_picture_with_pictfmt(struct x_connection *c, int w, int h,
|
||||
const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
uint8_t depth = pictfmt->depth;
|
||||
|
||||
xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, w, h);
|
||||
xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, w, h);
|
||||
if (!tmp_pixmap) {
|
||||
return XCB_NONE;
|
||||
}
|
||||
|
@ -353,23 +420,23 @@ x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int
|
|||
xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap(
|
||||
c, pictfmt, tmp_pixmap, valuemask, attr);
|
||||
|
||||
xcb_free_pixmap(c, tmp_pixmap);
|
||||
set_cant_fail_cookie(c, xcb_free_pixmap(c->c, tmp_pixmap));
|
||||
|
||||
return picture;
|
||||
}
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
||||
xcb_visualid_t visual, uint32_t valuemask,
|
||||
x_create_picture_with_visual(struct x_connection *c, int w, int h, xcb_visualid_t visual,
|
||||
uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
auto pictfmt = x_get_pictform_for_visual(c, visual);
|
||||
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
|
||||
return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr);
|
||||
}
|
||||
|
||||
bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_t *res) {
|
||||
bool x_fetch_region(struct x_connection *c, xcb_xfixes_region_t r, pixman_region32_t *res) {
|
||||
xcb_generic_error_t *e = NULL;
|
||||
xcb_xfixes_fetch_region_reply_t *xr =
|
||||
xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region(c, r), &e);
|
||||
xcb_xfixes_fetch_region_reply(c->c, xcb_xfixes_fetch_region(c->c, r), &e);
|
||||
if (!xr) {
|
||||
log_error_x_error(e, "Failed to fetch rectangles");
|
||||
return false;
|
||||
|
@ -390,7 +457,7 @@ bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_
|
|||
return ret;
|
||||
}
|
||||
|
||||
uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) {
|
||||
uint32_t x_create_region(struct x_connection *c, const region_t *reg) {
|
||||
if (!reg) {
|
||||
return XCB_NONE;
|
||||
}
|
||||
|
@ -410,8 +477,8 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) {
|
|||
}
|
||||
|
||||
xcb_xfixes_region_t ret = x_new_id(c);
|
||||
bool success =
|
||||
XCB_AWAIT_VOID(xcb_xfixes_create_region, c, ret, to_u32_checked(nrects), xrects);
|
||||
bool success = XCB_AWAIT_VOID(xcb_xfixes_create_region, c->c, ret,
|
||||
to_u32_checked(nrects), xrects);
|
||||
free(xrects);
|
||||
if (!success) {
|
||||
return XCB_NONE;
|
||||
|
@ -419,13 +486,13 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void x_destroy_region(xcb_connection_t *c, xcb_xfixes_region_t r) {
|
||||
void x_destroy_region(struct x_connection *c, xcb_xfixes_region_t r) {
|
||||
if (r != XCB_NONE) {
|
||||
xcb_xfixes_destroy_region(c, r);
|
||||
set_debug_cant_fail_cookie(c, xcb_xfixes_destroy_region(c->c, r));
|
||||
}
|
||||
}
|
||||
|
||||
void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
|
||||
void x_set_picture_clip_region(struct x_connection *c, xcb_render_picture_t pict,
|
||||
int16_t clip_x_origin, int16_t clip_y_origin,
|
||||
const region_t *reg) {
|
||||
int nrects;
|
||||
|
@ -440,9 +507,10 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
|
|||
};
|
||||
}
|
||||
|
||||
xcb_generic_error_t *e = xcb_request_check(
|
||||
c, xcb_render_set_picture_clip_rectangles_checked(
|
||||
c, pict, clip_x_origin, clip_y_origin, to_u32_checked(nrects), xrects));
|
||||
xcb_generic_error_t *e =
|
||||
xcb_request_check(c->c, xcb_render_set_picture_clip_rectangles_checked(
|
||||
c->c, pict, clip_x_origin, clip_y_origin,
|
||||
to_u32_checked(nrects), xrects));
|
||||
if (e) {
|
||||
log_error_x_error(e, "Failed to set clip region");
|
||||
free(e);
|
||||
|
@ -450,17 +518,28 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
|
|||
free(xrects);
|
||||
}
|
||||
|
||||
void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) {
|
||||
void x_clear_picture_clip_region(struct x_connection *c, xcb_render_picture_t pict) {
|
||||
assert(pict != XCB_NONE);
|
||||
xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE};
|
||||
xcb_generic_error_t *e = xcb_request_check(
|
||||
c, xcb_render_change_picture_checked(c, pict, XCB_RENDER_CP_CLIP_MASK, &v));
|
||||
c->c, xcb_render_change_picture_checked(c->c, pict, XCB_RENDER_CP_CLIP_MASK, &v));
|
||||
if (e) {
|
||||
log_error_x_error(e, "failed to clear clip region");
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a <code>Picture</code>.
|
||||
*
|
||||
* Picture must be valid.
|
||||
*/
|
||||
void x_free_picture(struct x_connection *c, xcb_render_picture_t p) {
|
||||
assert(p != XCB_NONE);
|
||||
auto cookie = xcb_render_free_picture(c->c, p);
|
||||
set_cant_fail_cookie(c, cookie);
|
||||
}
|
||||
|
||||
enum {
|
||||
XSyncBadCounter = 0,
|
||||
XSyncBadAlarm = 1,
|
||||
|
@ -593,12 +672,12 @@ const char *x_strerror(xcb_generic_error_t *e) {
|
|||
/**
|
||||
* Create a pixmap and check that creation succeeded.
|
||||
*/
|
||||
xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable,
|
||||
int width, int height) {
|
||||
xcb_pixmap_t x_create_pixmap(struct x_connection *c, uint8_t depth, int width, int height) {
|
||||
xcb_pixmap_t pix = x_new_id(c);
|
||||
xcb_void_cookie_t cookie = xcb_create_pixmap_checked(
|
||||
c, depth, pix, drawable, to_u16_checked(width), to_u16_checked(height));
|
||||
xcb_generic_error_t *err = xcb_request_check(c, cookie);
|
||||
xcb_void_cookie_t cookie =
|
||||
xcb_create_pixmap_checked(c->c, depth, pix, c->screen_info->root,
|
||||
to_u16_checked(width), to_u16_checked(height));
|
||||
xcb_generic_error_t *err = xcb_request_check(c->c, cookie);
|
||||
if (err == NULL) {
|
||||
return pix;
|
||||
}
|
||||
|
@ -614,12 +693,12 @@ xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t
|
|||
* Detect whether the pixmap is valid with XGetGeometry. Well, maybe there
|
||||
* are better ways.
|
||||
*/
|
||||
bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) {
|
||||
bool x_validate_pixmap(struct x_connection *c, xcb_pixmap_t pixmap) {
|
||||
if (pixmap == XCB_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto r = xcb_get_geometry_reply(c, xcb_get_geometry(c, pixmap), NULL);
|
||||
auto r = xcb_get_geometry_reply(c->c, xcb_get_geometry(c->c, pixmap), NULL);
|
||||
if (!r) {
|
||||
return false;
|
||||
}
|
||||
|
@ -641,14 +720,14 @@ bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) {
|
|||
/// https://github.com/ImageMagick/ImageMagick/blob/d04a47227637dbb3af9231b0107ccf9677bf985e/MagickCore/xwindow.c#L1853-L1922
|
||||
/// https://www.fvwm.org/Archive/Manpages/fvwm-root.html
|
||||
|
||||
xcb_pixmap_t
|
||||
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms) {
|
||||
xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms) {
|
||||
xcb_pixmap_t pixmap = XCB_NONE;
|
||||
|
||||
xcb_atom_t root_back_pixmap_atoms[] = {atoms->a_XROOTPMAP_ID, atoms->aESETROOT_PMAP_ID};
|
||||
for (size_t i = 0; i < ARR_SIZE(root_back_pixmap_atoms); i++) {
|
||||
winprop_t prop =
|
||||
x_get_prop(c, root, root_back_pixmap_atoms[i], 1, XCB_ATOM_PIXMAP, 32);
|
||||
x_get_prop(c, c->screen_info->root, root_back_pixmap_atoms[i], 1,
|
||||
XCB_ATOM_PIXMAP, 32);
|
||||
if (prop.nitems) {
|
||||
pixmap = (xcb_pixmap_t)*prop.p32;
|
||||
free_winprop(&prop);
|
||||
|
@ -669,24 +748,24 @@ bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom) {
|
|||
* Synchronizes a X Render drawable to ensure all pending painting requests
|
||||
* are completed.
|
||||
*/
|
||||
bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) {
|
||||
bool x_fence_sync(struct x_connection *c, xcb_sync_fence_t f) {
|
||||
// TODO(richardgv): If everybody just follows the rules stated in X Sync
|
||||
// prototype, we need only one fence per screen, but let's stay a bit
|
||||
// cautious right now
|
||||
|
||||
auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f));
|
||||
auto e = xcb_request_check(c->c, xcb_sync_trigger_fence_checked(c->c, f));
|
||||
if (e) {
|
||||
log_error_x_error(e, "Failed to trigger the fence");
|
||||
goto err;
|
||||
}
|
||||
|
||||
e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f));
|
||||
e = xcb_request_check(c->c, xcb_sync_await_fence_checked(c->c, 1, &f));
|
||||
if (e) {
|
||||
log_error_x_error(e, "Failed to await on a fence");
|
||||
goto err;
|
||||
}
|
||||
|
||||
e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f));
|
||||
e = xcb_request_check(c->c, xcb_sync_reset_fence_checked(c->c, f));
|
||||
if (e) {
|
||||
log_error_x_error(e, "Failed to reset the fence");
|
||||
goto err;
|
||||
|
@ -748,7 +827,7 @@ void x_create_convolution_kernel(const conv *kernel, double center,
|
|||
|
||||
/// Generate a search criteria for fbconfig from a X visual.
|
||||
/// Returns {-1, -1, -1, -1, -1, 0} on failure
|
||||
struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual) {
|
||||
struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t visual) {
|
||||
auto pictfmt = x_get_pictform_for_visual(c, visual);
|
||||
auto depth = x_get_visual_depth(c, visual);
|
||||
if (!pictfmt || depth == -1) {
|
||||
|
@ -776,10 +855,10 @@ struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual
|
|||
};
|
||||
}
|
||||
|
||||
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) {
|
||||
xcb_screen_t *x_screen_of_display(struct x_connection *c, int screen) {
|
||||
xcb_screen_iterator_t iter;
|
||||
|
||||
iter = xcb_setup_roots_iterator(xcb_get_setup(c));
|
||||
iter = xcb_setup_roots_iterator(xcb_get_setup(c->c));
|
||||
for (; iter.rem; --screen, xcb_screen_next(&iter)) {
|
||||
if (screen == 0) {
|
||||
return iter.data;
|
||||
|
@ -789,39 +868,34 @@ xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void x_update_randr_monitors(session_t *ps) {
|
||||
x_free_randr_info(ps);
|
||||
|
||||
if (!ps->o.crop_shadow_to_monitor || !ps->randr_exists) {
|
||||
return;
|
||||
}
|
||||
void x_update_monitors(struct x_connection *c, struct x_monitors *m) {
|
||||
x_free_monitor_info(m);
|
||||
|
||||
xcb_randr_get_monitors_reply_t *r = xcb_randr_get_monitors_reply(
|
||||
ps->c, xcb_randr_get_monitors(ps->c, ps->root, true), NULL);
|
||||
c->c, xcb_randr_get_monitors(c->c, c->screen_info->root, true), NULL);
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
ps->randr_nmonitors = xcb_randr_get_monitors_monitors_length(r);
|
||||
ps->randr_monitor_regs = ccalloc(ps->randr_nmonitors, region_t);
|
||||
m->count = xcb_randr_get_monitors_monitors_length(r);
|
||||
m->regions = ccalloc(m->count, region_t);
|
||||
xcb_randr_monitor_info_iterator_t monitor_info_it =
|
||||
xcb_randr_get_monitors_monitors_iterator(r);
|
||||
for (int i = 0; monitor_info_it.rem; xcb_randr_monitor_info_next(&monitor_info_it)) {
|
||||
xcb_randr_monitor_info_t *mi = monitor_info_it.data;
|
||||
pixman_region32_init_rect(&ps->randr_monitor_regs[i++], mi->x, mi->y,
|
||||
mi->width, mi->height);
|
||||
pixman_region32_init_rect(&m->regions[i++], mi->x, mi->y, mi->width, mi->height);
|
||||
}
|
||||
|
||||
free(r);
|
||||
}
|
||||
|
||||
void x_free_randr_info(session_t *ps) {
|
||||
if (ps->randr_monitor_regs) {
|
||||
for (int i = 0; i < ps->randr_nmonitors; i++) {
|
||||
pixman_region32_fini(&ps->randr_monitor_regs[i]);
|
||||
void x_free_monitor_info(struct x_monitors *m) {
|
||||
if (m->regions) {
|
||||
for (int i = 0; i < m->count; i++) {
|
||||
pixman_region32_fini(&m->regions[i]);
|
||||
}
|
||||
free(ps->randr_monitor_regs);
|
||||
ps->randr_monitor_regs = NULL;
|
||||
free(m->regions);
|
||||
m->regions = NULL;
|
||||
}
|
||||
ps->randr_nmonitors = 0;
|
||||
m->count = 0;
|
||||
}
|
||||
|
|
200
src/x.h
200
src/x.h
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
||||
#pragma once
|
||||
#include <X11/Xlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -55,6 +56,42 @@ struct xvisual_info {
|
|||
xcb_visualid_t visual;
|
||||
};
|
||||
|
||||
enum pending_reply_action {
|
||||
PENDING_REPLY_ACTION_IGNORE,
|
||||
PENDING_REPLY_ACTION_ABORT,
|
||||
PENDING_REPLY_ACTION_DEBUG_ABORT,
|
||||
};
|
||||
|
||||
typedef struct pending_reply {
|
||||
struct pending_reply *next;
|
||||
unsigned long sequence;
|
||||
enum pending_reply_action action;
|
||||
} pending_reply_t;
|
||||
|
||||
struct x_connection {
|
||||
/// XCB connection.
|
||||
xcb_connection_t *c;
|
||||
/// Display in use.
|
||||
Display *dpy;
|
||||
/// Head pointer of the error ignore linked list.
|
||||
pending_reply_t *pending_reply_head;
|
||||
/// Pointer to the <code>next</code> member of tail element of the error
|
||||
/// ignore linked list.
|
||||
pending_reply_t **pending_reply_tail;
|
||||
/// Previous handler of X errors
|
||||
XErrorHandler previous_xerror_handler;
|
||||
/// Default screen
|
||||
int screen;
|
||||
/// Information about the default screen
|
||||
xcb_screen_t *screen_info;
|
||||
};
|
||||
|
||||
/// Monitor info
|
||||
struct x_monitors {
|
||||
int count;
|
||||
region_t *regions;
|
||||
};
|
||||
|
||||
#define XCB_AWAIT_VOID(func, c, ...) \
|
||||
({ \
|
||||
bool __success = true; \
|
||||
|
@ -92,8 +129,8 @@ struct xvisual_info {
|
|||
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536))
|
||||
|
||||
/// Wraps x_new_id. abort the program if x_new_id returns error
|
||||
static inline uint32_t x_new_id(xcb_connection_t *c) {
|
||||
auto ret = xcb_generate_id(c);
|
||||
static inline uint32_t x_new_id(struct x_connection *c) {
|
||||
auto ret = xcb_generate_id(c->c);
|
||||
if (ret == (uint32_t)-1) {
|
||||
log_fatal("We seems to have run of XIDs. This is either a bug in the X "
|
||||
"server, or a resource leakage in the compositor. Please open "
|
||||
|
@ -103,6 +140,73 @@ static inline uint32_t x_new_id(xcb_connection_t *c) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void set_reply_action(struct x_connection *c, uint32_t sequence,
|
||||
enum pending_reply_action action) {
|
||||
auto i = cmalloc(pending_reply_t);
|
||||
|
||||
i->sequence = sequence;
|
||||
i->next = 0;
|
||||
i->action = action;
|
||||
*c->pending_reply_tail = i;
|
||||
c->pending_reply_tail = &i->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore X errors caused by given X request.
|
||||
*/
|
||||
static inline void attr_unused set_ignore_cookie(struct x_connection *c,
|
||||
xcb_void_cookie_t cookie) {
|
||||
set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_IGNORE);
|
||||
}
|
||||
|
||||
static inline void attr_unused set_cant_fail_cookie(struct x_connection *c,
|
||||
xcb_void_cookie_t cookie) {
|
||||
set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_ABORT);
|
||||
}
|
||||
|
||||
static inline void attr_unused set_debug_cant_fail_cookie(struct x_connection *c,
|
||||
xcb_void_cookie_t cookie) {
|
||||
#ifndef NDEBUG
|
||||
set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_DEBUG_ABORT);
|
||||
#else
|
||||
(void)c;
|
||||
(void)cookie;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void attr_unused free_x_connection(struct x_connection *c) {
|
||||
pending_reply_t *next = NULL;
|
||||
for (auto ign = c->pending_reply_head; ign; ign = next) {
|
||||
next = ign->next;
|
||||
|
||||
free(ign);
|
||||
}
|
||||
|
||||
// Reset head and tail
|
||||
c->pending_reply_head = NULL;
|
||||
c->pending_reply_tail = &c->pending_reply_head;
|
||||
|
||||
XSetErrorHandler(c->previous_xerror_handler);
|
||||
}
|
||||
|
||||
/// Initialize x_connection struct from an Xlib Display.
|
||||
///
|
||||
/// Note this function doesn't take ownership of the Display, the caller is still
|
||||
/// responsible for closing it after `free_x_connection` is called.
|
||||
void x_connection_init(struct x_connection *c, Display *dpy);
|
||||
|
||||
/// Discard queued pending replies.
|
||||
///
|
||||
/// We have received reply with sequence number `sequence`, which means all pending
|
||||
/// replies with sequence number less than `sequence` will never be received. So discard
|
||||
/// them.
|
||||
void x_discard_pending(struct x_connection *c, uint32_t sequence);
|
||||
|
||||
/// Handle X errors.
|
||||
///
|
||||
/// This function logs X errors, or aborts the program based on severity of the error.
|
||||
void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev);
|
||||
|
||||
/**
|
||||
* Send a request to X server and get the reply to make sure all previous
|
||||
* requests are processed, and their replies received
|
||||
|
@ -110,8 +214,8 @@ static inline uint32_t x_new_id(xcb_connection_t *c) {
|
|||
* xcb_get_input_focus is used here because it is the same request used by
|
||||
* libX11
|
||||
*/
|
||||
static inline void x_sync(xcb_connection_t *c) {
|
||||
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
|
||||
static inline void x_sync(struct x_connection *c) {
|
||||
free(xcb_get_input_focus_reply(c->c, xcb_get_input_focus(c->c), NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,25 +233,26 @@ static inline void x_sync(xcb_connection_t *c) {
|
|||
* @return a <code>winprop_t</code> structure containing the attribute
|
||||
* and number of items. A blank one on failure.
|
||||
*/
|
||||
winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom,
|
||||
winprop_t x_get_prop_with_offset(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom,
|
||||
int offset, int length, xcb_atom_t rtype, int rformat);
|
||||
|
||||
/**
|
||||
* Wrapper of wid_get_prop_adv().
|
||||
*/
|
||||
static inline winprop_t x_get_prop(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t atom,
|
||||
int length, xcb_atom_t rtype, int rformat) {
|
||||
static inline winprop_t
|
||||
x_get_prop(const struct x_connection *c, xcb_window_t wid, xcb_atom_t atom, int length,
|
||||
xcb_atom_t rtype, int rformat) {
|
||||
return x_get_prop_with_offset(c, wid, atom, 0L, length, rtype, rformat);
|
||||
}
|
||||
|
||||
/// Get the type, format and size in bytes of a window's specific attribute.
|
||||
winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom);
|
||||
winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom);
|
||||
|
||||
/// Discard all X events in queue or in flight. Should only be used when the server is
|
||||
/// grabbed
|
||||
static inline void x_discard_events(xcb_connection_t *c) {
|
||||
static inline void x_discard_events(struct x_connection *c) {
|
||||
xcb_generic_event_t *e;
|
||||
while ((e = xcb_poll_for_event(c))) {
|
||||
while ((e = xcb_poll_for_event(c->c))) {
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +262,7 @@ static inline void x_discard_events(xcb_connection_t *c) {
|
|||
*
|
||||
* @return the value if successful, 0 otherwise
|
||||
*/
|
||||
xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t aprop);
|
||||
xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop);
|
||||
|
||||
/**
|
||||
* Get the value of a text property of a window.
|
||||
|
@ -170,30 +275,30 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
|
|||
int *pnstr);
|
||||
|
||||
const xcb_render_pictforminfo_t *
|
||||
x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t);
|
||||
int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t);
|
||||
x_get_pictform_for_visual(struct x_connection *, xcb_visualid_t);
|
||||
int x_get_visual_depth(struct x_connection *, xcb_visualid_t);
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *,
|
||||
x_create_picture_with_pictfmt_and_pixmap(struct x_connection *,
|
||||
const xcb_render_pictforminfo_t *pictfmt,
|
||||
xcb_pixmap_t pixmap, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1, 2);
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_visual_and_pixmap(xcb_connection_t *, xcb_visualid_t visual,
|
||||
x_create_picture_with_visual_and_pixmap(struct x_connection *, xcb_visualid_t visual,
|
||||
xcb_pixmap_t pixmap, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1);
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_t standard,
|
||||
x_create_picture_with_standard_and_pixmap(struct x_connection *, xcb_pict_standard_t standard,
|
||||
xcb_pixmap_t pixmap, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1);
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
||||
x_create_picture_with_standard(struct x_connection *c, int w, int h,
|
||||
xcb_pict_standard_t standard, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1);
|
||||
|
@ -202,30 +307,37 @@ x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int
|
|||
* Create an picture.
|
||||
*/
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int w, int h,
|
||||
x_create_picture_with_pictfmt(struct x_connection *, int w, int h,
|
||||
const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1, 5);
|
||||
attr_nonnull(1, 4);
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h,
|
||||
xcb_visualid_t visual, uint32_t valuemask,
|
||||
x_create_picture_with_visual(struct x_connection *, int w, int h, xcb_visualid_t visual,
|
||||
uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1);
|
||||
|
||||
/// Fetch a X region and store it in a pixman region
|
||||
bool x_fetch_region(xcb_connection_t *, xcb_xfixes_region_t r, region_t *res);
|
||||
bool x_fetch_region(struct x_connection *, xcb_xfixes_region_t r, region_t *res);
|
||||
|
||||
/// Create a X region from a pixman region
|
||||
uint32_t x_create_region(xcb_connection_t *c, const region_t *reg);
|
||||
uint32_t x_create_region(struct x_connection *c, const region_t *reg);
|
||||
|
||||
/// Destroy a X region
|
||||
void x_destroy_region(xcb_connection_t *c, uint32_t region);
|
||||
void x_destroy_region(struct x_connection *c, uint32_t region);
|
||||
|
||||
void x_set_picture_clip_region(xcb_connection_t *, xcb_render_picture_t, int16_t clip_x_origin,
|
||||
int16_t clip_y_origin, const region_t *);
|
||||
void x_set_picture_clip_region(struct x_connection *, xcb_render_picture_t,
|
||||
int16_t clip_x_origin, int16_t clip_y_origin, const region_t *);
|
||||
|
||||
void x_clear_picture_clip_region(xcb_connection_t *, xcb_render_picture_t pict);
|
||||
void x_clear_picture_clip_region(struct x_connection *, xcb_render_picture_t pict);
|
||||
|
||||
/**
|
||||
* Destroy a <code>Picture</code>.
|
||||
*
|
||||
* Picture must be valid.
|
||||
*/
|
||||
void x_free_picture(struct x_connection *c, xcb_render_picture_t p);
|
||||
|
||||
/**
|
||||
* Log a X11 error
|
||||
|
@ -242,10 +354,9 @@ void x_log_error(enum log_level level, unsigned long serial, uint8_t major,
|
|||
*/
|
||||
const char *x_strerror(xcb_generic_error_t *e);
|
||||
|
||||
xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable,
|
||||
int width, int height);
|
||||
xcb_pixmap_t x_create_pixmap(struct x_connection *, uint8_t depth, int width, int height);
|
||||
|
||||
bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap);
|
||||
bool x_validate_pixmap(struct x_connection *, xcb_pixmap_t pxmap);
|
||||
|
||||
/**
|
||||
* Free a <code>winprop_t</code>.
|
||||
|
@ -254,22 +365,22 @@ bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap);
|
|||
*/
|
||||
static inline void free_winprop(winprop_t *pprop) {
|
||||
// Empty the whole structure to avoid possible issues
|
||||
if (pprop->r)
|
||||
if (pprop->r) {
|
||||
free(pprop->r);
|
||||
}
|
||||
pprop->ptr = NULL;
|
||||
pprop->r = NULL;
|
||||
pprop->nitems = 0;
|
||||
}
|
||||
|
||||
/// Get the back pixmap of the root window
|
||||
xcb_pixmap_t
|
||||
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms);
|
||||
xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms);
|
||||
|
||||
/// Return true if the atom refers to a property name that is used for the
|
||||
/// root window background pixmap
|
||||
bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom);
|
||||
|
||||
bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t);
|
||||
bool x_fence_sync(struct x_connection *, xcb_sync_fence_t);
|
||||
|
||||
struct x_convolution_kernel {
|
||||
int size;
|
||||
|
@ -293,23 +404,18 @@ void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double c
|
|||
|
||||
/// Generate a search criteria for fbconfig from a X visual.
|
||||
/// Returns {-1, -1, -1, -1, -1, -1} on failure
|
||||
struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual);
|
||||
struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t visual);
|
||||
|
||||
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
|
||||
xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std);
|
||||
|
||||
xcb_render_pictformat_t
|
||||
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
|
||||
x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std);
|
||||
|
||||
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen);
|
||||
xcb_screen_t *x_screen_of_display(struct x_connection *c, int screen);
|
||||
|
||||
/**
|
||||
* X RandR-related functions.
|
||||
*
|
||||
* The x_update_randr_monitors function populates ps->randr_nmonitors and
|
||||
* ps->randr_monitor_regs with the data X RandR provided and the
|
||||
* x_free_randr_info function frees them.
|
||||
*/
|
||||
void x_update_randr_monitors(session_t *ps);
|
||||
void x_free_randr_info(session_t *ps);
|
||||
/// Populates a `struct x_monitors` with the current monitor configuration.
|
||||
void x_update_monitors(struct x_connection *, struct x_monitors *);
|
||||
/// Free memory allocated for a `struct x_monitors`.
|
||||
void x_free_monitor_info(struct x_monitors *);
|
||||
|
||||
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);
|
||||
|
|
Loading…
Add table
Reference in a new issue