So you have to face a huge patch again... It fixes bug 1, 2, 3. 4, and 5. I did not do much tests to this patch, so please review it carefully.
diff --git a/src/compton.c b/src/compton.c
index b72dc59..4ad4662 100644
--- a/src/compton.c
+++ b/src/compton.c
@@ -72,9 +72,6 @@ Bool win_type_fade[NUM_WINTYPES];
* Macros
*/
-#define INACTIVE_OPACITY \
-(unsigned long)((double)inactive_opacity * OPAQUE)
-
#define IS_NORMAL_WIN(w) \
((w) && ((w)->window_type == WINTYPE_NORMAL \
|| (w)->window_type == WINTYPE_UTILITY))
@@ -99,8 +96,11 @@ Bool fade_trans = False;
Bool clear_shadow = False;
-double inactive_opacity = 0;
-double frame_opacity = 0;
+/// Default opacity for inactive windows, 0.0 if unset
+opacity_t inactive_opacity = 0;
+/// Whether inactive_opacity overrides the opacity set by window attributes
+Bool inactive_opacity_override = True;
+double frame_opacity = 0.0;
Bool synchronize = False;
@@ -194,21 +194,7 @@ set_fade(Display *dpy, win *w, double start,
}
f->callback = callback;
- w->opacity = f->cur * OPAQUE;
-
- determine_mode(dpy, w);
-
- if (w->shadow) {
- XRenderFreePicture(dpy, w->shadow);
- w->shadow = None;
-
- if (w->extents != None) {
- XFixesDestroyRegion(dpy, w->extents);
- }
-
- /* rebuild the shadow */
- w->extents = win_extents(dpy, w);
- }
+ set_opacity(dpy, w, f->cur * OPAQUE);
/* fading windows need to be drawn, mark
them as damaged. when a window maps,
@@ -1360,6 +1346,7 @@ map_win(Display *dpy, Window id,
if (!w) return;
+ w->focused = False;
w->a.map_state = IsViewable;
w->window_type = determine_wintype(dpy, w->id, w->id);
@@ -1374,8 +1361,7 @@ map_win(Display *dpy, Window id,
XSelectInput(dpy, id, PropertyChangeMask | FocusChangeMask);
}
- // this causes problems for inactive transparency
- //w->opacity = get_opacity_prop(dpy, w, OPAQUE);
+ calc_opacity(dpy, w, True);
determine_mode(dpy, w);
@@ -1477,8 +1463,7 @@ unmap_win(Display *dpy, Window id, Bool fade) {
finish_unmap_win(dpy, w);
}
-static unsigned int
-get_opacity_prop(Display *dpy, win *w, unsigned int def) {
+opacity_t get_opacity_prop(Display *dpy, win *w, opacity_t def) {
Atom actual;
int format;
unsigned long n, left;
@@ -1489,9 +1474,8 @@ get_opacity_prop(Display *dpy, win *w, unsigned int def) {
XA_CARDINAL, &actual, &format, &n, &left, &data);
if (result == Success && data != NULL) {
- unsigned int i;
- memcpy(&i, data, sizeof(unsigned int));
- XFree((void *)data);
+ opacity_t i = *((opacity_t *) data);
+ XFree(data);
return i;
}
@@ -1500,11 +1484,7 @@ get_opacity_prop(Display *dpy, win *w, unsigned int def) {
static double
get_opacity_percent(Display *dpy, win *w) {
- double def = win_type_opacity[w->window_type];
- unsigned int opacity =
- get_opacity_prop(dpy, w, (unsigned int)(OPAQUE * def));
-
- return opacity * 1.0 / OPAQUE;
+ return w->opacity * 1.0 / OPAQUE;
}
static void
@@ -1554,8 +1534,11 @@ determine_mode(Display *dpy, win *w) {
}
}
-static void
-set_opacity(Display *dpy, win *w, unsigned long opacity) {
+void set_opacity(Display *dpy, win *w, opacity_t opacity) {
+ // Do nothing if the opacity does not change
+ if (w->opacity == opacity)
+ return;
+
w->opacity = opacity;
determine_mode(dpy, w);
if (w->shadow) {
@@ -1571,6 +1554,51 @@ set_opacity(Display *dpy, win *w, unsigned long opacity) {
}
}
+/**
+ * Calculate and set the opacity of a window.
+ *
+ * If window is inactive and inactive_opacity_override is set, the
+ * priority is: (Simulates the old behavior)
+ *
+ * inactive_opacity > _NET_WM_WINDOW_OPACITY (if not opaque)
+ * > window type default opacity
+ *
+ * Otherwise:
+ *
+ * _NET_WM_WINDOW_OPACITY (if not opaque)
+ * > window type default opacity (if not opaque)
+ * > inactive_opacity
+ *
+ * @param dpy
+ * @param w
+ */
+void calc_opacity(Display *dpy, win *w, Bool refetch_prop) {
+ opacity_t opacity;
+
+ // 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;
+
+ // 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);
+
+ if (OPAQUE == (opacity = w->opacity_prop)) {
+ if (OPAQUE != win_type_opacity[w->window_type])
+ opacity = win_type_opacity[w->window_type] * OPAQUE;
+ }
+
+ // Respect inactive_opacity in some cases
+ if (IS_NORMAL_WIN(w) && False == w->focused && inactive_opacity
+ && (OPAQUE == opacity || inactive_opacity_override))
+ opacity = inactive_opacity;
+
+ set_opacity(dpy, w, opacity);
+}
+
static void
add_win(Display *dpy, Window id, Window prev, Bool override_redirect) {
if (find_win(dpy, id)) {
@@ -1628,6 +1656,8 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) {
new->shadow_width = 0;
new->shadow_height = 0;
new->opacity = OPAQUE;
+ new->opacity_prop = OPAQUE;
+ new->focused = False;
new->destroyed = False;
new->need_configure = False;
new->window_type = WINTYPE_UNKNOWN;
@@ -1657,9 +1687,6 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) {
if (new->a.map_state == IsViewable) {
new->window_type = determine_wintype(dpy, id, id);
- if (inactive_opacity && IS_NORMAL_WIN(new)) {
- new->opacity = INACTIVE_OPACITY;
- }
map_win(dpy, id, new->damage_sequence - 1, True, override_redirect);
}
}
@@ -1844,7 +1871,7 @@ destroy_win(Display *dpy, Window id, Bool fade) {
#if HAS_NAME_WINDOW_PIXMAP
if (w && w->pixmap && fade && win_type_fade[w->window_type]) {
- set_fade(dpy, w, w->opacity * 1.0 / OPAQUE,
+ set_fade(dpy, w, get_opacity_percent(dpy, w),
0.0, fade_out_step, destroy_callback,
False, True);
} else
@@ -2033,9 +2060,9 @@ ev_focus_in(XFocusChangeEvent *ev) {
if (!inactive_opacity) return;
win *w = find_win(dpy, ev->window);
- if (IS_NORMAL_WIN(w)) {
- set_opacity(dpy, w, OPAQUE);
- }
+
+ w->focused = True;
+ calc_opacity(dpy, w, False);
}
inline static void
@@ -2052,9 +2079,9 @@ ev_focus_out(XFocusChangeEvent *ev) {
}
win *w = find_win(dpy, ev->window);
- if (IS_NORMAL_WIN(w)) {
- set_opacity(dpy, w, INACTIVE_OPACITY);
- }
+
+ w->focused = False;
+ calc_opacity(dpy, w, False);
}
inline static void
@@ -2143,9 +2170,7 @@ ev_property_notify(XPropertyEvent *ev) {
/* reset mode and redraw window */
win *w = find_win(dpy, ev->window);
if (w) {
- double def = win_type_opacity[w->window_type];
- set_opacity(dpy, w,
- get_opacity_prop(dpy, w, (unsigned long)(OPAQUE * def)));
+ calc_opacity(dpy, w, True);
}
}
@@ -2447,10 +2472,13 @@ main(int argc, char **argv) {
shadow_offset_y = atoi(optarg);
break;
case 'i':
- inactive_opacity = (double)atof(optarg);
+ inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE);
+ break;
+ case 0:
+ inactive_opacity_override = True;
break;
case 'e':
- frame_opacity = (double)atof(optarg);
+ frame_opacity = normalize_d(atof(optarg));
break;
case 'z':
clear_shadow = True;
@@ -2564,6 +2592,37 @@ main(int argc, char **argv) {
add_win(dpy, children[i], i ? children[i-1] : None, False);
}
+ // Check the currently focused window so we can apply appropriate
+ // transparency on it
+ {
+ Window wid = 0;
+ int revert_to;
+ win *w = NULL;
+
+ XGetInputFocus(dpy, &wid, &revert_to);
+
+ // XGetInputFocus seemingly returns the application window focused
+ // instead of the WM window frame, so we traverse through its parents
+ // to find out the frame
+ while(wid && wid != root
+ && !array_wid_exists(children, nchildren, wid)) {
+ Window troot;
+ Window parent;
+ Window *tchildren;
+ unsigned tnchildren;
+
+ XQueryTree(dpy, wid, &troot, &parent, &tchildren, &tnchildren);
+ XFree(tchildren);
+ wid = parent;
+ }
+
+ // And we set the focus state and opacity here
+ if (wid && wid != root && (w = find_win(dpy, wid))) {
+ w->focused = True;
+ calc_opacity(dpy, w, False);
+ }
+ }
+
XFree(children);
XUngrabServer(dpy);
diff --git a/src/compton.h b/src/compton.h
index 18e3859..17dd332 100644
--- a/src/compton.h
+++ b/src/compton.h
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <inttypes.h>
#include <math.h>
#include <sys/poll.h>
#include <sys/time.h>
@@ -42,6 +43,8 @@
* Types
*/
+typedef uint32_t opacity_t;
+
typedef enum {
WINTYPE_UNKNOWN,
WINTYPE_DESKTOP,
@@ -92,8 +95,12 @@ typedef struct _win {
int shadow_dy;
int shadow_width;
int shadow_height;
- unsigned int opacity;
+ opacity_t opacity;
+ /// Cached value of opacity window attribute
+ opacity_t opacity_prop;
wintype window_type;
+ /// Whether the window is focused
+ Bool focused;
unsigned long damage_sequence; /* sequence when damage was created */
Bool destroyed;
unsigned int left_width;
@@ -128,6 +135,28 @@ typedef struct _fade {
* Functions
*/
+// inline functions must be made static to compile correctly under clang:
+// http://clang.llvm.org/compatibility.html#inline
+
+static inline double normalize_d(double d) {
+ if (d > 1.0)
+ return 1.0;
+ if (d < 0.0)
+ return 0.0;
+
+ return d;
+}
+
+static inline Bool array_wid_exists(const Window *arr,
+ int count, Window wid) {
+ while (count--) {
+ if (arr[count] == wid)
+ return True;
+ }
+
+ return False;
+}
+
static int
get_time_in_milliseconds();
@@ -248,8 +277,8 @@ unmap_callback(Display *dpy, win *w);
static void
unmap_win(Display *dpy, Window id, Bool fade);
-static unsigned int
-get_opacity_prop(Display *dpy, win *w, unsigned int def);
+opacity_t
+get_opacity_prop(Display *dpy, win *w, opacity_t def);
static double
get_opacity_percent(Display *dpy, win *w);
@@ -257,8 +286,9 @@ get_opacity_percent(Display *dpy, win *w);
static void
determine_mode(Display *dpy, win *w);
-static void
-set_opacity(Display *dpy, win *w, unsigned long opacity);
+void set_opacity(Display *dpy, win *w, opacity_t opacity);
+
+void calc_opacity(Display *dpy, win *w, Bool refetch_prop);
static void
add_win(Display *dpy, Window id, Window prev, Bool override_redirect);
The 6th bug (or design decision) is so easy to change and I don't need to explain anything, I guess.
Could you please look into the second bug I mentioned in the last reply in the "Maximized Chromium window" issue? It should be somewhere you changed so you probably have an idea where it comes from.