Improvement: Support reading _NET_WM_OPACITY from client windows
- Some WMs don't respect Keith Packard's proposal of _NET_WM_WINDOW_OPACITY, and do not copy _NET_WM_OPACITY attribute of a client window to its frame windows, thus cause opacity set by non-override-redirect windows to have no effect. This commit adds support for reading _NET_WM_OPACITY from client windows if running with --detect-client-opacity. Thanks to pvanek for reporting. - Change Makefile logic to determine options from 3 variables (NO_LIBCONFIG, NO_REGEX_PCRE, NO_REGEX_PCRE_JIT) instead of CFG to ensure compatibility when we add new options. CFG variable is no longer been respected.
This commit is contained in:
parent
b8f3d22a32
commit
1306b1591f
36
Makefile
36
Makefile
|
@ -4,20 +4,38 @@ PREFIX ?= /usr
|
||||||
BINDIR ?= $(PREFIX)/bin
|
BINDIR ?= $(PREFIX)/bin
|
||||||
MANDIR ?= $(PREFIX)/share/man/man1
|
MANDIR ?= $(PREFIX)/share/man/man1
|
||||||
|
|
||||||
PACKAGES = x11 xcomposite xfixes xdamage xrender xext libconfig
|
PACKAGES = x11 xcomposite xfixes xdamage xrender xext
|
||||||
LIBS = $(shell pkg-config --libs $(PACKAGES)) -lm
|
LIBS = -lm
|
||||||
|
INCS =
|
||||||
|
|
||||||
|
# Parse configuration flags
|
||||||
|
CFG =
|
||||||
|
|
||||||
|
ifeq "$(NO_LIBCONFIG)" ""
|
||||||
|
CFG += -DCONFIG_LIBCONFIG
|
||||||
|
PACKAGES += libconfig
|
||||||
|
|
||||||
|
# libconfig-1.3* does not define LIBCONFIG_VER* macros, so we use
|
||||||
|
# pkg-config to determine its version here
|
||||||
|
CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY')
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq "$(NO_REGEX_PCRE)" ""
|
||||||
|
CFG += -DCONFIG_REGEX_PCRE
|
||||||
LIBS += $(shell pcre-config --libs)
|
LIBS += $(shell pcre-config --libs)
|
||||||
INCS = $(shell pkg-config --cflags $(PACKAGES))
|
|
||||||
INCS += $(shell pcre-config --cflags)
|
INCS += $(shell pcre-config --cflags)
|
||||||
|
ifeq "$(NO_REGEX_PCRE_JIT)" ""
|
||||||
|
CFG += -DCONFIG_REGEX_PCRE_JIT
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += $(CFG)
|
||||||
|
|
||||||
|
LIBS += $(shell pkg-config --libs $(PACKAGES))
|
||||||
|
INCS += $(shell pkg-config --cflags $(PACKAGES))
|
||||||
CFLAGS += -Wall -std=c99
|
CFLAGS += -Wall -std=c99
|
||||||
OBJS = compton.o
|
OBJS = compton.o
|
||||||
|
|
||||||
CFG ?= -DCONFIG_LIBCONFIG -DCONFIG_REGEX_PCRE -DCONFIG_REGEX_PCRE_JIT
|
|
||||||
# libconfig-1.3* does not define LIBCONFIG_VER* macros, so we use pkg-config
|
|
||||||
# to determine its version here
|
|
||||||
CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY')
|
|
||||||
CFLAGS += $(CFG)
|
|
||||||
|
|
||||||
%.o: src/%.c src/%.h
|
%.o: src/%.c src/%.h
|
||||||
$(CC) $(CFLAGS) $(INCS) -c src/$*.c
|
$(CC) $(CFLAGS) $(INCS) -c src/$*.c
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ shadow-ignore-shaped = true;
|
||||||
menu-opacity = 0.8;
|
menu-opacity = 0.8;
|
||||||
inactive-opacity = 0.8;
|
inactive-opacity = 0.8;
|
||||||
frame-opacity = 0.7;
|
frame-opacity = 0.7;
|
||||||
inactive-opacity-override = true;
|
inactive-opacity-override = false;
|
||||||
|
|
||||||
# Fading
|
# Fading
|
||||||
fading = true;
|
fading = true;
|
||||||
|
@ -31,6 +31,7 @@ fade-out-step = 0.03;
|
||||||
mark-wmwin-focused = true;
|
mark-wmwin-focused = true;
|
||||||
mark-ovredir-focused = true;
|
mark-ovredir-focused = true;
|
||||||
detect-rounded-corners = true;
|
detect-rounded-corners = true;
|
||||||
|
detect-client-opacity = false;
|
||||||
|
|
||||||
# Window type settings
|
# Window type settings
|
||||||
wintypes:
|
wintypes:
|
||||||
|
|
|
@ -142,6 +142,7 @@ static options_t opts = {
|
||||||
.inactive_opacity = 0,
|
.inactive_opacity = 0,
|
||||||
.inactive_opacity_override = False,
|
.inactive_opacity_override = False,
|
||||||
.frame_opacity = 0.0,
|
.frame_opacity = 0.0,
|
||||||
|
.detect_client_opacity = False,
|
||||||
.inactive_dim = 0.0,
|
.inactive_dim = 0.0,
|
||||||
|
|
||||||
.track_focus = False,
|
.track_focus = False,
|
||||||
|
@ -942,7 +943,8 @@ determine_evmask(Display *dpy, Window wid, win_evmode_t mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WIN_EVMODE_CLIENT == mode || find_toplevel(dpy, wid)) {
|
if (WIN_EVMODE_CLIENT == mode || find_toplevel(dpy, wid)) {
|
||||||
if (opts.frame_opacity || opts.track_wdata)
|
if (opts.frame_opacity || opts.track_wdata
|
||||||
|
|| opts.detect_client_opacity)
|
||||||
evmask |= PropertyChangeMask;
|
evmask |= PropertyChangeMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1757,14 +1759,14 @@ unmap_win(Display *dpy, Window id, Bool fade) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static opacity_t
|
static opacity_t
|
||||||
get_opacity_prop(Display *dpy, win *w, opacity_t def) {
|
wid_get_opacity_prop(Display *dpy, Window wid, opacity_t def) {
|
||||||
Atom actual;
|
Atom actual;
|
||||||
int format;
|
int format;
|
||||||
unsigned long n, left;
|
unsigned long n, left;
|
||||||
|
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int result = XGetWindowProperty(
|
int result = XGetWindowProperty(
|
||||||
dpy, w->id, opacity_atom, 0L, 1L, False,
|
dpy, wid, opacity_atom, 0L, 1L, False,
|
||||||
XA_CARDINAL, &actual, &format, &n, &left, &data);
|
XA_CARDINAL, &actual, &format, &n, &left, &data);
|
||||||
|
|
||||||
if (result == Success && data != NULL) {
|
if (result == Success && data != NULL) {
|
||||||
|
@ -1838,14 +1840,19 @@ calc_opacity(Display *dpy, win *w, Bool refetch_prop) {
|
||||||
// Do not refetch the opacity window attribute unless necessary, this
|
// Do not refetch the opacity window attribute unless necessary, this
|
||||||
// is probably an expensive operation in some cases
|
// is probably an expensive operation in some cases
|
||||||
if (refetch_prop) {
|
if (refetch_prop) {
|
||||||
w->opacity_prop = get_opacity_prop(dpy, w, OPAQUE);
|
w->opacity_prop = wid_get_opacity_prop(dpy, w->id, OPAQUE);
|
||||||
|
if (!opts.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(dpy, w->client_win,
|
||||||
|
OPAQUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OPAQUE == (opacity = w->opacity_prop)) {
|
if (OPAQUE == (opacity = w->opacity_prop)
|
||||||
if (1.0 != opts.wintype_opacity[w->window_type]) {
|
&& OPAQUE == (opacity = w->opacity_prop_client)) {
|
||||||
opacity = opts.wintype_opacity[w->window_type] * OPAQUE;
|
opacity = opts.wintype_opacity[w->window_type] * OPAQUE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Respect inactive_opacity in some cases
|
// Respect inactive_opacity in some cases
|
||||||
if (opts.inactive_opacity && is_normal_win(w) && False == w->focused
|
if (opts.inactive_opacity && is_normal_win(w) && False == w->focused
|
||||||
|
@ -1945,12 +1952,13 @@ static void
|
||||||
mark_client_win(Display *dpy, win *w, Window client) {
|
mark_client_win(Display *dpy, win *w, Window client) {
|
||||||
w->client_win = client;
|
w->client_win = client;
|
||||||
|
|
||||||
|
XSelectInput(dpy, client, determine_evmask(dpy, client, WIN_EVMODE_CLIENT));
|
||||||
|
|
||||||
// Get the frame width and monitor further frame width changes on client
|
// Get the frame width and monitor further frame width changes on client
|
||||||
// window if necessary
|
// window if necessary
|
||||||
if (opts.frame_opacity) {
|
if (opts.frame_opacity) {
|
||||||
get_frame_extents(dpy, w, client);
|
get_frame_extents(dpy, w, client);
|
||||||
}
|
}
|
||||||
XSelectInput(dpy, client, determine_evmask(dpy, client, WIN_EVMODE_CLIENT));
|
|
||||||
|
|
||||||
// Detect window type here
|
// Detect window type here
|
||||||
if (WINTYPE_UNKNOWN == w->window_type)
|
if (WINTYPE_UNKNOWN == w->window_type)
|
||||||
|
@ -2037,6 +2045,7 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) {
|
||||||
new->opacity_tgt = 0;
|
new->opacity_tgt = 0;
|
||||||
new->opacity_cur = OPAQUE;
|
new->opacity_cur = OPAQUE;
|
||||||
new->opacity_prop = OPAQUE;
|
new->opacity_prop = OPAQUE;
|
||||||
|
new->opacity_prop_client = OPAQUE;
|
||||||
new->fade = False;
|
new->fade = False;
|
||||||
new->fade_callback = NULL;
|
new->fade_callback = NULL;
|
||||||
new->fade_fin = False;
|
new->fade_fin = False;
|
||||||
|
@ -2777,12 +2786,17 @@ ev_property_notify(XPropertyEvent *ev) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if Trans property was changed */
|
// If _NET_WM_OPACITY changes
|
||||||
if (ev->atom == opacity_atom) {
|
if (ev->atom == opacity_atom) {
|
||||||
/* reset mode and redraw window */
|
win *w = NULL;
|
||||||
win *w = find_win(dpy, ev->window);
|
if ((w = find_win(dpy, ev->window)))
|
||||||
|
w->opacity_prop = wid_get_opacity_prop(dpy, w->id, OPAQUE);
|
||||||
|
else if (opts.detect_client_opacity
|
||||||
|
&& (w = find_toplevel(dpy, ev->window)))
|
||||||
|
w->opacity_prop_client = wid_get_opacity_prop(dpy, w->client_win,
|
||||||
|
OPAQUE);
|
||||||
if (w) {
|
if (w) {
|
||||||
calc_opacity(dpy, w, True);
|
calc_opacity(dpy, w, False);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3007,6 +3021,10 @@ usage(void) {
|
||||||
"--detect-rounded-corners\n"
|
"--detect-rounded-corners\n"
|
||||||
" Try to detect windows with rounded corners and don't consider\n"
|
" Try to detect windows with rounded corners and don't consider\n"
|
||||||
" them shaped windows.\n"
|
" them shaped windows.\n"
|
||||||
|
"--detect-client-opacity\n"
|
||||||
|
" 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"
|
"\n"
|
||||||
"Format of a condition:\n"
|
"Format of a condition:\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -3267,6 +3285,9 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) {
|
||||||
// --detect-rounded-corners
|
// --detect-rounded-corners
|
||||||
lcfg_lookup_bool(&cfg, "detect-rounded-corners",
|
lcfg_lookup_bool(&cfg, "detect-rounded-corners",
|
||||||
&opts.detect_rounded_corners);
|
&opts.detect_rounded_corners);
|
||||||
|
// --detect-client-opacity
|
||||||
|
lcfg_lookup_bool(&cfg, "detect-client-opacity",
|
||||||
|
&opts.detect_client_opacity);
|
||||||
// --shadow-exclude
|
// --shadow-exclude
|
||||||
{
|
{
|
||||||
config_setting_t *setting =
|
config_setting_t *setting =
|
||||||
|
@ -3329,6 +3350,7 @@ get_cfg(int argc, char *const *argv) {
|
||||||
{ "no-fading-openclose", no_argument, NULL, 265 },
|
{ "no-fading-openclose", no_argument, NULL, 265 },
|
||||||
{ "shadow-ignore-shaped", no_argument, NULL, 266 },
|
{ "shadow-ignore-shaped", no_argument, NULL, 266 },
|
||||||
{ "detect-rounded-corners", no_argument, NULL, 267 },
|
{ "detect-rounded-corners", no_argument, NULL, 267 },
|
||||||
|
{ "detect-client-opacity", no_argument, NULL, 268 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -3483,6 +3505,10 @@ get_cfg(int argc, char *const *argv) {
|
||||||
// --detect-rounded-corners
|
// --detect-rounded-corners
|
||||||
opts.detect_rounded_corners = True;
|
opts.detect_rounded_corners = True;
|
||||||
break;
|
break;
|
||||||
|
case 268:
|
||||||
|
// --detect-client-opacity
|
||||||
|
opts.detect_client_opacity = True;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -198,6 +198,10 @@ typedef struct _win {
|
||||||
opacity_t opacity_cur;
|
opacity_t opacity_cur;
|
||||||
/// Cached value of opacity window attribute.
|
/// Cached value of opacity window attribute.
|
||||||
opacity_t opacity_prop;
|
opacity_t opacity_prop;
|
||||||
|
/// Cached value of opacity window attribute on client window. For
|
||||||
|
/// broken window managers not transferring client window's
|
||||||
|
/// _NET_WM_OPACITY value
|
||||||
|
opacity_t opacity_prop_client;
|
||||||
/// Alpha mask Picture to render window with opacity.
|
/// Alpha mask Picture to render window with opacity.
|
||||||
Picture alpha_pict;
|
Picture alpha_pict;
|
||||||
|
|
||||||
|
@ -302,7 +306,12 @@ typedef struct _options {
|
||||||
/// Whether inactive_opacity overrides the opacity set by window
|
/// Whether inactive_opacity overrides the opacity set by window
|
||||||
/// attributes.
|
/// attributes.
|
||||||
Bool inactive_opacity_override;
|
Bool inactive_opacity_override;
|
||||||
|
/// Frame opacity. Relative to window opacity, also affects shadow
|
||||||
|
/// opacity.
|
||||||
double frame_opacity;
|
double frame_opacity;
|
||||||
|
/// Whether to detect _NET_WM_OPACITY on client windows. Used on window
|
||||||
|
/// managers that don't pass _NET_WM_OPACITY to frame windows.
|
||||||
|
Bool detect_client_opacity;
|
||||||
/// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
|
/// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
|
||||||
double inactive_dim;
|
double inactive_dim;
|
||||||
|
|
||||||
|
@ -780,7 +789,7 @@ static void
|
||||||
unmap_win(Display *dpy, Window id, Bool fade);
|
unmap_win(Display *dpy, Window id, Bool fade);
|
||||||
|
|
||||||
static opacity_t
|
static opacity_t
|
||||||
get_opacity_prop(Display *dpy, win *w, opacity_t def);
|
wid_get_opacity_prop(Display *dpy, Window wid, opacity_t def);
|
||||||
|
|
||||||
static double
|
static double
|
||||||
get_opacity_percent(Display *dpy, win *w);
|
get_opacity_percent(Display *dpy, win *w);
|
||||||
|
|
Loading…
Reference in New Issue