Feature #65: --focus-exclude
- Add --focus-exclude, which should be used with a list of conditions to set certain windows to always be considered focused. - Change focus determination process, with a newly added w->focused_real that reflects whether the window is actually focused, while w->focused represents whether compton considers it focused. The primary difference is now when a window considered focused because of --mark-wmwin-focused or --mark-ovredir-focused receives a FocusOut event, it's still considered focused by compton. - Change opacity target and dim state calculation so that it's done at most once every paint. - Split window opacity property fetching from calc_opacity() to a new function win_update_opacity_prop(). - Silence a warning in wid_get_prop_wintype(). - Rename a few functions. Code clean-up. - My time is very limited currently, few tests are done, so this commit may very well introduce bugs. - Known issue: Dim picture opacity does not change based on window opacity, causing somehow annoying effects when a window fades off.
This commit is contained in:
parent
0f851b17a2
commit
72c18b6219
|
@ -40,6 +40,7 @@ dbe = false;
|
|||
paint-on-overlay = false;
|
||||
sw-opti = false;
|
||||
unredir-if-possible = false;
|
||||
focus-exclude = [ ];
|
||||
|
||||
# Window type settings
|
||||
wintypes:
|
||||
|
|
178
src/compton.c
178
src/compton.c
|
@ -948,7 +948,7 @@ recheck_focus(session_t *ps) {
|
|||
|
||||
// And we set the focus state and opacity here
|
||||
if (w) {
|
||||
set_focused(ps, w, true);
|
||||
win_set_focused(ps, w, true);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
@ -1241,6 +1241,12 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
if (ps->reg_ignore_expire)
|
||||
free_region(ps, &w->reg_ignore);
|
||||
|
||||
// Update window opacity target and dim state if asked
|
||||
if (WFLAG_OPCT_CHANGE & w->flags) {
|
||||
calc_opacity(ps, w);
|
||||
calc_dim(ps, w);
|
||||
}
|
||||
|
||||
// Run fading
|
||||
run_fade(ps, w, steps);
|
||||
|
||||
|
@ -1754,13 +1760,13 @@ repair_win(session_t *ps, win *w) {
|
|||
|
||||
static wintype_t
|
||||
wid_get_prop_wintype(session_t *ps, Window wid) {
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
set_ignore_next(ps);
|
||||
winprop_t prop = wid_get_prop(ps, wid, ps->atom_win_type, 32L, XA_ATOM, 32);
|
||||
|
||||
for (i = 0; i < prop.nitems; ++i) {
|
||||
for (j = 1; j < NUM_WINTYPES; ++j) {
|
||||
for (wintype_t j = 1; j < NUM_WINTYPES; ++j) {
|
||||
if (ps->atoms_wintypes[j] == (Atom) prop.data.p32[i]) {
|
||||
free_winprop(&prop);
|
||||
return j;
|
||||
|
@ -1780,9 +1786,10 @@ map_win(session_t *ps, Window id) {
|
|||
// Don't care about window mapping if it's an InputOnly window
|
||||
if (!w || InputOnly == w->a.class) return;
|
||||
|
||||
w->focused = false;
|
||||
if (ps->o.use_ewmh_active_win && w == ps->active_win)
|
||||
w->focused = true;
|
||||
w->focused_real = false;
|
||||
if (ps->o.track_focus && ps->o.use_ewmh_active_win
|
||||
&& w == ps->active_win)
|
||||
w->focused_real = true;
|
||||
|
||||
w->a.map_state = IsViewable;
|
||||
|
||||
|
@ -1841,23 +1848,22 @@ map_win(session_t *ps, Window id) {
|
|||
win_get_class(ps, w);
|
||||
}
|
||||
|
||||
if (ps->o.track_focus) {
|
||||
// Occasionally compton does not seem able to get a FocusIn event from
|
||||
// a window just mapped. I suspect it's a timing issue again when the
|
||||
// XSelectInput() is called too late. We have to recheck the focused
|
||||
// window here. It makes no sense if we are using EWMH
|
||||
// _NET_ACTIVE_WINDOW.
|
||||
if (!ps->o.use_ewmh_active_win)
|
||||
recheck_focus(ps);
|
||||
|
||||
// Consider a window without client window a WM window and mark it
|
||||
// focused if mark_wmwin_focused is on, or it's over-redirected and
|
||||
// mark_ovredir_focused is on
|
||||
if ((ps->o.mark_wmwin_focused && !w->client_win)
|
||||
|| (ps->o.mark_ovredir_focused && w->id == w->client_win))
|
||||
w->focused = true;
|
||||
// Occasionally compton does not seem able to get a FocusIn event from
|
||||
// a window just mapped. I suspect it's a timing issue again when the
|
||||
// XSelectInput() is called too late. We have to recheck the focused
|
||||
// window here. It makes no sense if we are using EWMH
|
||||
// _NET_ACTIVE_WINDOW.
|
||||
if (ps->o.track_focus && !ps->o.use_ewmh_active_win) {
|
||||
recheck_focus(ps);
|
||||
}
|
||||
|
||||
// Update window focus state
|
||||
win_update_focused(ps, w);
|
||||
|
||||
// Update opacity and dim state
|
||||
win_update_opacity_prop(ps, w);
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
|
||||
// Check for _COMPTON_SHADOW
|
||||
if (ps->o.respect_prop_shadow)
|
||||
win_update_attr_shadow_raw(ps, w);
|
||||
|
@ -1865,9 +1871,6 @@ map_win(session_t *ps, Window id) {
|
|||
// Many things above could affect shadow
|
||||
determine_shadow(ps, w);
|
||||
|
||||
// Fading in
|
||||
calc_opacity(ps, w, true);
|
||||
|
||||
// Set fading state
|
||||
if (ps->o.no_fading_openclose) {
|
||||
set_fade_callback(ps, w, finish_map_win, true);
|
||||
|
@ -1880,8 +1883,6 @@ map_win(session_t *ps, Window id) {
|
|||
determine_fade(ps, w);
|
||||
}
|
||||
|
||||
calc_dim(ps, w);
|
||||
|
||||
w->damaged = 1;
|
||||
|
||||
|
||||
|
@ -1931,7 +1932,7 @@ unmap_win(session_t *ps, Window id) {
|
|||
w->a.map_state = IsUnmapped;
|
||||
|
||||
// Fading out
|
||||
w->opacity_tgt = 0;
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
set_fade_callback(ps, w, unmap_callback, false);
|
||||
if (ps->o.no_fading_openclose)
|
||||
w->fade = false;
|
||||
|
@ -2006,35 +2007,23 @@ determine_mode(session_t *ps, win *w) {
|
|||
* refetched
|
||||
*/
|
||||
static void
|
||||
calc_opacity(session_t *ps, win *w, bool refetch_prop) {
|
||||
opacity_t opacity;
|
||||
calc_opacity(session_t *ps, win *w) {
|
||||
opacity_t opacity = OPAQUE;
|
||||
|
||||
// Do nothing for unmapped window, calc_opacity() will be called
|
||||
// when it's mapped
|
||||
// I suppose I need not to check for IsUnviewable here?
|
||||
if (IsViewable != w->a.map_state) return;
|
||||
if (w->destroyed || IsViewable != w->a.map_state)
|
||||
opacity = 0;
|
||||
else {
|
||||
// Try obeying opacity property and window type opacity firstly
|
||||
if (OPAQUE == (opacity = w->opacity_prop)
|
||||
&& OPAQUE == (opacity = w->opacity_prop_client)) {
|
||||
opacity = ps->o.wintype_opacity[w->window_type] * OPAQUE;
|
||||
}
|
||||
|
||||
// Do not refetch the opacity window attribute unless necessary, this
|
||||
// is probably an expensive operation in some cases
|
||||
if (refetch_prop) {
|
||||
w->opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE);
|
||||
if (!ps->o.detect_client_opacity || !w->client_win
|
||||
|| w->id == w->client_win)
|
||||
w->opacity_prop_client = OPAQUE;
|
||||
else
|
||||
w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win,
|
||||
OPAQUE);
|
||||
}
|
||||
|
||||
if (OPAQUE == (opacity = w->opacity_prop)
|
||||
&& OPAQUE == (opacity = w->opacity_prop_client)) {
|
||||
opacity = ps->o.wintype_opacity[w->window_type] * OPAQUE;
|
||||
}
|
||||
|
||||
// Respect inactive_opacity in some cases
|
||||
if (ps->o.inactive_opacity && is_normal_win(w) && false == w->focused
|
||||
&& (OPAQUE == opacity || ps->o.inactive_opacity_override)) {
|
||||
opacity = ps->o.inactive_opacity;
|
||||
// Respect inactive_opacity in some cases
|
||||
if (ps->o.inactive_opacity && is_normal_win(w) && false == w->focused
|
||||
&& (OPAQUE == opacity || ps->o.inactive_opacity_override)) {
|
||||
opacity = ps->o.inactive_opacity;
|
||||
}
|
||||
}
|
||||
|
||||
w->opacity_tgt = opacity;
|
||||
|
@ -2047,6 +2036,10 @@ static void
|
|||
calc_dim(session_t *ps, win *w) {
|
||||
bool dim;
|
||||
|
||||
// Make sure we do nothing if the window is unmapped / destroyed
|
||||
if (w->destroyed || IsViewable != w->a.map_state)
|
||||
return;
|
||||
|
||||
if (ps->o.inactive_dim && is_normal_win(w) && !(w->focused)) {
|
||||
dim = true;
|
||||
} else {
|
||||
|
@ -2273,6 +2266,7 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||
new->class_general = NULL;
|
||||
new->cache_sblst = NULL;
|
||||
new->cache_fblst = NULL;
|
||||
new->cache_fcblst = NULL;
|
||||
new->bounding_shaped = false;
|
||||
new->rounded_corners = false;
|
||||
|
||||
|
@ -2298,6 +2292,7 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||
new->frame_alpha_pict = None;
|
||||
new->dim = false;
|
||||
new->focused = false;
|
||||
new->focused_real = false;
|
||||
new->destroyed = false;
|
||||
new->need_configure = false;
|
||||
new->window_type = WINTYPE_UNKNOWN;
|
||||
|
@ -2517,7 +2512,7 @@ destroy_win(session_t *ps, Window id) {
|
|||
w->destroyed = true;
|
||||
|
||||
// Fading out the window
|
||||
w->opacity_tgt = 0;
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
set_fade_callback(ps, w, destroy_callback, false);
|
||||
}
|
||||
}
|
||||
|
@ -2909,7 +2904,7 @@ ev_focus_in(session_t *ps, XFocusChangeEvent *ev) {
|
|||
// To deal with events sent from windows just destroyed
|
||||
if (!w) return;
|
||||
|
||||
set_focused(ps, w, true);
|
||||
win_set_focused(ps, w, true);
|
||||
}
|
||||
|
||||
inline static void
|
||||
|
@ -2926,7 +2921,7 @@ ev_focus_out(session_t *ps, XFocusChangeEvent *ev) {
|
|||
// To deal with events sent from windows just destroyed
|
||||
if (!w) return;
|
||||
|
||||
set_focused(ps, w, false);
|
||||
win_set_focused(ps, w, false);
|
||||
}
|
||||
|
||||
inline static void
|
||||
|
@ -3039,10 +3034,9 @@ update_ewmh_active_win(session_t *ps) {
|
|||
|
||||
// Mark the window focused
|
||||
if (w) {
|
||||
if (!w->focused)
|
||||
set_focused(ps, w, true);
|
||||
win_set_focused(ps, w, true);
|
||||
if (ps->active_win && w != ps->active_win)
|
||||
set_focused(ps, ps->active_win, false);
|
||||
win_set_focused(ps, ps->active_win, false);
|
||||
ps->active_win = w;
|
||||
}
|
||||
}
|
||||
|
@ -3079,7 +3073,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
|
|||
w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win,
|
||||
OPAQUE);
|
||||
if (w) {
|
||||
calc_opacity(ps, w, false);
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3097,8 +3091,10 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
|
|||
if (ps->o.track_wdata
|
||||
&& (ps->atom_name == ev->atom || ps->atom_name_ewmh == ev->atom)) {
|
||||
win *w = find_toplevel(ps, ev->window);
|
||||
if (w && 1 == win_get_name(ps, w))
|
||||
if (w && 1 == win_get_name(ps, w)) {
|
||||
determine_shadow(ps, w);
|
||||
win_update_focused(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
// If class changes
|
||||
|
@ -3107,6 +3103,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
|
|||
if (w) {
|
||||
win_get_class(ps, w);
|
||||
determine_shadow(ps, w);
|
||||
win_update_focused(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3354,7 +3351,6 @@ usage(void) {
|
|||
" Detect _NET_WM_OPACITY on client windows, useful for window\n"
|
||||
" managers not passing _NET_WM_OPACITY of client windows to frame\n"
|
||||
" windows.\n"
|
||||
"\n"
|
||||
"--refresh-rate val\n"
|
||||
" Specify refresh rate of the screen. If not specified or 0, compton\n"
|
||||
" will try detecting this with X RandR extension.\n"
|
||||
|
@ -3390,6 +3386,9 @@ usage(void) {
|
|||
" Unredirect all windows if a full-screen opaque window is\n"
|
||||
" detected, to maximize performance for full-screen windows.\n"
|
||||
" Experimental.\n"
|
||||
"--focus-exclude condition\n"
|
||||
" Specify a list of conditions of windows that should always be\n"
|
||||
" considered focused.\n"
|
||||
"\n"
|
||||
"Format of a condition:\n"
|
||||
"\n"
|
||||
|
@ -3632,6 +3631,28 @@ parse_vsync(session_t *ps, const char *optarg) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a condition list in configuration file.
|
||||
*/
|
||||
static void
|
||||
parse_cfg_condlst(const config_t *pcfg, wincond_t **pcondlst,
|
||||
const char *name) {
|
||||
config_setting_t *setting = config_lookup(pcfg, name);
|
||||
if (setting) {
|
||||
// Parse an array of options
|
||||
if (config_setting_is_array(setting)) {
|
||||
int i = config_setting_length(setting);
|
||||
while (i--) {
|
||||
condlst_add(pcondlst, config_setting_get_string_elem(setting, i));
|
||||
}
|
||||
}
|
||||
// Treat it as a single pattern if it's a string
|
||||
else if (CONFIG_TYPE_STRING == config_setting_type(setting)) {
|
||||
condlst_add(pcondlst, config_setting_get_string(setting));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a configuration file from default location.
|
||||
*/
|
||||
|
@ -3763,25 +3784,9 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
|
|||
lcfg_lookup_bool(&cfg, "unredir-if-possible",
|
||||
&ps->o.unredir_if_possible);
|
||||
// --shadow-exclude
|
||||
{
|
||||
config_setting_t *setting =
|
||||
config_lookup(&cfg, "shadow-exclude");
|
||||
if (setting) {
|
||||
// Parse an array of shadow-exclude
|
||||
if (config_setting_is_array(setting)) {
|
||||
int i = config_setting_length(setting);
|
||||
while (i--) {
|
||||
condlst_add(&ps->o.shadow_blacklist,
|
||||
config_setting_get_string_elem(setting, i));
|
||||
}
|
||||
}
|
||||
// Treat it as a single pattern if it's a string
|
||||
else if (CONFIG_TYPE_STRING == config_setting_type(setting)) {
|
||||
condlst_add(&ps->o.shadow_blacklist,
|
||||
config_setting_get_string(setting));
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_cfg_condlst(&cfg, &ps->o.shadow_blacklist, "shadow-exclude");
|
||||
// --focus-exclude
|
||||
parse_cfg_condlst(&cfg, &ps->o.focus_blacklist, "focus-exclude");
|
||||
// Wintype settings
|
||||
{
|
||||
wintype_t i;
|
||||
|
@ -3835,6 +3840,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||
{ "use-ewmh-active-win", no_argument, NULL, 276 },
|
||||
{ "respect-prop-shadow", no_argument, NULL, 277 },
|
||||
{ "unredir-if-possible", no_argument, NULL, 278 },
|
||||
{ "focus-exclude", required_argument, NULL, 279 },
|
||||
// Must terminate with a NULL entry
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
@ -4036,6 +4042,10 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||
// --unredir-if-possible
|
||||
ps->o.unredir_if_possible = true;
|
||||
break;
|
||||
case 279:
|
||||
// --focus-exclude
|
||||
condlst_add(&ps->o.focus_blacklist, optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
@ -4082,7 +4092,8 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||
}
|
||||
|
||||
// Determine whether we need to track window name and class
|
||||
if (ps->o.shadow_blacklist || ps->o.fade_blacklist)
|
||||
if (ps->o.shadow_blacklist || ps->o.fade_blacklist
|
||||
|| ps->o.focus_blacklist)
|
||||
ps->o.track_wdata = true;
|
||||
}
|
||||
|
||||
|
@ -4564,6 +4575,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
.inactive_dim = 0.0,
|
||||
.alpha_step = 0.03,
|
||||
.use_ewmh_active_win = false,
|
||||
.focus_blacklist = NULL,
|
||||
|
||||
.track_focus = false,
|
||||
.track_wdata = false,
|
||||
|
|
|
@ -116,6 +116,8 @@
|
|||
#define WFLAG_SIZE_CHANGE 0x0001
|
||||
// Window size/position is changed
|
||||
#define WFLAG_POS_CHANGE 0x0002
|
||||
// Window opacity / dim state changed
|
||||
#define WFLAG_OPCT_CHANGE 0x0004
|
||||
|
||||
/**
|
||||
* Types
|
||||
|
@ -290,8 +292,12 @@ typedef struct {
|
|||
double inactive_dim;
|
||||
/// Step for pregenerating alpha pictures. 0.01 - 1.0.
|
||||
double alpha_step;
|
||||
|
||||
// === Focus related ===
|
||||
/// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
|
||||
bool use_ewmh_active_win;
|
||||
/// A list of windows always to be considered focused.
|
||||
wincond_t *focus_blacklist;
|
||||
|
||||
// === Calculated ===
|
||||
/// Whether compton needs to track focus changes.
|
||||
|
@ -512,8 +518,10 @@ typedef struct _win {
|
|||
XserverRegion extents;
|
||||
// Type of the window.
|
||||
wintype_t window_type;
|
||||
/// Whether the window is focused.
|
||||
/// Whether the window is to be considered focused.
|
||||
bool focused;
|
||||
/// Whether the window is actually focused.
|
||||
bool focused_real;
|
||||
/// Whether the window has been destroyed.
|
||||
bool destroyed;
|
||||
/// Cached width/height of the window including border.
|
||||
|
@ -531,6 +539,7 @@ typedef struct _win {
|
|||
char *class_general;
|
||||
wincond_t *cache_sblst;
|
||||
wincond_t *cache_fblst;
|
||||
wincond_t *cache_fcblst;
|
||||
|
||||
// Opacity-related members
|
||||
/// Current window opacity.
|
||||
|
@ -1354,6 +1363,20 @@ unmap_win(session_t *ps, Window id);
|
|||
static opacity_t
|
||||
wid_get_opacity_prop(session_t *ps, Window wid, opacity_t def);
|
||||
|
||||
/**
|
||||
* Reread opacity property of a window.
|
||||
*/
|
||||
static inline void
|
||||
win_update_opacity_prop(session_t *ps, win *w) {
|
||||
w->opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE);
|
||||
if (!ps->o.detect_client_opacity || !w->client_win
|
||||
|| w->id == w->client_win)
|
||||
w->opacity_prop_client = OPAQUE;
|
||||
else
|
||||
w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win,
|
||||
OPAQUE);
|
||||
}
|
||||
|
||||
static double
|
||||
get_opacity_percent(win *w);
|
||||
|
||||
|
@ -1361,16 +1384,39 @@ static void
|
|||
determine_mode(session_t *ps, win *w);
|
||||
|
||||
static void
|
||||
calc_opacity(session_t *ps, win *w, bool refetch_prop);
|
||||
calc_opacity(session_t *ps, win *w);
|
||||
|
||||
static void
|
||||
calc_dim(session_t *ps, win *w);
|
||||
|
||||
/**
|
||||
* Update focused state of a window.
|
||||
*/
|
||||
static inline void
|
||||
set_focused(session_t *ps, win *w, bool focused) {
|
||||
w->focused = focused;
|
||||
calc_opacity(ps, w, false);
|
||||
calc_dim(ps, w);
|
||||
win_update_focused(session_t *ps, win *w) {
|
||||
bool focused_old = w->focused;
|
||||
|
||||
w->focused = w->focused_real;
|
||||
|
||||
// Consider a window without client window a WM window and mark it
|
||||
// focused if mark_wmwin_focused is on, or it's over-redirected and
|
||||
// mark_ovredir_focused is on
|
||||
if ((ps->o.mark_wmwin_focused && !w->client_win)
|
||||
|| (ps->o.mark_ovredir_focused && w->id == w->client_win)
|
||||
|| win_match(w, ps->o.focus_blacklist, &w->cache_fcblst))
|
||||
w->focused = true;
|
||||
|
||||
if (w->focused != focused_old)
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set real focused state of a window.
|
||||
*/
|
||||
static inline void
|
||||
win_set_focused(session_t *ps, win *w, bool focused) {
|
||||
w->focused_real = focused;
|
||||
win_update_focused(ps, w);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1628,6 +1674,10 @@ lcfg_lookup_int(const config_t *config, const char *path, int *value) {
|
|||
static FILE *
|
||||
open_config_file(char *cpath, char **path);
|
||||
|
||||
static void
|
||||
parse_cfg_condlst(const config_t *pcfg, wincond_t **pcondlst,
|
||||
const char *name);
|
||||
|
||||
static void
|
||||
parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue