summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Grenville <[email protected]>2012-09-11 22:22:58 +0800
committerRichard Grenville <[email protected]>2012-09-11 22:22:58 +0800
commit00d29b07488415661f9306b9cd5fffc855c9c358 (patch)
tree16de17251ad876b8aeceb148f162f41f4bac6abf
parentbbf35f81556f3309b320705db1cd98830b4cf552 (diff)
downloadtdebase-00d29b07488415661f9306b9cd5fffc855c9c358.tar.gz
tdebase-00d29b07488415661f9306b9cd5fffc855c9c358.zip
Bug fix: Issue #37, fix 5 opacity-related bugs
More details in the bug report. - Rewritten much of the opacity calculation, code cleanup. - Commandline switch --inactive_opacity_override to restore the old behavior in which inactive_opacity has higher priority than _NET_WM_OPACITY.
-rw-r--r--compton.c167
-rw-r--r--compton.h41
2 files changed, 154 insertions, 54 deletions
diff --git a/compton.c b/compton.c
index 9f5e25958..9e1eef336 100644
--- a/compton.c
+++ b/compton.c
@@ -81,9 +81,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))
@@ -108,8 +105,14 @@ Bool fade_trans = False;
Bool clear_shadow = False;
-double inactive_opacity = 0;
-double frame_opacity = 0;
+/// Default opacity for inactive windows.
+/// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for
+/// not enabled, default.
+opacity_t inactive_opacity = 0;
+/// Whether inactive_opacity overrides the opacity set by window
+/// attributes.
+Bool inactive_opacity_override = False;
+double frame_opacity = 0.0;
Bool synchronize = False;
@@ -203,21 +206,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,
@@ -1364,6 +1353,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);
@@ -1382,8 +1372,7 @@ map_win(Display *dpy, Window id,
}
}
- // this causes problems for inactive transparency
- //w->opacity = get_opacity_prop(dpy, w, OPAQUE);
+ calc_opacity(dpy, w, True);
determine_mode(dpy, w);
@@ -1481,8 +1470,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;
@@ -1493,9 +1481,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;
}
@@ -1504,11 +1491,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
@@ -1558,8 +1541,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) {
@@ -1575,6 +1561,53 @@ 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 X display to use
+ * @param w struct _win object representing the window
+ * @param refetch_prop whether _NET_WM_OPACITY of the window needs to be
+ * refetched
+ */
+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)) {
@@ -1632,6 +1665,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;
@@ -1661,9 +1696,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);
}
}
@@ -1875,7 +1907,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
@@ -2169,9 +2201,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
@@ -2188,9 +2220,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
@@ -2282,9 +2314,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);
}
}
@@ -2456,6 +2486,8 @@ usage() {
" Green color value of shadow (0.0 - 1.0, defaults to 0).\n"
"--shadow-blue value\n"
" Blue color value of shadow (0.0 - 1.0, defaults to 0).\n"
+ "--inactive-opacity-override\n"
+ " Inactive opacity set by -i overrides value of _NET_WM_OPACITY.\n"
);
exit(1);
@@ -2561,6 +2593,7 @@ main(int argc, char **argv) {
{ "shadow-red", required_argument, NULL, 0 },
{ "shadow-green", required_argument, NULL, 0 },
{ "shadow-blue", required_argument, NULL, 0 },
+ { "inactive-opacity-override", no_argument, NULL, 0 },
};
XEvent ev;
@@ -2603,6 +2636,9 @@ main(int argc, char **argv) {
case 2:
shadow_blue = normalize_d(atof(optarg));
break;
+ case 3:
+ inactive_opacity_override = True;
+ break;
}
break;
// Short options
@@ -2664,10 +2700,12 @@ 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);
+ if (OPAQUE == inactive_opacity)
+ inactive_opacity = 0;
break;
case 'e':
- frame_opacity = (double)atof(optarg);
+ frame_opacity = normalize_d(atof(optarg));
break;
case 'z':
clear_shadow = True;
@@ -2792,6 +2830,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
+ // opacity 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
+ // ancestors 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/compton.h b/compton.h
index 517dc462e..21cccd826 100644
--- a/compton.h
+++ b/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>
@@ -44,6 +45,8 @@
* Types
*/
+typedef uint32_t opacity_t;
+
typedef enum {
WINTYPE_UNKNOWN,
WINTYPE_DESKTOP,
@@ -94,8 +97,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;
@@ -127,6 +134,7 @@ typedef struct _fade {
} fade;
extern int root_height, root_width;
+
/**
* Functions
*/
@@ -134,6 +142,11 @@ extern int root_height, root_width;
// inline functions must be made static to compile correctly under clang:
// http://clang.llvm.org/compatibility.html#inline
+/**
+ * Normalize a double value to 0.\ 0 - 1.\ 0.
+ *
+ * @param d double value to normalize
+ */
static inline double normalize_d(double d) {
if (d > 1.0)
return 1.0;
@@ -143,6 +156,23 @@ static inline double normalize_d(double d) {
return d;
}
+/**
+ * Check if a window ID exists in an array of window IDs.
+ *
+ * @param arr the array of window IDs
+ * @param count amount of elements in the array
+ * @param wid window ID to search for
+ */
+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();
@@ -263,8 +293,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);
@@ -272,8 +302,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);