summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common.h15
-rw-r--r--compton.c189
-rw-r--r--compton.h11
-rw-r--r--dbus.c1
4 files changed, 158 insertions, 58 deletions
diff --git a/common.h b/common.h
index f90cba714..ea95235ae 100644
--- a/common.h
+++ b/common.h
@@ -464,6 +464,11 @@ typedef struct {
/// Whether to unredirect all windows if a full-screen opaque window
/// is detected.
bool unredir_if_possible;
+ /// List of conditions of windows to ignore as a full-screen window
+ /// when determining if a window could be unredirected.
+ c2_lptr_t *unredir_if_possible_blacklist;
+ /// Delay before unredirecting screen.
+ time_ms_t unredir_if_possible_delay;
/// Forced redirection setting through D-Bus.
switch_t redirected_force;
/// Whether to stop painting. Controlled through D-Bus.
@@ -644,6 +649,10 @@ typedef struct {
int nfds_max;
/// Linked list of all timeouts.
struct _timeout_t *tmout_lst;
+ /// Timeout for delayed unredirection.
+ struct _timeout_t *tmout_unredir;
+ /// Whether we have hit unredirection timeout.
+ bool tmout_unredir_hit;
/// Whether we have received an event in this cycle.
bool ev_received;
/// Whether the program is idling. I.e. no fading, no potential window
@@ -921,6 +930,8 @@ typedef struct _win {
bool to_paint;
/// Whether the window is painting excluded.
bool paint_excluded;
+ /// Whether the window is unredirect-if-possible excluded.
+ bool unredir_if_possible_excluded;
/// Whether this window is in open/close state.
bool in_openclose;
@@ -962,6 +973,7 @@ typedef struct _win {
const c2_lptr_t *cache_bbblst;
const c2_lptr_t *cache_oparule;
const c2_lptr_t *cache_pblst;
+ const c2_lptr_t *cache_uipblst;
// Opacity-related members
/// Current window opacity.
@@ -1527,6 +1539,9 @@ timeout_invoke(session_t *ps, timeout_t *ptmout);
bool
timeout_drop(session_t *ps, timeout_t *prm);
+void
+timeout_reset(session_t *ps, timeout_t *ptmout);
+
/**
* Add a file descriptor to a select() fd_set.
*/
diff --git a/compton.c b/compton.c
index ae39e2417..b8f1fc6d5 100644
--- a/compton.c
+++ b/compton.c
@@ -1075,13 +1075,7 @@ get_alpha_pict_o(session_t *ps, opacity_t o) {
static win *
paint_preprocess(session_t *ps, win *list) {
- // Initialize unredir_possible
- bool unredir_possible = false;
-
- win *w;
win *t = NULL, *next = NULL;
- // Trace whether it's the highest window to paint
- bool is_highest = true;
// Fading step calculation
time_ms_t steps = 0L;
@@ -1097,7 +1091,10 @@ paint_preprocess(session_t *ps, win *list) {
XserverRegion last_reg_ignore = None;
- for (w = list; w; w = next) {
+ bool unredir_possible = false;
+ // Trace whether it's the highest window to paint
+ bool is_highest = true;
+ for (win *w = list; w; w = next) {
bool to_paint = true;
const winmode_t mode_old = w->mode;
@@ -1229,12 +1226,17 @@ paint_preprocess(session_t *ps, win *list) {
last_reg_ignore = w->reg_ignore;
+ // (Un)redirect screen
+ // We could definitely unredirect the screen when there's no window to
+ // paint, but this is typically unnecessary, may cause flickering when
+ // fading is enabled, and could create inconsistency when the wallpaper
+ // is not correctly set.
if (ps->o.unredir_if_possible && is_highest && to_paint) {
is_highest = false;
- // Disable unredirection for multi-screen setups
if (WMODE_SOLID == w->mode
&& (!w->frame_opacity || !win_has_frame(w))
- && win_is_fullscreen(ps, w))
+ && win_is_fullscreen(ps, w)
+ && !w->unredir_if_possible_excluded)
unredir_possible = true;
}
@@ -1242,7 +1244,6 @@ paint_preprocess(session_t *ps, win *list) {
w->flags = 0;
}
-
// Avoid setting w->to_paint if w is to be freed
bool destroyed = (w->opacity_tgt == w->opacity && w->destroyed);
@@ -1258,14 +1259,25 @@ paint_preprocess(session_t *ps, win *list) {
w->to_paint = to_paint;
}
+
// If possible, unredirect all windows and stop painting
if (UNSET != ps->o.redirected_force)
unredir_possible = !ps->o.redirected_force;
- if (unredir_possible)
- redir_stop(ps);
- else
+ if (unredir_possible) {
+ if (ps->redirected) {
+ if (!ps->o.unredir_if_possible_delay || ps->tmout_unredir_hit)
+ redir_stop(ps);
+ else if (!ps->tmout_unredir->enabled) {
+ timeout_reset(ps, ps->tmout_unredir);
+ ps->tmout_unredir->enabled = true;
+ }
+ }
+ }
+ else {
+ ps->tmout_unredir->enabled = false;
redir_start(ps);
+ }
return t;
}
@@ -1691,7 +1703,6 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
#ifdef DEBUG_REPAINT
static struct timespec last_paint = { 0 };
#endif
- win *w = NULL;
XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None;
#ifdef CONFIG_VSYNC_OPENGL
@@ -1771,7 +1782,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
reg_tmp = XFixesCreateRegion(ps->dpy, NULL, 0);
reg_tmp2 = XFixesCreateRegion(ps->dpy, NULL, 0);
- for (w = t; w; w = w->prev_trans) {
+ for (win *w = t; w; w = w->prev_trans) {
// Painting shadow
if (w->shadow) {
// Shadow is to be painted based on the ignore region of current
@@ -1953,7 +1964,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
printf("[ %5ld:%09ld ] ", diff.tv_sec, diff.tv_nsec);
last_paint = now;
printf("paint:");
- for (w = t; w; w = w->prev_trans)
+ for (win *w = t; w; w = w->prev_trans)
printf(" %#010lx", w->id);
putchar('\n');
fflush(stdout);
@@ -1962,7 +1973,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
// Check if fading is finished on all painted windows
{
win *pprev = NULL;
- for (w = t; w; w = pprev) {
+ for (win *w = t; w; w = pprev) {
pprev = w->prev_trans;
check_fade_fin(ps, w);
}
@@ -1971,6 +1982,11 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
static void
add_damage(session_t *ps, XserverRegion damage) {
+ // Ignore damage when screen isn't redirected
+ if (!ps->redirected)
+ free_region(ps, &damage);
+
+ if (!damage) return;
if (ps->all_damage) {
XFixesUnionRegion(ps->dpy, ps->all_damage, ps->all_damage, damage);
XFixesDestroyRegion(ps->dpy, damage);
@@ -1999,13 +2015,18 @@ repair_win(session_t *ps, win *w) {
w->a.y + w->a.border_width);
}
+ w->damaged = true;
+ w->pixmap_damaged = true;
+
+ // Why care about damage when screen is unredirected?
+ // We will force full-screen repaint on redirection.
+ if (!ps->redirected) return;
+
// Remove the part in the damage area that could be ignored
if (!ps->reg_ignore_expire && w->prev_trans && w->prev_trans->reg_ignore)
XFixesSubtractRegion(ps->dpy, parts, parts, w->prev_trans->reg_ignore);
add_damage(ps, parts);
- w->damaged = true;
- w->pixmap_damaged = true;
}
static wintype_t
@@ -2507,6 +2528,9 @@ win_on_factor_change(session_t *ps, win *w) {
if (ps->o.paint_blacklist)
w->paint_excluded = win_match(ps, w, ps->o.paint_blacklist,
&w->cache_pblst);
+ if (ps->o.unredir_if_possible_blacklist)
+ w->unredir_if_possible_excluded = win_match(ps, w,
+ ps->o.unredir_if_possible_blacklist, &w->cache_uipblst);
}
/**
@@ -3677,9 +3701,8 @@ ev_name(session_t *ps, XEvent *ev) {
CASESTRRET(PropertyNotify);
CASESTRRET(ClientMessage);
default:
- if (ev->type == ps->damage_event + XDamageNotify) {
+ if (isdamagenotify(ps, ev))
return "Damage";
- }
if (ps->shape_exists && ev->type == ps->shape_event) {
return "ShapeNotify";
@@ -3718,7 +3741,7 @@ ev_window(session_t *ps, XEvent *ev) {
case ClientMessage:
return ev->xclient.window;
default:
- if (ev->type == ps->damage_event + XDamageNotify) {
+ if (isdamagenotify(ps, ev)) {
return ((XDamageNotifyEvent *)ev)->drawable;
}
@@ -4166,7 +4189,7 @@ ev_handle(session_t *ps, XEvent *ev) {
}
#ifdef DEBUG_EVENTS
- if (ev->type != ps->damage_event + XDamageNotify) {
+ if (!isdamagenotify(ps, ev)) {
Window wid = ev_window(ps, ev);
char *window_name = NULL;
bool to_free = false;
@@ -4228,10 +4251,10 @@ ev_handle(session_t *ps, XEvent *ev) {
ev_screen_change_notify(ps, (XRRScreenChangeNotifyEvent *) ev);
break;
}
- if (ev->type == ps->damage_event + XDamageNotify) {
- ev_damage_notify(ps, (XDamageNotifyEvent *)ev);
+ if (isdamagenotify(ps, ev)) {
+ ev_damage_notify(ps, (XDamageNotifyEvent *) ev);
+ break;
}
- break;
}
}
@@ -4376,6 +4399,12 @@ usage(int ret) {
"--unredir-if-possible\n"
" Unredirect all windows if a full-screen opaque window is\n"
" detected, to maximize performance for full-screen windows.\n"
+ "--unredir-if-possible-delay ms\n"
+ " Delay before unredirecting the window, in milliseconds.\n"
+ " Defaults to 0.\n"
+ "--unredir-if-possible-exclude condition\n"
+ " Conditions of windows that shouldn't be considered full-screen\n"
+ " for unredirecting screen.\n"
"--focus-exclude condition\n"
" Specify a list of conditions of windows that should always be\n"
" considered focused.\n"
@@ -4603,6 +4632,27 @@ fork_after(session_t *ps) {
}
/**
+ * Parse a long number.
+ */
+static inline bool
+parse_long(const char *s, long *dest) {
+ const char *endptr = NULL;
+ long val = strtol(s, (char **) &endptr, 0);
+ if (!endptr || endptr == s) {
+ printf_errf("(\"%s\"): Invalid number.", s);
+ return false;
+ }
+ while (isspace(*endptr))
+ ++endptr;
+ if (*endptr) {
+ printf_errf("(\"%s\"): Trailing characters.", s);
+ return false;
+ }
+ *dest = val;
+ return true;
+}
+
+/**
* Parse a floating-point number in matrix.
*/
static inline const char *
@@ -5288,6 +5338,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "shadow-exclude-reg", required_argument, NULL, 305 },
{ "paint-exclude", required_argument, NULL, 306 },
{ "xinerama-shadow-crop", no_argument, NULL, 307 },
+ { "unredir-if-possible-exclude", required_argument, NULL, 308 },
+ { "unredir-if-possible-delay", required_argument, NULL, 309 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
@@ -5344,17 +5396,22 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
optind = 1;
while (-1 !=
(o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
+ long val = 0;
switch (o) {
#define P_CASEBOOL(idx, option) case idx: ps->o.option = true; break
+#define P_CASELONG(idx, option) \
+ case idx: \
+ if (!parse_long(optarg, &val)) exit(1); \
+ ps->o.option = val; \
+ break
+
// Short options
case 'h':
usage(0);
break;
case 'd':
break;
- case 'D':
- ps->o.fade_delta = atoi(optarg);
- break;
+ P_CASELONG('D', fade_delta);
case 'I':
ps->o.fade_in_step = normalize_d(atof(optarg)) * OPAQUE;
break;
@@ -5378,18 +5435,12 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
fading_enable = true;
break;
P_CASEBOOL('S', synchronize);
- case 'r':
- ps->o.shadow_radius = atoi(optarg);
- break;
+ P_CASELONG('r', shadow_radius);
case 'o':
ps->o.shadow_opacity = atof(optarg);
break;
- case 'l':
- ps->o.shadow_offset_x = atoi(optarg);
- break;
- case 't':
- ps->o.shadow_offset_y = atoi(optarg);
- break;
+ P_CASELONG('l', shadow_offset_x);
+ P_CASELONG('t', shadow_offset_y);
case 'i':
ps->o.inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE);
break;
@@ -5434,10 +5485,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
P_CASEBOOL(266, shadow_ignore_shaped);
P_CASEBOOL(267, detect_rounded_corners);
P_CASEBOOL(268, detect_client_opacity);
- case 269:
- // --refresh-rate
- ps->o.refresh_rate = atoi(optarg);
- break;
+ P_CASELONG(269, refresh_rate);
case 270:
// --vsync
if (!parse_vsync(ps, optarg))
@@ -5484,10 +5532,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
break;
P_CASEBOOL(291, glx_no_stencil);
P_CASEBOOL(292, glx_copy_from_front);
- case 293:
- // --benchmark
- ps->o.benchmark = atoi(optarg);
- break;
+ P_CASELONG(293, benchmark);
case 294:
// --benchmark-wid
ps->o.benchmark_wid = strtol(optarg, NULL, 0);
@@ -5516,10 +5561,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
if (!parse_conv_kern_lst(ps, optarg, ps->o.blur_kerns, MAX_BLUR_PASS))
exit(1);
break;
- case 302:
- // --resize-damage
- ps->o.resize_damage = atoi(optarg);
- break;
+ P_CASELONG(302, resize_damage);
P_CASEBOOL(303, glx_use_gpushader4);
case 304:
// --opacity-rule
@@ -5536,6 +5578,11 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
condlst_add(ps, &ps->o.paint_blacklist, optarg);
break;
P_CASEBOOL(307, xinerama_shadow_crop);
+ case 308:
+ // --unredir-if-possible-exclude
+ condlst_add(ps, &ps->o.unredir_if_possible_blacklist, optarg);
+ break;
+ P_CASELONG(309, unredir_if_possible_delay);
default:
usage(1);
break;
@@ -5583,10 +5630,6 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
if (ps->o.blur_background_frame)
ps->o.blur_background = true;
- // Free background blur blacklist if background blur is not actually enabled
- if (!ps->o.blur_background)
- free_wincondlst(&ps->o.blur_background_blacklist);
-
// Other variables determined by options
// Determine whether we need to track focus changes
@@ -6110,7 +6153,8 @@ static void
redir_start(session_t *ps) {
if (!ps->redirected) {
#ifdef DEBUG_REDIR
- printf("redir_start(): Screen redirected.\n");
+ print_timestamp(ps);
+ printf_dbgf("(): Screen redirected.\n");
#endif
// Map overlay window. Done firstly according to this:
@@ -6133,6 +6177,9 @@ redir_start(session_t *ps) {
XSync(ps->dpy, False);
ps->redirected = true;
+
+ // Repaint the whole screen
+ force_repaint(ps);
}
}
@@ -6273,13 +6320,22 @@ timeout_invoke(session_t *ps, timeout_t *ptmout) {
}
/**
+ * Reset a timeout to initial state.
+ */
+void
+timeout_reset(session_t *ps, timeout_t *ptmout) {
+ ptmout->firstrun = ptmout->lastrun = get_time_ms();
+}
+
+/**
* Unredirect all windows.
*/
static void
redir_stop(session_t *ps) {
if (ps->redirected) {
#ifdef DEBUG_REDIR
- printf("redir_stop(): Screen unredirected.\n");
+ print_timestamp(ps);
+ printf_dbgf("(): Screen unredirected.\n");
#endif
// Destroy all Pictures as they expire once windows are unredirected
// If we don't destroy them here, looks like the resources are just
@@ -6300,6 +6356,17 @@ redir_stop(session_t *ps) {
}
/**
+ * Unredirection timeout callback.
+ */
+static bool
+tmout_unredir_callback(session_t *ps, timeout_t *tmout) {
+ ps->tmout_unredir_hit = true;
+ tmout->enabled = false;
+
+ return true;
+}
+
+/**
* Main loop.
*/
static bool
@@ -6452,6 +6519,8 @@ session_init(session_t *ps_old, int argc, char **argv) {
.paint_on_overlay = false,
.resize_damage = 0,
.unredir_if_possible = false,
+ .unredir_if_possible_blacklist = NULL,
+ .unredir_if_possible_delay = 0,
.redirected_force = UNSET,
.stoppaint_force = UNSET,
.dbus = false,
@@ -6829,11 +6898,12 @@ session_init(session_t *ps_old, int argc, char **argv) {
}
fds_insert(ps, ConnectionNumber(ps->dpy), POLLIN);
+ ps->tmout_unredir = timeout_insert(ps, ps->o.unredir_if_possible_delay,
+ tmout_unredir_callback, NULL);
+ ps->tmout_unredir->enabled = false;
XGrabServer(ps->dpy);
- redir_start(ps);
-
{
Window root_return, parent_return;
Window *children;
@@ -6942,6 +7012,7 @@ session_destroy(session_t *ps) {
free_wincondlst(&ps->o.blur_background_blacklist);
free_wincondlst(&ps->o.opacity_rules);
free_wincondlst(&ps->o.paint_blacklist);
+ free_wincondlst(&ps->o.unredir_if_possible_blacklist);
#endif
// Free tracked atom list
@@ -7047,6 +7118,7 @@ session_destroy(session_t *ps) {
XSync(ps->dpy, True);
// Free timeouts
+ ps->tmout_unredir = NULL;
timeout_clear(ps);
if (ps == ps_g)
@@ -7101,6 +7173,7 @@ session_run(session_t *ps) {
ps->idling = true;
t = paint_preprocess(ps, ps->list);
+ ps->tmout_unredir_hit = false;
// If the screen is unredirected, free all_damage to stop painting
if (!ps->redirected || ON == ps->o.stoppaint_force)
diff --git a/compton.h b/compton.h
index c66739dd4..d44544633 100644
--- a/compton.h
+++ b/compton.h
@@ -325,6 +325,14 @@ ms_to_tv(int timeout) {
}
/**
+ * Whether an event is DamageNotify.
+ */
+static inline bool
+isdamagenotify(session_t *ps, const XEvent *ev) {
+ return ps->damage_event + XDamageNotify == ev->type;
+}
+
+/**
* Create a XTextProperty of a single string.
*/
static inline XTextProperty *
@@ -1206,6 +1214,9 @@ static void
timeout_clear(session_t *ps);
static bool
+tmout_unredir_callback(session_t *ps, timeout_t *tmout);
+
+static bool
mainloop(session_t *ps);
#ifdef CONFIG_XINERAMA
diff --git a/dbus.c b/dbus.c
index 8f53eeefa..299c5ac0b 100644
--- a/dbus.c
+++ b/dbus.c
@@ -898,6 +898,7 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
+ cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32);
cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum);
cdbus_m_opts_get_do(stoppaint_force, cdbus_reply_enum);
cdbus_m_opts_get_do(logpath, cdbus_reply_string);