From f5aed89a67b2e43110cf93a2c4deca5de197d2a6 Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Tue, 11 Sep 2012 21:33:03 +0800 Subject: [PATCH] Bug fix: Issue #36: Chromium window painting problems More descriptions on issue #36. - Listens ShapeNotify event to get around the Chromium window painting issues. - Adds dependency on X Shape extension. - Adds a few functions for convenience, so a bit code clean up. - Better event debug support, adds restack_win() debug. --- Makefile | 2 +- README.md | 1 + src/compton.c | 229 ++++++++++++++++++++++++++++++++++++++++++++------ src/compton.h | 39 +++++++++ 4 files changed, 246 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index b0c9d5e..60a5c7a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man/man1 -PACKAGES = x11 xcomposite xfixes xdamage xrender +PACKAGES = x11 xcomposite xfixes xdamage xrender xext LIBS = $(shell pkg-config --libs $(PACKAGES)) -lm INCS = $(shell pkg-config --cflags $(PACKAGES)) CFLAGS += -Wall diff --git a/README.md b/README.md index 0b4050a..8cea571 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ __R__ for runtime * libxcomposite (B,R) * libxdamage (B,R) * libxfixes (B,R) +* libXext (B,R) * libxrender (B,R) * pkg-config (B) * make (B) diff --git a/src/compton.c b/src/compton.c index 0272615..c3af632 100644 --- a/src/compton.c +++ b/src/compton.c @@ -10,6 +10,10 @@ #include "compton.h" +#if DEBUG_EVENTS +static int window_get_name(Window w, char **name); +#endif + /** * Shared */ @@ -36,6 +40,10 @@ ignore *ignore_head, **ignore_tail = &ignore_head; int xfixes_event, xfixes_error; int damage_event, damage_error; int composite_event, composite_error; +/// Whether X Shape extension exists. +Bool shape_exists = True; +/// Event base number and error base number for X Shape extension. +int shape_event, shape_error; int render_event, render_error; int composite_opcode; @@ -954,12 +962,7 @@ paint_all(Display *dpy, XserverRegion region) { win *t = 0; if (!region) { - XRectangle r; - r.x = 0; - r.y = 0; - r.width = root_width; - r.height = root_height; - region = XFixesCreateRegion(dpy, &r, 1); + region = get_screen_region(dpy); } #if MONITOR_REPAINT @@ -1029,11 +1032,7 @@ paint_all(Display *dpy, XserverRegion region) { #endif if (clip_changed) { - if (w->border_size) { - set_ignore(dpy, NextRequest(dpy)); - XFixesDestroyRegion(dpy, w->border_size); - w->border_size = None; - } + win_free_border_size(dpy, w); if (w->extents) { XFixesDestroyRegion(dpy, w->extents); w->extents = None; @@ -1376,6 +1375,10 @@ map_win(Display *dpy, Window id, so that no property changes are lost */ if (!override_redirect) { XSelectInput(dpy, id, PropertyChangeMask | FocusChangeMask); + // Notify compton when the shape of a window changes + if (shape_exists) { + XShapeSelectInput(dpy, id, ShapeNotifyMask); + } } // this causes problems for inactive transparency @@ -1429,11 +1432,7 @@ finish_unmap_win(Display *dpy, win *w) { w->picture = None; } - if (w->border_size) { - set_ignore(dpy, NextRequest(dpy)); - XFixesDestroyRegion(dpy, w->border_size); - w->border_size = None; - } + win_free_border_size(dpy, w); if (w->shadow) { XRenderFreePicture(dpy, w->shadow); @@ -1696,6 +1695,33 @@ restack_win(Display *dpy, win *w, Window new_above) { w->next = *prev; *prev = w; + +#if DEBUG_RESTACK + { + const char *desc; + char *window_name; + Bool to_free; + win* c = list; + + printf("restack_win(%#010lx, %#010lx): Window stack modified. Current stack:\n", w->id, new_above); + for (; c; c = c->next) { + window_name = "(Failed to get title)"; + if (root == c->id) + window_name = "(Root window)"; + else + to_free = window_get_name(c->id, &window_name); + desc = ""; + if (c->destroyed) + desc = "(D) "; + printf("%#010lx \"%s\" %s-> ", c->id, window_name, desc); + if (to_free) { + XFree(window_name); + window_name = NULL; + } + } + fputs("\n", stdout); + } +#endif } } @@ -1961,6 +1987,60 @@ error(Display *dpy, XErrorEvent *ev) { break; } + switch (ev->error_code) { + case BadAccess: + name = "BadAccess"; + break; + case BadAlloc: + name = "BadAlloc"; + break; + case BadAtom: + name = "BadAtom"; + break; + case BadColor: + name = "BadColor"; + break; + case BadCursor: + name = "BadCursor"; + break; + case BadDrawable: + name = "BadDrawable"; + break; + case BadFont: + name = "BadFont"; + break; + case BadGC: + name = "BadGC"; + break; + case BadIDChoice: + name = "BadIDChoice"; + break; + case BadImplementation: + name = "BadImplementation"; + break; + case BadLength: + name = "BadLength"; + break; + case BadMatch: + name = "BadMatch"; + break; + case BadName: + name = "BadName"; + break; + case BadPixmap: + name = "BadPixmap"; + break; + case BadRequest: + name = "BadRequest"; + break; + case BadValue: + name = "BadValue"; + break; + case BadWindow: + name = "BadWindow"; + break; + } + printf("error %d (%s) request %d minor %d serial %lu\n", ev->error_code, name, ev->request_code, ev->minor_code, ev->serial); @@ -1974,10 +2054,36 @@ expose_root(Display *dpy, Window root, XRectangle *rects, int nrects) { add_damage(dpy, region); } -#if DEBUG_EVENTS +#if DEBUG_EVENTS || DEBUG_RESTACK +static int window_get_name(Window w, char **name) { + Atom prop = XInternAtom(dpy, "_NET_WM_NAME", False); + Atom utf8_type = XInternAtom(dpy, "UTF8_STRING", False); + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long leftover; + char *data = NULL; + Status ret; + + set_ignore(dpy, NextRequest(dpy)); + if (Success != (ret = XGetWindowProperty(dpy, w, prop, 0L, (long) BUFSIZ, + False, utf8_type, &actual_type, &actual_format, &nitems, + &leftover, (unsigned char **) &data))) { + if (BadWindow == ret) + return 0; + set_ignore(dpy, NextRequest(dpy)); + printf("Window %#010lx: _NET_WM_NAME unset, falling back to WM_NAME.\n", w); + if (!XFetchName(dpy, w, &data)) + return 0; + } + // if (actual_type == utf8_type && actual_format == 8) + *name = (char *) data; + return 1; +} + static int ev_serial(XEvent *ev) { - if (ev->type & 0x7f != KeymapNotify) { + if ((ev->type & 0x7f) != KeymapNotify) { return ev->xany.serial; } return NextRequest(ev->xany.display); @@ -1987,8 +2093,16 @@ static char * ev_name(XEvent *ev) { static char buf[128]; switch (ev->type & 0x7f) { - case Expose: - return "Expose"; + case FocusIn: + return "FocusIn"; + case FocusOut: + return "FocusOut"; + case CreateNotify: + return "CreateNotify"; + case ConfigureNotify: + return "ConfigureNotify"; + case DestroyNotify: + return "DestroyNotify"; case MapNotify: return "Map"; case UnmapNotify: @@ -1997,10 +2111,16 @@ ev_name(XEvent *ev) { return "Reparent"; case CirculateNotify: return "Circulate"; + case Expose: + return "Expose"; + case PropertyNotify: + return "PropertyNotify"; default: if (ev->type == damage_event + XDamageNotify) { return "Damage"; } + if (shape_exists && ev->type == shape_event) + return "ShapeNotify"; sprintf(buf, "Event %d", ev->type); return buf; } @@ -2009,8 +2129,13 @@ ev_name(XEvent *ev) { static Window ev_window(XEvent *ev) { switch (ev->type) { - case Expose: - return ev->xexpose.window; + case FocusIn: + case FocusOut: + return ev->xfocus.window; + case CreateNotify: + return ev->xcreatewindow.window; + case ConfigureNotify: + return ev->xconfigure.window; case MapNotify: return ev->xmap.window; case UnmapNotify: @@ -2019,10 +2144,16 @@ ev_window(XEvent *ev) { return ev->xreparent.window; case CirculateNotify: return ev->xcirculate.window; + case Expose: + return ev->xexpose.window; + case PropertyNotify: + return ev->xproperty.window; default: if (ev->type == damage_event + XDamageNotify) { return ((XDamageNotifyEvent *)ev)->drawable; } + if (shape_exists && ev->type == shape_event) + return ((XShapeEvent *) ev)->window; return 0; } } @@ -2068,6 +2199,9 @@ ev_create_notify(XCreateWindowEvent *ev) { inline static void ev_configure_notify(XConfigureEvent *ev) { +#if DEBUG_EVENTS + printf("{ send_event: %d, above: %#010lx, override_redirect: %d }\n", ev->send_event, ev->above, ev->override_redirect); +#endif configure_win(dpy, ev); } @@ -2168,16 +2302,56 @@ ev_damage_notify(XDamageNotifyEvent *ev) { damage_win(dpy, ev); } +static void ev_shape_notify(XShapeEvent *ev) { + win *w = find_win(dpy, ev->window); + + /* + * Empty border_size may indicated an + * unmapped/destroyed window, in which case + * seemingly BadRegion errors would be triggered + * if we attempt to rebuild border_size + */ + if (w->border_size) { + // Mark the old border_size as damaged + add_damage(dpy, w->border_size); + + w->border_size = border_size(dpy, w); + + // Mark the new border_size as damaged + add_damage(dpy, copy_region(dpy, w->border_size)); + } + +} + inline static void ev_handle(XEvent *ev) { + +#if DEBUG_EVENTS + Window w; + char *window_name; + Bool to_free = False; +#endif + if ((ev->type & 0x7f) != KeymapNotify) { discard_ignore(dpy, ev->xany.serial); } #if DEBUG_EVENTS + w = ev_window(ev); + window_name = "(Failed to get title)"; + if (w) { + if (root == w) + window_name = "(Root window)"; + else + to_free = (Bool) window_get_name(w, &window_name); + } if (ev->type != damage_event + XDamageNotify) { - printf("event %10.10s serial 0x%08x window 0x%08x\n", - ev_name(ev), ev_serial(ev), ev_window(ev)); + printf("event %10.10s serial %#010x window %#010lx \"%s\"\n", + ev_name(ev), ev_serial(ev), w, window_name); + } + if (to_free) { + XFree(window_name); + window_name = NULL; } #endif @@ -2216,6 +2390,10 @@ ev_handle(XEvent *ev) { ev_property_notify((XPropertyEvent *)ev); break; default: + if (shape_exists && ev->type == shape_event) { + ev_shape_notify((XShapeEvent *) ev); + break; + } if (ev->type == damage_event + XDamageNotify) { ev_damage_notify((XDamageNotifyEvent *)ev); } @@ -2528,6 +2706,9 @@ main(int argc, char **argv) { exit(1); } + if (!XShapeQueryExtension(dpy, &shape_event, &shape_error)) + shape_exists = False; + register_cm(scr); if (fork_after_register) fork_after(); diff --git a/src/compton.h b/src/compton.h index 18e3859..6f30391 100644 --- a/src/compton.h +++ b/src/compton.h @@ -20,6 +20,7 @@ #include #include #include +#include #if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2 #define HAS_NAME_WINDOW_PIXMAP 1 @@ -28,6 +29,7 @@ #define CAN_DO_USABLE 0 #define DEBUG_REPAINT 0 #define DEBUG_EVENTS 0 +#define DEBUG_RESTACK 0 #define DEBUG_WINTYPE 0 #define MONITOR_REPAINT 0 @@ -124,6 +126,7 @@ typedef struct _fade { Display *dpy; } fade; +extern int root_height, root_width; /** * Functions */ @@ -345,6 +348,42 @@ ev_property_notify(XPropertyEvent *ev); inline static void ev_damage_notify(XDamageNotifyEvent *ev); +/** + * Destory the cached border_size of a window. + */ +inline static void win_free_border_size(Display *dpy, win *w) { + if (w->border_size) { + set_ignore(dpy, NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->border_size); + w->border_size = None; + } +} + +/** + * Get a region of the screen size. + */ +inline static XserverRegion get_screen_region(Display *dpy) { + XRectangle r; + + r.x = 0; + r.y = 0; + r.width = root_width; + r.height = root_height; + return XFixesCreateRegion(dpy, &r, 1); +} + +/** + * Copies a region + */ +inline static XserverRegion copy_region(Display *dpy, + XserverRegion oldregion) { + XserverRegion region = XFixesCreateRegion(dpy, NULL, 0); + + XFixesCopyRegion(dpy, region, oldregion); + + return region; +} + inline static void ev_handle(XEvent *ev);