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,
|
||||
.vsync = VSYNC_NONE,
|
||||
.dbe = False,
|
||||
.vsync_aggressive = False,
|
||||
|
||||
.wintype_shadow = { False },
|
||||
.shadow_red = 0.0,
|
||||
|
@ -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) {
|
||||
// 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()
|
||||
|
@ -1479,6 +1489,7 @@ paint_preprocess(Display *dpy, win *list) {
|
|||
else
|
||||
w->reg_ignore = win_get_region_noframe(dpy, w);
|
||||
|
||||
if (w->border_size)
|
||||
XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore,
|
||||
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
|
||||
// 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
|
||||
|
@ -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);
|
||||
|
||||
if (w->border_size)
|
||||
XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size);
|
||||
}
|
||||
else {
|
||||
if (w->border_size)
|
||||
XFixesIntersectRegion(dpy, reg_paint, region, w->border_size);
|
||||
else
|
||||
reg_paint = region;
|
||||
}
|
||||
|
||||
if (!is_region_empty(dpy, reg_paint)) {
|
||||
|
@ -1719,7 +1735,16 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
|||
if (!opts.dbe)
|
||||
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();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (opts.vsync_aggressive)
|
||||
vsync_wait();
|
||||
|
||||
XFlush(dpy);
|
||||
|
||||
#ifdef DEBUG_REPAINT
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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 },
|
||||
};
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
@ -280,7 +282,7 @@ typedef struct _win {
|
|||
struct _win *prev_trans;
|
||||
} win;
|
||||
|
||||
typedef enum _vsync_t {
|
||||
typedef enum {
|
||||
VSYNC_NONE,
|
||||
VSYNC_DRM,
|
||||
VSYNC_OPENGL,
|
||||
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue