Skip to content

Commit

Permalink
Improvement: border_size & ConfigureNotify & VSync changes
Browse files Browse the repository at this point in the history
- Run XSync() before the final paint to catch VBlank better. Stolen from
  Xfwm4 VSync patch.

- Add --vsync-aggressive that sends out the final painting request
  earlier, simulating xfwm4 VSync patch. But this thing does have the
  possibility of breaking VSync, I think...

- Change handling of ConfigureNotify to avoid freeing w->extents and
  w->border_size if possible.

- Change logic in paint_prepreprocess() to use win_get_region() for
  border_size generation instead of border_size() if the window is not
  shaped to try to avoid some BadRegion error messages when a window
  loses its border_size then is unmapped, about which Adys complained in
  #25.

- Detect if w->border_size is None before using it in various places.
  Practically the effect is pretty limited because
  XFixesCreateRegionFromWindow() usually returns an invalid X ID instead
  of None on error.

- Fix a bug that rounded corner detection could fail if the window size
  is changed by a ConfigureNotify immediately.
  • Loading branch information
richardgv committed Nov 1, 2012
1 parent 35c9e44 commit fb2ca16
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 15 deletions.
72 changes: 58 additions & 14 deletions src/compton.c
Expand Up @@ -181,6 +181,7 @@ static options_t opts = {
.sw_opti = False,
.vsync = VSYNC_NONE,
.dbe = False,
.vsync_aggressive = False,

.wintype_shadow = { False },
.shadow_red = 0.0,
Expand Down Expand Up @@ -1413,11 +1414,20 @@ paint_preprocess(Display *dpy, win *list) {
dpy, draw, format, CPSubwindowMode, &pa);
}

// Fetch bounding region and extents if needed
// Fetch bounding region
if (!w->border_size) {
w->border_size = border_size(dpy, w);
// Build a border_size ourselves if window is not shaped, to avoid
// getting an invalid border_size region from X if the window is
// unmapped/destroyed
if (!w->bounding_shaped) {
w->border_size = win_get_region(dpy, w);
}
else if (IsUnmapped != w->a.map_state) {
w->border_size = border_size(dpy, w);
}
}

// Fetch window extents
if (!w->extents) {
w->extents = win_extents(dpy, w);
// If w->extents does not exist, the previous add_damage_win()
Expand Down Expand Up @@ -1479,8 +1489,9 @@ paint_preprocess(Display *dpy, win *list) {
else
w->reg_ignore = win_get_region_noframe(dpy, w);

XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore,
w->border_size);
if (w->border_size)
XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore,
w->border_size);

if (last_reg_ignore)
XFixesUnionRegion(dpy, w->reg_ignore, w->reg_ignore,
Expand Down Expand Up @@ -1674,7 +1685,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
}
// Clear the shadow here instead of in make_shadow() for saving GPU
// power and handling shaped windows
if (opts.clear_shadow)
if (opts.clear_shadow && w->border_size)
XFixesSubtractRegion(dpy, reg_paint, reg_paint, w->border_size);

// Detect if the region is empty before painting
Expand All @@ -1694,10 +1705,15 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
// Copy the subtracted region to be used for shadow painting in next
// cycle
XFixesCopyRegion(dpy, reg_tmp2, reg_paint);
XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size);

if (w->border_size)
XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size);
}
else {
XFixesIntersectRegion(dpy, reg_paint, region, w->border_size);
if (w->border_size)
XFixesIntersectRegion(dpy, reg_paint, region, w->border_size);
else
reg_paint = region;
}

if (!is_region_empty(dpy, reg_paint)) {
Expand All @@ -1719,8 +1735,17 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
if (!opts.dbe)
XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, None);

// Wait for VBlank
vsync_wait();
if (VSYNC_NONE != opts.vsync) {
// Make sure all previous requests are processed to achieve best
// effect
XSync(dpy, False);
}

// Wait for VBlank. We could do it aggressively (send the painting
// request and XFlush() on VBlank) or conservatively (send the request
// only on VBlank).
if (!opts.vsync_aggressive)
vsync_wait();

