From 1306b1591f2841a1629de974c14f355bd63760da Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Wed, 3 Oct 2012 21:13:34 +0800 Subject: [PATCH] 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. --- Makefile | 40 ++++++++++++++++++++++++---------- compton.sample.conf | 3 ++- src/compton.c | 52 +++++++++++++++++++++++++++++++++------------ src/compton.h | 11 +++++++++- 4 files changed, 80 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 47be5943..fda1e856 100644 --- a/Makefile +++ b/Makefile @@ -4,20 +4,38 @@ PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man/man1 -PACKAGES = x11 xcomposite xfixes xdamage xrender xext libconfig -LIBS = $(shell pkg-config --libs $(PACKAGES)) -lm -LIBS += $(shell pcre-config --libs) -INCS = $(shell pkg-config --cflags $(PACKAGES)) -INCS += $(shell pcre-config --cflags) +PACKAGES = x11 xcomposite xfixes xdamage xrender xext +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) + 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 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 $(CC) $(CFLAGS) $(INCS) -c src/$*.c diff --git a/compton.sample.conf b/compton.sample.conf index 857c9149..f814f87e 100644 --- a/compton.sample.conf +++ b/compton.sample.conf @@ -18,7 +18,7 @@ shadow-ignore-shaped = true; menu-opacity = 0.8; inactive-opacity = 0.8; frame-opacity = 0.7; -inactive-opacity-override = true; +inactive-opacity-override = false; # Fading fading = true; @@ -31,6 +31,7 @@ fade-out-step = 0.03; mark-wmwin-focused = true; mark-ovredir-focused = true; detect-rounded-corners = true; +detect-client-opacity = false; # Window type settings wintypes: diff --git a/src/compton.c b/src/compton.c index 80f19aeb..a64b0b7b 100644 --- a/src/compton.c +++ b/src/compton.c @@ -142,6 +142,7 @@ static options_t opts = { .inactive_opacity = 0, .inactive_opacity_override = False, .frame_opacity = 0.0, + .detect_client_opacity = False, .inactive_dim = 0.0, .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 (opts.frame_opacity || opts.track_wdata) + if (opts.frame_opacity || opts.track_wdata + || opts.detect_client_opacity) evmask |= PropertyChangeMask; } @@ -1757,14 +1759,14 @@ unmap_win(Display *dpy, Window id, Bool fade) { } 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; int format; unsigned long n, left; unsigned char *data; 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); if (result == Success && data != NULL) { @@ -1838,13 +1840,18 @@ calc_opacity(Display *dpy, win *w, Bool refetch_prop) { // Do not refetch the opacity window attribute unless necessary, this // is probably an expensive operation in some cases 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 (1.0 != opts.wintype_opacity[w->window_type]) { - opacity = opts.wintype_opacity[w->window_type] * OPAQUE; - } + if (OPAQUE == (opacity = w->opacity_prop) + && OPAQUE == (opacity = w->opacity_prop_client)) { + opacity = opts.wintype_opacity[w->window_type] * OPAQUE; } // Respect inactive_opacity in some cases @@ -1945,12 +1952,13 @@ static void mark_client_win(Display *dpy, win *w, Window 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 // window if necessary if (opts.frame_opacity) { get_frame_extents(dpy, w, client); } - XSelectInput(dpy, client, determine_evmask(dpy, client, WIN_EVMODE_CLIENT)); // Detect window type here 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_cur = OPAQUE; new->opacity_prop = OPAQUE; + new->opacity_prop_client = OPAQUE; new->fade = False; new->fade_callback = NULL; 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) { - /* reset mode and redraw window */ - win *w = find_win(dpy, ev->window); + win *w = NULL; + 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) { - calc_opacity(dpy, w, True); + calc_opacity(dpy, w, False); } } @@ -3007,6 +3021,10 @@ usage(void) { "--detect-rounded-corners\n" " Try to detect windows with rounded corners and don't consider\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" "Format of a condition:\n" "\n" @@ -3267,6 +3285,9 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { // --detect-rounded-corners lcfg_lookup_bool(&cfg, "detect-rounded-corners", &opts.detect_rounded_corners); + // --detect-client-opacity + lcfg_lookup_bool(&cfg, "detect-client-opacity", + &opts.detect_client_opacity); // --shadow-exclude { config_setting_t *setting = @@ -3329,6 +3350,7 @@ get_cfg(int argc, char *const *argv) { { "no-fading-openclose", no_argument, NULL, 265 }, { "shadow-ignore-shaped", no_argument, NULL, 266 }, { "detect-rounded-corners", no_argument, NULL, 267 }, + { "detect-client-opacity", no_argument, NULL, 268 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -3483,6 +3505,10 @@ get_cfg(int argc, char *const *argv) { // --detect-rounded-corners opts.detect_rounded_corners = True; break; + case 268: + // --detect-client-opacity + opts.detect_client_opacity = True; + break; default: usage(); break; diff --git a/src/compton.h b/src/compton.h index 7a71fa80..dca11b68 100644 --- a/src/compton.h +++ b/src/compton.h @@ -198,6 +198,10 @@ typedef struct _win { opacity_t opacity_cur; /// Cached value of opacity window attribute. 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. Picture alpha_pict; @@ -302,7 +306,12 @@ typedef struct _options { /// Whether inactive_opacity overrides the opacity set by window /// attributes. Bool inactive_opacity_override; + /// Frame opacity. Relative to window opacity, also affects shadow + /// 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. double inactive_dim; @@ -780,7 +789,7 @@ static void unmap_win(Display *dpy, Window id, Bool fade); 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 get_opacity_percent(Display *dpy, win *w);