Improvement: Add painting on overlay support

- Add support for painting on X Composite overlay window instead of root
  window (--paint-on-overlay). I intended to use this to fix the
  conflict between conky (own-window off) and compton, but it's
  unsuccessful. Will have to ask somebody to figure out how to solve
  this problem.

- Rename a few variables to avoid confusion.

- Slightly change how root window content (wallpaper) change is
  detected.

- Slightly improve window name detection in DEBUG_EVENTS.
This commit is contained in:
Richard Grenville 2012-10-24 10:09:59 +08:00
parent 5dd544d29d
commit 049621bed7
3 changed files with 153 additions and 49 deletions

View File

@ -34,6 +34,7 @@ mark-ovredir-focused = true;
detect-rounded-corners = true; detect-rounded-corners = true;
detect-client-opacity = false; detect-client-opacity = false;
refresh-rate = 0; refresh-rate = 0;
paint-on-overlay = true;
# Window type settings # Window type settings
wintypes: wintypes:

View File

@ -38,12 +38,20 @@ win *list;
Display *dpy = NULL; Display *dpy = NULL;
int scr; int scr;
Window root; /// Root window.
Window root = None;
/// Damage of root window.
Damage root_damage = None;
/// X Composite overlay window. Used if --paint-on-overlay.
Window overlay = None;
/// Picture of root window. Destination of painting in no-DBE painting /// Picture of root window. Destination of painting in no-DBE painting
/// mode. /// mode.
Picture root_picture = None; Picture root_picture = None;
/// A Picture acting as the painting target.
Picture tgt_picture = None;
/// Temporary buffer to paint to before sending to display. /// Temporary buffer to paint to before sending to display.
Picture root_buffer = None; Picture tgt_buffer = None;
/// DBE back buffer for root window. Used in DBE painting mode. /// DBE back buffer for root window. Used in DBE painting mode.
XdbeBackBuffer root_dbe = None; XdbeBackBuffer root_dbe = None;
@ -168,6 +176,7 @@ static options_t opts = {
.fork_after_register = False, .fork_after_register = False,
.synchronize = False, .synchronize = False,
.detect_rounded_corners = False, .detect_rounded_corners = False,
.paint_on_overlay = False,
.refresh_rate = 0, .refresh_rate = 0,
.vsync = VSYNC_NONE, .vsync = VSYNC_NONE,
@ -1105,6 +1114,11 @@ recheck_focus(Display *dpy) {
static Picture static Picture
root_tile_f(Display *dpy) { root_tile_f(Display *dpy) {
/*
if (opts.paint_on_overlay) {
return root_picture;
} */
Picture picture; Picture picture;
Atom actual_type; Atom actual_type;
Pixmap pixmap; Pixmap pixmap;
@ -1165,7 +1179,7 @@ paint_root(Display *dpy) {
XRenderComposite( XRenderComposite(
dpy, PictOpSrc, root_tile, None, dpy, PictOpSrc, root_tile, None,
root_buffer, 0, 0, 0, 0, 0, 0, tgt_buffer, 0, 0, 0, 0, 0, 0,
root_width, root_height); root_width, root_height);
} }
@ -1492,10 +1506,10 @@ paint_preprocess(Display *dpy, win *list) {
* Paint the shadow of a window. * Paint the shadow of a window.
*/ */
static inline void static inline void
win_paint_shadow(Display *dpy, win *w, Picture root_buffer) { win_paint_shadow(Display *dpy, win *w, Picture tgt_buffer) {
XRenderComposite( XRenderComposite(
dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict,
root_buffer, 0, 0, 0, 0, tgt_buffer, 0, 0, 0, 0,
w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height); w->shadow_width, w->shadow_height);
} }
@ -1504,7 +1518,7 @@ win_paint_shadow(Display *dpy, win *w, Picture root_buffer) {
* Paint a window itself and dim it if asked. * Paint a window itself and dim it if asked.
*/ */
static inline void static inline void
win_paint_win(Display *dpy, win *w, Picture root_buffer) { win_paint_win(Display *dpy, win *w, Picture tgt_buffer) {
int x = w->a.x; int x = w->a.x;
int y = w->a.y; int y = w->a.y;
int wid = w->widthb; int wid = w->widthb;
@ -1515,7 +1529,7 @@ win_paint_win(Display *dpy, win *w, Picture root_buffer) {
if (!w->frame_opacity) { if (!w->frame_opacity) {
XRenderComposite(dpy, op, w->picture, alpha_mask, XRenderComposite(dpy, op, w->picture, alpha_mask,
root_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; unsigned int t = w->top_width;
@ -1525,22 +1539,22 @@ win_paint_win(Display *dpy, win *w, Picture root_buffer) {
// top // top
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict,
root_buffer, 0, 0, 0, 0, x, y, wid, t); tgt_buffer, 0, 0, 0, 0, x, y, wid, t);
// left // left
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict,
root_buffer, 0, t, 0, t, x, y + t, l, hei - t); tgt_buffer, 0, t, 0, t, x, y + t, l, hei - t);
// bottom // bottom
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict,
root_buffer, l, hei - b, l, hei - b, x + l, y + hei - b, wid - l - r, b); tgt_buffer, l, hei - b, l, hei - b, x + l, y + hei - b, wid - l - r, b);
// right // right
XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict,
root_buffer, wid - r, t, wid - r, t, x + wid - r, y + t, r, hei - t); tgt_buffer, wid - r, t, wid - r, t, x + wid - r, y + t, r, hei - t);
// body // body
XRenderComposite(dpy, op, w->picture, alpha_mask, root_buffer, XRenderComposite(dpy, op, w->picture, alpha_mask, tgt_buffer,
l, t, l, t, x + l, y + t, wid - l - r, hei - t - b); l, t, l, t, x + l, y + t, wid - l - r, hei - t - b);
} }
@ -1548,7 +1562,7 @@ win_paint_win(Display *dpy, win *w, Picture root_buffer) {
// 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,
root_buffer, 0, 0, 0, 0, x, y, wid, hei); tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
} }
} }
@ -1567,12 +1581,12 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
#ifdef MONITOR_REPAINT #ifdef MONITOR_REPAINT
// Note: MONITOR_REPAINT cannot work with DBE right now. // Note: MONITOR_REPAINT cannot work with DBE right now.
root_buffer = root_picture; tgt_buffer = tgt_picture;
#else #else
if (!root_buffer) { if (!tgt_buffer) {
// DBE painting mode: Directly paint to a Picture of the back buffer // DBE painting mode: Directly paint to a Picture of the back buffer
if (opts.dbe) { if (opts.dbe) {
root_buffer = XRenderCreatePicture(dpy, root_dbe, tgt_buffer = XRenderCreatePicture(dpy, root_dbe,
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
0, 0); 0, 0);
} }
@ -1583,7 +1597,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
dpy, root, root_width, root_height, dpy, root, root_width, root_height,
DefaultDepth(dpy, scr)); DefaultDepth(dpy, scr));
root_buffer = XRenderCreatePicture(dpy, root_pixmap, tgt_buffer = XRenderCreatePicture(dpy, root_pixmap,
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
0, 0); 0, 0);
@ -1592,12 +1606,12 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
} }
#endif #endif
XFixesSetPictureClipRegion(dpy, root_picture, 0, 0, region); XFixesSetPictureClipRegion(dpy, tgt_picture, 0, 0, region);
#ifdef MONITOR_REPAINT #ifdef MONITOR_REPAINT
XRenderComposite( XRenderComposite(
dpy, PictOpSrc, black_picture, None, dpy, PictOpSrc, black_picture, None,
root_picture, 0, 0, 0, 0, 0, 0, tgt_picture, 0, 0, 0, 0, 0, 0,
root_width, root_height); root_width, root_height);
#endif #endif
@ -1616,7 +1630,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
reg_paint = region; reg_paint = region;
} }
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, reg_paint); XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint);
paint_root(dpy); paint_root(dpy);
@ -1653,9 +1667,9 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
// Detect if the region is empty before painting // Detect if the region is empty before painting
if (region == reg_paint || !is_region_empty(dpy, reg_paint)) { if (region == reg_paint || !is_region_empty(dpy, reg_paint)) {
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, reg_paint); XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint);
win_paint_shadow(dpy, w, root_buffer); win_paint_shadow(dpy, w, tgt_buffer);
} }
} }
@ -1675,10 +1689,10 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
} }
if (!is_region_empty(dpy, reg_paint)) { if (!is_region_empty(dpy, reg_paint)) {
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, reg_paint); XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint);
// Painting the window // Painting the window
win_paint_win(dpy, w, root_buffer); win_paint_win(dpy, w, tgt_buffer);
} }
check_fade_fin(dpy, w); check_fade_fin(dpy, w);
@ -1697,17 +1711,18 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
// DBE painting mode, only need to swap the buffer // DBE painting mode, only need to swap the buffer
if (opts.dbe) { if (opts.dbe) {
XdbeSwapInfo swap_info = { XdbeSwapInfo swap_info = {
.swap_window = root, .swap_window = (opts.paint_on_overlay ? overlay: root),
// Is it safe to use XdbeUndefined? // Is it safe to use XdbeUndefined?
.swap_action = XdbeCopied .swap_action = XdbeCopied
}; };
XdbeSwapBuffers(dpy, &swap_info, 1); XdbeSwapBuffers(dpy, &swap_info, 1);
} }
else if (root_buffer != root_picture) { // No-DBE painting mode
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, None); else if (tgt_buffer != tgt_picture) {
XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, None);
XRenderComposite( XRenderComposite(
dpy, PictOpSrc, root_buffer, None, dpy, PictOpSrc, tgt_buffer, None,
root_picture, 0, 0, 0, 0, tgt_picture, 0, 0, 0, 0,
0, 0, root_width, root_height); 0, 0, root_width, root_height);
} }
} }
@ -2358,9 +2373,9 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
if (!w) { if (!w) {
if (ce->window == root) { if (ce->window == root) {
if (root_buffer) { if (tgt_buffer) {
XRenderFreePicture(dpy, root_buffer); XRenderFreePicture(dpy, tgt_buffer);
root_buffer = None; tgt_buffer = None;
} }
root_width = ce->width; root_width = ce->width;
root_height = ce->height; root_height = ce->height;
@ -2479,8 +2494,33 @@ destroy_win(Display *dpy, Window id, Bool fade) {
} }
} }
static inline void
root_damaged(void) {
if (root_tile) {
XClearArea(dpy, root, 0, 0, 0, 0, True);
// if (root_picture != root_tile) {
XRenderFreePicture(dpy, root_tile);
root_tile = None;
/* }
if (root_damage) {
XserverRegion parts = XFixesCreateRegion(dpy, 0, 0);
XDamageSubtract(dpy, root_damage, None, parts);
add_damage(dpy, parts);
} */
}
// Mark screen damaged if we are painting on overlay
if (opts.paint_on_overlay)
add_damage(dpy, get_screen_region(dpy));
}
static void static void
damage_win(Display *dpy, XDamageNotifyEvent *de) { damage_win(Display *dpy, XDamageNotifyEvent *de) {
/*
if (root == de->drawable) {
root_damaged();
return;
} */
win *w = find_win(dpy, de->drawable); win *w = find_win(dpy, de->drawable);
if (!w) return; if (!w) return;
@ -2979,16 +3019,16 @@ ev_expose(XExposeEvent *ev) {
inline static void inline static void
ev_property_notify(XPropertyEvent *ev) { ev_property_notify(XPropertyEvent *ev) {
int p; // Destroy the root "image" if the wallpaper probably changed
for (p = 0; background_props[p]; p++) { if (root == ev->window) {
if (ev->atom == XInternAtom(dpy, background_props[p], False)) { for (int p = 0; background_props[p]; p++) {
if (root_tile) { if (ev->atom == XInternAtom(dpy, background_props[p], False)) {
XClearArea(dpy, root, 0, 0, 0, 0, True); root_damaged();
XRenderFreePicture(dpy, root_tile);
root_tile = None;
break; break;
} }
} }
// Unconcerned about any other proprties on root window
return;
} }
// If _NET_WM_OPACITY changes // If _NET_WM_OPACITY changes
@ -3093,24 +3133,31 @@ ev_handle(XEvent *ev) {
#ifdef DEBUG_EVENTS #ifdef DEBUG_EVENTS
if (ev->type != damage_event + XDamageNotify) { if (ev->type != damage_event + XDamageNotify) {
Window w; Window wid;
char *window_name; char *window_name;
Bool to_free = False; Bool to_free = False;
w = ev_window(ev); wid = ev_window(ev);
window_name = "(Failed to get title)"; window_name = "(Failed to get title)";
if (w) { if (wid) {
if (root == w) { if (root == wid)
window_name = "(Root window)"; window_name = "(Root window)";
} else { else {
to_free = (Bool) wid_get_name(dpy, w, &window_name); win *w = find_win(dpy, wid);
if (!w)
w = find_toplevel(dpy, wid);
if (w->name)
window_name = w->name;
else
to_free = (Bool) wid_get_name(dpy, wid, &window_name);
} }
} }
print_timestamp(); print_timestamp();
printf("event %10.10s serial %#010x window %#010lx \"%s\"\n", printf("event %10.10s serial %#010x window %#010lx \"%s\"\n",
ev_name(ev), ev_serial(ev), w, window_name); ev_name(ev), ev_serial(ev), wid, window_name);
if (to_free) { if (to_free) {
XFree(window_name); XFree(window_name);
@ -3272,6 +3319,8 @@ usage(void) {
"--dbe\n" "--dbe\n"
" Enable DBE painting mode, intended to use with VSync to\n" " Enable DBE painting mode, intended to use with VSync to\n"
" (hopefully) eliminate tearing.\n" " (hopefully) eliminate tearing.\n"
"--paint-on-overlay\n"
" Painting on X Composite overlay window.\n"
"\n" "\n"
"Format of a condition:\n" "Format of a condition:\n"
"\n" "\n"
@ -3590,6 +3639,8 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) {
lcfg_lookup_int(&cfg, "refresh-rate", &opts.refresh_rate); lcfg_lookup_int(&cfg, "refresh-rate", &opts.refresh_rate);
// --alpha-step // --alpha-step
config_lookup_float(&cfg, "alpha-step", &opts.alpha_step); config_lookup_float(&cfg, "alpha-step", &opts.alpha_step);
// --paint-on-overlay
lcfg_lookup_bool(&cfg, "paint-on-overlay", &opts.paint_on_overlay);
// --shadow-exclude // --shadow-exclude
{ {
config_setting_t *setting = config_setting_t *setting =
@ -3657,6 +3708,7 @@ get_cfg(int argc, char *const *argv) {
{ "vsync", required_argument, NULL, 270 }, { "vsync", required_argument, NULL, 270 },
{ "alpha-step", required_argument, NULL, 271 }, { "alpha-step", required_argument, NULL, 271 },
{ "dbe", no_argument, NULL, 272 }, { "dbe", no_argument, NULL, 272 },
{ "paint-on-overlay", no_argument, NULL, 273 },
// Must terminate with a NULL entry // Must terminate with a NULL entry
{ NULL, 0, NULL, 0 }, { NULL, 0, NULL, 0 },
}; };
@ -3847,6 +3899,10 @@ get_cfg(int argc, char *const *argv) {
// --dbe // --dbe
opts.dbe = True; opts.dbe = True;
break; break;
case 273:
// --paint-on-overlay
opts.paint_on_overlay = True;
break;
default: default:
usage(); usage();
break; break;
@ -4232,7 +4288,8 @@ init_alpha_picts(Display *dpy) {
*/ */
static void static void
init_dbe(void) { init_dbe(void) {
if (!(root_dbe = XdbeAllocateBackBufferName(dpy, root, XdbeCopied))) { if (!(root_dbe = XdbeAllocateBackBufferName(dpy,
(opts.paint_on_overlay ? overlay: root), XdbeCopied))) {
fprintf(stderr, "Failed to create double buffer. Double buffering " fprintf(stderr, "Failed to create double buffer. Double buffering "
"turned off.\n"); "turned off.\n");
opts.dbe = False; opts.dbe = False;
@ -4240,6 +4297,31 @@ init_dbe(void) {
} }
} }
/**
* Initialize X composite overlay window.
*/
static void
init_overlay(void) {
overlay = XCompositeGetOverlayWindow(dpy, root);
if (overlay) {
// Set window region of the overlay window, code stolen from
// compiz-0.8.8
XserverRegion region = XFixesCreateRegion (dpy, NULL, 0);
XFixesSetWindowShapeRegion(dpy, overlay, ShapeBounding, 0, 0, 0);
XFixesSetWindowShapeRegion(dpy, overlay, ShapeInput, 0, 0, region);
XFixesDestroyRegion (dpy, region);
// Retrieve DamageNotify on root window if we are painting on an
// overlay
// root_damage = XDamageCreate(dpy, root, XDamageReportNonEmpty);
}
else {
fprintf(stderr, "Cannot get X Composite overlay window. Falling "
"back to painting on root window.\n");
opts.paint_on_overlay = False;
}
}
int int
main(int argc, char **argv) { main(int argc, char **argv) {
XEvent ev; XEvent ev;
@ -4353,6 +4435,10 @@ main(int argc, char **argv) {
|| (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init())) || (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init()))
opts.vsync = VSYNC_NONE; opts.vsync = VSYNC_NONE;
// Overlay must be initialized before double buffer
if (opts.paint_on_overlay)
init_overlay();
if (opts.dbe) if (opts.dbe)
init_dbe(); init_dbe();
@ -4370,8 +4456,16 @@ main(int argc, char **argv) {
root_height = DisplayHeight(dpy, scr); root_height = DisplayHeight(dpy, scr);
root_picture = XRenderCreatePicture(dpy, root, root_picture = XRenderCreatePicture(dpy, root,
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
CPSubwindowMode, &pa); CPSubwindowMode, &pa);
if (opts.paint_on_overlay) {
tgt_picture = XRenderCreatePicture(dpy, overlay,
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
CPSubwindowMode, &pa);
}
else {
tgt_picture = root_picture;
}
black_picture = solid_picture(dpy, True, 1, 0, 0, 0); black_picture = solid_picture(dpy, True, 1, 0, 0, 0);

View File

@ -307,6 +307,9 @@ typedef struct _options {
Bool fork_after_register; Bool fork_after_register;
/// Whether to detect rounded corners. /// Whether to detect rounded corners.
Bool detect_rounded_corners; Bool detect_rounded_corners;
/// Whether to paint on X Composite overlay window instead of root
/// window.
Bool paint_on_overlay;
/// Whether to work under synchronized mode for debugging. /// Whether to work under synchronized mode for debugging.
Bool synchronize; Bool synchronize;
@ -1159,3 +1162,9 @@ vsync_wait(Display *dpy, struct pollfd *fd, int timeout);
static void static void
init_alpha_picts(Display *dpy); init_alpha_picts(Display *dpy);
static void
init_dbe(void);
static void
init_overlay(void);