Handle asyncronous X11 errors

Errors for requests sent via Xlib that expect a reply are handled via
XSetErrorHandler(), which sets up a callback function that Xlib calls.
Errors for requests that do not expect a reply or for errors caused via
unchecked XCB requests show up as events of type 0 in the event handling
function.

Before this commit, errors were ignored here. This commit changes the
code so that the errors are printed instead.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2018-09-29 11:11:43 +02:00
parent 3ed73b1f8e
commit 00ae9718ee
1 changed files with 34 additions and 16 deletions

View File

@ -2496,21 +2496,21 @@ root_damaged(session_t *ps) {
}
/**
* Xlib error handler function.
* X11 error handler function.
*/
static int
xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
static void
xerror_common(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 (should_ignore(ps, ev->serial)) {
return 0;
if (should_ignore(ps, serial)) {
return;
}
if (ev->request_code == ps->composite_opcode
&& ev->minor_code == XCB_COMPOSITE_REDIRECT_SUBWINDOWS) {
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);
@ -2518,17 +2518,17 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
#define CASESTRRET2(s) case s: name = #s; break
o = ev->error_code - ps->xfixes_error;
o = error_code - ps->xfixes_error;
switch (o) {
CASESTRRET2(BadRegion);
}
o = ev->error_code - ps->damage_error;
o = error_code - ps->damage_error;
switch (o) {
CASESTRRET2(XCB_DAMAGE_BAD_DAMAGE);
}
o = ev->error_code - ps->render_error;
o = error_code - ps->render_error;
switch (o) {
CASESTRRET2(XCB_RENDER_PICT_FORMAT);
CASESTRRET2(XCB_RENDER_PICTURE);
@ -2539,7 +2539,7 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
#ifdef CONFIG_OPENGL
if (ps->glx_exists) {
o = ev->error_code - ps->glx_error;
o = error_code - ps->glx_error;
switch (o) {
CASESTRRET2(GLX_BAD_SCREEN);
CASESTRRET2(GLX_BAD_ATTRIBUTE);
@ -2554,7 +2554,7 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
#ifdef CONFIG_XSYNC
if (ps->xsync_exists) {
o = ev->error_code - ps->xsync_error;
o = error_code - ps->xsync_error;
switch (o) {
CASESTRRET2(XSyncBadCounter);
CASESTRRET2(XSyncBadAlarm);
@ -2563,7 +2563,7 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
}
#endif
switch (ev->error_code) {
switch (error_code) {
CASESTRRET2(BadAccess);
CASESTRRET2(BadAlloc);
CASESTRRET2(BadAtom);
@ -2588,17 +2588,32 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
print_timestamp(ps);
{
char buf[BUF_LEN] = "";
XGetErrorText(ps->dpy, ev->error_code, buf, BUF_LEN);
XGetErrorText(ps->dpy, error_code, buf, BUF_LEN);
printf("error %4d %-12s request %4d minor %4d serial %6lu: \"%s\"\n",
ev->error_code, name, ev->request_code,
ev->minor_code, ev->serial, buf);
error_code, name, major,
minor, serial, buf);
}
// print_backtrace();
}
/**
* Xlib error handler function.
*/
static int
xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
xerror_common(ev->serial, ev->request_code, ev->minor_code, ev->error_code);
return 0;
}
/**
* XCB error handler function.
*/
inline static void
ev_xcb_error(session_t __attribute__((unused)) *ps, xcb_generic_error_t *err) {
xerror_common(err->sequence, err->major_code, err->minor_code, err->error_code);
}
static void
expose_root(session_t *ps, XRectangle *rects, int nrects) {
free_all_damage_last(ps);
@ -3268,6 +3283,9 @@ 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;
default:
if (ps->shape_exists && ev->response_type == ps->shape_event) {
ev_shape_notify(ps, (xcb_shape_notify_event_t *) ev);