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:
Richard Grenville 2012-10-03 21:13:34 +08:00
parent b8f3d22a32
commit 1306b1591f
4 changed files with 80 additions and 26 deletions

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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);