Bug fix #17: Try to fix artifacts after animating/shading shaped wins in Openbox

- Correct design mistakes in win_get_region_noframe(). I must be
  sleepwalking when I wrote that thing!

- Intersect border_size with window region rectangle because Openbox is
  offering wrong window shapes larger than the window rectangle for shaped
  windows. Shame on you, Openbox.

- Change logic in reg_ignore calculation as border_size is now
  intersected with window rectangle and we don't need to do this here
  again.

- Rewrite window painting with frame opacity part in win_paint_win() to
  deal with absurd frame widths WM offers. Again, Openbox, this is your
  fault.

- As I'm in a pretty bad state (continuously working on compton for 10+
  hours without rest...), all these changes are not well tested, and
  bugs are to be expected.
This commit is contained in:
Richard Grenville 2012-11-01 19:03:56 +08:00
parent 46dfd1a766
commit 66d3f30978
1 changed files with 90 additions and 47 deletions

View File

@ -1194,12 +1194,15 @@ static XserverRegion
win_get_region_noframe(Display *dpy, win *w) { win_get_region_noframe(Display *dpy, win *w) {
XRectangle r; XRectangle r;
r.x = w->a.x + w->left_width; r.x = w->a.x + w->a.border_width + w->left_width;
r.y = w->a.y + w->top_width; r.y = w->a.y + w->a.border_width + w->top_width;
r.width = w->a.width; r.width = max_i(w->a.width - w->left_width - w->right_width, 0);
r.height = w->a.height; r.height = max_i(w->a.height - w->top_width - w->bottom_width, 0);
return XFixesCreateRegion(dpy, &r, 1); if (r.width > 0 && r.height > 0)
return XFixesCreateRegion(dpy, &r, 1);
else
return XFixesCreateRegion(dpy, NULL, 0);
} }
/** /**
@ -1249,28 +1252,38 @@ win_extents(Display *dpy, win *w) {
static XserverRegion static XserverRegion
border_size(Display *dpy, win *w) { border_size(Display *dpy, win *w) {
XserverRegion border; // Start with the window rectangular region
XserverRegion fin = win_get_region(dpy, w);
/* // Only request for a bounding region if the window is shaped
* if window doesn't exist anymore, this will generate an error if (w->bounding_shaped) {
* as well as not generate a region. Perhaps a better XFixes /*
* architecture would be to have a request that copies instead * if window doesn't exist anymore, this will generate an error
* of creates, that way you'd just end up with an empty region * as well as not generate a region. Perhaps a better XFixes
* instead of an invalid XID. * architecture would be to have a request that copies instead
*/ * of creates, that way you'd just end up with an empty region
* instead of an invalid XID.
*/
border = XFixesCreateRegionFromWindow( XserverRegion border = XFixesCreateRegionFromWindow(
dpy, w->id, WindowRegionBounding); dpy, w->id, WindowRegionBounding);
if (!border) if (!border)
return None; return fin;
/* translate this */ // Translate the region to the correct place
XFixesTranslateRegion(dpy, border, XFixesTranslateRegion(dpy, border,
w->a.x + w->a.border_width, w->a.x + w->a.border_width,
w->a.y + w->a.border_width); w->a.y + w->a.border_width);
return border; // Intersect the bounding region we got with the window rectangle, to
// make sure the bounding region is not bigger than the window
// rectangle
XFixesIntersectRegion(dpy, fin, fin, border);
XFixesDestroyRegion(dpy, border);
}
return fin;
} }
static Window static Window
@ -1484,14 +1497,18 @@ paint_preprocess(Display *dpy, win *list) {
// If the window is solid, we add the window region to the // If the window is solid, we add the window region to the
// ignored region // ignored region
if (WINDOW_SOLID == w->mode) { if (WINDOW_SOLID == w->mode) {
if (!w->frame_opacity) if (!w->frame_opacity) {
w->reg_ignore = win_get_region(dpy, w); if (w->border_size)
else w->reg_ignore = copy_region(dpy, w->border_size);
else
w->reg_ignore = win_get_region(dpy, w);
}
else {
w->reg_ignore = win_get_region_noframe(dpy, w); w->reg_ignore = win_get_region_noframe(dpy, w);
if (w->border_size)
if (w->border_size) XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore,
XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore, w->border_size);
w->border_size); }
if (last_reg_ignore) if (last_reg_ignore)
XFixesUnionRegion(dpy, w->reg_ignore, w->reg_ignore, XFixesUnionRegion(dpy, w->reg_ignore, w->reg_ignore,
@ -1555,33 +1572,59 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) {
tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
} }
else { else {
unsigned int t = w->top_width; int t = w->top_width;
unsigned int l = w->left_width; int l = w->left_width;
unsigned int b = w->bottom_width; int b = w->bottom_width;
unsigned int r = w->right_width; int r = w->right_width;
#define COMP_BDR(cx, cy, cwid, chei) \
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, \
tgt_buffer, (cx), (cy), 0, 0, x + (cx), y + (cy), (cwid), (chei))
// The following complicated logic is requried because some broken
// window managers (I'm talking about you, Openbox!) that makes
// top_width + bottom_width > height in some cases.
// top // top
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, COMP_BDR(0, 0, wid, min_i(t, hei));
tgt_buffer, 0, 0, 0, 0, x, y, wid, t);
// left if (hei > t) {
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, int phei = min_i(hei - t, b);
tgt_buffer, 0, t, 0, t, x, y + t, l, hei - t);
// bottom // bottom
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, if (phei) {
tgt_buffer, l, hei - b, l, hei - b, x + l, y + hei - b, wid - l - r, b); assert(phei > 0);
COMP_BDR(0, hei - phei, wid, phei);
// right phei = hei - t - phei;
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, if (phei) {
tgt_buffer, wid - r, t, wid - r, t, x + wid - r, y + t, r, hei - t); assert(phei > 0);
// left
COMP_BDR(0, t, min_i(l, wid), phei);
// body if (wid > l) {
XRenderComposite(dpy, op, w->picture, alpha_mask, tgt_buffer, int pwid = min_i(wid - l, r);
l, t, l, t, x + l, y + t, wid - l - r, hei - t - b);
if (pwid) {
assert(pwid > 0);
// right
COMP_BDR(wid - pwid, t, pwid, phei);
pwid = wid - l - pwid;
if (pwid)
assert(pwid > 0);
// body
XRenderComposite(dpy, op, w->picture, alpha_mask,
tgt_buffer, l, t, 0, 0, x + l, y + t, pwid, phei);
}
}
}
}
}
} }
#undef COMP_BDR
// Dimming the window if needed // Dimming the window if needed
if (w->dim) { if (w->dim) {
XRenderComposite(dpy, PictOpOver, dim_picture, None, XRenderComposite(dpy, PictOpOver, dim_picture, None,