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.
This commit is contained in:
parent
8628371a83
commit
f5aed89a67
2
Makefile
2
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
|
||||
|
|
|
@ -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)
|
||||
|
|
229
src/compton.c
229
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();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <X11/extensions/Xcomposite.h>
|
||||
#include <X11/extensions/Xdamage.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue