1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2024-11-11 13:51:02 -05:00
picom/src/x.c
Yuxuan Shui 50e2259404 Remove xrender-sync and xrender-sync-fence
This was a dubious "fix" for a Nvidia driver problem. The problem was
never fully understood, and the then developers took a shotgun approach
and implemented xsync fences as a fix. Which somehow fixed the problem.
Again, I don't see any indication that the developers understood why
this "fix" worked.

(for details, see chjj/compton#152 and chjj/compton#181)

The driver problem should have been fixed almost 5 years ago. So this
shouldn't be needed anymore. In addition the way compton uses xsync fences
is apparently wrong according to the xsync spec (fences are attached to
screen, but compton uses them as if they were attached to drawables).

So, I will try removing it and see if anyone will complain. If there are
real concrete reasons why fences are needed, it will be brought back.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-10-28 23:36:55 +00:00

369 lines
9.8 KiB
C

// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
#include <stdbool.h>
#include <X11/Xutil.h>
#include <X11/Xlib.h>
#include <xcb/xcb_renderutil.h>
#include <xcb/xfixes.h>
#include <pixman.h>
#include "common.h"
#include "x.h"
/**
* Get a specific attribute of a window.
*
* Returns a blank structure if the returned type and format does not
* match the requested type and format.
*
* @param ps current session
* @param w window
* @param atom atom of attribute to fetch
* @param length length to read
* @param rtype atom of the requested type
* @param rformat requested format
* @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure.
*/
winprop_t
wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
long length, Atom rtype, int rformat) {
Atom type = None;
int format = 0;
unsigned long nitems = 0, after = 0;
unsigned char *data = NULL;
if (Success == XGetWindowProperty(ps->dpy, w, atom, offset, length,
False, rtype, &type, &format, &nitems, &after, &data)
&& nitems && (AnyPropertyType == type || type == rtype)
&& (!rformat || format == rformat)
&& (8 == format || 16 == format || 32 == format)) {
return (winprop_t) {
.data.p8 = data,
.nitems = nitems,
.type = type,
.format = format,
};
}
cxfree(data);
return (winprop_t) {
.data.p8 = NULL,
.nitems = 0,
.type = AnyPropertyType,
.format = 0
};
}
/**
* Get the value of a type-<code>Window</code> property of a window.
*
* @return the value if successful, 0 otherwise
*/
Window
wid_get_prop_window(session_t *ps, Window wid, Atom aprop) {
// Get the attribute
Window p = None;
winprop_t prop = wid_get_prop(ps, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);
// Return it
if (prop.nitems) {
p = *prop.data.p32;
}
free_winprop(&prop);
return p;
}
/**
* Get the value of a text property of a window.
*/
bool wid_get_text_prop(session_t *ps, Window wid, Atom prop,
char ***pstrlst, int *pnstr) {
XTextProperty text_prop = { NULL, None, 0, 0 };
if (!(XGetTextProperty(ps->dpy, wid, &text_prop, prop) && text_prop.value))
return false;
if (Success !=
XmbTextPropertyToTextList(ps->dpy, &text_prop, pstrlst, pnstr)
|| !*pnstr) {
*pnstr = 0;
if (*pstrlst)
XFreeStringList(*pstrlst);
cxfree(text_prop.value);
return false;
}
cxfree(text_prop.value);
return true;
}
static inline void x_get_server_pictfmts(session_t *ps) {
if (ps->pictfmts)
return;
xcb_generic_error_t *e = NULL;
// Get window picture format
ps->pictfmts =
xcb_render_query_pict_formats_reply(ps->c,
xcb_render_query_pict_formats(ps->c), &e);
if (e || !ps->pictfmts) {
printf_errf("(): failed to get pict formats\n");
abort();
}
}
xcb_render_pictforminfo_t *x_get_pictform_for_visual(session_t *ps, xcb_visualid_t visual) {
if (!ps->pictfmts)
x_get_server_pictfmts(ps);
xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(ps->pictfmts, visual);
for(xcb_render_pictforminfo_iterator_t i =
xcb_render_query_pict_formats_formats_iterator(ps->pictfmts); i.rem;
xcb_render_pictforminfo_next(&i)) {
if (i.data->id == pv->format) {
return i.data;
}
}
return NULL;
}
xcb_render_picture_t
x_create_picture_with_pictfmt_and_pixmap(
session_t *ps, xcb_render_pictforminfo_t * pictfmt,
xcb_pixmap_t pixmap, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr)
{
void *buf = NULL;
if (attr) {
xcb_render_create_picture_value_list_serialize(&buf, valuemask, attr);
if (!buf) {
printf_errf("(): failed to serialize picture attributes");
return None;
}
}
xcb_render_picture_t tmp_picture = xcb_generate_id(ps->c);
xcb_generic_error_t *e =
xcb_request_check(ps->c, xcb_render_create_picture_checked(ps->c, tmp_picture,
pixmap, pictfmt->id, valuemask, buf));
free(buf);
if (e) {
printf_errf("(): failed to create picture");
return None;
}
return tmp_picture;
}
xcb_render_picture_t
x_create_picture_with_visual_and_pixmap(
session_t *ps, xcb_visualid_t visual,
xcb_pixmap_t pixmap, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr)
{
xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(ps, visual);
return x_create_picture_with_pictfmt_and_pixmap(ps, pictfmt, pixmap, valuemask, attr);
}
xcb_render_picture_t
x_create_picture_with_standard_and_pixmap(
session_t *ps, xcb_pict_standard_t standard,
xcb_pixmap_t pixmap, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr)
{
if (!ps->pictfmts)
x_get_server_pictfmts(ps);
xcb_render_pictforminfo_t *pictfmt =
xcb_render_util_find_standard_format(ps->pictfmts, standard);
assert(pictfmt);
return x_create_picture_with_pictfmt_and_pixmap(ps, pictfmt, pixmap, valuemask, attr);
}
/**
* Create an picture.
*/
xcb_render_picture_t
x_create_picture(session_t *ps, int wid, int hei,
xcb_render_pictforminfo_t *pictfmt, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr)
{
if (!pictfmt)
pictfmt = x_get_pictform_for_visual(ps, ps->vis);
if (!pictfmt) {
printf_errf("(): default visual is invalid");
abort();
}
int depth = pictfmt->depth;
xcb_pixmap_t tmp_pixmap = x_create_pixmap(ps, depth, ps->root, wid, hei);
if (!tmp_pixmap)
return None;
xcb_render_picture_t picture =
x_create_picture_with_pictfmt_and_pixmap(ps, pictfmt, tmp_pixmap, valuemask, attr);
xcb_free_pixmap(ps->c, tmp_pixmap);
return picture;
}
bool x_fetch_region(session_t *ps, 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(ps->c,
xcb_xfixes_fetch_region(ps->c, r), &e);
if (!xr) {
printf_errf("(): failed to fetch rectangles");
return false;
}
int nrect = xcb_xfixes_fetch_region_rectangles_length(xr);
pixman_box32_t *b = calloc(nrect, sizeof *b);
xcb_rectangle_t *xrect = xcb_xfixes_fetch_region_rectangles(xr);
for (int i = 0; i < nrect; i++) {
b[i] = (pixman_box32_t) {
.x1 = xrect[i].x,
.y1 = xrect[i].y,
.x2 = xrect[i].x + xrect[i].width,
.y2 = xrect[i].y + xrect[i].height
};
}
bool ret = pixman_region32_init_rects(res, b, nrect);
free(b);
free(xr);
return ret;
}
void x_set_picture_clip_region(session_t *ps, xcb_render_picture_t pict,
int clip_x_origin, int clip_y_origin, const region_t *reg) {
int nrects;
const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects);
xcb_rectangle_t *xrects = calloc(nrects, sizeof *xrects);
for (int i = 0; i < nrects; i++)
xrects[i] = (xcb_rectangle_t){
.x = rects[i].x1,
.y = rects[i].y1,
.width = rects[i].x2 - rects[i].x1,
.height = rects[i].y2 - rects[i].y1,
};
xcb_generic_error_t *e =
xcb_request_check(ps->c, xcb_render_set_picture_clip_rectangles_checked(ps->c, pict,
clip_x_origin, clip_y_origin, nrects, xrects));
if (e)
printf_errf("(): failed to set clip region");
free(e);
free(xrects);
return;
}
/**
* X11 error handler function.
*
* XXX consider making this error to string
*/
void
x_print_error(unsigned long serial, uint8_t major, uint8_t minor, uint8_t error_code) {
session_t * const ps = ps_g;
int o = 0;
const char *name = "Unknown";
if (major == ps->composite_opcode
&& minor == XCB_COMPOSITE_REDIRECT_SUBWINDOWS) {
fprintf(stderr, "Another composite manager is already running "
"(and does not handle _NET_WM_CM_Sn correctly)\n");
exit(1);
}
#define CASESTRRET2(s) case s: name = #s; break
o = error_code - ps->xfixes_error;
switch (o) {
CASESTRRET2(XCB_XFIXES_BAD_REGION);
}
o = error_code - ps->damage_error;
switch (o) {
CASESTRRET2(XCB_DAMAGE_BAD_DAMAGE);
}
o = error_code - ps->render_error;
switch (o) {
CASESTRRET2(XCB_RENDER_PICT_FORMAT);
CASESTRRET2(XCB_RENDER_PICTURE);
CASESTRRET2(XCB_RENDER_PICT_OP);
CASESTRRET2(XCB_RENDER_GLYPH_SET);
CASESTRRET2(XCB_RENDER_GLYPH);
}
#ifdef CONFIG_OPENGL
if (ps->glx_exists) {
o = error_code - ps->glx_error;
switch (o) {
CASESTRRET2(GLX_BAD_SCREEN);
CASESTRRET2(GLX_BAD_ATTRIBUTE);
CASESTRRET2(GLX_NO_EXTENSION);
CASESTRRET2(GLX_BAD_VISUAL);
CASESTRRET2(GLX_BAD_CONTEXT);
CASESTRRET2(GLX_BAD_VALUE);
CASESTRRET2(GLX_BAD_ENUM);
}
}
#endif
switch (error_code) {
CASESTRRET2(BadAccess);
CASESTRRET2(BadAlloc);
CASESTRRET2(BadAtom);
CASESTRRET2(BadColor);
CASESTRRET2(BadCursor);
CASESTRRET2(BadDrawable);
CASESTRRET2(BadFont);
CASESTRRET2(BadGC);
CASESTRRET2(BadIDChoice);
CASESTRRET2(BadImplementation);
CASESTRRET2(BadLength);
CASESTRRET2(BadMatch);
CASESTRRET2(BadName);
CASESTRRET2(BadPixmap);
CASESTRRET2(BadRequest);
CASESTRRET2(BadValue);
CASESTRRET2(BadWindow);
}
#undef CASESTRRET2
print_timestamp(ps);
{
char buf[BUF_LEN] = "";
XGetErrorText(ps->dpy, error_code, buf, BUF_LEN);
printf("error %4d %-12s request %4d minor %4d serial %6lu: \"%s\"\n",
error_code, name, major,
minor, serial, buf);
}
// print_backtrace();
}
/**
* Create a pixmap and check that creation succeeded.
*/
xcb_pixmap_t
x_create_pixmap(session_t *ps, uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height) {
xcb_pixmap_t pix = xcb_generate_id(ps->c);
xcb_void_cookie_t cookie = xcb_create_pixmap_checked(ps->c, depth, pix, drawable, width, height);
xcb_generic_error_t *err = xcb_request_check(ps->c, cookie);
if (err == NULL)
return pix;
printf_err("Failed to create pixmap:");
ev_xcb_error(ps, err);
free(err);
return XCB_NONE;
}