2003-11-10 11:45:17 +08:00
|
|
|
/*
|
2012-02-27 12:00:12 +08:00
|
|
|
* Compton - a compositor for X11
|
2003-11-10 11:45:17 +08:00
|
|
|
*
|
2012-02-27 12:00:12 +08:00
|
|
|
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
2003-11-10 11:45:17 +08:00
|
|
|
*
|
2012-02-27 12:00:12 +08:00
|
|
|
* Copyright (c) 2011, Christopher Jeffrey
|
2011-11-07 09:58:30 +08:00
|
|
|
* See LICENSE for more information.
|
2003-11-10 11:45:17 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-02-08 18:31:39 +08:00
|
|
|
#include "compton.h"
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
/**
|
|
|
|
* Shared
|
|
|
|
*/
|
|
|
|
|
2012-09-25 21:04:10 +08:00
|
|
|
const char *WINTYPES[NUM_WINTYPES] = {
|
|
|
|
"unknown",
|
|
|
|
"desktop",
|
|
|
|
"dock",
|
|
|
|
"toolbar",
|
|
|
|
"menu",
|
|
|
|
"utility",
|
|
|
|
"splash",
|
|
|
|
"dialog",
|
|
|
|
"normal",
|
|
|
|
"dropdown_menu",
|
|
|
|
"popup_menu",
|
|
|
|
"tooltip",
|
|
|
|
"notify",
|
|
|
|
"combo",
|
|
|
|
"dnd",
|
|
|
|
};
|
|
|
|
|
2012-09-12 09:08:15 +08:00
|
|
|
struct timeval time_start = { 0, 0 };
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
win *list;
|
|
|
|
Display *dpy;
|
|
|
|
int scr;
|
2012-02-09 06:45:08 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
Window root;
|
|
|
|
Picture root_picture;
|
|
|
|
Picture root_buffer;
|
|
|
|
Picture black_picture;
|
2012-09-11 21:57:50 +08:00
|
|
|
Picture cshadow_picture;
|
2012-09-12 10:52:52 +08:00
|
|
|
/// Picture used for dimming inactive windows.
|
|
|
|
Picture dim_picture = 0;
|
2011-11-04 16:41:56 +08:00
|
|
|
Picture root_tile;
|
|
|
|
XserverRegion all_damage;
|
2004-06-28 05:29:23 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
2011-11-04 16:41:56 +08:00
|
|
|
Bool has_name_pixmap;
|
2004-06-28 05:29:23 +08:00
|
|
|
#endif
|
2011-11-04 16:41:56 +08:00
|
|
|
int root_height, root_width;
|
2012-09-29 22:53:57 +08:00
|
|
|
/// Whether the program is idling. I.e. no fading, no potential window
|
|
|
|
/// changes.
|
|
|
|
Bool idling;
|
2012-02-09 06:45:08 +08:00
|
|
|
|
|
|
|
/* errors */
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
ignore *ignore_head = NULL, **ignore_tail = &ignore_head;
|
2011-11-04 16:41:56 +08:00
|
|
|
int xfixes_event, xfixes_error;
|
|
|
|
int damage_event, damage_error;
|
|
|
|
int composite_event, composite_error;
|
2012-09-11 21:33:03 +08:00
|
|
|
/// Whether X Shape extension exists.
|
|
|
|
Bool shape_exists = True;
|
|
|
|
/// Event base number and error base number for X Shape extension.
|
|
|
|
int shape_event, shape_error;
|
2011-11-04 16:41:56 +08:00
|
|
|
int render_event, render_error;
|
|
|
|
int composite_opcode;
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2012-02-09 06:45:08 +08:00
|
|
|
/* shadows */
|
|
|
|
conv *gaussian_map;
|
|
|
|
|
|
|
|
/* for shadow precomputation */
|
2012-06-04 00:08:50 +08:00
|
|
|
int cgsize = -1;
|
2012-02-09 06:45:08 +08:00
|
|
|
unsigned char *shadow_corner = NULL;
|
|
|
|
unsigned char *shadow_top = NULL;
|
|
|
|
|
|
|
|
/* for root tile */
|
|
|
|
static const char *background_props[] = {
|
|
|
|
"_XROOTPMAP_ID",
|
|
|
|
"_XSETROOT_ID",
|
|
|
|
0,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* for expose events */
|
|
|
|
XRectangle *expose_rects = 0;
|
|
|
|
int size_expose = 0;
|
|
|
|
int n_expose = 0;
|
|
|
|
|
2012-09-20 13:50:27 +08:00
|
|
|
// atoms
|
2012-02-01 06:10:30 +08:00
|
|
|
Atom extents_atom;
|
2011-11-04 16:41:56 +08:00
|
|
|
Atom opacity_atom;
|
2012-09-20 13:50:27 +08:00
|
|
|
Atom frame_extents_atom;
|
|
|
|
Atom client_atom;
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
Atom name_atom;
|
|
|
|
Atom name_ewmh_atom;
|
|
|
|
Atom class_atom;
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
Atom win_type_atom;
|
|
|
|
Atom win_type[NUM_WINTYPES];
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
unsigned long fade_time;
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2012-02-09 06:45:08 +08:00
|
|
|
/**
|
|
|
|
* Macros
|
|
|
|
*/
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2012-02-27 20:49:50 +08:00
|
|
|
#define HAS_FRAME_OPACITY(w) \
|
|
|
|
(frame_opacity && (w)->top_width)
|
2012-02-09 06:45:08 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Options
|
|
|
|
*/
|
2003-11-10 09:32:01 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
static options_t opts = {
|
2012-09-26 09:53:18 +08:00
|
|
|
.display = NULL,
|
|
|
|
.shadow_radius = 12,
|
|
|
|
.shadow_offset_x = -15,
|
|
|
|
.shadow_offset_y = -15,
|
|
|
|
.shadow_opacity = .75,
|
|
|
|
.fade_in_step = 0.028 * OPAQUE,
|
|
|
|
.fade_out_step = 0.03 * OPAQUE,
|
|
|
|
.fade_delta = 10,
|
2012-09-26 21:40:48 +08:00
|
|
|
.no_fading_openclose = False,
|
2012-09-26 09:53:18 +08:00
|
|
|
.clear_shadow = False,
|
|
|
|
.inactive_opacity = 0,
|
|
|
|
.inactive_opacity_override = False,
|
|
|
|
.frame_opacity = 0.0,
|
|
|
|
.inactive_dim = 0.0,
|
|
|
|
.mark_wmwin_focused = False,
|
2012-09-26 19:48:36 +08:00
|
|
|
.mark_ovredir_focused = False,
|
2012-09-26 09:53:18 +08:00
|
|
|
.shadow_blacklist = NULL,
|
|
|
|
.fade_blacklist = NULL,
|
|
|
|
.fork_after_register = False,
|
|
|
|
.shadow_red = 0.0,
|
|
|
|
.shadow_green = 0.0,
|
|
|
|
.shadow_blue = 0.0,
|
2012-09-26 18:54:35 +08:00
|
|
|
.wintype_opacity = { 0.0 },
|
|
|
|
.wintype_shadow = { False },
|
|
|
|
.wintype_fade = { False },
|
2012-09-26 09:53:18 +08:00
|
|
|
.synchronize = False,
|
2012-09-26 18:54:35 +08:00
|
|
|
.track_focus = False,
|
|
|
|
.track_wdata = False,
|
2012-09-26 09:53:18 +08:00
|
|
|
};
|
2012-09-25 10:19:20 +08:00
|
|
|
|
2012-02-09 06:45:08 +08:00
|
|
|
/**
|
|
|
|
* Fades
|
|
|
|
*/
|
2004-09-22 06:59:38 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
/**
|
|
|
|
* Get current system clock in milliseconds.
|
|
|
|
*
|
|
|
|
* The return type must be unsigned long because so many milliseconds have
|
|
|
|
* passed since the epoch.
|
|
|
|
*/
|
|
|
|
static unsigned long
|
2011-11-04 14:33:23 +08:00
|
|
|
get_time_in_milliseconds() {
|
2011-11-04 16:41:56 +08:00
|
|
|
struct timeval tv;
|
2004-07-08 15:07:26 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
gettimeofday(&tv, NULL);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
/**
|
|
|
|
* Get the time left before next fading point.
|
|
|
|
*
|
|
|
|
* In milliseconds.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
fade_timeout(void) {
|
2012-09-26 18:54:35 +08:00
|
|
|
int diff = opts.fade_delta - get_time_in_milliseconds() + fade_time;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
if (diff < 0)
|
|
|
|
diff = 0;
|
2004-07-08 15:07:26 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
return diff;
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
/**
|
|
|
|
* Run fading on a window.
|
|
|
|
*
|
|
|
|
* @param steps steps of fading
|
|
|
|
*/
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2012-09-19 20:49:16 +08:00
|
|
|
run_fade(Display *dpy, win *w, unsigned steps) {
|
|
|
|
// If we reach target opacity, set fade_fin so the callback gets
|
|
|
|
// executed
|
|
|
|
if (w->opacity == w->opacity_tgt) {
|
|
|
|
w->fade_fin = True;
|
|
|
|
return;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2004-07-08 15:07:26 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
if (!w->fade)
|
|
|
|
w->opacity = w->opacity_tgt;
|
|
|
|
else if (steps) {
|
|
|
|
// Use double below because opacity_t will probably overflow during
|
|
|
|
// calculations
|
|
|
|
if (w->opacity < w->opacity_tgt)
|
|
|
|
w->opacity = normalize_d_range(
|
2012-09-26 18:54:35 +08:00
|
|
|
(double) w->opacity + (double) opts.fade_in_step * steps,
|
2012-09-19 20:49:16 +08:00
|
|
|
0.0, w->opacity_tgt);
|
|
|
|
else
|
|
|
|
w->opacity = normalize_d_range(
|
2012-09-26 18:54:35 +08:00
|
|
|
(double) w->opacity - (double) opts.fade_out_step * steps,
|
2012-09-19 20:49:16 +08:00
|
|
|
w->opacity_tgt, OPAQUE);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2004-07-08 15:07:26 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
if (w->opacity == w->opacity_tgt) {
|
|
|
|
w->fade_fin = True;
|
2011-11-04 14:33:23 +08:00
|
|
|
return;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2012-09-29 22:53:57 +08:00
|
|
|
else {
|
|
|
|
idling = False;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
w->fade_fin = False;
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
/**
|
|
|
|
* Set fade callback of a window, and possibly execute the previous
|
|
|
|
* callback.
|
|
|
|
*
|
|
|
|
* @param exec_callback whether the previous callback is to be executed
|
|
|
|
*/
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2012-09-19 20:49:16 +08:00
|
|
|
set_fade_callback(Display *dpy, win *w,
|
|
|
|
void (*callback) (Display *dpy, win *w), Bool exec_callback) {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
void (*old_callback) (Display *dpy, win *w) = w->fade_callback;
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
w->fade_callback = callback;
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// Must be the last line as the callback could destroy w!
|
2012-09-29 22:53:57 +08:00
|
|
|
if (exec_callback && old_callback) {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
old_callback(dpy, w);
|
2012-09-29 22:53:57 +08:00
|
|
|
// Although currently no callback function affects window state on
|
|
|
|
// next paint, it could, in the future
|
|
|
|
idling = False;
|
|
|
|
}
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2012-02-09 06:45:08 +08:00
|
|
|
/**
|
|
|
|
* Shadows
|
|
|
|
*/
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static double
|
2011-11-04 14:33:23 +08:00
|
|
|
gaussian(double r, double x, double y) {
|
|
|
|
return ((1 / (sqrt(2 * M_PI * r))) *
|
2012-02-27 20:49:50 +08:00
|
|
|
exp((- (x * x + y * y)) / (2 * r * r)));
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static conv *
|
2011-11-04 14:33:23 +08:00
|
|
|
make_gaussian_map(Display *dpy, double r) {
|
2011-11-04 16:41:56 +08:00
|
|
|
conv *c;
|
|
|
|
int size = ((int) ceil((r * 3)) + 1) & ~1;
|
|
|
|
int center = size / 2;
|
|
|
|
int x, y;
|
|
|
|
double t;
|
|
|
|
double g;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
c = malloc(sizeof(conv) + size * size * sizeof(double));
|
|
|
|
c->size = size;
|
|
|
|
c->data = (double *) (c + 1);
|
|
|
|
t = 0.0;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
for (y = 0; y < size; y++) {
|
2011-11-04 14:33:23 +08:00
|
|
|
for (x = 0; x < size; x++) {
|
|
|
|
g = gaussian(r, (double) (x - center), (double) (y - center));
|
|
|
|
t += g;
|
|
|
|
c->data[y * size + x] = g;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (y = 0; y < size; y++) {
|
2011-11-04 14:33:23 +08:00
|
|
|
for (x = 0; x < size; x++) {
|
2011-11-07 05:52:39 +08:00
|
|
|
c->data[y * size + x] /= t;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return c;
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A picture will help
|
|
|
|
*
|
2011-11-04 17:01:45 +08:00
|
|
|
* -center 0 width width+center
|
2003-11-10 09:32:01 +08:00
|
|
|
* -center +-----+-------------------+-----+
|
2011-11-04 17:01:45 +08:00
|
|
|
* | | | |
|
|
|
|
* | | | |
|
|
|
|
* 0 +-----+-------------------+-----+
|
|
|
|
* | | | |
|
|
|
|
* | | | |
|
|
|
|
* | | | |
|
2003-11-10 09:32:01 +08:00
|
|
|
* height +-----+-------------------+-----+
|
2011-11-04 17:01:45 +08:00
|
|
|
* | | | |
|
|
|
|
* height+ | | | |
|
2003-11-10 09:32:01 +08:00
|
|
|
* center +-----+-------------------+-----+
|
|
|
|
*/
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static unsigned char
|
2011-11-04 17:18:10 +08:00
|
|
|
sum_gaussian(conv *map, double opacity,
|
|
|
|
int x, int y, int width, int height) {
|
2011-11-04 16:41:56 +08:00
|
|
|
int fx, fy;
|
|
|
|
double *g_data;
|
|
|
|
double *g_line = map->data;
|
|
|
|
int g_size = map->size;
|
|
|
|
int center = g_size / 2;
|
|
|
|
int fx_start, fx_end;
|
|
|
|
int fy_start, fy_end;
|
|
|
|
double v;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute set of filter values which are "in range",
|
|
|
|
* that's the set with:
|
|
|
|
* 0 <= x + (fx-center) && x + (fx-center) < width &&
|
|
|
|
* 0 <= y + (fy-center) && y + (fy-center) < height
|
|
|
|
*
|
|
|
|
* 0 <= x + (fx - center) x + fx - center < width
|
|
|
|
* center - x <= fx fx < width + center - x
|
|
|
|
*/
|
|
|
|
|
|
|
|
fx_start = center - x;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (fx_start < 0) fx_start = 0;
|
2011-11-04 14:33:23 +08:00
|
|
|
fx_end = width + center - x;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (fx_end > g_size) fx_end = g_size;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
fy_start = center - y;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (fy_start < 0) fy_start = 0;
|
2011-11-04 14:33:23 +08:00
|
|
|
fy_end = height + center - y;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (fy_end > g_size) fy_end = g_size;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
g_line = g_line + fy_start * g_size + fx_start;
|
|
|
|
|
|
|
|
v = 0;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
for (fy = fy_start; fy < fy_end; fy++) {
|
|
|
|
g_data = g_line;
|
|
|
|
g_line += g_size;
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
for (fx = fx_start; fx < fx_end; fx++) {
|
2011-11-04 14:33:23 +08:00
|
|
|
v += *g_data++;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
if (v > 1) v = 1;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
return ((unsigned char) (v * opacity * 255.0));
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 17:18:10 +08:00
|
|
|
/* precompute shadow corners and sides
|
|
|
|
to save time for large windows */
|
2012-02-27 20:49:50 +08:00
|
|
|
|
2004-09-22 06:59:38 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
presum_gaussian(conv *map) {
|
2012-02-27 20:49:50 +08:00
|
|
|
int center = map->size / 2;
|
2011-11-04 14:33:23 +08:00
|
|
|
int opacity, x, y;
|
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
cgsize = map->size;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (shadow_corner) free((void *)shadow_corner);
|
|
|
|
if (shadow_top) free((void *)shadow_top);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_corner = (unsigned char *)(malloc((cgsize + 1) * (cgsize + 1) * 26));
|
|
|
|
shadow_top = (unsigned char *)(malloc((cgsize + 1) * 26));
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
for (x = 0; x <= cgsize; x++) {
|
|
|
|
shadow_top[25 * (cgsize + 1) + x] =
|
|
|
|
sum_gaussian(map, 1, x - center, center, cgsize * 2, cgsize * 2);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
for (opacity = 0; opacity < 25; opacity++) {
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_top[opacity * (cgsize + 1) + x] =
|
|
|
|
shadow_top[25 * (cgsize + 1) + x] * opacity / 25;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (y = 0; y <= x; y++) {
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_corner[25 * (cgsize + 1) * (cgsize + 1) + y * (cgsize + 1) + x]
|
|
|
|
= sum_gaussian(map, 1, x - center, y - center, cgsize * 2, cgsize * 2);
|
|
|
|
shadow_corner[25 * (cgsize + 1) * (cgsize + 1) + x * (cgsize + 1) + y]
|
|
|
|
= shadow_corner[25 * (cgsize + 1) * (cgsize + 1) + y * (cgsize + 1) + x];
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
for (opacity = 0; opacity < 25; opacity++) {
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_corner[opacity * (cgsize + 1) * (cgsize + 1)
|
|
|
|
+ y * (cgsize + 1) + x]
|
|
|
|
= shadow_corner[opacity * (cgsize + 1) * (cgsize + 1)
|
|
|
|
+ x * (cgsize + 1) + y]
|
|
|
|
= shadow_corner[25 * (cgsize + 1) * (cgsize + 1)
|
|
|
|
+ y * (cgsize + 1) + x] * opacity / 25;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
}
|
2004-09-22 06:59:38 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static XImage *
|
2011-11-04 17:18:10 +08:00
|
|
|
make_shadow(Display *dpy, double opacity,
|
|
|
|
int width, int height) {
|
2011-11-04 16:41:56 +08:00
|
|
|
XImage *ximage;
|
|
|
|
unsigned char *data;
|
|
|
|
int ylimit, xlimit;
|
2012-09-29 13:15:09 +08:00
|
|
|
int swidth = width + cgsize;
|
|
|
|
int sheight = height + cgsize;
|
|
|
|
int center = cgsize / 2;
|
2011-11-04 16:41:56 +08:00
|
|
|
int x, y;
|
|
|
|
unsigned char d;
|
|
|
|
int x_diff;
|
|
|
|
int opacity_int = (int)(opacity * 25);
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
data = malloc(swidth * sheight * sizeof(unsigned char));
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!data) return 0;
|
|
|
|
|
|
|
|
ximage = XCreateImage(
|
|
|
|
dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 8,
|
|
|
|
ZPixmap, 0, (char *) data, swidth, sheight, 8,
|
|
|
|
swidth * sizeof(unsigned char));
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!ximage) {
|
|
|
|
free(data);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
/*
|
|
|
|
* Build the gaussian in sections
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* center (fill the complete data array)
|
|
|
|
*/
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
// If clear_shadow is enabled and the border & corner shadow (which
|
2012-09-12 21:01:06 +08:00
|
|
|
// later will be filled) could entirely cover the area of the shadow
|
|
|
|
// that will be displayed, do not bother filling other pixels. If it
|
|
|
|
// can't, we must fill the other pixels here.
|
2012-09-26 18:54:35 +08:00
|
|
|
if (!(opts.clear_shadow && opts.shadow_offset_x <= 0 && opts.shadow_offset_x >= -cgsize
|
|
|
|
&& opts.shadow_offset_y <= 0 && opts.shadow_offset_y >= -cgsize)) {
|
2012-06-04 00:08:50 +08:00
|
|
|
if (cgsize > 0) {
|
|
|
|
d = shadow_top[opacity_int * (cgsize + 1) + cgsize];
|
2012-02-27 12:00:12 +08:00
|
|
|
} else {
|
|
|
|
d = sum_gaussian(gaussian_map,
|
|
|
|
opacity, center, center, width, height);
|
|
|
|
}
|
|
|
|
memset(data, d, sheight * swidth);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
/*
|
|
|
|
* corners
|
|
|
|
*/
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
ylimit = cgsize;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2;
|
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
xlimit = cgsize;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
for (y = 0; y < ylimit; y++) {
|
2011-11-04 14:33:23 +08:00
|
|
|
for (x = 0; x < xlimit; x++) {
|
2012-06-04 00:08:50 +08:00
|
|
|
if (xlimit == cgsize && ylimit == cgsize) {
|
|
|
|
d = shadow_corner[opacity_int * (cgsize + 1) * (cgsize + 1)
|
|
|
|
+ y * (cgsize + 1) + x];
|
2011-11-04 16:41:56 +08:00
|
|
|
} else {
|
2011-11-04 17:18:10 +08:00
|
|
|
d = sum_gaussian(gaussian_map,
|
|
|
|
opacity, x - center, y - center, width, height);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
data[y * swidth + x] = d;
|
|
|
|
data[(sheight - y - 1) * swidth + x] = d;
|
|
|
|
data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d;
|
|
|
|
data[y * swidth + (swidth - x - 1)] = d;
|
|
|
|
}
|
2012-02-27 12:00:12 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* top/bottom
|
|
|
|
*/
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
x_diff = swidth - (cgsize * 2);
|
2011-11-04 14:33:23 +08:00
|
|
|
if (x_diff > 0 && ylimit > 0) {
|
|
|
|
for (y = 0; y < ylimit; y++) {
|
2012-06-04 00:08:50 +08:00
|
|
|
if (ylimit == cgsize) {
|
|
|
|
d = shadow_top[opacity_int * (cgsize + 1) + y];
|
2011-11-04 16:41:56 +08:00
|
|
|
} else {
|
2011-11-04 17:18:10 +08:00
|
|
|
d = sum_gaussian(gaussian_map,
|
|
|
|
opacity, center, y - center, width, height);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2012-09-29 13:15:09 +08:00
|
|
|
memset(&data[y * swidth + cgsize], d, x_diff);
|
|
|
|
memset(&data[(sheight - y - 1) * swidth + cgsize], d, x_diff);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sides
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (x = 0; x < xlimit; x++) {
|
2012-06-04 00:08:50 +08:00
|
|
|
if (xlimit == cgsize) {
|
|
|
|
d = shadow_top[opacity_int * (cgsize + 1) + x];
|
2011-11-04 16:41:56 +08:00
|
|
|
} else {
|
2011-11-04 17:18:10 +08:00
|
|
|
d = sum_gaussian(gaussian_map,
|
|
|
|
opacity, x - center, center, width, height);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2012-09-29 13:15:09 +08:00
|
|
|
for (y = cgsize; y < sheight - cgsize; y++) {
|
2011-11-04 14:33:23 +08:00
|
|
|
data[y * swidth + x] = d;
|
|
|
|
data[y * swidth + (swidth - x - 1)] = d;
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2003-11-10 09:32:01 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.clear_shadow) {
|
2012-09-12 21:01:06 +08:00
|
|
|
// Clear the region in the shadow that the window would cover based
|
|
|
|
// on shadow_offset_{x,y} user provides
|
2012-09-26 18:54:35 +08:00
|
|
|
int xstart = normalize_i_range(- (int) opts.shadow_offset_x, 0, swidth);
|
|
|
|
int xrange = normalize_i_range(width - (int) opts.shadow_offset_x,
|
2012-09-12 21:01:06 +08:00
|
|
|
0, swidth) - xstart;
|
2012-09-26 18:54:35 +08:00
|
|
|
int ystart = normalize_i_range(- (int) opts.shadow_offset_y, 0, sheight);
|
|
|
|
int yend = normalize_i_range(height - (int) opts.shadow_offset_y,
|
2012-09-12 21:01:06 +08:00
|
|
|
0, sheight);
|
|
|
|
int y;
|
|
|
|
|
2012-09-13 13:58:05 +08:00
|
|
|
for (y = ystart; y < yend; y++) {
|
2012-09-12 21:01:06 +08:00
|
|
|
memset(&data[y * swidth + xstart], 0, xrange);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-02-02 03:52:35 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return ximage;
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static Picture
|
2012-09-17 22:15:04 +08:00
|
|
|
shadow_picture(Display *dpy, double opacity, int width, int height) {
|
2012-09-29 13:15:09 +08:00
|
|
|
XImage *shadow_image = NULL;
|
|
|
|
Pixmap shadow_pixmap = None, shadow_pixmap_argb = None;
|
|
|
|
Picture shadow_picture = None, shadow_picture_argb = None;
|
|
|
|
GC gc = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_image = make_shadow(dpy, opacity, width, height);
|
2012-09-29 13:15:09 +08:00
|
|
|
if (!shadow_image)
|
|
|
|
return None;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_pixmap = XCreatePixmap(dpy, root,
|
|
|
|
shadow_image->width, shadow_image->height, 8);
|
2012-09-29 13:15:09 +08:00
|
|
|
shadow_pixmap_argb = XCreatePixmap(dpy, root,
|
|
|
|
shadow_image->width, shadow_image->height, 32);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
if (!shadow_pixmap || !shadow_pixmap_argb)
|
|
|
|
goto shadow_picture_err;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap,
|
2011-11-04 16:41:56 +08:00
|
|
|
XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0);
|
2012-09-29 13:15:09 +08:00
|
|
|
shadow_picture_argb = XRenderCreatePicture(dpy, shadow_pixmap_argb,
|
|
|
|
XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0);
|
|
|
|
if (!shadow_picture || !shadow_picture_argb)
|
|
|
|
goto shadow_picture_err;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-06-04 00:08:50 +08:00
|
|
|
gc = XCreateGC(dpy, shadow_pixmap, 0, 0);
|
2012-09-29 13:15:09 +08:00
|
|
|
if (!gc)
|
|
|
|
goto shadow_picture_err;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
XPutImage(dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0,
|
2012-06-04 00:08:50 +08:00
|
|
|
shadow_image->width, shadow_image->height);
|
2012-09-29 13:15:09 +08:00
|
|
|
XRenderComposite(dpy, PictOpSrc, cshadow_picture, shadow_picture,
|
|
|
|
shadow_picture_argb, 0, 0, 0, 0, 0, 0,
|
|
|
|
shadow_image->width, shadow_image->height);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
XFreeGC(dpy, gc);
|
2012-06-04 00:08:50 +08:00
|
|
|
XDestroyImage(shadow_image);
|
|
|
|
XFreePixmap(dpy, shadow_pixmap);
|
2012-09-29 13:15:09 +08:00
|
|
|
XFreePixmap(dpy, shadow_pixmap_argb);
|
|
|
|
XRenderFreePicture(dpy, shadow_picture);
|
|
|
|
|
|
|
|
return shadow_picture_argb;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
shadow_picture_err:
|
|
|
|
if (shadow_image)
|
|
|
|
XDestroyImage(shadow_image);
|
|
|
|
if (shadow_pixmap)
|
|
|
|
XFreePixmap(dpy, shadow_pixmap);
|
|
|
|
if (shadow_pixmap_argb)
|
|
|
|
XFreePixmap(dpy, shadow_pixmap_argb);
|
|
|
|
if (shadow_picture)
|
|
|
|
XRenderFreePicture(dpy, shadow_picture);
|
|
|
|
if (shadow_picture_argb)
|
|
|
|
XRenderFreePicture(dpy, shadow_picture_argb);
|
|
|
|
if (gc)
|
|
|
|
XFreeGC(dpy, gc);
|
|
|
|
return None;
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static Picture
|
2011-11-04 17:18:10 +08:00
|
|
|
solid_picture(Display *dpy, Bool argb, double a,
|
|
|
|
double r, double g, double b) {
|
2011-11-04 16:41:56 +08:00
|
|
|
Pixmap pixmap;
|
|
|
|
Picture picture;
|
|
|
|
XRenderPictureAttributes pa;
|
|
|
|
XRenderColor c;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
pixmap = XCreatePixmap(dpy, root, 1, 1, argb ? 32 : 8);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
if (!pixmap) return None;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
pa.repeat = True;
|
|
|
|
picture = XRenderCreatePicture(dpy, pixmap,
|
2011-11-04 17:18:10 +08:00
|
|
|
XRenderFindStandardFormat(dpy, argb
|
|
|
|
? PictStandardARGB32 : PictStandardA8),
|
2011-11-04 16:41:56 +08:00
|
|
|
CPRepeat,
|
|
|
|
&pa);
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!picture) {
|
|
|
|
XFreePixmap(dpy, pixmap);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
c.alpha = a * 0xffff;
|
|
|
|
c.red = r * 0xffff;
|
|
|
|
c.green = g * 0xffff;
|
|
|
|
c.blue = b * 0xffff;
|
2011-11-05 05:18:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
|
|
|
|
XFreePixmap(dpy, pixmap);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return picture;
|
2004-06-27 12:48:37 +08:00
|
|
|
}
|
|
|
|
|
2012-02-09 06:45:08 +08:00
|
|
|
/**
|
|
|
|
* Errors
|
|
|
|
*/
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
discard_ignore(Display *dpy, unsigned long sequence) {
|
|
|
|
while (ignore_head) {
|
|
|
|
if ((long) (sequence - ignore_head->sequence) > 0) {
|
|
|
|
ignore *next = ignore_head->next;
|
|
|
|
free(ignore_head);
|
|
|
|
ignore_head = next;
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!ignore_head) {
|
2011-11-04 14:33:23 +08:00
|
|
|
ignore_tail = &ignore_head;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
} else {
|
2011-11-04 14:33:23 +08:00
|
|
|
break;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2004-06-27 12:48:37 +08:00
|
|
|
}
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
set_ignore(Display *dpy, unsigned long sequence) {
|
2011-11-04 16:41:56 +08:00
|
|
|
ignore *i = malloc(sizeof(ignore));
|
|
|
|
if (!i) return;
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
i->sequence = sequence;
|
|
|
|
i->next = 0;
|
|
|
|
*ignore_tail = i;
|
|
|
|
ignore_tail = &i->next;
|
2004-06-27 12:48:37 +08:00
|
|
|
}
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static int
|
2011-11-04 14:33:23 +08:00
|
|
|
should_ignore(Display *dpy, unsigned long sequence) {
|
|
|
|
discard_ignore(dpy, sequence);
|
|
|
|
return ignore_head && ignore_head->sequence == sequence;
|
2004-06-27 12:48:37 +08:00
|
|
|
}
|
|
|
|
|
2012-02-09 06:45:08 +08:00
|
|
|
/**
|
|
|
|
* Windows
|
|
|
|
*/
|
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
/**
|
|
|
|
* Match a window against a single window condition.
|
|
|
|
*
|
|
|
|
* @return true if matched, false otherwise.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
win_match_once(win *w, const wincond *cond) {
|
|
|
|
const char *target;
|
|
|
|
bool matched = false;
|
|
|
|
|
|
|
|
#ifdef DEBUG_WINMATCH
|
|
|
|
printf("win_match_once(%#010lx \"%s\"): cond = %p", w->id, w->name,
|
|
|
|
cond);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Determine the target
|
|
|
|
target = NULL;
|
|
|
|
switch (cond->target) {
|
|
|
|
case CONDTGT_NAME:
|
|
|
|
target = w->name;
|
|
|
|
break;
|
|
|
|
case CONDTGT_CLASSI:
|
|
|
|
target = w->class_instance;
|
|
|
|
break;
|
|
|
|
case CONDTGT_CLASSG:
|
|
|
|
target = w->class_general;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!target) {
|
|
|
|
#ifdef DEBUG_WINMATCH
|
|
|
|
printf(": Target not found\n");
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine pattern type and match
|
|
|
|
switch (cond->type) {
|
|
|
|
case CONDTP_EXACT:
|
|
|
|
if (cond->flags & CONDF_IGNORECASE)
|
|
|
|
matched = !strcasecmp(target, cond->pattern);
|
|
|
|
else
|
|
|
|
matched = !strcmp(target, cond->pattern);
|
|
|
|
break;
|
|
|
|
case CONDTP_ANYWHERE:
|
|
|
|
if (cond->flags & CONDF_IGNORECASE)
|
|
|
|
matched = strcasestr(target, cond->pattern);
|
|
|
|
else
|
|
|
|
matched = strstr(target, cond->pattern);
|
|
|
|
break;
|
|
|
|
case CONDTP_FROMSTART:
|
|
|
|
if (cond->flags & CONDF_IGNORECASE)
|
|
|
|
matched = !strncasecmp(target, cond->pattern,
|
|
|
|
strlen(cond->pattern));
|
|
|
|
else
|
|
|
|
matched = !strncmp(target, cond->pattern,
|
|
|
|
strlen(cond->pattern));
|
|
|
|
break;
|
|
|
|
case CONDTP_WILDCARD:
|
|
|
|
{
|
|
|
|
int flags = 0;
|
|
|
|
if (cond->flags & CONDF_IGNORECASE)
|
|
|
|
flags = FNM_CASEFOLD;
|
|
|
|
matched = !fnmatch(cond->pattern, target, flags);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CONDTP_REGEX_PCRE:
|
|
|
|
#ifdef CONFIG_REGEX_PCRE
|
|
|
|
matched = (pcre_exec(cond->regex_pcre, cond->regex_pcre_extra,
|
|
|
|
target, strlen(target), 0, 0, NULL, 0) >= 0);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_WINMATCH
|
|
|
|
printf(", matched = %d\n", matched);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return matched;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Match a window against a condition linked list.
|
|
|
|
*
|
|
|
|
* @param cache a place to cache the last matched condition
|
|
|
|
* @return true if matched, false otherwise.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
win_match(win *w, wincond *condlst, wincond **cache) {
|
|
|
|
// Check if the cached entry matches firstly
|
|
|
|
if (cache && *cache && win_match_once(w, *cache))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Then go through the whole linked list
|
|
|
|
for (; condlst; condlst = condlst->next) {
|
|
|
|
if (win_match_once(w, condlst)) {
|
|
|
|
*cache = condlst;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a pattern to a condition linked list.
|
|
|
|
*/
|
|
|
|
static Bool
|
|
|
|
condlst_add(wincond **pcondlst, const char *pattern) {
|
2012-09-25 10:19:20 +08:00
|
|
|
if (!pattern)
|
|
|
|
return False;
|
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
unsigned plen = strlen(pattern);
|
|
|
|
wincond *cond;
|
|
|
|
const char *pos;
|
|
|
|
|
|
|
|
if (plen < 4 || ':' != pattern[1] || !strchr(pattern + 2, ':')) {
|
|
|
|
printf("Pattern \"%s\": Format invalid.\n", pattern);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate memory for the new condition
|
|
|
|
cond = malloc(sizeof(wincond));
|
|
|
|
|
|
|
|
// Determine the pattern target
|
|
|
|
switch (pattern[0]) {
|
|
|
|
case 'n':
|
|
|
|
cond->target = CONDTGT_NAME;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
cond->target = CONDTGT_CLASSI;
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
cond->target = CONDTGT_CLASSG;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("Pattern \"%s\": Target \"%c\" invalid.\n",
|
|
|
|
pattern, pattern[0]);
|
|
|
|
free(cond);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the pattern type
|
|
|
|
switch (pattern[2]) {
|
|
|
|
case 'e':
|
|
|
|
cond->type = CONDTP_EXACT;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
cond->type = CONDTP_ANYWHERE;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
cond->type = CONDTP_FROMSTART;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
cond->type = CONDTP_WILDCARD;
|
|
|
|
break;
|
|
|
|
#ifdef CONFIG_REGEX_PCRE
|
|
|
|
case 'p':
|
|
|
|
cond->type = CONDTP_REGEX_PCRE;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
printf("Pattern \"%s\": Type \"%c\" invalid.\n",
|
|
|
|
pattern, pattern[2]);
|
|
|
|
free(cond);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the pattern flags
|
|
|
|
pos = &pattern[3];
|
|
|
|
cond->flags = 0;
|
|
|
|
while (':' != *pos) {
|
|
|
|
switch (*pos) {
|
|
|
|
case 'i':
|
|
|
|
cond->flags |= CONDF_IGNORECASE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("Pattern \"%s\": Flag \"%c\" invalid.\n",
|
|
|
|
pattern, *pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the pattern
|
|
|
|
++pos;
|
|
|
|
cond->pattern = NULL;
|
|
|
|
#ifdef CONFIG_REGEX_PCRE
|
|
|
|
cond->regex_pcre = NULL;
|
|
|
|
cond->regex_pcre_extra = NULL;
|
|
|
|
#endif
|
|
|
|
if (CONDTP_REGEX_PCRE == cond->type) {
|
|
|
|
#ifdef CONFIG_REGEX_PCRE
|
|
|
|
const char *error = NULL;
|
|
|
|
int erroffset = 0;
|
|
|
|
int options = 0;
|
|
|
|
|
|
|
|
if (cond->flags & CONDF_IGNORECASE)
|
|
|
|
options |= PCRE_CASELESS;
|
|
|
|
|
|
|
|
cond->regex_pcre = pcre_compile(pos, options, &error, &erroffset,
|
|
|
|
NULL);
|
|
|
|
if (!cond->regex_pcre) {
|
|
|
|
printf("Pattern \"%s\": PCRE regular expression parsing failed on "
|
|
|
|
"offset %d: %s\n", pattern, erroffset, error);
|
|
|
|
free(cond);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_REGEX_PCRE_JIT
|
|
|
|
cond->regex_pcre_extra = pcre_study(cond->regex_pcre, PCRE_STUDY_JIT_COMPILE, &error);
|
|
|
|
if (!cond->regex_pcre_extra) {
|
|
|
|
printf("Pattern \"%s\": PCRE regular expression study failed: %s",
|
|
|
|
pattern, error);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cond->pattern = mstrcpy(pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert it into the linked list
|
|
|
|
cond->next = *pcondlst;
|
|
|
|
*pcondlst = cond;
|
|
|
|
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
2012-09-13 23:24:37 +08:00
|
|
|
static long
|
|
|
|
determine_evmask(Display *dpy, Window wid, win_evmode_t mode) {
|
2012-09-13 22:30:18 +08:00
|
|
|
long evmask = NoEventMask;
|
|
|
|
|
|
|
|
if (WIN_EVMODE_FRAME == mode || find_win(dpy, wid)) {
|
|
|
|
evmask |= PropertyChangeMask;
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.track_focus) evmask |= FocusChangeMask;
|
2012-09-13 22:30:18 +08:00
|
|
|
}
|
2012-09-13 23:12:54 +08:00
|
|
|
|
2012-09-20 13:50:27 +08:00
|
|
|
if (WIN_EVMODE_CLIENT == mode || find_toplevel(dpy, wid)) {
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.frame_opacity || opts.track_wdata)
|
2012-09-14 11:51:46 +08:00
|
|
|
evmask |= PropertyChangeMask;
|
2012-09-13 22:30:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return evmask;
|
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static win *
|
2011-11-04 14:33:23 +08:00
|
|
|
find_win(Display *dpy, Window id) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win *w;
|
2003-11-09 15:08:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
for (w = list; w; w = w->next) {
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->id == id && !w->destroyed)
|
|
|
|
return w;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return 0;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-13 21:38:55 +08:00
|
|
|
/**
|
|
|
|
* Find out the WM frame of a client window using existing data.
|
|
|
|
*
|
|
|
|
* @param dpy display to use
|
|
|
|
* @param w window ID
|
|
|
|
* @return struct _win object of the found window, NULL if not found
|
|
|
|
*/
|
2012-09-13 23:12:54 +08:00
|
|
|
static win *
|
|
|
|
find_toplevel(Display *dpy, Window id) {
|
2012-02-01 06:10:30 +08:00
|
|
|
win *w;
|
|
|
|
|
|
|
|
for (w = list; w; w = w->next) {
|
|
|
|
if (w->client_win == id && !w->destroyed)
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
2012-09-13 21:38:55 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find out the WM frame of a client window by querying X.
|
|
|
|
*
|
|
|
|
* @param dpy display to use
|
|
|
|
* @param w window ID
|
|
|
|
* @return struct _win object of the found window, NULL if not found
|
|
|
|
*/
|
2012-09-13 23:12:54 +08:00
|
|
|
static win *
|
|
|
|
find_toplevel2(Display *dpy, Window wid) {
|
2012-09-13 21:38:55 +08:00
|
|
|
win *w = NULL;
|
|
|
|
|
|
|
|
// We traverse through its ancestors to find out the frame
|
2012-09-13 23:12:54 +08:00
|
|
|
while (wid && wid != root && !(w = find_win(dpy, wid))) {
|
2012-09-13 21:38:55 +08:00
|
|
|
Window troot;
|
|
|
|
Window parent;
|
|
|
|
Window *tchildren;
|
|
|
|
unsigned tnchildren;
|
|
|
|
|
|
|
|
// XQueryTree probably fails if you run compton when X is somehow
|
|
|
|
// initializing (like add it in .xinitrc). In this case
|
|
|
|
// just leave it alone.
|
2012-09-13 23:12:54 +08:00
|
|
|
if (!XQueryTree(dpy, wid, &troot, &parent, &tchildren,
|
2012-09-13 21:38:55 +08:00
|
|
|
&tnchildren)) {
|
2012-09-17 16:04:04 +08:00
|
|
|
parent = 0;
|
2012-09-13 21:38:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-09-13 23:12:54 +08:00
|
|
|
if (tchildren) XFree(tchildren);
|
|
|
|
|
2012-09-13 21:38:55 +08:00
|
|
|
wid = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recheck currently focused window and set its <code>w->focused</code>
|
|
|
|
* to True.
|
|
|
|
*
|
|
|
|
* @param dpy display to use
|
|
|
|
* @return struct _win of currently focused window, NULL if not found
|
|
|
|
*/
|
2012-09-13 23:12:54 +08:00
|
|
|
static win *
|
|
|
|
recheck_focus(Display *dpy) {
|
2012-09-13 21:38:55 +08:00
|
|
|
// Determine 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);
|
|
|
|
|
|
|
|
// Fallback to the old method if find_toplevel() fails
|
2012-09-13 23:12:54 +08:00
|
|
|
if (!(w = find_toplevel(dpy, wid))) {
|
2012-09-13 21:38:55 +08:00
|
|
|
w = find_toplevel2(dpy, wid);
|
2012-09-13 23:12:54 +08:00
|
|
|
}
|
2012-09-13 21:38:55 +08:00
|
|
|
|
|
|
|
// And we set the focus state and opacity here
|
|
|
|
if (w) {
|
2012-09-20 13:50:27 +08:00
|
|
|
set_focused(dpy, w, True);
|
2012-09-13 21:38:55 +08:00
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2012-02-01 06:10:30 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static Picture
|
2011-11-04 16:41:56 +08:00
|
|
|
root_tile_f(Display *dpy) {
|
|
|
|
Picture picture;
|
|
|
|
Atom actual_type;
|
|
|
|
Pixmap pixmap;
|
|
|
|
int actual_format;
|
|
|
|
unsigned long nitems;
|
|
|
|
unsigned long bytes_after;
|
|
|
|
unsigned char *prop;
|
|
|
|
Bool fill;
|
|
|
|
XRenderPictureAttributes pa;
|
|
|
|
int p;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
pixmap = None;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
for (p = 0; background_props[p]; p++) {
|
2012-09-23 11:49:02 +08:00
|
|
|
prop = NULL;
|
2011-11-05 05:18:56 +08:00
|
|
|
if (XGetWindowProperty(dpy, root,
|
|
|
|
XInternAtom(dpy, background_props[p], False),
|
|
|
|
0, 4, False, AnyPropertyType, &actual_type,
|
|
|
|
&actual_format, &nitems, &bytes_after, &prop
|
2011-11-04 16:41:56 +08:00
|
|
|
) == Success
|
|
|
|
&& actual_type == XInternAtom(dpy, "PIXMAP", False)
|
|
|
|
&& actual_format == 32 && nitems == 1) {
|
2011-11-04 14:33:23 +08:00
|
|
|
memcpy(&pixmap, prop, 4);
|
|
|
|
XFree(prop);
|
|
|
|
fill = False;
|
|
|
|
break;
|
2012-09-23 11:49:02 +08:00
|
|
|
} else if (prop)
|
|
|
|
XFree(prop);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!pixmap) {
|
|
|
|
pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, scr));
|
|
|
|
fill = True;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
pa.repeat = True;
|
2011-11-04 16:41:56 +08:00
|
|
|
picture = XRenderCreatePicture(
|
|
|
|
dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
|
|
|
|
CPRepeat, &pa);
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (fill) {
|
|
|
|
XRenderColor c;
|
|
|
|
|
|
|
|
c.red = c.green = c.blue = 0x8080;
|
|
|
|
c.alpha = 0xffff;
|
2011-11-04 16:41:56 +08:00
|
|
|
XRenderFillRectangle(
|
|
|
|
dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return picture;
|
2003-11-10 10:03:26 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
paint_root(Display *dpy) {
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!root_tile) {
|
|
|
|
root_tile = root_tile_f(dpy);
|
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpSrc, root_tile, None,
|
|
|
|
root_buffer, 0, 0, 0, 0, 0, 0,
|
|
|
|
root_width, root_height);
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
/**
|
|
|
|
* Get a rectangular region a window (and possibly its shadow) occupies.
|
|
|
|
*
|
|
|
|
* Note w->shadow and shadow geometry must be correct before calling this
|
|
|
|
* function.
|
|
|
|
*/
|
2003-11-20 00:12:15 +08:00
|
|
|
static XserverRegion
|
2011-11-04 14:33:23 +08:00
|
|
|
win_extents(Display *dpy, win *w) {
|
2011-11-04 16:41:56 +08:00
|
|
|
XRectangle r;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
r.x = w->a.x;
|
|
|
|
r.y = w->a.y;
|
2012-09-17 22:15:04 +08:00
|
|
|
r.width = w->widthb;
|
|
|
|
r.height = w->heightb;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
if (w->shadow) {
|
2011-11-04 17:18:10 +08:00
|
|
|
XRectangle sr;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 17:18:10 +08:00
|
|
|
sr.x = w->a.x + w->shadow_dx;
|
|
|
|
sr.y = w->a.y + w->shadow_dy;
|
|
|
|
sr.width = w->shadow_width;
|
|
|
|
sr.height = w->shadow_height;
|
|
|
|
|
|
|
|
if (sr.x < r.x) {
|
|
|
|
r.width = (r.x + r.width) - sr.x;
|
|
|
|
r.x = sr.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sr.y < r.y) {
|
|
|
|
r.height = (r.y + r.height) - sr.y;
|
|
|
|
r.y = sr.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sr.x + sr.width > r.x + r.width) {
|
|
|
|
r.width = sr.x + sr.width - r.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sr.y + sr.height > r.y + r.height) {
|
|
|
|
r.height = sr.y + sr.height - r.y;
|
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return XFixesCreateRegion(dpy, &r, 1);
|
2003-11-10 09:32:01 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static XserverRegion
|
2011-11-04 14:33:23 +08:00
|
|
|
border_size(Display *dpy, win *w) {
|
2011-11-04 16:41:56 +08:00
|
|
|
XserverRegion border;
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
/*
|
|
|
|
* if window doesn't exist anymore, this will generate an error
|
|
|
|
* as well as not generate a region. Perhaps a better XFixes
|
|
|
|
* architecture would be to have a request that copies instead
|
|
|
|
* of creates, that way you'd just end up with an empty region
|
|
|
|
* instead of an invalid XID.
|
|
|
|
*/
|
2011-11-04 17:18:10 +08:00
|
|
|
|
|
|
|
border = XFixesCreateRegionFromWindow(
|
|
|
|
dpy, w->id, WindowRegionBounding);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
/* translate this */
|
|
|
|
XFixesTranslateRegion(dpy, border,
|
2011-11-04 16:41:56 +08:00
|
|
|
w->a.x + w->a.border_width,
|
|
|
|
w->a.y + w->a.border_width);
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return border;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-13 23:12:54 +08:00
|
|
|
static Window
|
|
|
|
find_client_win(Display *dpy, Window w) {
|
2012-09-20 13:50:27 +08:00
|
|
|
if (win_has_attr(dpy, w, client_atom)) {
|
2012-09-13 21:38:55 +08:00
|
|
|
return w;
|
2012-09-13 23:12:54 +08:00
|
|
|
}
|
2011-11-06 10:39:58 +08:00
|
|
|
|
|
|
|
Window *children;
|
|
|
|
unsigned int nchildren;
|
|
|
|
unsigned int i;
|
2012-09-13 21:38:55 +08:00
|
|
|
Window ret = 0;
|
2011-11-06 10:39:58 +08:00
|
|
|
|
2012-09-13 23:12:54 +08:00
|
|
|
if (!win_get_children(dpy, w, &children, &nchildren)) {
|
2011-11-06 10:39:58 +08:00
|
|
|
return 0;
|
2012-09-13 23:12:54 +08:00
|
|
|
}
|
2011-11-06 10:39:58 +08:00
|
|
|
|
2012-09-13 23:12:54 +08:00
|
|
|
for (i = 0; i < nchildren; ++i) {
|
2012-09-13 21:38:55 +08:00
|
|
|
if ((ret = find_client_win(dpy, children[i])))
|
|
|
|
break;
|
2012-09-13 23:12:54 +08:00
|
|
|
}
|
2011-11-06 10:39:58 +08:00
|
|
|
|
2012-09-13 21:38:55 +08:00
|
|
|
XFree(children);
|
2011-11-06 10:39:58 +08:00
|
|
|
|
2012-09-13 21:38:55 +08:00
|
|
|
return ret;
|
2011-11-06 10:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-09-20 13:50:27 +08:00
|
|
|
get_frame_extents(Display *dpy, win *w, Window client) {
|
2011-11-06 10:39:58 +08:00
|
|
|
long *extents;
|
|
|
|
Atom type;
|
|
|
|
int format;
|
|
|
|
unsigned long nitems, after;
|
|
|
|
unsigned char *data = NULL;
|
|
|
|
int result;
|
|
|
|
|
2012-09-20 13:50:27 +08:00
|
|
|
w->left_width = 0;
|
|
|
|
w->right_width = 0;
|
|
|
|
w->top_width = 0;
|
|
|
|
w->bottom_width = 0;
|
2011-11-06 10:39:58 +08:00
|
|
|
|
|
|
|
result = XGetWindowProperty(
|
2012-09-20 13:50:27 +08:00
|
|
|
dpy, client, frame_extents_atom,
|
2011-11-06 10:39:58 +08:00
|
|
|
0L, 4L, False, AnyPropertyType,
|
|
|
|
&type, &format, &nitems, &after,
|
2012-09-20 13:50:27 +08:00
|
|
|
&data);
|
2011-11-06 10:39:58 +08:00
|
|
|
|
|
|
|
if (result == Success) {
|
|
|
|
if (nitems == 4 && after == 0) {
|
2012-09-20 13:50:27 +08:00
|
|
|
extents = (long *) data;
|
|
|
|
w->left_width = extents[0];
|
|
|
|
w->right_width = extents[1];
|
|
|
|
w->top_width = extents[2];
|
|
|
|
w->bottom_width = extents[3];
|
2011-11-06 10:39:58 +08:00
|
|
|
}
|
|
|
|
XFree(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
static win *
|
|
|
|
paint_preprocess(Display *dpy, win *list) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win *w;
|
2012-09-19 20:49:16 +08:00
|
|
|
win *t = NULL, *next = NULL;
|
|
|
|
// Sounds like the timeout in poll() frequently does not work
|
|
|
|
// accurately, asking it to wait to 20ms, and often it would wait for
|
|
|
|
// 19ms, so the step value has to be rounded.
|
2012-09-26 18:54:35 +08:00
|
|
|
unsigned steps = roundl((double) (get_time_in_milliseconds() - fade_time) / opts.fade_delta);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
// Reset fade_time
|
|
|
|
fade_time = get_time_in_milliseconds();
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
for (w = list; w; w = next) {
|
|
|
|
// In case calling the fade callback function destroys this window
|
|
|
|
next = w->next;
|
|
|
|
opacity_t opacity_old = w->opacity;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2004-08-13 16:25:51 +08:00
|
|
|
#if CAN_DO_USABLE
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!w->usable) continue;
|
2004-08-13 16:25:51 +08:00
|
|
|
#endif
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Run fading
|
|
|
|
run_fade(dpy, w, steps);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Give up if it's not damaged or invisible
|
|
|
|
if (!w->damaged
|
|
|
|
|| w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1
|
2011-11-04 16:41:56 +08:00
|
|
|
|| w->a.x >= root_width || w->a.y >= root_height) {
|
2012-09-19 20:49:16 +08:00
|
|
|
check_fade_fin(dpy, w);
|
2011-11-04 14:33:23 +08:00
|
|
|
continue;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2012-09-20 13:50:27 +08:00
|
|
|
// If opacity changes
|
|
|
|
if (w->opacity != opacity_old) {
|
|
|
|
determine_mode(dpy, w);
|
|
|
|
add_damage_win(dpy, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!w->opacity) {
|
|
|
|
check_fade_fin(dpy, w);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Fetch the picture and pixmap if needed
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!w->picture) {
|
2011-11-04 16:41:56 +08:00
|
|
|
XRenderPictureAttributes pa;
|
|
|
|
XRenderPictFormat *format;
|
|
|
|
Drawable draw = w->id;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2004-07-08 15:07:26 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
2011-11-04 16:41:56 +08:00
|
|
|
if (has_name_pixmap && !w->pixmap) {
|
2011-11-04 14:33:23 +08:00
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
w->pixmap = XCompositeNameWindowPixmap(dpy, w->id);
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
if (w->pixmap) draw = w->pixmap;
|
2004-07-08 15:07:26 +08:00
|
|
|
#endif
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
format = XRenderFindVisualFormat(dpy, w->a.visual);
|
|
|
|
pa.subwindow_mode = IncludeInferiors;
|
2011-11-04 16:41:56 +08:00
|
|
|
w->picture = XRenderCreatePicture(
|
|
|
|
dpy, draw, format, CPSubwindowMode, &pa);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Fetch bounding region and extents if needed
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!w->border_size) {
|
2012-06-04 00:12:30 +08:00
|
|
|
w->border_size = border_size(dpy, w);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!w->extents) {
|
2011-11-04 14:33:23 +08:00
|
|
|
w->extents = win_extents(dpy, w);
|
2012-09-25 10:19:20 +08:00
|
|
|
// If w->extents does not exist, the previous add_damage_win()
|
|
|
|
// call when opacity changes has no effect, so redo it here.
|
|
|
|
if (w->opacity != opacity_old)
|
|
|
|
add_damage_win(dpy, w);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2012-09-17 12:31:01 +08:00
|
|
|
// Rebuild alpha_pict only if necessary
|
|
|
|
if (OPAQUE != w->opacity
|
|
|
|
&& (!w->alpha_pict || w->opacity != w->opacity_cur)) {
|
|
|
|
free_picture(dpy, &w->alpha_pict);
|
|
|
|
w->alpha_pict = solid_picture(
|
|
|
|
dpy, False, get_opacity_percent(dpy, w), 0, 0, 0);
|
|
|
|
w->opacity_cur = w->opacity;
|
|
|
|
}
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
// Calculate frame_opacity
|
|
|
|
if (opts.frame_opacity && 1.0 != opts.frame_opacity && w->top_width)
|
|
|
|
w->frame_opacity = get_opacity_percent(dpy, w) * opts.frame_opacity;
|
2012-09-17 12:31:01 +08:00
|
|
|
else
|
|
|
|
w->frame_opacity = 0.0;
|
|
|
|
|
|
|
|
// Rebuild frame_alpha_pict only if necessary
|
|
|
|
if (w->frame_opacity
|
|
|
|
&& (!w->frame_alpha_pict
|
|
|
|
|| w->frame_opacity != w->frame_opacity_cur)) {
|
|
|
|
free_picture(dpy, &w->frame_alpha_pict);
|
|
|
|
w->frame_alpha_pict = solid_picture(
|
|
|
|
dpy, False, w->frame_opacity, 0, 0, 0);
|
|
|
|
w->frame_opacity_cur = w->frame_opacity;
|
|
|
|
}
|
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
// Calculate shadow opacity
|
|
|
|
if (w->frame_opacity)
|
2012-09-26 18:54:35 +08:00
|
|
|
w->shadow_opacity = opts.shadow_opacity * w->frame_opacity;
|
2012-09-17 22:15:04 +08:00
|
|
|
else
|
2012-09-26 18:54:35 +08:00
|
|
|
w->shadow_opacity = opts.shadow_opacity * get_opacity_percent(dpy, w);
|
2012-09-17 22:15:04 +08:00
|
|
|
|
|
|
|
// Rebuild shadow_pict if necessary
|
|
|
|
if (w->flags & WFLAG_SIZE_CHANGE)
|
|
|
|
free_picture(dpy, &w->shadow_pict);
|
|
|
|
|
2012-09-29 13:15:09 +08:00
|
|
|
if (w->shadow && !w->shadow_pict) {
|
|
|
|
w->shadow_pict = shadow_picture(dpy, 1,
|
|
|
|
w->widthb, w->heightb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rebuild shadow_alpha_pict if necessary
|
2012-09-17 22:15:04 +08:00
|
|
|
if (w->shadow
|
2012-09-29 13:15:09 +08:00
|
|
|
&& (!w->shadow_alpha_pict
|
2012-09-17 22:15:04 +08:00
|
|
|
|| w->shadow_opacity != w->shadow_opacity_cur)) {
|
2012-09-29 13:15:09 +08:00
|
|
|
free_picture(dpy, &w->shadow_alpha_pict);
|
|
|
|
w->shadow_alpha_pict = solid_picture(
|
|
|
|
dpy, False, w->shadow_opacity, 0, 0, 0);
|
2012-09-17 22:15:04 +08:00
|
|
|
w->shadow_opacity_cur = w->shadow_opacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset flags
|
|
|
|
w->flags = 0;
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->prev_trans = t;
|
|
|
|
t = w;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
paint_all(Display *dpy, XserverRegion region, win *t) {
|
|
|
|
win *w;
|
|
|
|
|
|
|
|
if (!region) {
|
|
|
|
region = get_screen_region(dpy);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MONITOR_REPAINT
|
|
|
|
root_buffer = root_picture;
|
|
|
|
#else
|
|
|
|
if (!root_buffer) {
|
|
|
|
Pixmap root_pixmap = XCreatePixmap(
|
|
|
|
dpy, root, root_width, root_height,
|
|
|
|
DefaultDepth(dpy, scr));
|
|
|
|
|
|
|
|
root_buffer = XRenderCreatePicture(dpy, root_pixmap,
|
|
|
|
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
|
|
|
|
0, 0);
|
|
|
|
|
|
|
|
XFreePixmap(dpy, root_pixmap);
|
|
|
|
}
|
2003-11-24 07:20:42 +08:00
|
|
|
#endif
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
XFixesSetPictureClipRegion(dpy, root_picture, 0, 0, region);
|
|
|
|
|
|
|
|
#ifdef MONITOR_REPAINT
|
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpSrc, black_picture, None,
|
|
|
|
root_picture, 0, 0, 0, 0, 0, 0,
|
|
|
|
root_width, root_height);
|
|
|
|
#endif
|
2012-09-13 13:58:05 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
paint_root(dpy);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
#ifdef DEBUG_REPAINT
|
|
|
|
printf("paint:");
|
|
|
|
#endif
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
for (w = t; w; w = w->prev_trans) {
|
2012-09-17 16:04:04 +08:00
|
|
|
int x, y, wid, hei;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
|
|
|
x = w->a.x;
|
|
|
|
y = w->a.y;
|
2012-09-17 22:15:04 +08:00
|
|
|
wid = w->widthb;
|
|
|
|
hei = w->heightb;
|
2012-09-17 16:04:04 +08:00
|
|
|
#else
|
|
|
|
x = w->a.x + w->a.border_width;
|
|
|
|
y = w->a.y + w->a.border_width;
|
|
|
|
wid = w->a.width;
|
|
|
|
hei = w->a.height;
|
|
|
|
#endif
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
#ifdef DEBUG_REPAINT
|
|
|
|
printf(" %#010lx", w->id);
|
|
|
|
#endif
|
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
// Allow shadow to be painted anywhere in the damaged region
|
|
|
|
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, region);
|
|
|
|
|
|
|
|
// Painting shadow
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
if (w->shadow) {
|
2011-11-04 16:41:56 +08:00
|
|
|
XRenderComposite(
|
2012-09-29 13:15:09 +08:00
|
|
|
dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict,
|
2011-11-04 16:41:56 +08:00
|
|
|
root_buffer, 0, 0, 0, 0,
|
|
|
|
w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
|
|
|
|
w->shadow_width, w->shadow_height);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
// The window only could be painted in its bounding region
|
|
|
|
XserverRegion paint_reg = XFixesCreateRegion(dpy, NULL, 0);
|
|
|
|
XFixesIntersectRegion(dpy, paint_reg, region, w->border_size);
|
|
|
|
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, paint_reg);
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
Picture alpha_mask = (OPAQUE == w->opacity ? None: w->alpha_pict);
|
|
|
|
int op = (w->mode == WINDOW_SOLID ? PictOpSrc: PictOpOver);
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
// Painting the window
|
|
|
|
if (!w->frame_opacity) {
|
|
|
|
XRenderComposite(dpy, op, w->picture, alpha_mask,
|
|
|
|
root_buffer, 0, 0, 0, 0, x, y, wid, hei);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
unsigned int t = w->top_width;
|
|
|
|
unsigned int l = w->left_width;
|
|
|
|
unsigned int b = w->bottom_width;
|
|
|
|
unsigned int r = w->right_width;
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
/* top */
|
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpOver, w->picture, w->frame_alpha_pict, root_buffer,
|
|
|
|
0, 0, 0, 0, x, y, wid, t);
|
2012-09-17 12:31:01 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
/* left */
|
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpOver, w->picture, w->frame_alpha_pict, root_buffer,
|
|
|
|
0, t, 0, t, x, y + t, l, hei - t);
|
|
|
|
|
|
|
|
/* bottom */
|
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpOver, w->picture, w->frame_alpha_pict, root_buffer,
|
|
|
|
l, hei - b, l, hei - b, x + l, y + hei - b, wid - l - r, b);
|
|
|
|
|
|
|
|
/* right */
|
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpOver, w->picture, w->frame_alpha_pict, root_buffer,
|
|
|
|
wid - r, t, wid - r, t, x + wid - r, y + t, r, hei - t);
|
|
|
|
|
|
|
|
/* body */
|
|
|
|
XRenderComposite(
|
|
|
|
dpy, op, w->picture, alpha_mask, root_buffer,
|
|
|
|
l, t, l, t, x + l, y + t, wid - l - r, hei - t - b);
|
2012-09-12 10:52:52 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
// Dimming the window if needed
|
|
|
|
if (w->dim) {
|
|
|
|
XRenderComposite(dpy, PictOpOver, dim_picture, None,
|
|
|
|
root_buffer, 0, 0, 0, 0, x, y, wid, hei);
|
|
|
|
}
|
|
|
|
|
|
|
|
XFixesDestroyRegion(dpy, paint_reg);
|
2012-09-19 20:49:16 +08:00
|
|
|
|
|
|
|
check_fade_fin(dpy, w);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
#ifdef DEBUG_REPAINT
|
|
|
|
printf("\n");
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
XFixesDestroyRegion(dpy, region);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
if (root_buffer != root_picture) {
|
|
|
|
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, None);
|
2011-11-04 17:18:10 +08:00
|
|
|
XRenderComposite(
|
|
|
|
dpy, PictOpSrc, root_buffer, None,
|
|
|
|
root_picture, 0, 0, 0, 0,
|
|
|
|
0, 0, root_width, root_height);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
add_damage(Display *dpy, XserverRegion damage) {
|
2011-11-04 16:41:56 +08:00
|
|
|
if (all_damage) {
|
|
|
|
XFixesUnionRegion(dpy, all_damage, all_damage, damage);
|
2011-11-04 14:33:23 +08:00
|
|
|
XFixesDestroyRegion(dpy, damage);
|
2011-11-04 16:41:56 +08:00
|
|
|
} else {
|
|
|
|
all_damage = damage;
|
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
repair_win(Display *dpy, win *w) {
|
2011-11-04 16:41:56 +08:00
|
|
|
XserverRegion parts;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
if (!w->damaged) {
|
|
|
|
parts = win_extents(dpy, w);
|
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
XDamageSubtract(dpy, w->damage, None, None);
|
|
|
|
} else {
|
|
|
|
parts = XFixesCreateRegion(dpy, 0, 0);
|
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
XDamageSubtract(dpy, w->damage, None, parts);
|
|
|
|
XFixesTranslateRegion(dpy, parts,
|
2011-11-04 16:41:56 +08:00
|
|
|
w->a.x + w->a.border_width,
|
|
|
|
w->a.y + w->a.border_width);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
add_damage(dpy, parts);
|
|
|
|
w->damaged = 1;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2008-02-15 12:38:32 +08:00
|
|
|
static wintype
|
2012-09-22 20:49:17 +08:00
|
|
|
get_wintype_prop(Display *dpy, Window wid) {
|
2011-11-04 14:33:23 +08:00
|
|
|
Atom actual;
|
|
|
|
int format;
|
2012-09-22 20:49:17 +08:00
|
|
|
unsigned long n = 0, left, i;
|
|
|
|
long *data = NULL;
|
|
|
|
int j;
|
2011-11-04 17:18:10 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
if (Success != XGetWindowProperty(
|
|
|
|
dpy, wid, win_type_atom, 0L, 32L, False, XA_ATOM,
|
|
|
|
&actual, &format, &n, &left, (unsigned char **) &data)
|
|
|
|
|| !data || !n) {
|
|
|
|
if (data)
|
|
|
|
XFree(data);
|
|
|
|
return WINTYPE_UNKNOWN;
|
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
for (j = 1; j < NUM_WINTYPES; ++j) {
|
|
|
|
if (win_type[j] == (Atom) data[i]) {
|
|
|
|
XFree(data);
|
|
|
|
return j;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
}
|
2012-09-22 20:49:17 +08:00
|
|
|
}
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
XFree(data);
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
return WINTYPE_UNKNOWN;
|
2008-02-15 12:38:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static wintype
|
2012-09-22 20:49:17 +08:00
|
|
|
determine_wintype(Display *dpy, Window w) {
|
2011-11-04 16:41:56 +08:00
|
|
|
Window *children = NULL;
|
2011-11-04 14:33:23 +08:00
|
|
|
unsigned int nchildren, i;
|
2011-11-04 16:41:56 +08:00
|
|
|
wintype type;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
type = get_wintype_prop(dpy, w);
|
2012-01-15 19:02:24 +08:00
|
|
|
if (type != WINTYPE_UNKNOWN) return type;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
if (!win_get_children(dpy, w, &children, &nchildren))
|
2012-01-15 19:02:24 +08:00
|
|
|
return WINTYPE_UNKNOWN;
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2011-11-05 01:02:17 +08:00
|
|
|
for (i = 0; i < nchildren; i++) {
|
2012-09-22 20:49:17 +08:00
|
|
|
type = determine_wintype(dpy, children[i]);
|
2012-01-15 19:02:24 +08:00
|
|
|
if (type != WINTYPE_UNKNOWN) return type;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (children) {
|
2011-11-04 14:33:23 +08:00
|
|
|
XFree((void *)children);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
return WINTYPE_UNKNOWN;
|
2008-02-15 12:38:32 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 17:18:10 +08:00
|
|
|
map_win(Display *dpy, Window id,
|
2012-01-15 00:12:54 +08:00
|
|
|
unsigned long sequence, Bool fade,
|
|
|
|
Bool override_redirect) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win *w = find_win(dpy, id);
|
2003-11-09 15:08:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!w) return;
|
2004-09-10 13:55:19 +08:00
|
|
|
|
2012-09-11 22:22:58 +08:00
|
|
|
w->focused = False;
|
2011-11-04 14:33:23 +08:00
|
|
|
w->a.map_state = IsViewable;
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2012-09-18 11:28:09 +08:00
|
|
|
// Call XSelectInput() before reading properties so that no property
|
|
|
|
// changes are lost
|
|
|
|
XSelectInput(dpy, id, determine_evmask(dpy, id, WIN_EVMODE_FRAME));
|
|
|
|
|
|
|
|
// Notify compton when the shape of a window changes
|
|
|
|
if (shape_exists) {
|
|
|
|
XShapeSelectInput(dpy, id, ShapeNotifyMask);
|
|
|
|
}
|
2012-09-14 11:51:46 +08:00
|
|
|
|
2012-09-18 11:28:09 +08:00
|
|
|
// Detect client window here instead of in add_win() as the client
|
|
|
|
// window should have been prepared at this point
|
2012-09-20 13:50:27 +08:00
|
|
|
if (!w->client_win) {
|
2012-09-18 11:28:09 +08:00
|
|
|
Window cw = find_client_win(dpy, w->id);
|
2012-09-20 13:50:27 +08:00
|
|
|
#ifdef DEBUG_CLIENTWIN
|
|
|
|
printf("find_client_win(%#010lx): client %#010lx\n", w->id, cw);
|
|
|
|
#endif
|
2012-09-18 11:28:09 +08:00
|
|
|
if (cw) {
|
|
|
|
mark_client_win(dpy, w, cw);
|
2012-09-11 21:33:03 +08:00
|
|
|
}
|
2012-02-27 12:00:12 +08:00
|
|
|
}
|
2012-09-26 18:54:35 +08:00
|
|
|
else if (opts.frame_opacity) {
|
2012-09-20 13:50:27 +08:00
|
|
|
// Refetch frame extents just in case it changes when the window is
|
|
|
|
// unmapped
|
|
|
|
get_frame_extents(dpy, w, w->client_win);
|
|
|
|
}
|
2011-11-05 01:02:17 +08:00
|
|
|
|
2012-09-22 20:49:17 +08:00
|
|
|
if (WINTYPE_UNKNOWN == w->window_type)
|
|
|
|
w->window_type = determine_wintype(dpy, w->id);
|
|
|
|
|
|
|
|
#ifdef DEBUG_WINTYPE
|
|
|
|
printf("map_win(%#010lx): type %s\n",
|
2012-09-25 21:04:10 +08:00
|
|
|
w->id, WINTYPES[w->window_type]);
|
2012-09-22 20:49:17 +08:00
|
|
|
#endif
|
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// Get window name and class if we are tracking them
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.track_wdata) {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
win_get_name(dpy, w);
|
|
|
|
win_get_class(dpy, w);
|
|
|
|
}
|
|
|
|
|
2012-09-12 11:06:16 +08:00
|
|
|
/*
|
|
|
|
* Occasionally compton does not seem able to get a FocusIn event from a
|
|
|
|
* window just mapped. I suspect it's a timing issue again when the
|
2012-09-13 21:38:55 +08:00
|
|
|
* XSelectInput() is called too late. We have to recheck the focused
|
|
|
|
* window here.
|
2012-09-12 11:06:16 +08:00
|
|
|
*/
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.track_focus) {
|
2012-09-13 21:38:55 +08:00
|
|
|
recheck_focus(dpy);
|
2012-09-20 13:50:27 +08:00
|
|
|
// Consider a window without client window a WM window and mark it
|
2012-09-26 19:48:36 +08:00
|
|
|
// focused if mark_wmwin_focused is on, or it's over-redirected and
|
|
|
|
// mark_ovredir_focused is on
|
|
|
|
if ((opts.mark_wmwin_focused && !w->client_win)
|
|
|
|
|| (opts.mark_ovredir_focused && w->a.override_redirect))
|
2012-09-20 13:50:27 +08:00
|
|
|
w->focused = True;
|
2012-09-13 23:12:54 +08:00
|
|
|
}
|
2012-09-12 11:06:16 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// Window type change could affect shadow and fade
|
|
|
|
determine_shadow(dpy, w);
|
|
|
|
|
|
|
|
// Determine mode here just in case the colormap changes
|
|
|
|
determine_mode(dpy, w);
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Fading in
|
2012-09-11 22:22:58 +08:00
|
|
|
calc_opacity(dpy, w, True);
|
2012-09-26 21:40:48 +08:00
|
|
|
|
|
|
|
if (opts.no_fading_openclose) {
|
|
|
|
set_fade_callback(dpy, w, finish_map_win, True);
|
|
|
|
// Must be set after we execute the old fade callback, in case we
|
|
|
|
// receive two continuous MapNotify for the same window
|
|
|
|
w->fade = False;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
set_fade_callback(dpy, w, NULL, True);
|
|
|
|
determine_fade(dpy, w);
|
|
|
|
}
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
calc_dim(dpy, w);
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2004-08-13 16:25:51 +08:00
|
|
|
#if CAN_DO_USABLE
|
2011-11-04 14:33:23 +08:00
|
|
|
w->damage_bounds.x = w->damage_bounds.y = 0;
|
|
|
|
w->damage_bounds.width = w->damage_bounds.height = 0;
|
2004-08-13 16:25:51 +08:00
|
|
|
#endif
|
2012-09-19 20:49:16 +08:00
|
|
|
w->damaged = 1;
|
2004-09-10 13:55:19 +08:00
|
|
|
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2011-11-04 17:18:10 +08:00
|
|
|
/* if any configure events happened while
|
|
|
|
the window was unmapped, then configure
|
|
|
|
the window to its correct place */
|
2011-11-04 16:41:56 +08:00
|
|
|
if (w->need_configure) {
|
2011-11-04 14:33:23 +08:00
|
|
|
configure_win(dpy, &w->queue_configure);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-26 21:40:48 +08:00
|
|
|
static void
|
|
|
|
finish_map_win(Display *dpy, win *w) {
|
|
|
|
if (opts.no_fading_openclose)
|
|
|
|
determine_fade(dpy, w);
|
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
finish_unmap_win(Display *dpy, win *w) {
|
|
|
|
w->damaged = 0;
|
2004-08-13 16:25:51 +08:00
|
|
|
#if CAN_DO_USABLE
|
2011-11-04 14:33:23 +08:00
|
|
|
w->usable = False;
|
2004-08-13 16:25:51 +08:00
|
|
|
#endif
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->extents != None) {
|
2012-02-27 12:00:12 +08:00
|
|
|
/* destroys region */
|
|
|
|
add_damage(dpy, w->extents);
|
2011-11-04 14:33:23 +08:00
|
|
|
w->extents = None;
|
|
|
|
}
|
|
|
|
|
2004-06-28 05:29:23 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
2012-09-16 23:12:02 +08:00
|
|
|
free_pixmap(dpy, &w->pixmap);
|
2004-06-28 05:29:23 +08:00
|
|
|
#endif
|
2004-07-08 15:07:26 +08:00
|
|
|
|
2012-09-16 23:12:02 +08:00
|
|
|
free_picture(dpy, &w->picture);
|
|
|
|
free_region(dpy, &w->border_size);
|
|
|
|
free_picture(dpy, &w->shadow_pict);
|
2003-11-25 01:11:00 +08:00
|
|
|
}
|
|
|
|
|
2004-07-08 15:07:26 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
unmap_callback(Display *dpy, win *w) {
|
|
|
|
finish_unmap_win(dpy, w);
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2004-07-08 15:07:26 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
unmap_win(Display *dpy, Window id, Bool fade) {
|
|
|
|
win *w = find_win(dpy, id);
|
2011-11-04 16:41:56 +08:00
|
|
|
|
|
|
|
if (!w) return;
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->a.map_state = IsUnmapped;
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Fading out
|
|
|
|
w->opacity_tgt = 0;
|
|
|
|
set_fade_callback(dpy, w, unmap_callback, False);
|
2012-09-26 21:40:48 +08:00
|
|
|
if (opts.no_fading_openclose)
|
|
|
|
w->fade = False;
|
2012-09-19 20:49:16 +08:00
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
// don't care about properties anymore
|
|
|
|
// Will get BadWindow if the window is destroyed
|
2011-11-04 14:33:23 +08:00
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
XSelectInput(dpy, w->id, 0);
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2012-02-28 15:51:21 +08:00
|
|
|
if (w->client_win) {
|
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
XSelectInput(dpy, w->client_win, 0);
|
|
|
|
}
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2012-09-13 13:58:05 +08:00
|
|
|
static opacity_t
|
|
|
|
get_opacity_prop(Display *dpy, win *w, opacity_t def) {
|
2011-11-04 14:33:23 +08:00
|
|
|
Atom actual;
|
|
|
|
int format;
|
|
|
|
unsigned long n, left;
|
|
|
|
|
|
|
|
unsigned char *data;
|
2011-11-04 16:41:56 +08:00
|
|
|
int result = XGetWindowProperty(
|
|
|
|
dpy, w->id, opacity_atom, 0L, 1L, False,
|
|
|
|
XA_CARDINAL, &actual, &format, &n, &left, &data);
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (result == Success && data != NULL) {
|
2012-09-11 22:22:58 +08:00
|
|
|
opacity_t i = *((opacity_t *) data);
|
|
|
|
XFree(data);
|
2011-11-04 14:33:23 +08:00
|
|
|
return i;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
return def;
|
2003-11-25 01:11:00 +08:00
|
|
|
}
|
|
|
|
|
2004-09-10 13:55:19 +08:00
|
|
|
static double
|
2011-11-04 14:33:23 +08:00
|
|
|
get_opacity_percent(Display *dpy, win *w) {
|
2012-09-16 23:12:02 +08:00
|
|
|
return ((double) w->opacity) / OPAQUE;
|
2004-09-10 13:55:19 +08:00
|
|
|
}
|
|
|
|
|
2004-07-08 15:07:26 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
determine_mode(Display *dpy, win *w) {
|
|
|
|
int mode;
|
|
|
|
XRenderPictFormat *format;
|
|
|
|
|
2012-06-04 00:12:30 +08:00
|
|
|
/* if trans prop == -1 fall back on previous tests */
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
if (w->a.class == InputOnly) {
|
|
|
|
format = 0;
|
|
|
|
} else {
|
|
|
|
format = XRenderFindVisualFormat(dpy, w->a.visual);
|
|
|
|
}
|
|
|
|
|
2011-11-04 17:18:10 +08:00
|
|
|
if (format && format->type == PictTypeDirect
|
|
|
|
&& format->direct.alphaMask) {
|
2011-11-04 14:33:23 +08:00
|
|
|
mode = WINDOW_ARGB;
|
|
|
|
} else if (w->opacity != OPAQUE) {
|
|
|
|
mode = WINDOW_TRANS;
|
|
|
|
} else {
|
|
|
|
mode = WINDOW_SOLID;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->mode = mode;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-11 22:22:58 +08:00
|
|
|
/**
|
|
|
|
* Calculate and set the opacity of a window.
|
|
|
|
*
|
2012-09-26 18:54:35 +08:00
|
|
|
* If window is inactive and inactive_opacity_override is set, the
|
2012-09-11 22:22:58 +08:00
|
|
|
* priority is: (Simulates the old behavior)
|
|
|
|
*
|
2012-09-26 18:54:35 +08:00
|
|
|
* inactive_opacity > _NET_WM_WINDOW_OPACITY (if not opaque)
|
2012-09-11 22:22:58 +08:00
|
|
|
* > window type default opacity
|
|
|
|
*
|
|
|
|
* Otherwise:
|
|
|
|
*
|
|
|
|
* _NET_WM_WINDOW_OPACITY (if not opaque)
|
|
|
|
* > window type default opacity (if not opaque)
|
2012-09-26 18:54:35 +08:00
|
|
|
* > inactive_opacity
|
2012-09-11 22:22:58 +08:00
|
|
|
*
|
|
|
|
* @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
|
|
|
|
*/
|
2012-09-13 13:58:05 +08:00
|
|
|
static void
|
|
|
|
calc_opacity(Display *dpy, win *w, Bool refetch_prop) {
|
2012-09-11 22:22:58 +08:00
|
|
|
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?
|
2012-09-13 13:58:05 +08:00
|
|
|
if (IsViewable != w->a.map_state) return;
|
2012-09-11 22:22:58 +08:00
|
|
|
|
|
|
|
// Do not refetch the opacity window attribute unless necessary, this
|
|
|
|
// is probably an expensive operation in some cases
|
2012-09-13 13:58:05 +08:00
|
|
|
if (refetch_prop) {
|
2012-09-11 22:22:58 +08:00
|
|
|
w->opacity_prop = get_opacity_prop(dpy, w, OPAQUE);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-11 22:22:58 +08:00
|
|
|
|
|
|
|
if (OPAQUE == (opacity = w->opacity_prop)) {
|
2012-09-26 18:54:35 +08:00
|
|
|
if (1.0 != opts.wintype_opacity[w->window_type]) {
|
|
|
|
opacity = opts.wintype_opacity[w->window_type] * OPAQUE;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-11 22:22:58 +08:00
|
|
|
}
|
2012-09-13 13:39:43 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
// Respect inactive_opacity in some cases
|
|
|
|
if (opts.inactive_opacity && is_normal_win(w) && False == w->focused
|
|
|
|
&& (OPAQUE == opacity || opts.inactive_opacity_override)) {
|
|
|
|
opacity = opts.inactive_opacity;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-11 22:22:58 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
w->opacity_tgt = opacity;
|
2012-09-11 22:22:58 +08:00
|
|
|
}
|
|
|
|
|
2012-09-13 13:58:05 +08:00
|
|
|
static void
|
|
|
|
calc_dim(Display *dpy, win *w) {
|
2012-09-12 10:52:52 +08:00
|
|
|
Bool dim;
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.inactive_dim && is_normal_win(w) && !(w->focused)) {
|
2012-09-12 10:52:52 +08:00
|
|
|
dim = True;
|
2012-09-13 13:58:05 +08:00
|
|
|
} else {
|
2012-09-12 10:52:52 +08:00
|
|
|
dim = False;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-12 10:52:52 +08:00
|
|
|
|
|
|
|
if (dim != w->dim) {
|
|
|
|
w->dim = dim;
|
|
|
|
add_damage_win(dpy, w);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
/**
|
2012-09-19 20:49:16 +08:00
|
|
|
* Determine if a window should fade on opacity change.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
determine_fade(Display *dpy, win *w) {
|
2012-09-26 18:54:35 +08:00
|
|
|
w->fade = opts.wintype_fade[w->window_type];
|
2012-09-19 20:49:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine if a window should have shadow, and update things depending
|
|
|
|
* on shadow state.
|
2012-09-17 22:15:04 +08:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
determine_shadow(Display *dpy, win *w) {
|
2012-09-19 20:49:16 +08:00
|
|
|
Bool shadow_old = w->shadow;
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
w->shadow = (opts.wintype_shadow[w->window_type]
|
|
|
|
&& !win_match(w, opts.shadow_blacklist, &w->cache_sblst));
|
2012-09-19 20:49:16 +08:00
|
|
|
|
|
|
|
// Window extents need update on shadow state change
|
|
|
|
if (w->shadow != shadow_old) {
|
|
|
|
// Shadow geometry currently doesn't change on shadow state change
|
|
|
|
// calc_shadow_geometry(dpy, w);
|
|
|
|
if (w->extents) {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// Mark the old extents as damaged if the shadow is removed
|
|
|
|
if (!w->shadow)
|
|
|
|
add_damage(dpy, w->extents);
|
|
|
|
else
|
|
|
|
free_region(dpy, &w->extents);
|
2012-09-19 20:49:16 +08:00
|
|
|
w->extents = win_extents(dpy, w);
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// Mark the new extents as damaged if the shadow is added
|
|
|
|
if (w->shadow)
|
|
|
|
add_damage_win(dpy, w);
|
2012-09-19 20:49:16 +08:00
|
|
|
}
|
|
|
|
}
|
2012-09-17 22:15:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update cache data in struct _win that depends on window size.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
calc_win_size(Display *dpy, win *w) {
|
|
|
|
w->widthb = w->a.width + w->a.border_width * 2;
|
|
|
|
w->heightb = w->a.height + w->a.border_width * 2;
|
|
|
|
calc_shadow_geometry(dpy, w);
|
|
|
|
w->flags |= WFLAG_SIZE_CHANGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate and update geometry of the shadow of a window.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
calc_shadow_geometry(Display *dpy, win *w) {
|
2012-09-26 18:54:35 +08:00
|
|
|
w->shadow_dx = opts.shadow_offset_x;
|
|
|
|
w->shadow_dy = opts.shadow_offset_y;
|
2012-09-17 22:15:04 +08:00
|
|
|
w->shadow_width = w->widthb + gaussian_map->size;
|
|
|
|
w->shadow_height = w->heightb + gaussian_map->size;
|
|
|
|
}
|
|
|
|
|
2012-09-14 11:51:46 +08:00
|
|
|
/**
|
|
|
|
* Mark a window as the client window of another.
|
|
|
|
*
|
|
|
|
* @param dpy display to use
|
|
|
|
* @param w struct _win of the parent window
|
|
|
|
* @param client window ID of the client window
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mark_client_win(Display *dpy, win *w, Window client) {
|
|
|
|
w->client_win = client;
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
2012-09-14 11:51:46 +08:00
|
|
|
// Get the frame width and monitor further frame width changes on client
|
|
|
|
// window if necessary
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.frame_opacity) {
|
2012-09-20 13:50:27 +08:00
|
|
|
get_frame_extents(dpy, w, client);
|
2012-09-14 11:51:46 +08:00
|
|
|
}
|
|
|
|
XSelectInput(dpy, client, determine_evmask(dpy, client, WIN_EVMODE_CLIENT));
|
2012-09-22 20:49:17 +08:00
|
|
|
if (WINTYPE_UNKNOWN == w->window_type)
|
|
|
|
w->window_type = get_wintype_prop(dpy, w->client_win);
|
2012-09-14 11:51:46 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2012-01-15 00:12:54 +08:00
|
|
|
add_win(Display *dpy, Window id, Window prev, Bool override_redirect) {
|
2012-09-09 10:13:56 +08:00
|
|
|
if (find_win(dpy, id)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
win *new = malloc(sizeof(win));
|
|
|
|
win **p;
|
|
|
|
|
|
|
|
if (!new) return;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
if (prev) {
|
2011-11-04 16:41:56 +08:00
|
|
|
for (p = &list; *p; p = &(*p)->next) {
|
2011-11-04 14:33:23 +08:00
|
|
|
if ((*p)->id == prev && !(*p)->destroyed)
|
|
|
|
break;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
} else {
|
2011-11-04 14:33:23 +08:00
|
|
|
p = &list;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
new->id = id;
|
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!XGetWindowAttributes(dpy, id, &new->a)) {
|
|
|
|
free(new);
|
|
|
|
return;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
new->damaged = 0;
|
2004-08-13 16:25:51 +08:00
|
|
|
#if CAN_DO_USABLE
|
2011-11-04 14:33:23 +08:00
|
|
|
new->usable = False;
|
2004-08-13 16:25:51 +08:00
|
|
|
#endif
|
2004-07-08 15:07:26 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
2011-11-04 14:33:23 +08:00
|
|
|
new->pixmap = None;
|
2004-07-08 15:07:26 +08:00
|
|
|
#endif
|
2011-11-04 14:33:23 +08:00
|
|
|
new->picture = None;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (new->a.class == InputOnly) {
|
|
|
|
new->damage_sequence = 0;
|
|
|
|
new->damage = None;
|
|
|
|
} else {
|
|
|
|
new->damage_sequence = NextRequest(dpy);
|
|
|
|
set_ignore(dpy, NextRequest(dpy));
|
|
|
|
new->damage = XDamageCreate(dpy, id, XDamageReportNonEmpty);
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
new->name = NULL;
|
|
|
|
new->class_instance = NULL;
|
|
|
|
new->class_general = NULL;
|
|
|
|
new->cache_sblst = NULL;
|
|
|
|
new->cache_fblst = NULL;
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
new->border_size = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
new->extents = None;
|
2012-09-17 22:15:04 +08:00
|
|
|
new->shadow = False;
|
|
|
|
new->shadow_opacity = 0.0;
|
|
|
|
new->shadow_opacity_cur = 0.0;
|
|
|
|
new->shadow_pict = None;
|
2012-09-29 13:15:09 +08:00
|
|
|
new->shadow_alpha_pict = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
new->shadow_dx = 0;
|
|
|
|
new->shadow_dy = 0;
|
|
|
|
new->shadow_width = 0;
|
|
|
|
new->shadow_height = 0;
|
2012-09-19 20:49:16 +08:00
|
|
|
new->opacity = 0;
|
|
|
|
new->opacity_tgt = 0;
|
2012-09-17 12:31:01 +08:00
|
|
|
new->opacity_cur = OPAQUE;
|
2012-09-11 22:22:58 +08:00
|
|
|
new->opacity_prop = OPAQUE;
|
2012-09-19 20:49:16 +08:00
|
|
|
new->fade = False;
|
|
|
|
new->fade_callback = NULL;
|
|
|
|
new->fade_fin = False;
|
2012-09-17 12:31:01 +08:00
|
|
|
new->alpha_pict = None;
|
|
|
|
new->frame_opacity = 1.0;
|
|
|
|
new->frame_opacity_cur = 1.0;
|
|
|
|
new->frame_alpha_pict = None;
|
2012-09-12 10:52:52 +08:00
|
|
|
new->dim = False;
|
2012-09-11 22:22:58 +08:00
|
|
|
new->focused = False;
|
2011-11-04 14:33:23 +08:00
|
|
|
new->destroyed = False;
|
|
|
|
new->need_configure = False;
|
2012-01-15 19:02:24 +08:00
|
|
|
new->window_type = WINTYPE_UNKNOWN;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
new->prev_trans = 0;
|
|
|
|
|
2011-11-06 11:33:50 +08:00
|
|
|
new->left_width = 0;
|
|
|
|
new->right_width = 0;
|
2011-11-06 10:39:58 +08:00
|
|
|
new->top_width = 0;
|
2011-11-06 11:33:50 +08:00
|
|
|
new->bottom_width = 0;
|
2011-11-07 05:52:39 +08:00
|
|
|
|
2012-02-01 06:10:30 +08:00
|
|
|
new->client_win = 0;
|
2011-11-07 05:52:39 +08:00
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
new->flags = 0;
|
|
|
|
|
|
|
|
calc_win_size(dpy, new);
|
|
|
|
|
2011-11-07 05:52:39 +08:00
|
|
|
new->next = *p;
|
|
|
|
*p = new;
|
2011-11-06 10:39:58 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (new->a.map_state == IsViewable) {
|
2012-01-15 00:12:54 +08:00
|
|
|
map_win(dpy, id, new->damage_sequence - 1, True, override_redirect);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2003-11-24 07:20:42 +08:00
|
|
|
}
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
restack_win(Display *dpy, win *w, Window new_above) {
|
2011-11-04 16:41:56 +08:00
|
|
|
Window old_above;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (w->next) {
|
2011-11-04 14:33:23 +08:00
|
|
|
old_above = w->next->id;
|
2011-11-04 16:41:56 +08:00
|
|
|
} else {
|
2011-11-04 14:33:23 +08:00
|
|
|
old_above = None;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (old_above != new_above) {
|
|
|
|
win **prev;
|
|
|
|
|
|
|
|
/* unhook */
|
2011-11-04 16:41:56 +08:00
|
|
|
for (prev = &list; *prev; prev = &(*prev)->next) {
|
|
|
|
if ((*prev) == w) break;
|
|
|
|
}
|
2011-11-05 20:00:39 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
*prev = w->next;
|
|
|
|
|
|
|
|
/* rehook */
|
|
|
|
for (prev = &list; *prev; prev = &(*prev)->next) {
|
|
|
|
if ((*prev)->id == new_above && !(*prev)->destroyed)
|
|
|
|
break;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->next = *prev;
|
|
|
|
*prev = w;
|
2012-09-11 21:33:03 +08:00
|
|
|
|
2012-09-12 09:08:15 +08:00
|
|
|
#ifdef DEBUG_RESTACK
|
2012-09-11 21:33:03 +08:00
|
|
|
{
|
|
|
|
const char *desc;
|
|
|
|
char *window_name;
|
|
|
|
Bool to_free;
|
|
|
|
win* c = list;
|
2012-09-13 13:39:43 +08:00
|
|
|
|
2012-09-13 13:58:05 +08:00
|
|
|
printf("restack_win(%#010lx, %#010lx): "
|
|
|
|
"Window stack modified. Current stack:\n", w->id, new_above);
|
|
|
|
|
2012-09-11 21:33:03 +08:00
|
|
|
for (; c; c = c->next) {
|
|
|
|
window_name = "(Failed to get title)";
|
2012-09-13 13:58:05 +08:00
|
|
|
|
|
|
|
if (root == c->id) {
|
2012-09-11 21:33:03 +08:00
|
|
|
window_name = "(Root window)";
|
2012-09-13 13:58:05 +08:00
|
|
|
} else {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
to_free = wid_get_name(dpy, c->id, &window_name);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
|
|
|
|
2012-09-11 21:33:03 +08:00
|
|
|
desc = "";
|
2012-09-13 13:58:05 +08:00
|
|
|
if (c->destroyed) desc = "(D) ";
|
2012-09-11 21:33:03 +08:00
|
|
|
printf("%#010lx \"%s\" %s-> ", c->id, window_name, desc);
|
2012-09-13 13:58:05 +08:00
|
|
|
|
2012-09-11 21:33:03 +08:00
|
|
|
if (to_free) {
|
|
|
|
XFree(window_name);
|
|
|
|
window_name = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fputs("\n", stdout);
|
|
|
|
}
|
|
|
|
#endif
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
configure_win(Display *dpy, XConfigureEvent *ce) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win *w = find_win(dpy, ce->window);
|
|
|
|
XserverRegion damage = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
if (!w) {
|
|
|
|
if (ce->window == root) {
|
2011-11-04 16:41:56 +08:00
|
|
|
if (root_buffer) {
|
|
|
|
XRenderFreePicture(dpy, root_buffer);
|
|
|
|
root_buffer = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
root_width = ce->width;
|
|
|
|
root_height = ce->height;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w->a.map_state == IsUnmapped) {
|
|
|
|
/* save the configure event for when the window maps */
|
|
|
|
w->need_configure = True;
|
|
|
|
w->queue_configure = *ce;
|
2012-09-08 00:51:08 +08:00
|
|
|
restack_win(dpy, w, ce->above);
|
2011-11-04 14:33:23 +08:00
|
|
|
} else {
|
2012-09-13 13:58:05 +08:00
|
|
|
if (!(w->need_configure)) {
|
2012-09-08 00:51:08 +08:00
|
|
|
restack_win(dpy, w, ce->above);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->need_configure = False;
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2004-08-13 16:25:51 +08:00
|
|
|
#if CAN_DO_USABLE
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->usable)
|
2004-08-13 16:25:51 +08:00
|
|
|
#endif
|
2011-11-04 14:33:23 +08:00
|
|
|
{
|
|
|
|
damage = XFixesCreateRegion(dpy, 0, 0);
|
2012-09-13 13:58:05 +08:00
|
|
|
if (w->extents != None) {
|
2011-11-04 14:33:23 +08:00
|
|
|
XFixesCopyRegion(dpy, damage, w->extents);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->a.x = ce->x;
|
|
|
|
w->a.y = ce->y;
|
2011-11-05 20:00:39 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->a.width != ce->width || w->a.height != ce->height) {
|
2004-07-08 15:07:26 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
2012-09-16 23:12:02 +08:00
|
|
|
free_pixmap(dpy, &w->pixmap);
|
|
|
|
free_picture(dpy, &w->picture);
|
2011-11-04 14:33:23 +08:00
|
|
|
#endif
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
if (w->a.width != ce->width || w->a.height != ce->height
|
|
|
|
|| w->a.border_width != ce->border_width) {
|
|
|
|
w->a.width = ce->width;
|
|
|
|
w->a.height = ce->height;
|
|
|
|
w->a.border_width = ce->border_width;
|
|
|
|
calc_win_size(dpy, w);
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->a.map_state != IsUnmapped && damage) {
|
2011-11-04 17:18:10 +08:00
|
|
|
XserverRegion extents = win_extents(dpy, w);
|
2011-11-04 14:33:23 +08:00
|
|
|
XFixesUnionRegion(dpy, damage, damage, extents);
|
|
|
|
XFixesDestroyRegion(dpy, extents);
|
|
|
|
add_damage(dpy, damage);
|
|
|
|
}
|
|
|
|
|
2012-09-17 22:15:04 +08:00
|
|
|
// Window extents and border_size may have changed
|
|
|
|
free_region(dpy, &w->extents);
|
|
|
|
free_region(dpy, &w->border_size);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2008-02-20 14:20:40 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
w->a.override_redirect = ce->override_redirect;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2003-11-24 07:20:42 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
circulate_win(Display *dpy, XCirculateEvent *ce) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win *w = find_win(dpy, ce->window);
|
|
|
|
Window new_above;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (!w) return;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (ce->place == PlaceOnTop) {
|
2011-11-04 14:33:23 +08:00
|
|
|
new_above = list->id;
|
2011-11-04 16:41:56 +08:00
|
|
|
} else {
|
2011-11-04 14:33:23 +08:00
|
|
|
new_above = None;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
restack_win(dpy, w, new_above);
|
2003-11-24 07:20:42 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
finish_destroy_win(Display *dpy, Window id) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win **prev, *w;
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-05 05:18:56 +08:00
|
|
|
for (prev = &list; (w = *prev); prev = &w->next) {
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->id == id && w->destroyed) {
|
|
|
|
finish_unmap_win(dpy, w);
|
|
|
|
*prev = w->next;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-16 23:12:02 +08:00
|
|
|
free_picture(dpy, &w->alpha_pict);
|
2012-09-17 12:31:01 +08:00
|
|
|
free_picture(dpy, &w->frame_alpha_pict);
|
2012-09-16 23:12:02 +08:00
|
|
|
free_picture(dpy, &w->shadow_pict);
|
|
|
|
free_damage(dpy, &w->damage);
|
2012-09-23 11:49:02 +08:00
|
|
|
free(w->name);
|
|
|
|
free(w->class_instance);
|
|
|
|
free(w->class_general);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
free(w);
|
|
|
|
break;
|
|
|
|
}
|
2011-11-05 05:18:56 +08:00
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2004-07-08 15:07:26 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
destroy_callback(Display *dpy, win *w) {
|
|
|
|
finish_destroy_win(dpy, w->id);
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
destroy_win(Display *dpy, Window id, Bool fade) {
|
|
|
|
win *w = find_win(dpy, id);
|
2008-02-15 13:55:17 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
if (w) {
|
|
|
|
w->destroyed = True;
|
2008-02-19 05:44:41 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
// Fading out the window
|
|
|
|
w->opacity_tgt = 0;
|
|
|
|
set_fade_callback(dpy, w, destroy_callback, False);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2004-07-08 15:07:26 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
damage_win(Display *dpy, XDamageNotifyEvent *de) {
|
2011-11-04 16:41:56 +08:00
|
|
|
win *w = find_win(dpy, de->drawable);
|
|
|
|
|
|
|
|
if (!w) return;
|
2004-08-13 16:25:51 +08:00
|
|
|
|
|
|
|
#if CAN_DO_USABLE
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!w->usable) {
|
|
|
|
if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0) {
|
|
|
|
w->damage_bounds = de->area;
|
|
|
|
} else {
|
|
|
|
if (de->area.x < w->damage_bounds.x) {
|
|
|
|
w->damage_bounds.width += (w->damage_bounds.x - de->area.x);
|
|
|
|
w->damage_bounds.x = de->area.x;
|
|
|
|
}
|
|
|
|
if (de->area.y < w->damage_bounds.y) {
|
|
|
|
w->damage_bounds.height += (w->damage_bounds.y - de->area.y);
|
|
|
|
w->damage_bounds.y = de->area.y;
|
|
|
|
}
|
2011-11-04 17:18:10 +08:00
|
|
|
if (de->area.x + de->area.width
|
|
|
|
> w->damage_bounds.x + w->damage_bounds.width) {
|
|
|
|
w->damage_bounds.width =
|
|
|
|
de->area.x + de->area.width - w->damage_bounds.x;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 17:18:10 +08:00
|
|
|
if (de->area.y + de->area.height
|
|
|
|
> w->damage_bounds.y + w->damage_bounds.height) {
|
|
|
|
w->damage_bounds.height =
|
|
|
|
de->area.y + de->area.height - w->damage_bounds.y;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-05 05:18:56 +08:00
|
|
|
if (w->damage_bounds.x <= 0
|
|
|
|
&& w->damage_bounds.y <= 0
|
|
|
|
&& w->a.width <= w->damage_bounds.x + w->damage_bounds.width
|
|
|
|
&& w->a.height <= w->damage_bounds.y + w->damage_bounds.height) {
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.wintype_fade[w->window_type]) {
|
2011-11-04 14:33:23 +08:00
|
|
|
set_fade(dpy, w, 0, get_opacity_percent(dpy, w),
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_in_step, 0, True, True);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
w->usable = True;
|
|
|
|
}
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (w->usable)
|
2004-08-13 16:25:51 +08:00
|
|
|
#endif
|
2011-11-04 14:33:23 +08:00
|
|
|
repair_win(dpy, w);
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static int
|
2011-11-04 14:33:23 +08:00
|
|
|
error(Display *dpy, XErrorEvent *ev) {
|
2011-11-04 16:41:56 +08:00
|
|
|
int o;
|
2011-11-05 05:18:56 +08:00
|
|
|
const char *name = "Unknown";
|
2003-11-20 00:12:15 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
if (should_ignore(dpy, ev->serial)) {
|
2003-11-20 00:12:15 +08:00
|
|
|
return 0;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2011-11-04 17:18:10 +08:00
|
|
|
if (ev->request_code == composite_opcode
|
|
|
|
&& ev->minor_code == X_CompositeRedirectSubwindows) {
|
2011-11-04 14:33:23 +08:00
|
|
|
fprintf(stderr, "Another composite manager is already running\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
o = ev->error_code - xfixes_error;
|
|
|
|
switch (o) {
|
2011-11-04 17:18:10 +08:00
|
|
|
case BadRegion:
|
|
|
|
name = "BadRegion";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
o = ev->error_code - damage_error;
|
|
|
|
switch (o) {
|
2011-11-04 17:18:10 +08:00
|
|
|
case BadDamage:
|
|
|
|
name = "BadDamage";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
o = ev->error_code - render_error;
|
|
|
|
switch (o) {
|
2011-11-04 17:18:10 +08:00
|
|
|
case BadPictFormat:
|
2012-02-27 12:00:12 +08:00
|
|
|
name = "BadPictFormat";
|
2011-11-04 17:18:10 +08:00
|
|
|
break;
|
|
|
|
case BadPicture:
|
2012-02-27 12:00:12 +08:00
|
|
|
name = "BadPicture";
|
2011-11-04 17:18:10 +08:00
|
|
|
break;
|
|
|
|
case BadPictOp:
|
2012-02-27 12:00:12 +08:00
|
|
|
name = "BadPictOp";
|
2011-11-04 17:18:10 +08:00
|
|
|
break;
|
|
|
|
case BadGlyphSet:
|
2012-02-27 12:00:12 +08:00
|
|
|
name = "BadGlyphSet";
|
2011-11-04 17:18:10 +08:00
|
|
|
break;
|
|
|
|
case BadGlyph:
|
2012-02-27 12:00:12 +08:00
|
|
|
name = "BadGlyph";
|
2011-11-04 17:18:10 +08:00
|
|
|
break;
|
2011-11-05 02:30:53 +08:00
|
|
|
default:
|
|
|
|
break;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-11 21:33:03 +08:00
|
|
|
switch (ev->error_code) {
|
|
|
|
case BadAccess:
|
|
|
|
name = "BadAccess";
|
|
|
|
break;
|
|
|
|
case BadAlloc:
|
|
|
|
name = "BadAlloc";
|
|
|
|
break;
|
|
|
|
case BadAtom:
|
|
|
|
name = "BadAtom";
|
|
|
|
break;
|
|
|
|
case BadColor:
|
|
|
|
name = "BadColor";
|
|
|
|
break;
|
|
|
|
case BadCursor:
|
|
|
|
name = "BadCursor";
|
|
|
|
break;
|
|
|
|
case BadDrawable:
|
|
|
|
name = "BadDrawable";
|
|
|
|
break;
|
|
|
|
case BadFont:
|
|
|
|
name = "BadFont";
|
|
|
|
break;
|
|
|
|
case BadGC:
|
|
|
|
name = "BadGC";
|
|
|
|
break;
|
|
|
|
case BadIDChoice:
|
|
|
|
name = "BadIDChoice";
|
|
|
|
break;
|
|
|
|
case BadImplementation:
|
|
|
|
name = "BadImplementation";
|
|
|
|
break;
|
|
|
|
case BadLength:
|
|
|
|
name = "BadLength";
|
|
|
|
break;
|
|
|
|
case BadMatch:
|
|
|
|
name = "BadMatch";
|
|
|
|
break;
|
|
|
|
case BadName:
|
|
|
|
name = "BadName";
|
|
|
|
break;
|
|
|
|
case BadPixmap:
|
|
|
|
name = "BadPixmap";
|
|
|
|
break;
|
|
|
|
case BadRequest:
|
|
|
|
name = "BadRequest";
|
|
|
|
break;
|
|
|
|
case BadValue:
|
|
|
|
name = "BadValue";
|
|
|
|
break;
|
|
|
|
case BadWindow:
|
|
|
|
name = "BadWindow";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-09-17 16:04:04 +08:00
|
|
|
print_timestamp();
|
2011-11-05 02:30:53 +08:00
|
|
|
printf("error %d (%s) request %d minor %d serial %lu\n",
|
2012-02-27 12:00:12 +08:00
|
|
|
ev->error_code, name, ev->request_code,
|
|
|
|
ev->minor_code, ev->serial);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
return 0;
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
2003-11-20 00:12:15 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
expose_root(Display *dpy, Window root, XRectangle *rects, int nrects) {
|
2011-11-05 20:00:39 +08:00
|
|
|
XserverRegion region = XFixesCreateRegion(dpy, rects, nrects);
|
2011-11-04 14:33:23 +08:00
|
|
|
add_damage(dpy, region);
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
static Bool
|
|
|
|
wid_get_text_prop(Display *dpy, Window wid, Atom prop,
|
|
|
|
char ***pstrlst, int *pnstr) {
|
|
|
|
XTextProperty text_prop;
|
2012-09-11 21:33:03 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
if (!(XGetTextProperty(dpy, wid, &text_prop, prop) && text_prop.value))
|
|
|
|
return False;
|
2012-09-13 13:58:05 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
if (Success !=
|
|
|
|
XmbTextPropertyToTextList(dpy, &text_prop, pstrlst, pnstr)
|
|
|
|
|| !*pnstr) {
|
|
|
|
*pnstr = 0;
|
|
|
|
if (*pstrlst)
|
|
|
|
XFreeStringList(*pstrlst);
|
|
|
|
return False;
|
|
|
|
}
|
2012-09-13 13:58:05 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
return True;
|
|
|
|
}
|
2012-09-13 13:58:05 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
static Bool
|
|
|
|
wid_get_name(Display *dpy, Window wid, char **name) {
|
|
|
|
XTextProperty text_prop;
|
|
|
|
char **strlst = NULL;
|
|
|
|
int nstr = 0;
|
|
|
|
|
|
|
|
// set_ignore(dpy, NextRequest(dpy));
|
|
|
|
if (!(XGetTextProperty(dpy, wid, &text_prop, name_ewmh_atom)
|
|
|
|
&& text_prop.value)) {
|
|
|
|
// set_ignore(dpy, NextRequest(dpy));
|
|
|
|
#ifdef DEBUG_WINDATA
|
|
|
|
printf("wid_get_name(%#010lx): _NET_WM_NAME unset, falling back to WM_NAME.\n", wid);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!(XGetWMName(dpy, wid, &text_prop) && text_prop.value)) {
|
|
|
|
return False;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-11 21:33:03 +08:00
|
|
|
}
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
if (Success !=
|
|
|
|
XmbTextPropertyToTextList(dpy, &text_prop, &strlst, &nstr)
|
|
|
|
|| !nstr || !strlst) {
|
|
|
|
if (strlst)
|
|
|
|
XFreeStringList(strlst);
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
*name = mstrcpy(strlst[0]);
|
|
|
|
|
|
|
|
XFreeStringList(strlst);
|
|
|
|
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
win_get_name(Display *dpy, win *w) {
|
|
|
|
Bool ret;
|
|
|
|
char *name_old = w->name;
|
|
|
|
|
|
|
|
// Can't do anything if there's no client window
|
|
|
|
if (!w->client_win)
|
|
|
|
return False;
|
|
|
|
|
|
|
|
// Get the name
|
|
|
|
ret = wid_get_name(dpy, w->client_win, &w->name);
|
|
|
|
|
|
|
|
// Return -1 if wid_get_name() failed, 0 if name didn't change, 1 if
|
|
|
|
// it changes
|
|
|
|
if (!ret)
|
|
|
|
ret = -1;
|
|
|
|
else if (name_old && !strcmp(w->name, name_old))
|
|
|
|
ret = 0;
|
|
|
|
else
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
// Keep the old name if there's no new one
|
|
|
|
if (w->name != name_old)
|
|
|
|
free(name_old);
|
|
|
|
|
|
|
|
#ifdef DEBUG_WINDATA
|
|
|
|
printf("win_get_name(%#010lx): client = %#010lx, name = \"%s\", "
|
|
|
|
"ret = %d\n", w->id, w->client_win, w->name, ret);
|
|
|
|
#endif
|
2012-09-13 13:58:05 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
return ret;
|
2012-09-11 21:33:03 +08:00
|
|
|
}
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
|
|
|
static Bool
|
|
|
|
win_get_class(Display *dpy, win *w) {
|
|
|
|
char **strlst = NULL;
|
|
|
|
int nstr = 0;
|
|
|
|
|
|
|
|
// Can't do anything if there's no client window
|
|
|
|
if (!w->client_win)
|
|
|
|
return False;
|
|
|
|
|
|
|
|
// Free and reset old strings
|
|
|
|
free(w->class_instance);
|
|
|
|
free(w->class_general);
|
|
|
|
w->class_instance = NULL;
|
|
|
|
w->class_general = NULL;
|
|
|
|
|
|
|
|
// Retrieve the property string list
|
|
|
|
if (!wid_get_text_prop(dpy, w->client_win, class_atom, &strlst, &nstr))
|
|
|
|
return False;
|
|
|
|
|
|
|
|
// Copy the strings if successful
|
|
|
|
w->class_instance = mstrcpy(strlst[0]);
|
|
|
|
|
|
|
|
if (nstr > 1)
|
|
|
|
w->class_general = mstrcpy(strlst[1]);
|
|
|
|
|
|
|
|
XFreeStringList(strlst);
|
|
|
|
|
|
|
|
#ifdef DEBUG_WINDATA
|
|
|
|
printf("win_get_class(%#010lx): client = %#010lx, "
|
|
|
|
"instance = \"%s\", general = \"%s\"\n",
|
|
|
|
w->id, w->client_win, w->class_instance, w->class_general);
|
2012-09-12 09:08:15 +08:00
|
|
|
#endif
|
2012-09-11 21:33:03 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
2012-09-12 09:08:15 +08:00
|
|
|
#ifdef DEBUG_EVENTS
|
2003-11-24 07:20:42 +08:00
|
|
|
static int
|
2011-11-04 14:33:23 +08:00
|
|
|
ev_serial(XEvent *ev) {
|
2012-09-11 21:33:03 +08:00
|
|
|
if ((ev->type & 0x7f) != KeymapNotify) {
|
2011-11-04 14:33:23 +08:00
|
|
|
return ev->xany.serial;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
return NextRequest(ev->xany.display);
|
2003-11-24 07:20:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2011-11-04 14:33:23 +08:00
|
|
|
ev_name(XEvent *ev) {
|
2011-11-04 17:18:10 +08:00
|
|
|
static char buf[128];
|
2011-11-04 14:33:23 +08:00
|
|
|
switch (ev->type & 0x7f) {
|
2012-09-11 21:33:03 +08:00
|
|
|
case FocusIn:
|
|
|
|
return "FocusIn";
|
|
|
|
case FocusOut:
|
|
|
|
return "FocusOut";
|
|
|
|
case CreateNotify:
|
|
|
|
return "CreateNotify";
|
|
|
|
case ConfigureNotify:
|
|
|
|
return "ConfigureNotify";
|
|
|
|
case DestroyNotify:
|
|
|
|
return "DestroyNotify";
|
2011-11-04 16:41:56 +08:00
|
|
|
case MapNotify:
|
|
|
|
return "Map";
|
|
|
|
case UnmapNotify:
|
|
|
|
return "Unmap";
|
|
|
|
case ReparentNotify:
|
|
|
|
return "Reparent";
|
|
|
|
case CirculateNotify:
|
|
|
|
return "Circulate";
|
2012-09-11 21:33:03 +08:00
|
|
|
case Expose:
|
|
|
|
return "Expose";
|
|
|
|
case PropertyNotify:
|
|
|
|
return "PropertyNotify";
|
2012-09-18 11:28:09 +08:00
|
|
|
case ClientMessage:
|
|
|
|
return "ClientMessage";
|
2011-11-04 16:41:56 +08:00
|
|
|
default:
|
|
|
|
if (ev->type == damage_event + XDamageNotify) {
|
|
|
|
return "Damage";
|
|
|
|
}
|
2012-09-13 13:58:05 +08:00
|
|
|
|
|
|
|
if (shape_exists && ev->type == shape_event) {
|
2012-09-11 21:33:03 +08:00
|
|
|
return "ShapeNotify";
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
sprintf(buf, "Event %d", ev->type);
|
2012-09-13 13:58:05 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
return buf;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2003-11-24 07:20:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Window
|
2011-11-04 14:33:23 +08:00
|
|
|
ev_window(XEvent *ev) {
|
|
|
|
switch (ev->type) {
|
2012-09-11 21:33:03 +08:00
|
|
|
case FocusIn:
|
|
|
|
case FocusOut:
|
|
|
|
return ev->xfocus.window;
|
|
|
|
case CreateNotify:
|
|
|
|
return ev->xcreatewindow.window;
|
|
|
|
case ConfigureNotify:
|
|
|
|
return ev->xconfigure.window;
|
2012-09-19 20:49:16 +08:00
|
|
|
case DestroyNotify:
|
|
|
|
return ev->xdestroywindow.window;
|
2011-11-04 16:41:56 +08:00
|
|
|
case MapNotify:
|
|
|
|
return ev->xmap.window;
|
|
|
|
case UnmapNotify:
|
|
|
|
return ev->xunmap.window;
|
|
|
|
case ReparentNotify:
|
|
|
|
return ev->xreparent.window;
|
|
|
|
case CirculateNotify:
|
|
|
|
return ev->xcirculate.window;
|
2012-09-11 21:33:03 +08:00
|
|
|
case Expose:
|
|
|
|
return ev->xexpose.window;
|
|
|
|
case PropertyNotify:
|
|
|
|
return ev->xproperty.window;
|
2012-09-18 11:28:09 +08:00
|
|
|
case ClientMessage:
|
|
|
|
return ev->xclient.window;
|
2011-11-04 16:41:56 +08:00
|
|
|
default:
|
|
|
|
if (ev->type == damage_event + XDamageNotify) {
|
2011-11-04 17:18:10 +08:00
|
|
|
return ((XDamageNotifyEvent *)ev)->drawable;
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2012-09-13 13:58:05 +08:00
|
|
|
|
|
|
|
if (shape_exists && ev->type == shape_event) {
|
2012-09-11 21:33:03 +08:00
|
|
|
return ((XShapeEvent *) ev)->window;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
return 0;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2003-11-24 07:20:42 +08:00
|
|
|
}
|
2007-03-12 20:37:32 +08:00
|
|
|
#endif
|
2003-11-24 07:20:42 +08:00
|
|
|
|
2012-02-09 17:37:46 +08:00
|
|
|
/**
|
|
|
|
* Events
|
|
|
|
*/
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_focus_in(XFocusChangeEvent *ev) {
|
2012-02-27 12:00:12 +08:00
|
|
|
win *w = find_win(dpy, ev->window);
|
2012-09-11 22:22:58 +08:00
|
|
|
|
2012-09-13 22:30:18 +08:00
|
|
|
// To deal with events sent from windows just destroyed
|
2012-09-13 23:28:27 +08:00
|
|
|
if (!w) return;
|
2012-09-13 22:30:18 +08:00
|
|
|
|
2012-09-20 13:50:27 +08:00
|
|
|
set_focused(dpy, w, True);
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_focus_out(XFocusChangeEvent *ev) {
|
|
|
|
if (ev->mode == NotifyGrab
|
|
|
|
|| (ev->mode == NotifyNormal
|
|
|
|
&& (ev->detail == NotifyNonlinear
|
|
|
|
|| ev->detail == NotifyNonlinearVirtual))) {
|
|
|
|
;
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
win *w = find_win(dpy, ev->window);
|
2012-09-11 22:22:58 +08:00
|
|
|
|
2012-09-13 22:30:18 +08:00
|
|
|
// To deal with events sent from windows just destroyed
|
2012-09-13 23:28:27 +08:00
|
|
|
if (!w) return;
|
|
|
|
|
2012-09-20 13:50:27 +08:00
|
|
|
set_focused(dpy, w, False);
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_create_notify(XCreateWindowEvent *ev) {
|
|
|
|
add_win(dpy, ev->window, 0, ev->override_redirect);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_configure_notify(XConfigureEvent *ev) {
|
2012-09-12 09:08:15 +08:00
|
|
|
#ifdef DEBUG_EVENTS
|
2012-09-13 13:58:05 +08:00
|
|
|
printf("{ send_event: %d, "
|
|
|
|
" above: %#010lx, "
|
|
|
|
" override_redirect: %d }\n",
|
|
|
|
ev->send_event, ev->above, ev->override_redirect);
|
2012-09-11 21:33:03 +08:00
|
|
|
#endif
|
2012-02-09 17:37:46 +08:00
|
|
|
configure_win(dpy, ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_destroy_notify(XDestroyWindowEvent *ev) {
|
|
|
|
destroy_win(dpy, ev->window, True);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_map_notify(XMapEvent *ev) {
|
|
|
|
map_win(dpy, ev->window, ev->serial, True, ev->override_redirect);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_unmap_notify(XUnmapEvent *ev) {
|
|
|
|
unmap_win(dpy, ev->window, True);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_reparent_notify(XReparentEvent *ev) {
|
|
|
|
if (ev->parent == root) {
|
|
|
|
add_win(dpy, ev->window, 0, ev->override_redirect);
|
|
|
|
} else {
|
|
|
|
destroy_win(dpy, ev->window, True);
|
2012-09-13 22:30:18 +08:00
|
|
|
// Reset event mask in case something wrong happens
|
|
|
|
XSelectInput(dpy, ev->window,
|
|
|
|
determine_evmask(dpy, ev->window, WIN_EVMODE_UNKNOWN));
|
2012-09-14 11:51:46 +08:00
|
|
|
/*
|
|
|
|
// Check if the window is a client window of another
|
|
|
|
win *w_top = find_toplevel2(dpy, ev->window);
|
|
|
|
if (w_top && !(w_top->client_win)) {
|
|
|
|
mark_client_win(dpy, w_top, ev->window);
|
|
|
|
} */
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_circulate_notify(XCirculateEvent *ev) {
|
|
|
|
circulate_win(dpy, ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_expose(XExposeEvent *ev) {
|
|
|
|
if (ev->window == root) {
|
|
|
|
int more = ev->count + 1;
|
|
|
|
if (n_expose == size_expose) {
|
|
|
|
if (expose_rects) {
|
|
|
|
expose_rects = realloc(expose_rects,
|
|
|
|
(size_expose + more) * sizeof(XRectangle));
|
|
|
|
size_expose += more;
|
|
|
|
} else {
|
|
|
|
expose_rects = malloc(more * sizeof(XRectangle));
|
|
|
|
size_expose = more;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expose_rects[n_expose].x = ev->x;
|
|
|
|
expose_rects[n_expose].y = ev->y;
|
|
|
|
expose_rects[n_expose].width = ev->width;
|
|
|
|
expose_rects[n_expose].height = ev->height;
|
|
|
|
n_expose++;
|
|
|
|
|
|
|
|
if (ev->count == 0) {
|
|
|
|
expose_root(dpy, root, expose_rects, n_expose);
|
|
|
|
n_expose = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_property_notify(XPropertyEvent *ev) {
|
|
|
|
int p;
|
|
|
|
for (p = 0; background_props[p]; p++) {
|
|
|
|
if (ev->atom == XInternAtom(dpy, background_props[p], False)) {
|
|
|
|
if (root_tile) {
|
|
|
|
XClearArea(dpy, root, 0, 0, 0, 0, True);
|
|
|
|
XRenderFreePicture(dpy, root_tile);
|
|
|
|
root_tile = None;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if Trans property was changed */
|
|
|
|
if (ev->atom == opacity_atom) {
|
|
|
|
/* reset mode and redraw window */
|
|
|
|
win *w = find_win(dpy, ev->window);
|
|
|
|
if (w) {
|
2012-09-11 22:22:58 +08:00
|
|
|
calc_opacity(dpy, w, True);
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// If frame extents property changes
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.frame_opacity && ev->atom == extents_atom) {
|
2012-02-09 17:37:46 +08:00
|
|
|
win *w = find_toplevel(dpy, ev->window);
|
|
|
|
if (w) {
|
2012-09-20 13:50:27 +08:00
|
|
|
get_frame_extents(dpy, w, ev->window);
|
|
|
|
// If frame extents change, the window needs repaint
|
|
|
|
add_damage_win(dpy, w);
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
|
|
|
}
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
|
|
|
// If name changes
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.track_wdata
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
&& (name_atom == ev->atom || name_ewmh_atom == ev->atom)) {
|
|
|
|
win *w = find_toplevel(dpy, ev->window);
|
|
|
|
if (w && 1 == win_get_name(dpy, w))
|
|
|
|
determine_shadow(dpy, w);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If class changes
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.track_wdata && class_atom == ev->atom) {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
win *w = find_toplevel(dpy, ev->window);
|
|
|
|
if (w) {
|
|
|
|
win_get_class(dpy, w);
|
|
|
|
determine_shadow(dpy, w);
|
|
|
|
}
|
|
|
|
}
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static void
|
|
|
|
ev_damage_notify(XDamageNotifyEvent *ev) {
|
|
|
|
damage_win(dpy, ev);
|
|
|
|
}
|
|
|
|
|
2012-09-13 13:58:05 +08:00
|
|
|
inline static void
|
|
|
|
ev_shape_notify(XShapeEvent *ev) {
|
2012-09-11 21:33:03 +08:00
|
|
|
win *w = find_win(dpy, ev->window);
|
2012-09-13 13:58:05 +08:00
|
|
|
if (!w) return;
|
2012-09-11 21:33:03 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Empty border_size may indicated an
|
|
|
|
* unmapped/destroyed window, in which case
|
|
|
|
* seemingly BadRegion errors would be triggered
|
|
|
|
* if we attempt to rebuild border_size
|
|
|
|
*/
|
|
|
|
if (w->border_size) {
|
|
|
|
// Mark the old border_size as damaged
|
|
|
|
add_damage(dpy, w->border_size);
|
|
|
|
|
|
|
|
w->border_size = border_size(dpy, w);
|
|
|
|
|
|
|
|
// Mark the new border_size as damaged
|
|
|
|
add_damage(dpy, copy_region(dpy, w->border_size));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-09 17:37:46 +08:00
|
|
|
inline static void
|
2012-02-27 12:00:12 +08:00
|
|
|
ev_handle(XEvent *ev) {
|
2012-02-09 17:37:46 +08:00
|
|
|
if ((ev->type & 0x7f) != KeymapNotify) {
|
|
|
|
discard_ignore(dpy, ev->xany.serial);
|
|
|
|
}
|
|
|
|
|
2012-09-12 09:08:15 +08:00
|
|
|
#ifdef DEBUG_EVENTS
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
if (ev->type != damage_event + XDamageNotify) {
|
|
|
|
Window w;
|
|
|
|
char *window_name;
|
|
|
|
Bool to_free = False;
|
2012-09-13 13:58:05 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
w = ev_window(ev);
|
|
|
|
window_name = "(Failed to get title)";
|
|
|
|
|
|
|
|
if (w) {
|
|
|
|
if (root == w) {
|
|
|
|
window_name = "(Root window)";
|
|
|
|
} else {
|
|
|
|
to_free = (Bool) wid_get_name(dpy, w, &window_name);
|
|
|
|
}
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
|
|
|
|
2012-09-12 09:08:15 +08:00
|
|
|
print_timestamp();
|
2012-09-11 21:33:03 +08:00
|
|
|
printf("event %10.10s serial %#010x window %#010lx \"%s\"\n",
|
|
|
|
ev_name(ev), ev_serial(ev), w, window_name);
|
2012-09-13 13:58:05 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
if (to_free) {
|
|
|
|
XFree(window_name);
|
|
|
|
window_name = NULL;
|
|
|
|
}
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
2012-02-09 17:37:46 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (ev->type) {
|
|
|
|
case FocusIn:
|
|
|
|
ev_focus_in((XFocusChangeEvent *)ev);
|
|
|
|
break;
|
|
|
|
case FocusOut:
|
|
|
|
ev_focus_out((XFocusChangeEvent *)ev);
|
|
|
|
break;
|
|
|
|
case CreateNotify:
|
|
|
|
ev_create_notify((XCreateWindowEvent *)ev);
|
|
|
|
break;
|
|
|
|
case ConfigureNotify:
|
|
|
|
ev_configure_notify((XConfigureEvent *)ev);
|
|
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
|
|
ev_destroy_notify((XDestroyWindowEvent *)ev);
|
|
|
|
break;
|
|
|
|
case MapNotify:
|
|
|
|
ev_map_notify((XMapEvent *)ev);
|
|
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
|
|
ev_unmap_notify((XUnmapEvent *)ev);
|
|
|
|
break;
|
|
|
|
case ReparentNotify:
|
|
|
|
ev_reparent_notify((XReparentEvent *)ev);
|
|
|
|
break;
|
|
|
|
case CirculateNotify:
|
|
|
|
ev_circulate_notify((XCirculateEvent *)ev);
|
|
|
|
break;
|
|
|
|
case Expose:
|
|
|
|
ev_expose((XExposeEvent *)ev);
|
|
|
|
break;
|
|
|
|
case PropertyNotify:
|
|
|
|
ev_property_notify((XPropertyEvent *)ev);
|
|
|
|
break;
|
|
|
|
default:
|
2012-09-11 21:33:03 +08:00
|
|
|
if (shape_exists && ev->type == shape_event) {
|
|
|
|
ev_shape_notify((XShapeEvent *) ev);
|
|
|
|
break;
|
|
|
|
}
|
2012-02-09 17:37:46 +08:00
|
|
|
if (ev->type == damage_event + XDamageNotify) {
|
|
|
|
ev_damage_notify((XDamageNotifyEvent *)ev);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main
|
|
|
|
*/
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2012-09-17 16:04:04 +08:00
|
|
|
usage(void) {
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
fprintf(stderr, "compton (development version)\n");
|
2012-02-27 12:00:12 +08:00
|
|
|
fprintf(stderr, "usage: compton [options]\n");
|
2011-11-04 14:33:23 +08:00
|
|
|
fprintf(stderr,
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
"Options:\n"
|
|
|
|
"\n"
|
2012-02-27 20:49:50 +08:00
|
|
|
"-d display\n"
|
|
|
|
" Which display should be managed.\n"
|
|
|
|
"-r radius\n"
|
|
|
|
" The blur radius for shadows. (default 12)\n"
|
|
|
|
"-o opacity\n"
|
|
|
|
" The translucency for shadows. (default .75)\n"
|
|
|
|
"-l left-offset\n"
|
|
|
|
" The left offset for shadows. (default -15)\n"
|
|
|
|
"-t top-offset\n"
|
|
|
|
" The top offset for shadows. (default -15)\n"
|
|
|
|
"-I fade-in-step\n"
|
|
|
|
" Opacity change between steps while fading in. (default 0.028)\n"
|
|
|
|
"-O fade-out-step\n"
|
|
|
|
" Opacity change between steps while fading out. (default 0.03)\n"
|
|
|
|
"-D fade-delta-time\n"
|
|
|
|
" The time between steps in a fade in milliseconds. (default 10)\n"
|
|
|
|
"-m opacity\n"
|
|
|
|
" The opacity for menus. (default 1.0)\n"
|
|
|
|
"-c\n"
|
|
|
|
" Enabled client-side shadows on windows.\n"
|
|
|
|
"-C\n"
|
|
|
|
" Avoid drawing shadows on dock/panel windows.\n"
|
|
|
|
"-z\n"
|
2012-03-18 00:29:01 +08:00
|
|
|
" Zero the part of the shadow's mask behind the window (experimental).\n"
|
2012-02-27 20:49:50 +08:00
|
|
|
"-f\n"
|
2012-09-26 21:40:48 +08:00
|
|
|
" Fade windows in/out when opening/closing and when opacity\n"
|
|
|
|
" changes, unless --no-fading-openclose is used.\n"
|
2012-02-27 20:49:50 +08:00
|
|
|
"-F\n"
|
2012-09-26 21:40:48 +08:00
|
|
|
" Equals -f. Deprecated.\n"
|
2012-02-27 20:49:50 +08:00
|
|
|
"-i opacity\n"
|
|
|
|
" Opacity of inactive windows. (0.1 - 1.0)\n"
|
|
|
|
"-e opacity\n"
|
|
|
|
" Opacity of window titlebars and borders. (0.1 - 1.0)\n"
|
|
|
|
"-G\n"
|
|
|
|
" Don't draw shadows on DND windows\n"
|
|
|
|
"-b daemonize\n"
|
|
|
|
" Daemonize process.\n"
|
|
|
|
"-S\n"
|
2012-09-11 21:57:50 +08:00
|
|
|
" Enable synchronous operation (for debugging).\n"
|
2012-09-25 10:19:20 +08:00
|
|
|
"--config path\n"
|
|
|
|
" Look for configuration file at the path.\n"
|
2012-09-11 21:57:50 +08:00
|
|
|
"--shadow-red value\n"
|
|
|
|
" Red color value of shadow (0.0 - 1.0, defaults to 0).\n"
|
|
|
|
"--shadow-green value\n"
|
|
|
|
" 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"
|
2012-09-11 22:22:58 +08:00
|
|
|
"--inactive-opacity-override\n"
|
|
|
|
" Inactive opacity set by -i overrides value of _NET_WM_OPACITY.\n"
|
2012-09-12 10:52:52 +08:00
|
|
|
"--inactive-dim value\n"
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
" Dim inactive windows. (0.0 - 1.0, defaults to 0)\n"
|
|
|
|
"--mark-wmwin-focused\n"
|
|
|
|
" Try to detect WM windows and mark them as active.\n"
|
|
|
|
"--shadow-exclude condition\n"
|
|
|
|
" Exclude conditions for shadows.\n"
|
2012-09-26 19:48:36 +08:00
|
|
|
"--mark-ovredir-focused\n"
|
|
|
|
" Mark over-redirect windows as active.\n"
|
2012-09-26 21:40:48 +08:00
|
|
|
"--no-fading-openclose\n"
|
|
|
|
" Do not fade on window open/close.\n"
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
"\n"
|
|
|
|
"Format of a condition:\n"
|
|
|
|
"\n"
|
|
|
|
" condition = <target>:<type>[<flags>]:<pattern>\n"
|
|
|
|
"\n"
|
|
|
|
" <target> is one of \"n\" (window name), \"i\" (window class\n"
|
|
|
|
" instance), and \"g\" (window general class)\n"
|
|
|
|
"\n"
|
|
|
|
" <type> is one of \"e\" (exact match), \"a\" (match anywhere),\n"
|
|
|
|
" \"s\" (match from start), \"w\" (wildcard), and \"p\" (PCRE\n"
|
|
|
|
" regular expressions, if compiled with the support).\n"
|
|
|
|
"\n"
|
2012-09-22 20:49:17 +08:00
|
|
|
" <flags> could be a series of flags. Currently the only defined\n"
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
" flag is \"i\" (ignore case).\n"
|
|
|
|
"\n"
|
|
|
|
" <pattern> is the actual pattern string.\n"
|
|
|
|
);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
exit(1);
|
2004-06-27 13:08:33 +08:00
|
|
|
}
|
|
|
|
|
2005-10-07 08:08:02 +08:00
|
|
|
static void
|
2011-11-04 14:33:23 +08:00
|
|
|
register_cm(int scr) {
|
|
|
|
Window w;
|
|
|
|
Atom a;
|
|
|
|
char *buf;
|
|
|
|
int len, s;
|
|
|
|
|
|
|
|
if (scr < 0) return;
|
2008-02-15 13:09:11 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
w = XCreateSimpleWindow(
|
|
|
|
dpy, RootWindow(dpy, 0),
|
|
|
|
0, 0, 1, 1, 0, None, None);
|
2006-09-07 01:04:47 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
Xutf8SetWMProperties(
|
|
|
|
dpy, w, "xcompmgr", "xcompmgr",
|
|
|
|
NULL, 0, NULL, NULL, NULL);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
len = strlen(REGISTER_PROP) + 2;
|
|
|
|
s = scr;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
while (s >= 10) {
|
|
|
|
++len;
|
|
|
|
s /= 10;
|
|
|
|
}
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
buf = malloc(len);
|
|
|
|
snprintf(buf, len, REGISTER_PROP"%d", scr);
|
|
|
|
|
|
|
|
a = XInternAtom(dpy, buf, False);
|
|
|
|
free(buf);
|
|
|
|
|
|
|
|
XSetSelectionOwner(dpy, a, w, 0);
|
2005-10-07 08:08:02 +08:00
|
|
|
}
|
|
|
|
|
2012-02-27 12:00:12 +08:00
|
|
|
static void
|
2012-09-17 16:04:04 +08:00
|
|
|
fork_after(void) {
|
2012-02-27 12:00:12 +08:00
|
|
|
if (getppid() == 1) return;
|
|
|
|
|
|
|
|
int pid = fork();
|
|
|
|
|
|
|
|
if (pid == -1) {
|
|
|
|
fprintf(stderr, "Fork failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid > 0) _exit(0);
|
|
|
|
|
|
|
|
setsid();
|
|
|
|
|
|
|
|
freopen("/dev/null", "r", stdin);
|
|
|
|
freopen("/dev/null", "w", stdout);
|
|
|
|
freopen("/dev/null", "w", stderr);
|
|
|
|
}
|
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
#ifdef CONFIG_LIBCONFIG
|
|
|
|
/**
|
|
|
|
* Get a file stream of the configuration file to read.
|
|
|
|
*
|
|
|
|
* Follows the XDG specification to search for the configuration file.
|
|
|
|
*/
|
|
|
|
static FILE *
|
|
|
|
open_config_file(char *cpath, char **ppath) {
|
|
|
|
const static char *config_filename = "/compton.conf";
|
|
|
|
const static char *config_filename_legacy = "/.compton.conf";
|
|
|
|
const static char *config_home_suffix = "/.config";
|
|
|
|
const static char *config_system_dir = "/etc/xdg";
|
|
|
|
|
|
|
|
char *dir = NULL, *home = NULL;
|
|
|
|
char *path = cpath;
|
|
|
|
FILE *f = NULL;
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
f = fopen(path, "r");
|
|
|
|
if (f && ppath)
|
|
|
|
*ppath = path;
|
|
|
|
else
|
|
|
|
free(path);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check user configuration file in $XDG_CONFIG_HOME firstly
|
|
|
|
if (!((dir = getenv("XDG_CONFIG_HOME")) && strlen(dir))) {
|
|
|
|
if (!((home = getenv("HOME")) && strlen(home)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
path = mstrjoin3(home, config_home_suffix, config_filename);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
path = mstrjoin(dir, config_filename);
|
|
|
|
|
|
|
|
f = fopen(path, "r");
|
|
|
|
|
|
|
|
if (f && ppath)
|
|
|
|
*ppath = path;
|
|
|
|
else
|
|
|
|
free(path);
|
|
|
|
if (f)
|
|
|
|
return f;
|
|
|
|
|
|
|
|
// Then check user configuration file in $HOME
|
|
|
|
if ((home = getenv("HOME")) && strlen(home)) {
|
|
|
|
path = mstrjoin(home, config_filename_legacy);
|
|
|
|
f = fopen(path, "r");
|
|
|
|
if (f && ppath)
|
|
|
|
*ppath = path;
|
|
|
|
else
|
|
|
|
free(path);
|
|
|
|
if (f)
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check system configuration file in $XDG_CONFIG_DIRS at last
|
|
|
|
if ((dir = getenv("XDG_CONFIG_DIRS")) && strlen(dir)) {
|
|
|
|
char *part = strtok(dir, ":");
|
|
|
|
while (part) {
|
|
|
|
path = mstrjoin(part, config_filename);
|
|
|
|
f = fopen(path, "r");
|
|
|
|
if (f && ppath)
|
|
|
|
*ppath = path;
|
|
|
|
else
|
|
|
|
free(path);
|
|
|
|
if (f)
|
|
|
|
return f;
|
|
|
|
part = strtok(NULL, ":");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
path = mstrjoin(config_system_dir, config_filename);
|
|
|
|
f = fopen(path, "r");
|
|
|
|
if (f && ppath)
|
|
|
|
*ppath = path;
|
|
|
|
else
|
|
|
|
free(path);
|
|
|
|
if (f)
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse a configuration file from default location.
|
|
|
|
*/
|
2012-02-09 17:37:46 +08:00
|
|
|
static void
|
2012-09-26 18:54:35 +08:00
|
|
|
parse_config(char *cpath, struct options_tmp *pcfgtmp) {
|
2012-09-28 09:10:34 +08:00
|
|
|
char *path = NULL;
|
2012-09-25 10:19:20 +08:00
|
|
|
FILE *f;
|
|
|
|
config_t cfg;
|
|
|
|
int ival = 0;
|
|
|
|
double dval = 0.0;
|
|
|
|
|
|
|
|
f = open_config_file(cpath, &path);
|
|
|
|
if (!f) {
|
|
|
|
if (cpath)
|
|
|
|
printf("Failed to read the specified configuration file.\n");
|
|
|
|
return;
|
|
|
|
}
|
2012-02-09 17:37:46 +08:00
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
config_init(&cfg);
|
2012-09-28 09:10:34 +08:00
|
|
|
#ifndef CONFIG_LIBCONFIG_LEGACY
|
|
|
|
char *parent = dirname(path);
|
2012-09-25 10:19:20 +08:00
|
|
|
if (parent)
|
|
|
|
config_set_include_dir(&cfg, parent);
|
2012-09-28 09:10:34 +08:00
|
|
|
#endif
|
2012-09-25 10:19:20 +08:00
|
|
|
|
|
|
|
if (CONFIG_FALSE == config_read(&cfg, f)) {
|
|
|
|
printf("Error when reading configuration file \"%s\", line %d: %s\n",
|
|
|
|
path, config_error_line(&cfg), config_error_text(&cfg));
|
|
|
|
config_destroy(&cfg);
|
|
|
|
free(path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config_set_auto_convert(&cfg, 1);
|
|
|
|
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
// Get options from the configuration file. We don't do range checking
|
|
|
|
// right now. It will be done later
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
// -D (fade_delta)
|
2012-09-28 09:10:34 +08:00
|
|
|
if (lcfg_lookup_int(&cfg, "fade-delta", &ival))
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_delta = ival;
|
|
|
|
// -I (fade_in_step)
|
2012-09-25 10:19:20 +08:00
|
|
|
if (config_lookup_float(&cfg, "fade-in-step", &dval))
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_in_step = normalize_d(dval) * OPAQUE;
|
|
|
|
// -O (fade_out_step)
|
2012-09-25 10:19:20 +08:00
|
|
|
if (config_lookup_float(&cfg, "fade-out-step", &dval))
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_out_step = normalize_d(dval) * OPAQUE;
|
|
|
|
// -r (shadow_radius)
|
2012-09-28 09:10:34 +08:00
|
|
|
lcfg_lookup_int(&cfg, "shadow-radius", &opts.shadow_radius);
|
2012-09-26 18:54:35 +08:00
|
|
|
// -o (shadow_opacity)
|
|
|
|
config_lookup_float(&cfg, "shadow-opacity", &opts.shadow_opacity);
|
|
|
|
// -l (shadow_offset_x)
|
2012-09-28 09:10:34 +08:00
|
|
|
lcfg_lookup_int(&cfg, "shadow-offset-x", &opts.shadow_offset_x);
|
2012-09-26 18:54:35 +08:00
|
|
|
// -t (shadow_offset_y)
|
2012-09-28 09:10:34 +08:00
|
|
|
lcfg_lookup_int(&cfg, "shadow-offset-y", &opts.shadow_offset_y);
|
2012-09-26 18:54:35 +08:00
|
|
|
// -i (inactive_opacity)
|
2012-09-25 10:19:20 +08:00
|
|
|
if (config_lookup_float(&cfg, "inactive-opacity", &dval))
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.inactive_opacity = normalize_d(dval) * OPAQUE;
|
|
|
|
// -e (frame_opacity)
|
|
|
|
config_lookup_float(&cfg, "frame-opacity", &opts.frame_opacity);
|
|
|
|
// -z (clear_shadow)
|
|
|
|
lcfg_lookup_bool(&cfg, "clear-shadow", &opts.clear_shadow);
|
|
|
|
// -c (shadow_enable)
|
|
|
|
if (config_lookup_bool(&cfg, "shadow", &ival) && ival)
|
|
|
|
wintype_arr_enable(opts.wintype_shadow);
|
|
|
|
// -C (no_dock_shadow)
|
|
|
|
lcfg_lookup_bool(&cfg, "no-dock-shadow", &pcfgtmp->no_dock_shadow);
|
|
|
|
// -G (no_dnd_shadow)
|
|
|
|
lcfg_lookup_bool(&cfg, "no-dnd-shadow", &pcfgtmp->no_dnd_shadow);
|
|
|
|
// -m (menu_opacity)
|
|
|
|
config_lookup_float(&cfg, "menu-opacity", &pcfgtmp->menu_opacity);
|
|
|
|
// -f (fading_enable)
|
|
|
|
if (config_lookup_bool(&cfg, "fading", &ival) && ival)
|
|
|
|
wintype_arr_enable(opts.wintype_fade);
|
2012-09-26 21:40:48 +08:00
|
|
|
// --no-fading-open-close
|
|
|
|
lcfg_lookup_bool(&cfg, "no-fading-openclose", &opts.no_fading_openclose);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --shadow-red
|
2012-09-26 18:54:35 +08:00
|
|
|
config_lookup_float(&cfg, "shadow-red", &opts.shadow_red);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --shadow-green
|
2012-09-26 18:54:35 +08:00
|
|
|
config_lookup_float(&cfg, "shadow-green", &opts.shadow_green);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --shadow-blue
|
2012-09-26 18:54:35 +08:00
|
|
|
config_lookup_float(&cfg, "shadow-blue", &opts.shadow_blue);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --inactive-opacity-override
|
2012-09-26 18:54:35 +08:00
|
|
|
lcfg_lookup_bool(&cfg, "inactive-opacity-override",
|
|
|
|
&opts.inactive_opacity_override);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --inactive-dim
|
2012-09-26 18:54:35 +08:00
|
|
|
config_lookup_float(&cfg, "inactive-dim", &opts.inactive_dim);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --mark-wmwin-focused
|
2012-09-26 18:54:35 +08:00
|
|
|
lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &opts.mark_wmwin_focused);
|
2012-09-26 19:48:36 +08:00
|
|
|
// --mark-ovredir-focused
|
|
|
|
lcfg_lookup_bool(&cfg, "mark-ovredir-focused",
|
|
|
|
&opts.mark_ovredir_focused);
|
2012-09-25 10:19:20 +08:00
|
|
|
// --shadow-exclude
|
|
|
|
{
|
2012-09-25 21:04:10 +08:00
|
|
|
config_setting_t *setting =
|
2012-09-25 10:19:20 +08:00
|
|
|
config_lookup(&cfg, "shadow-exclude");
|
2012-09-25 21:04:10 +08:00
|
|
|
if (setting) {
|
2012-09-25 10:19:20 +08:00
|
|
|
// Parse an array of shadow-exclude
|
2012-09-25 21:04:10 +08:00
|
|
|
if (config_setting_is_array(setting)) {
|
|
|
|
int i = config_setting_length(setting);
|
2012-09-25 10:19:20 +08:00
|
|
|
while (i--) {
|
2012-09-26 18:54:35 +08:00
|
|
|
condlst_add(&opts.shadow_blacklist,
|
2012-09-25 21:04:10 +08:00
|
|
|
config_setting_get_string_elem(setting, i));
|
2012-09-25 10:19:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Treat it as a single pattern if it's a string
|
2012-09-25 21:04:10 +08:00
|
|
|
else if (CONFIG_TYPE_STRING == config_setting_type(setting)) {
|
2012-09-26 18:54:35 +08:00
|
|
|
condlst_add(&opts.shadow_blacklist,
|
2012-09-25 21:04:10 +08:00
|
|
|
config_setting_get_string(setting));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Wintype settings
|
|
|
|
{
|
|
|
|
wintype i;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_WINTYPES; ++i) {
|
|
|
|
char *str = mstrjoin("wintypes.", WINTYPES[i]);
|
|
|
|
config_setting_t *setting = config_lookup(&cfg, str);
|
|
|
|
free(str);
|
|
|
|
if (setting) {
|
|
|
|
if (config_setting_lookup_bool(setting, "shadow", &ival))
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.wintype_shadow[i] = (Bool) ival;
|
2012-09-25 21:04:10 +08:00
|
|
|
if (config_setting_lookup_bool(setting, "fade", &ival))
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.wintype_fade[i] = (Bool) ival;
|
2012-09-25 21:04:10 +08:00
|
|
|
config_setting_lookup_float(setting, "opacity",
|
2012-09-26 18:54:35 +08:00
|
|
|
&opts.wintype_opacity[i]);
|
2012-09-25 10:19:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
config_destroy(&cfg);
|
2012-02-09 17:37:46 +08:00
|
|
|
}
|
2012-09-25 10:19:20 +08:00
|
|
|
#endif
|
2012-02-09 17:37:46 +08:00
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
/**
|
|
|
|
* Process arguments and configuration files.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
get_cfg(int argc, char *const *argv) {
|
|
|
|
const static char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:scnfFCaSzGb";
|
|
|
|
const static struct option longopts[] = {
|
|
|
|
{ "config", required_argument, NULL, 256 },
|
|
|
|
{ "shadow-red", required_argument, NULL, 257 },
|
|
|
|
{ "shadow-green", required_argument, NULL, 258 },
|
|
|
|
{ "shadow-blue", required_argument, NULL, 259 },
|
|
|
|
{ "inactive-opacity-override", no_argument, NULL, 260 },
|
|
|
|
{ "inactive-dim", required_argument, NULL, 261 },
|
|
|
|
{ "mark-wmwin-focused", no_argument, NULL, 262 },
|
|
|
|
{ "shadow-exclude", required_argument, NULL, 263 },
|
2012-09-26 19:48:36 +08:00
|
|
|
{ "mark-ovredir-focused", no_argument, NULL, 264 },
|
2012-09-26 21:40:48 +08:00
|
|
|
{ "no-fading-openclose", no_argument, NULL, 265 },
|
2012-09-11 23:11:23 +08:00
|
|
|
// Must terminate with a NULL entry
|
|
|
|
{ NULL, 0, NULL, 0 },
|
2012-09-11 21:57:50 +08:00
|
|
|
};
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
struct options_tmp cfgtmp = {
|
|
|
|
.no_dock_shadow = False,
|
|
|
|
.no_dnd_shadow = False,
|
|
|
|
.menu_opacity = 1.0,
|
|
|
|
};
|
|
|
|
Bool shadow_enable = False, fading_enable = False;
|
2012-09-25 10:19:20 +08:00
|
|
|
int o, longopt_idx, i;
|
|
|
|
char *config_file = NULL;
|
2012-09-27 22:30:16 +08:00
|
|
|
char *lc_numeric_old = mstrcpy(setlocale(LC_NUMERIC, NULL));
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
for (i = 0; i < NUM_WINTYPES; ++i) {
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.wintype_fade[i] = False;
|
|
|
|
opts.wintype_shadow[i] = False;
|
|
|
|
opts.wintype_opacity[i] = 1.0;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
// Pre-parse the commandline arguments to check for --config and invalid
|
|
|
|
// switches
|
|
|
|
while (-1 !=
|
|
|
|
(o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
|
|
|
|
if (256 == o)
|
|
|
|
config_file = mstrcpy(optarg);
|
|
|
|
else if ('?' == o || ':' == o)
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_LIBCONFIG
|
2012-09-26 18:54:35 +08:00
|
|
|
parse_config(config_file, &cfgtmp);
|
2012-09-25 10:19:20 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Parse commandline arguments. Range checking will be done later.
|
2012-09-27 22:30:16 +08:00
|
|
|
|
|
|
|
// Enforce LC_NUMERIC locale "C" here to make sure dots are recognized
|
|
|
|
// instead of commas in atof().
|
|
|
|
setlocale(LC_NUMERIC, "C");
|
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
optind = 1;
|
|
|
|
while (-1 !=
|
|
|
|
(o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
|
2011-11-04 14:33:23 +08:00
|
|
|
switch (o) {
|
2012-09-11 21:57:50 +08:00
|
|
|
// Short options
|
2011-11-04 16:41:56 +08:00
|
|
|
case 'd':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.display = optarg;
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'D':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_delta = atoi(optarg);
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'I':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_in_step = normalize_d(atof(optarg)) * OPAQUE;
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'O':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_out_step = normalize_d(atof(optarg)) * OPAQUE;
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
2011-11-07 09:29:23 +08:00
|
|
|
case 'c':
|
2012-09-26 18:54:35 +08:00
|
|
|
shadow_enable = True;
|
2011-11-07 09:29:23 +08:00
|
|
|
break;
|
2011-11-04 16:41:56 +08:00
|
|
|
case 'C':
|
2012-09-26 18:54:35 +08:00
|
|
|
cfgtmp.no_dock_shadow = True;
|
|
|
|
break;
|
|
|
|
case 'G':
|
|
|
|
cfgtmp.no_dnd_shadow = True;
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'm':
|
2012-09-26 18:54:35 +08:00
|
|
|
cfgtmp.menu_opacity = atof(optarg);
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
case 'F':
|
2012-09-26 21:40:48 +08:00
|
|
|
fading_enable = True;
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'S':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.synchronize = True;
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'r':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_radius = atoi(optarg);
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'o':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_opacity = atof(optarg);
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 'l':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_offset_x = atoi(optarg);
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
|
|
|
case 't':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_offset_y = atoi(optarg);
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
2011-11-05 01:02:17 +08:00
|
|
|
case 'i':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE);
|
2011-11-05 01:02:17 +08:00
|
|
|
break;
|
2011-11-06 11:33:50 +08:00
|
|
|
case 'e':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.frame_opacity = atof(optarg);
|
2011-11-06 10:39:58 +08:00
|
|
|
break;
|
2012-02-05 11:46:13 +08:00
|
|
|
case 'z':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.clear_shadow = True;
|
2012-02-05 11:46:13 +08:00
|
|
|
break;
|
2011-11-04 16:41:56 +08:00
|
|
|
case 'n':
|
|
|
|
case 'a':
|
|
|
|
case 's':
|
2011-11-07 09:29:23 +08:00
|
|
|
fprintf(stderr, "Warning: "
|
|
|
|
"-n, -a, and -s have been removed.\n");
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
2012-02-27 01:02:42 +08:00
|
|
|
case 'b':
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fork_after_register = True;
|
2012-02-27 01:02:42 +08:00
|
|
|
break;
|
2012-09-25 10:19:20 +08:00
|
|
|
// Long options
|
|
|
|
case 256:
|
|
|
|
// --config
|
|
|
|
break;
|
|
|
|
case 257:
|
|
|
|
// --shadow-red
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_red = atof(optarg);
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
|
|
|
case 258:
|
|
|
|
// --shadow-green
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_green = atof(optarg);
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
|
|
|
case 259:
|
|
|
|
// --shadow-blue
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_blue = atof(optarg);
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
|
|
|
case 260:
|
|
|
|
// --inactive-opacity-override
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.inactive_opacity_override = True;
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
|
|
|
case 261:
|
|
|
|
// --inactive-dim
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.inactive_dim = atof(optarg);
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
|
|
|
case 262:
|
|
|
|
// --mark-wmwin-focused
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.mark_wmwin_focused = True;
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
|
|
|
case 263:
|
|
|
|
// --shadow-exclude
|
2012-09-26 18:54:35 +08:00
|
|
|
condlst_add(&opts.shadow_blacklist, optarg);
|
2012-09-25 10:19:20 +08:00
|
|
|
break;
|
2012-09-26 19:48:36 +08:00
|
|
|
case 264:
|
|
|
|
// --mark-ovredir-focused
|
|
|
|
opts.mark_ovredir_focused = True;
|
|
|
|
break;
|
2012-09-26 21:40:48 +08:00
|
|
|
case 265:
|
|
|
|
// --no-fading-openclose
|
|
|
|
opts.no_fading_openclose = True;
|
|
|
|
break;
|
2011-11-04 16:41:56 +08:00
|
|
|
default:
|
2012-02-27 12:00:12 +08:00
|
|
|
usage();
|
2011-11-04 16:41:56 +08:00
|
|
|
break;
|
2008-02-15 12:38:32 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
|
2012-09-27 22:30:16 +08:00
|
|
|
// Restore LC_NUMERIC
|
|
|
|
setlocale(LC_NUMERIC, lc_numeric_old);
|
|
|
|
free(lc_numeric_old);
|
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
// Range checking and option assignments
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.fade_delta = max_i(opts.fade_delta, 1);
|
|
|
|
opts.shadow_radius = max_i(opts.shadow_radius, 1);
|
|
|
|
opts.shadow_red = normalize_d(opts.shadow_red);
|
|
|
|
opts.shadow_green = normalize_d(opts.shadow_green);
|
|
|
|
opts.shadow_blue = normalize_d(opts.shadow_blue);
|
|
|
|
opts.inactive_dim = normalize_d(opts.inactive_dim);
|
|
|
|
opts.frame_opacity = normalize_d(opts.frame_opacity);
|
|
|
|
opts.shadow_opacity = normalize_d(opts.shadow_opacity);
|
|
|
|
cfgtmp.menu_opacity = normalize_d(cfgtmp.menu_opacity);
|
|
|
|
if (OPAQUE == opts.inactive_opacity) {
|
|
|
|
opts.inactive_opacity = 0;
|
|
|
|
}
|
|
|
|
if (shadow_enable)
|
|
|
|
wintype_arr_enable(opts.wintype_shadow);
|
|
|
|
opts.wintype_shadow[WINTYPE_DESKTOP] = False;
|
|
|
|
if (cfgtmp.no_dock_shadow)
|
|
|
|
opts.wintype_shadow[WINTYPE_DOCK] = False;
|
|
|
|
if (cfgtmp.no_dnd_shadow)
|
|
|
|
opts.wintype_shadow[WINTYPE_DND] = False;
|
|
|
|
if (fading_enable)
|
|
|
|
wintype_arr_enable(opts.wintype_fade);
|
|
|
|
if (1.0 != cfgtmp.menu_opacity) {
|
|
|
|
opts.wintype_opacity[WINTYPE_DROPDOWN_MENU] = cfgtmp.menu_opacity;
|
|
|
|
opts.wintype_opacity[WINTYPE_POPUP_MENU] = cfgtmp.menu_opacity;
|
2012-02-27 12:00:12 +08:00
|
|
|
}
|
2012-02-27 00:35:17 +08:00
|
|
|
|
2012-09-25 10:19:20 +08:00
|
|
|
// Other variables determined by options
|
|
|
|
|
2012-09-13 11:47:31 +08:00
|
|
|
// Determine whether we need to track focus changes
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.inactive_opacity || opts.inactive_dim) {
|
|
|
|
opts.track_focus = True;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-13 11:47:31 +08:00
|
|
|
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
// Determine whether we need to track window name and class
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.shadow_blacklist || opts.fade_blacklist)
|
|
|
|
opts.track_wdata = True;
|
2012-09-25 10:19:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_atoms(void) {
|
|
|
|
extents_atom = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False);
|
|
|
|
opacity_atom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
|
|
|
|
frame_extents_atom = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False);
|
|
|
|
client_atom = XA_WM_CLASS;
|
|
|
|
name_atom = XA_WM_NAME;
|
|
|
|
name_ewmh_atom = XInternAtom(dpy, "_NET_WM_NAME", False);
|
|
|
|
class_atom = XA_WM_CLASS;
|
|
|
|
|
|
|
|
win_type_atom = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE", False);
|
|
|
|
win_type[WINTYPE_UNKNOWN] = 0;
|
|
|
|
win_type[WINTYPE_DESKTOP] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_DESKTOP", False);
|
|
|
|
win_type[WINTYPE_DOCK] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_DOCK", False);
|
|
|
|
win_type[WINTYPE_TOOLBAR] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_TOOLBAR", False);
|
|
|
|
win_type[WINTYPE_MENU] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_MENU", False);
|
|
|
|
win_type[WINTYPE_UTILITY] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_UTILITY", False);
|
|
|
|
win_type[WINTYPE_SPLASH] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_SPLASH", False);
|
|
|
|
win_type[WINTYPE_DIALOG] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_DIALOG", False);
|
|
|
|
win_type[WINTYPE_NORMAL] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_NORMAL", False);
|
|
|
|
win_type[WINTYPE_DROPDOWN_MENU] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
|
|
|
|
win_type[WINTYPE_POPUP_MENU] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
|
|
|
|
win_type[WINTYPE_TOOLTIP] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_TOOLTIP", False);
|
|
|
|
win_type[WINTYPE_NOTIFY] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
|
|
|
|
win_type[WINTYPE_COMBO] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_COMBO", False);
|
|
|
|
win_type[WINTYPE_DND] = XInternAtom(dpy,
|
|
|
|
"_NET_WM_WINDOW_TYPE_DND", False);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char **argv) {
|
|
|
|
XEvent ev;
|
|
|
|
Window root_return, parent_return;
|
|
|
|
Window *children;
|
|
|
|
unsigned int nchildren;
|
|
|
|
int i;
|
|
|
|
XRenderPictureAttributes pa;
|
|
|
|
struct pollfd ufd;
|
|
|
|
int composite_major, composite_minor;
|
|
|
|
win *t;
|
|
|
|
|
|
|
|
gettimeofday(&time_start, NULL);
|
|
|
|
|
|
|
|
// Set locale so window names with special characters are interpreted
|
|
|
|
// correctly
|
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
|
|
|
|
get_cfg(argc, argv);
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 11:42:39 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
fade_time = get_time_in_milliseconds();
|
2012-09-19 20:49:16 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
dpy = XOpenDisplay(opts.display);
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!dpy) {
|
|
|
|
fprintf(stderr, "Can't open display\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2008-02-15 12:38:32 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
XSetErrorHandler(error);
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.synchronize) {
|
2011-11-04 14:33:23 +08:00
|
|
|
XSynchronize(dpy, 1);
|
2011-11-04 16:41:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
scr = DefaultScreen(dpy);
|
|
|
|
root = RootWindow(dpy, scr);
|
|
|
|
|
|
|
|
if (!XRenderQueryExtension(dpy, &render_event, &render_error)) {
|
|
|
|
fprintf(stderr, "No render extension\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode,
|
2011-11-04 17:18:10 +08:00
|
|
|
&composite_event, &composite_error)) {
|
2011-11-04 14:33:23 +08:00
|
|
|
fprintf(stderr, "No composite extension\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
XCompositeQueryVersion(dpy, &composite_major, &composite_minor);
|
2003-11-25 01:11:00 +08:00
|
|
|
|
2004-06-28 05:29:23 +08:00
|
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
2011-11-04 16:41:56 +08:00
|
|
|
if (composite_major > 0 || composite_minor >= 2) {
|
|
|
|
has_name_pixmap = True;
|
|
|
|
}
|
2004-06-27 12:48:37 +08:00
|
|
|
#endif
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) {
|
|
|
|
fprintf(stderr, "No damage extension\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) {
|
|
|
|
fprintf(stderr, "No XFixes extension\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-09-13 13:58:05 +08:00
|
|
|
if (!XShapeQueryExtension(dpy, &shape_event, &shape_error)) {
|
2012-09-11 21:33:03 +08:00
|
|
|
shape_exists = False;
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-11 21:33:03 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
register_cm(scr);
|
2012-02-27 12:00:12 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.fork_after_register) fork_after();
|
2012-02-27 12:00:12 +08:00
|
|
|
|
2012-02-08 18:20:22 +08:00
|
|
|
get_atoms();
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
pa.subwindow_mode = IncludeInferiors;
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
gaussian_map = make_gaussian_map(dpy, opts.shadow_radius);
|
2011-11-04 16:41:56 +08:00
|
|
|
presum_gaussian(gaussian_map);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
|
|
|
root_width = DisplayWidth(dpy, scr);
|
|
|
|
root_height = DisplayHeight(dpy, scr);
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
root_picture = XRenderCreatePicture(dpy, root,
|
|
|
|
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
|
|
|
|
CPSubwindowMode, &pa);
|
2012-02-27 12:00:12 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
black_picture = solid_picture(dpy, True, 1, 0, 0, 0);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-09-11 21:57:50 +08:00
|
|
|
// Generates another Picture for shadows if the color is modified by
|
|
|
|
// user
|
2012-09-26 18:54:35 +08:00
|
|
|
if (!opts.shadow_red && !opts.shadow_green && !opts.shadow_blue) {
|
2012-09-11 21:57:50 +08:00
|
|
|
cshadow_picture = black_picture;
|
2012-09-13 13:58:05 +08:00
|
|
|
} else {
|
2012-09-11 21:57:50 +08:00
|
|
|
cshadow_picture = solid_picture(dpy, True, 1,
|
2012-09-26 18:54:35 +08:00
|
|
|
opts.shadow_red, opts.shadow_green, opts.shadow_blue);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-11 21:57:50 +08:00
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
// Generates a picture for inactive_dim
|
|
|
|
if (opts.inactive_dim) {
|
|
|
|
dim_picture = solid_picture(dpy, True, opts.inactive_dim, 0, 0, 0);
|
2012-09-13 13:58:05 +08:00
|
|
|
}
|
2012-09-12 10:52:52 +08:00
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
all_damage = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
XGrabServer(dpy);
|
|
|
|
|
2011-11-04 17:18:10 +08:00
|
|
|
XCompositeRedirectSubwindows(
|
|
|
|
dpy, root, CompositeRedirectManual);
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
XSelectInput(dpy, root,
|
2011-11-04 17:18:10 +08:00
|
|
|
SubstructureNotifyMask
|
|
|
|
| ExposureMask
|
|
|
|
| StructureNotifyMask
|
|
|
|
| PropertyChangeMask);
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
XQueryTree(dpy, root, &root_return,
|
|
|
|
&parent_return, &children, &nchildren);
|
|
|
|
|
|
|
|
for (i = 0; i < nchildren; i++) {
|
2012-01-15 00:12:54 +08:00
|
|
|
add_win(dpy, children[i], i ? children[i-1] : None, False);
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
|
2011-11-04 16:41:56 +08:00
|
|
|
XFree(children);
|
|
|
|
|
2012-09-26 18:54:35 +08:00
|
|
|
if (opts.track_focus) {
|
2012-09-13 21:38:55 +08:00
|
|
|
recheck_focus(dpy);
|
2012-09-13 23:12:54 +08:00
|
|
|
}
|
2012-09-13 21:38:55 +08:00
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
XUngrabServer(dpy);
|
|
|
|
|
|
|
|
ufd.fd = ConnectionNumber(dpy);
|
|
|
|
ufd.events = POLLIN;
|
2011-11-04 16:41:56 +08:00
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
t = paint_preprocess(dpy, list);
|
|
|
|
paint_all(dpy, None, t);
|
2011-11-04 14:33:23 +08:00
|
|
|
|
2012-09-29 22:53:57 +08:00
|
|
|
// Initialize idling
|
|
|
|
idling = False;
|
|
|
|
|
2011-11-04 14:33:23 +08:00
|
|
|
for (;;) {
|
|
|
|
do {
|
|
|
|
if (!QLength(dpy)) {
|
2012-09-29 22:53:57 +08:00
|
|
|
if (poll(&ufd, 1, (idling ? -1: fade_timeout())) == 0) {
|
2011-11-04 14:33:23 +08:00
|
|
|
break;
|
2011-11-05 05:18:56 +08:00
|
|
|
}
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
XNextEvent(dpy, &ev);
|
2012-02-27 12:00:12 +08:00
|
|
|
ev_handle((XEvent *)&ev);
|
2011-11-04 14:33:23 +08:00
|
|
|
} while (QLength(dpy));
|
|
|
|
|
2012-09-29 22:53:57 +08:00
|
|
|
// idling will be turned off during paint_preprocess() if needed
|
|
|
|
idling = True;
|
|
|
|
|
2012-09-19 20:49:16 +08:00
|
|
|
t = paint_preprocess(dpy, list);
|
2011-11-04 16:41:56 +08:00
|
|
|
if (all_damage) {
|
|
|
|
static int paint;
|
2012-09-19 20:49:16 +08:00
|
|
|
paint_all(dpy, all_damage, t);
|
2011-11-04 14:33:23 +08:00
|
|
|
paint++;
|
|
|
|
XSync(dpy, False);
|
2011-11-04 16:41:56 +08:00
|
|
|
all_damage = None;
|
2011-11-04 14:33:23 +08:00
|
|
|
}
|
|
|
|
}
|
2003-11-09 15:08:23 +08:00
|
|
|
}
|