// DBE painting mode, only need to swap the buffer
if (opts.dbe) {
Expand All @@ -1739,6 +1764,9 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
0, 0, root_width, root_height);
}

if (opts.vsync_aggressive)
vsync_wait();

XFlush(dpy);

#ifdef DEBUG_REPAINT
Expand Down Expand Up @@ -2127,7 +2155,7 @@ determine_fade(Display *dpy, win *w) {
*/
static void
win_update_shape(Display *dpy, win *w) {
if (shape_exists && (opts.shadow_ignore_shaped /* || opts.clear_shadow */)) {
if (shape_exists) {
// Bool bounding_shaped_old = w->bounding_shaped;

w->bounding_shaped = wid_bounding_shaped(dpy, w->id);
Expand Down Expand Up @@ -2436,6 +2464,13 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
XFixesCopyRegion(dpy, damage, w->extents);
}

// If window geometry did not change, don't free extents here
if (w->a.x != ce->x || w->a.y != ce->y
|| w->a.width != ce->width || w->a.height != ce->height) {
free_region(dpy, &w->extents);
free_region(dpy, &w->border_size);
}

w->a.x = ce->x;
w->a.y = ce->y;

Expand All @@ -2450,6 +2485,11 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
w->a.height = ce->height;
w->a.border_width = ce->border_width;
calc_win_size(dpy, w);

// Rounded corner detection is affected by window size
if (shape_exists && opts.shadow_ignore_shaped
&& opts.detect_rounded_corners && w->bounding_shaped)
win_update_shape(dpy, w);
}

if (w->a.map_state != IsUnmapped && damage) {
Expand All @@ -2458,10 +2498,6 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
XFixesDestroyRegion(dpy, extents);
add_damage(dpy, damage);
}

// Window extents and border_size may have changed
free_region(dpy, &w->extents);
free_region(dpy, &w->border_size);
}

w->a.override_redirect = ce->override_redirect;
Expand Down Expand Up @@ -3307,6 +3343,9 @@ usage(void) {
"--sw-opti\n"
" Limit compton to repaint at most once every 1 / refresh_rate\n"
" second to boost performance. Experimental.\n"
"--vsync-aggressive\n"
" Attempt to send painting request before VBlank and do XFlush()\n"
" during VBlank. This switch may be lifted out at any moment.\n"
"\n"
"Format of a condition:\n"
"\n"
Expand Down Expand Up @@ -3727,6 +3766,7 @@ get_cfg(int argc, char *const *argv) {
{ "dbe", no_argument, NULL, 272 },
{ "paint-on-overlay", no_argument, NULL, 273 },
{ "sw-opti", no_argument, NULL, 274 },
{ "vsync-aggressive", no_argument, NULL, 275 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
Expand Down Expand Up @@ -3909,6 +3949,10 @@ get_cfg(int argc, char *const *argv) {
// --sw-opti
opts.sw_opti = True;
break;
case 275:
// --vsync-aggressive
opts.vsync_aggressive = True;
break;
default:
usage();
break;
Expand Down
6 changes: 5 additions & 1 deletion src/compton.h
Expand Up @@ -115,6 +115,8 @@ extern struct timeval time_start;

// Window size is changed
#define WFLAG_SIZE_CHANGE 0x0001
// Window size/position is changed
#define WFLAG_POS_CHANGE 0x0002

/**
* Types
Expand Down Expand Up @@ -280,7 +282,7 @@ typedef struct _win {
struct _win *prev_trans;
} win;

typedef enum _vsync_t {
typedef enum {
VSYNC_NONE,
VSYNC_DRM,
VSYNC_OPENGL,
Expand Down Expand Up @@ -317,6 +319,8 @@ typedef struct _options {
vsync_t vsync;
/// Whether to enable double buffer.
Bool dbe;
/// Whether to do VSync aggressively.
Bool vsync_aggressive;

// Shadow
Bool wintype_shadow[NUM_WINTYPES];
Expand Down

0 comments on commit fb2ca16

Please sign in to comment.