Improvement: border_size & ConfigureNotify & VSync changes
- 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.
This commit is contained in:
parent
35c9e44de2
commit
fb2ca16cb8
|
@ -181,6 +181,7 @@ static options_t opts = {
|
||||||
.sw_opti = False,
|
.sw_opti = False,
|
||||||
.vsync = VSYNC_NONE,
|
.vsync = VSYNC_NONE,
|
||||||
.dbe = False,
|
.dbe = False,
|
||||||
|
.vsync_aggressive = False,
|
||||||
|
|
||||||
.wintype_shadow = { False },
|
.wintype_shadow = { False },
|
||||||
.shadow_red = 0.0,
|
.shadow_red = 0.0,
|
||||||
|
@ -1413,11 +1414,20 @@ paint_preprocess(Display *dpy, win *list) {
|
||||||
dpy, draw, format, CPSubwindowMode, &pa);
|
dpy, draw, format, CPSubwindowMode, &pa);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch bounding region and extents if needed
|
// Fetch bounding region
|
||||||
if (!w->border_size) {
|
if (!w->border_size) {
|
||||||
|
// 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);
|
w->border_size = border_size(dpy, w);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch window extents
|
||||||
if (!w->extents) {
|
if (!w->extents) {
|
||||||
w->extents = win_extents(dpy, w);
|
w->extents = win_extents(dpy, w);
|
||||||
// If w->extents does not exist, the previous add_damage_win()
|
// If w->extents does not exist, the previous add_damage_win()
|
||||||
|
@ -1479,6 +1489,7 @@ paint_preprocess(Display *dpy, win *list) {
|
||||||
else
|
else
|
||||||
w->reg_ignore = win_get_region_noframe(dpy, w);
|
w->reg_ignore = win_get_region_noframe(dpy, w);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
@ -1674,7 +1685,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
}
|
}
|
||||||
// Clear the shadow here instead of in make_shadow() for saving GPU
|
// Clear the shadow here instead of in make_shadow() for saving GPU
|
||||||
// power and handling shaped windows
|
// 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);
|
XFixesSubtractRegion(dpy, reg_paint, reg_paint, w->border_size);
|
||||||
|
|
||||||
// Detect if the region is empty before painting
|
// Detect if the region is empty before painting
|
||||||
|
@ -1694,10 +1705,15 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
// Copy the subtracted region to be used for shadow painting in next
|
// Copy the subtracted region to be used for shadow painting in next
|
||||||
// cycle
|
// cycle
|
||||||
XFixesCopyRegion(dpy, reg_tmp2, reg_paint);
|
XFixesCopyRegion(dpy, reg_tmp2, reg_paint);
|
||||||
|
|
||||||
|
if (w->border_size)
|
||||||
XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size);
|
XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (w->border_size)
|
||||||
XFixesIntersectRegion(dpy, reg_paint, region, w->border_size);
|
XFixesIntersectRegion(dpy, reg_paint, region, w->border_size);
|
||||||
|
else
|
||||||
|
reg_paint = region;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_region_empty(dpy, reg_paint)) {
|
if (!is_region_empty(dpy, reg_paint)) {
|
||||||
|
@ -1719,7 +1735,16 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
if (!opts.dbe)
|
if (!opts.dbe)
|
||||||
XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, None);
|
XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, None);
|
||||||
|
|
||||||
// Wait for VBlank
|
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();
|
vsync_wait();
|
||||||
|
|
||||||
// DBE painting mode, only need to swap the buffer
|
// DBE painting mode, only need to swap the buffer
|
||||||
|
@ -1739,6 +1764,9 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
0, 0, root_width, root_height);
|
0, 0, root_width, root_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts.vsync_aggressive)
|
||||||
|
vsync_wait();
|
||||||
|
|
||||||
XFlush(dpy);
|
XFlush(dpy);
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
#ifdef DEBUG_REPAINT
|
||||||
|
@ -2127,7 +2155,7 @@ determine_fade(Display *dpy, win *w) {
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
win_update_shape(Display *dpy, win *w) {
|
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;
|
// Bool bounding_shaped_old = w->bounding_shaped;
|
||||||
|
|
||||||
w->bounding_shaped = wid_bounding_shaped(dpy, w->id);
|
w->bounding_shaped = wid_bounding_shaped(dpy, w->id);
|
||||||
|
@ -2436,6 +2464,13 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
|
||||||
XFixesCopyRegion(dpy, damage, w->extents);
|
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.x = ce->x;
|
||||||
w->a.y = ce->y;
|
w->a.y = ce->y;
|
||||||
|
|
||||||
|
@ -2450,6 +2485,11 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
|
||||||
w->a.height = ce->height;
|
w->a.height = ce->height;
|
||||||
w->a.border_width = ce->border_width;
|
w->a.border_width = ce->border_width;
|
||||||
calc_win_size(dpy, w);
|
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) {
|
if (w->a.map_state != IsUnmapped && damage) {
|
||||||
|
@ -2458,10 +2498,6 @@ configure_win(Display *dpy, XConfigureEvent *ce) {
|
||||||
XFixesDestroyRegion(dpy, extents);
|
XFixesDestroyRegion(dpy, extents);
|
||||||
add_damage(dpy, damage);
|
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;
|
w->a.override_redirect = ce->override_redirect;
|
||||||
|
@ -3307,6 +3343,9 @@ usage(void) {
|
||||||
"--sw-opti\n"
|
"--sw-opti\n"
|
||||||
" Limit compton to repaint at most once every 1 / refresh_rate\n"
|
" Limit compton to repaint at most once every 1 / refresh_rate\n"
|
||||||
" second to boost performance. Experimental.\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"
|
"\n"
|
||||||
"Format of a condition:\n"
|
"Format of a condition:\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -3727,6 +3766,7 @@ get_cfg(int argc, char *const *argv) {
|
||||||
{ "dbe", no_argument, NULL, 272 },
|
{ "dbe", no_argument, NULL, 272 },
|
||||||
{ "paint-on-overlay", no_argument, NULL, 273 },
|
{ "paint-on-overlay", no_argument, NULL, 273 },
|
||||||
{ "sw-opti", no_argument, NULL, 274 },
|
{ "sw-opti", no_argument, NULL, 274 },
|
||||||
|
{ "vsync-aggressive", no_argument, NULL, 275 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -3909,6 +3949,10 @@ get_cfg(int argc, char *const *argv) {
|
||||||
// --sw-opti
|
// --sw-opti
|
||||||
opts.sw_opti = True;
|
opts.sw_opti = True;
|
||||||
break;
|
break;
|
||||||
|
case 275:
|
||||||
|
// --vsync-aggressive
|
||||||
|
opts.vsync_aggressive = True;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -115,6 +115,8 @@ extern struct timeval time_start;
|
||||||
|
|
||||||
// Window size is changed
|
// Window size is changed
|
||||||
#define WFLAG_SIZE_CHANGE 0x0001
|
#define WFLAG_SIZE_CHANGE 0x0001
|
||||||
|
// Window size/position is changed
|
||||||
|
#define WFLAG_POS_CHANGE 0x0002
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
|
@ -280,7 +282,7 @@ typedef struct _win {
|
||||||
struct _win *prev_trans;
|
struct _win *prev_trans;
|
||||||
} win;
|
} win;
|
||||||
|
|
||||||
typedef enum _vsync_t {
|
typedef enum {
|
||||||
VSYNC_NONE,
|
VSYNC_NONE,
|
||||||
VSYNC_DRM,
|
VSYNC_DRM,
|
||||||
VSYNC_OPENGL,
|
VSYNC_OPENGL,
|
||||||
|
@ -317,6 +319,8 @@ typedef struct _options {
|
||||||
vsync_t vsync;
|
vsync_t vsync;
|
||||||
/// Whether to enable double buffer.
|
/// Whether to enable double buffer.
|
||||||
Bool dbe;
|
Bool dbe;
|
||||||
|
/// Whether to do VSync aggressively.
|
||||||
|
Bool vsync_aggressive;
|
||||||
|
|
||||||
// Shadow
|
// Shadow
|
||||||
Bool wintype_shadow[NUM_WINTYPES];
|
Bool wintype_shadow[NUM_WINTYPES];
|
||||||
|
|
Loading…
Reference in New Issue