diff --git a/Makefile b/Makefile index 7d62596..47be594 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,12 @@ INCS += $(shell pcre-config --cflags) CFLAGS += -Wall -std=c99 OBJS = compton.o +CFG ?= -DCONFIG_LIBCONFIG -DCONFIG_REGEX_PCRE -DCONFIG_REGEX_PCRE_JIT +# libconfig-1.3* does not define LIBCONFIG_VER* macros, so we use pkg-config +# to determine its version here +CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY') +CFLAGS += $(CFG) + %.o: src/%.c src/%.h $(CC) $(CFLAGS) $(INCS) -c src/$*.c diff --git a/compton.sample.conf b/compton.sample.conf index d7c11b6..857c914 100644 --- a/compton.sample.conf +++ b/compton.sample.conf @@ -3,15 +3,16 @@ shadow = true; no-dnd-shadow = true; no-dock-shadow = true; clear-shadow = true; -shadow-radius = 7 -shadow-offset-x = -7 -shadow-offset-y = -7 -# shadow-opacity = 0.7 -# shadow-red = 0.0 -# shadow-green = 0.0 -# shadow-blue = 0.0 +shadow-radius = 7; +shadow-offset-x = -7; +shadow-offset-y = -7; +# shadow-opacity = 0.7; +# shadow-red = 0.0; +# shadow-green = 0.0; +# shadow-blue = 0.0; shadow-exclude = [ "n:e:Notification" ]; # shadow-exclude = "n:e:Notification"; +shadow-ignore-shaped = true; # Opacity menu-opacity = 0.8; @@ -21,17 +22,18 @@ inactive-opacity-override = true; # Fading fading = true; -# fade-delta = 30 -fade-in-step = 0.03 -fade-out-step = 0.03 +# fade-delta = 30; +fade-in-step = 0.03; +fade-out-step = 0.03; # no-fading-openclose = true; # Other mark-wmwin-focused = true; mark-ovredir-focused = true; +detect-rounded-corners = true; # Window type settings wintypes: { tooltip = { fade = true; shadow = false; opacity = 0.75; }; -} +}; diff --git a/src/compton.c b/src/compton.c index 1050ab0..bb9d7bb 100644 --- a/src/compton.c +++ b/src/compton.c @@ -51,6 +51,9 @@ XserverRegion all_damage; Bool has_name_pixmap; #endif int root_height, root_width; +/// Whether the program is idling. I.e. no fading, no potential window +/// changes. +Bool idling; /* errors */ ignore *ignore_head = NULL, **ignore_tail = &ignore_head; @@ -109,31 +112,37 @@ Atom win_type[NUM_WINTYPES]; static options_t opts = { .display = NULL, + .mark_wmwin_focused = False, + .mark_ovredir_focused = False, + .fork_after_register = False, + .synchronize = False, + .detect_rounded_corners = False, + + .wintype_shadow = { False }, + .shadow_red = 0.0, + .shadow_green = 0.0, + .shadow_blue = 0.0, .shadow_radius = 12, .shadow_offset_x = -15, .shadow_offset_y = -15, .shadow_opacity = .75, + .clear_shadow = False, + .shadow_blacklist = NULL, + .shadow_ignore_shaped = False, + + .wintype_fade = { False }, .fade_in_step = 0.028 * OPAQUE, .fade_out_step = 0.03 * OPAQUE, .fade_delta = 10, .no_fading_openclose = False, - .clear_shadow = False, + .fade_blacklist = NULL, + + .wintype_opacity = { 0.0 }, .inactive_opacity = 0, .inactive_opacity_override = False, .frame_opacity = 0.0, .inactive_dim = 0.0, - .mark_wmwin_focused = False, - .mark_ovredir_focused = False, - .shadow_blacklist = NULL, - .fade_blacklist = NULL, - .fork_after_register = False, - .shadow_red = 0.0, - .shadow_green = 0.0, - .shadow_blue = 0.0, - .wintype_opacity = { 0.0 }, - .wintype_shadow = { False }, - .wintype_fade = { False }, - .synchronize = False, + .track_focus = False, .track_wdata = False, }; @@ -207,6 +216,9 @@ run_fade(Display *dpy, win *w, unsigned steps) { w->fade_fin = True; return; } + else { + idling = False; + } w->fade_fin = False; } @@ -224,8 +236,12 @@ set_fade_callback(Display *dpy, win *w, w->fade_callback = callback; // Must be the last line as the callback could destroy w! - if (exec_callback && old_callback) + if (exec_callback && old_callback) { old_callback(dpy, w); + // Although currently no callback function affects window state on + // next paint, it could, in the future + idling = False; + } } /** @@ -384,11 +400,10 @@ make_shadow(Display *dpy, double opacity, int width, int height) { XImage *ximage; unsigned char *data; - int gsize = gaussian_map->size; int ylimit, xlimit; - int swidth = width + gsize; - int sheight = height + gsize; - int center = gsize / 2; + int swidth = width + cgsize; + int sheight = height + cgsize; + int center = cgsize / 2; int x, y; unsigned char d; int x_diff; @@ -434,10 +449,10 @@ make_shadow(Display *dpy, double opacity, * corners */ - ylimit = gsize; + ylimit = cgsize; if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2; - xlimit = gsize; + xlimit = cgsize; if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2; for (y = 0; y < ylimit; y++) { @@ -460,7 +475,7 @@ make_shadow(Display *dpy, double opacity, * top/bottom */ - x_diff = swidth - (gsize * 2); + x_diff = swidth - (cgsize * 2); if (x_diff > 0 && ylimit > 0) { for (y = 0; y < ylimit; y++) { if (ylimit == cgsize) { @@ -469,8 +484,8 @@ make_shadow(Display *dpy, double opacity, d = sum_gaussian(gaussian_map, opacity, center, y - center, width, height); } - memset(&data[y * swidth + gsize], d, x_diff); - memset(&data[(sheight - y - 1) * swidth + gsize], d, x_diff); + memset(&data[y * swidth + cgsize], d, x_diff); + memset(&data[(sheight - y - 1) * swidth + cgsize], d, x_diff); } } @@ -485,7 +500,7 @@ make_shadow(Display *dpy, double opacity, d = sum_gaussian(gaussian_map, opacity, x - center, center, width, height); } - for (y = gsize; y < sheight - gsize; y++) { + for (y = cgsize; y < sheight - cgsize; y++) { data[y * swidth + x] = d; data[y * swidth + (swidth - x - 1)] = d; } @@ -512,48 +527,62 @@ make_shadow(Display *dpy, double opacity, static Picture shadow_picture(Display *dpy, double opacity, int width, int height) { - XImage *shadow_image; - Pixmap shadow_pixmap; - Picture shadow_picture; - GC gc; + XImage *shadow_image = NULL; + Pixmap shadow_pixmap = None, shadow_pixmap_argb = None; + Picture shadow_picture = None, shadow_picture_argb = None; + GC gc = None; shadow_image = make_shadow(dpy, opacity, width, height); - if (!shadow_image) return None; + if (!shadow_image) + return None; shadow_pixmap = XCreatePixmap(dpy, root, shadow_image->width, shadow_image->height, 8); + shadow_pixmap_argb = XCreatePixmap(dpy, root, + shadow_image->width, shadow_image->height, 32); - if (!shadow_pixmap) { - XDestroyImage(shadow_image); - return None; - } + if (!shadow_pixmap || !shadow_pixmap_argb) + goto shadow_picture_err; shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap, XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0); - - if (!shadow_picture) { - XDestroyImage(shadow_image); - XFreePixmap(dpy, shadow_pixmap); - return None; - } + shadow_picture_argb = XRenderCreatePicture(dpy, shadow_pixmap_argb, + XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0); + if (!shadow_picture || !shadow_picture_argb) + goto shadow_picture_err; gc = XCreateGC(dpy, shadow_pixmap, 0, 0); - if (!gc) { - XDestroyImage(shadow_image); - XFreePixmap(dpy, shadow_pixmap); - XRenderFreePicture(dpy, shadow_picture); - return None; - } + if (!gc) + goto shadow_picture_err; - XPutImage( - dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, + XPutImage(dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, shadow_image->width, shadow_image->height); + XRenderComposite(dpy, PictOpSrc, cshadow_picture, shadow_picture, + shadow_picture_argb, 0, 0, 0, 0, 0, 0, + shadow_image->width, shadow_image->height); XFreeGC(dpy, gc); XDestroyImage(shadow_image); XFreePixmap(dpy, shadow_pixmap); + XFreePixmap(dpy, shadow_pixmap_argb); + XRenderFreePicture(dpy, shadow_picture); - return shadow_picture; + return shadow_picture_argb; + +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; } static Picture @@ -632,6 +661,48 @@ should_ignore(Display *dpy, unsigned long sequence) { * Windows */ +/** + * Check if a window has rounded corners. + */ +static void +win_rounded_corners(Display *dpy, win *w) { + if (!w->bounding_shaped) + return; + + // Fetch its bounding region + if (!w->border_size) + w->border_size = border_size(dpy, w); + + // Quit if border_size() returns None + if (!w->border_size) + return; + + // Determine the minimum width/height of a rectangle that could mark + // a window as having rounded corners + unsigned short minwidth = max_i(w->widthb * (1 - ROUNDED_PERCENT), + w->widthb - ROUNDED_PIXELS); + unsigned short minheight = max_i(w->heightb * (1 - ROUNDED_PERCENT), + w->heightb - ROUNDED_PIXELS); + + // Get the rectangles in the bounding region + int nrects = 0, i; + XRectangle *rects = XFixesFetchRegion(dpy, w->border_size, &nrects); + if (!rects) + return; + + // Look for a rectangle large enough for this window be considered + // having rounded corners + for (i = 0; i < nrects; ++i) + if (rects[i].width >= minwidth && rects[i].height >= minheight) { + w->rounded_corners = True; + XFree(rects); + return; + } + + w->rounded_corners = False; + XFree(rects); +} + /** * Match a window against a single window condition. * @@ -1110,7 +1181,7 @@ border_size(Display *dpy, win *w) { static Window find_client_win(Display *dpy, Window w) { - if (win_has_attr(dpy, w, client_atom)) { + if (wid_has_attr(dpy, w, client_atom)) { return w; } @@ -1119,7 +1190,7 @@ find_client_win(Display *dpy, Window w) { unsigned int i; Window ret = 0; - if (!win_get_children(dpy, w, &children, &nchildren)) { + if (!wid_get_children(dpy, w, &children, &nchildren)) { return 0; } @@ -1276,12 +1347,18 @@ paint_preprocess(Display *dpy, win *list) { if (w->flags & WFLAG_SIZE_CHANGE) free_picture(dpy, &w->shadow_pict); - if (w->shadow - && (!w->shadow_pict - || w->shadow_opacity != w->shadow_opacity_cur)) { - free_picture(dpy, &w->shadow_pict); - w->shadow_pict = shadow_picture(dpy, w->shadow_opacity, + if (w->shadow && !w->shadow_pict) { + w->shadow_pict = shadow_picture(dpy, 1, w->widthb, w->heightb); + } + + // Rebuild shadow_alpha_pict if necessary + if (w->shadow + && (!w->shadow_alpha_pict + || w->shadow_opacity != w->shadow_opacity_cur)) { + free_picture(dpy, &w->shadow_alpha_pict); + w->shadow_alpha_pict = solid_picture( + dpy, False, w->shadow_opacity, 0, 0, 0); w->shadow_opacity_cur = w->shadow_opacity; } @@ -1359,7 +1436,7 @@ paint_all(Display *dpy, XserverRegion region, win *t) { // Painting shadow if (w->shadow) { XRenderComposite( - dpy, PictOpOver, cshadow_picture, w->shadow_pict, + dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, root_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); @@ -1510,7 +1587,7 @@ determine_wintype(Display *dpy, Window w) { type = get_wintype_prop(dpy, w); if (type != WINTYPE_UNKNOWN) return type; - if (!win_get_children(dpy, w, &children, &nchildren)) + if (!wid_get_children(dpy, w, &children, &nchildren)) return WINTYPE_UNKNOWN; for (i = 0; i < nchildren; i++) { @@ -1570,6 +1647,13 @@ map_win(Display *dpy, Window id, w->id, WINTYPES[w->window_type]); #endif + // Detect if the window is shaped or has rounded corners + if (opts.shadow_ignore_shaped) { + w->bounding_shaped = wid_bounding_shaped(dpy, w->id); + if (w->bounding_shaped && opts.detect_rounded_corners) + win_rounded_corners(dpy, w); + } + // Get window name and class if we are tracking them if (opts.track_wdata) { win_get_name(dpy, w); @@ -1592,7 +1676,8 @@ map_win(Display *dpy, Window id, w->focused = True; } - // Window type change could affect shadow and fade + // Window type change and bounding shape state change could affect + // shadow determine_shadow(dpy, w); // Determine mode here just in case the colormap changes @@ -1601,6 +1686,7 @@ map_win(Display *dpy, Window id, // Fading in calc_opacity(dpy, w, True); + // Set fading state 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 @@ -1820,7 +1906,9 @@ determine_shadow(Display *dpy, win *w) { Bool shadow_old = w->shadow; w->shadow = (opts.wintype_shadow[w->window_type] - && !win_match(w, opts.shadow_blacklist, &w->cache_sblst)); + && !win_match(w, opts.shadow_blacklist, &w->cache_sblst) + && !(opts.shadow_ignore_shaped && w->bounding_shaped + && !w->rounded_corners)); // Window extents need update on shadow state change if (w->shadow != shadow_old) { @@ -1935,6 +2023,8 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->class_general = NULL; new->cache_sblst = NULL; new->cache_fblst = NULL; + new->bounding_shaped = False; + new->rounded_corners = False; new->border_size = None; new->extents = None; @@ -1942,6 +2032,7 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->shadow_opacity = 0.0; new->shadow_opacity_cur = 0.0; new->shadow_pict = None; + new->shadow_alpha_pict = None; new->shadow_dx = 0; new->shadow_dy = 0; new->shadow_width = 0; @@ -2752,6 +2843,16 @@ ev_shape_notify(XShapeEvent *ev) { // Mark the new border_size as damaged add_damage(dpy, copy_region(dpy, w->border_size)); } + + // Redo bounding shape detection and rounded corner detection + if (opts.shadow_ignore_shaped) { + w->bounding_shaped = wid_bounding_shaped(dpy, w->id); + if (w->bounding_shaped && opts.detect_rounded_corners) + win_rounded_corners(dpy, w); + + // Shadow state could be changed + determine_shadow(dpy, w); + } } inline static void @@ -2905,6 +3006,11 @@ usage(void) { " Mark over-redirect windows as active.\n" "--no-fading-openclose\n" " Do not fade on window open/close.\n" + "--shadow-ignore-shaped\n" + " Do not paint shadows on shaped windows.\n" + "--detect-rounded-corners\n" + " Try to detect windows with rounded corners and don't consider\n" + " them shaped windows.\n" "\n" "Format of a condition:\n" "\n" @@ -3071,7 +3177,7 @@ open_config_file(char *cpath, char **ppath) { */ static void parse_config(char *cpath, struct options_tmp *pcfgtmp) { - char *path = NULL, *parent = NULL; + char *path = NULL; FILE *f; config_t cfg; int ival = 0; @@ -3085,9 +3191,11 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { } config_init(&cfg); - parent = dirname(path); +#ifndef CONFIG_LIBCONFIG_LEGACY + char *parent = dirname(path); if (parent) config_set_include_dir(&cfg, parent); +#endif if (CONFIG_FALSE == config_read(&cfg, f)) { printf("Error when reading configuration file \"%s\", line %d: %s\n", @@ -3104,7 +3212,7 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { // right now. It will be done later // -D (fade_delta) - if (config_lookup_int(&cfg, "fade-delta", &ival)) + if (lcfg_lookup_int(&cfg, "fade-delta", &ival)) opts.fade_delta = ival; // -I (fade_in_step) if (config_lookup_float(&cfg, "fade-in-step", &dval)) @@ -3113,13 +3221,13 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { if (config_lookup_float(&cfg, "fade-out-step", &dval)) opts.fade_out_step = normalize_d(dval) * OPAQUE; // -r (shadow_radius) - config_lookup_int(&cfg, "shadow-radius", &opts.shadow_radius); + lcfg_lookup_int(&cfg, "shadow-radius", &opts.shadow_radius); // -o (shadow_opacity) config_lookup_float(&cfg, "shadow-opacity", &opts.shadow_opacity); // -l (shadow_offset_x) - config_lookup_int(&cfg, "shadow-offset-x", &opts.shadow_offset_x); + lcfg_lookup_int(&cfg, "shadow-offset-x", &opts.shadow_offset_x); // -t (shadow_offset_y) - config_lookup_int(&cfg, "shadow-offset-y", &opts.shadow_offset_y); + lcfg_lookup_int(&cfg, "shadow-offset-y", &opts.shadow_offset_y); // -i (inactive_opacity) if (config_lookup_float(&cfg, "inactive-opacity", &dval)) opts.inactive_opacity = normalize_d(dval) * OPAQUE; @@ -3157,6 +3265,12 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { // --mark-ovredir-focused lcfg_lookup_bool(&cfg, "mark-ovredir-focused", &opts.mark_ovredir_focused); + // --shadow-ignore-shaped + lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", + &opts.shadow_ignore_shaped); + // --detect-rounded-corners + lcfg_lookup_bool(&cfg, "detect-rounded-corners", + &opts.detect_rounded_corners); // --shadow-exclude { config_setting_t *setting = @@ -3217,6 +3331,8 @@ get_cfg(int argc, char *const *argv) { { "shadow-exclude", required_argument, NULL, 263 }, { "mark-ovredir-focused", no_argument, NULL, 264 }, { "no-fading-openclose", no_argument, NULL, 265 }, + { "shadow-ignore-shaped", no_argument, NULL, 266 }, + { "detect-rounded-corners", no_argument, NULL, 267 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -3363,6 +3479,14 @@ get_cfg(int argc, char *const *argv) { // --no-fading-openclose opts.no_fading_openclose = True; break; + case 266: + // --shadow-ignore-shaped + opts.shadow_ignore_shaped = True; + break; + case 267: + // --detect-rounded-corners + opts.detect_rounded_corners = True; + break; default: usage(); break; @@ -3591,10 +3715,13 @@ main(int argc, char **argv) { t = paint_preprocess(dpy, list); paint_all(dpy, None, t); + // Initialize idling + idling = False; + for (;;) { do { if (!QLength(dpy)) { - if (poll(&ufd, 1, fade_timeout()) == 0) { + if (poll(&ufd, 1, (idling ? -1: fade_timeout())) == 0) { break; } } @@ -3603,6 +3730,9 @@ main(int argc, char **argv) { ev_handle((XEvent *)&ev); } while (QLength(dpy)); + // idling will be turned off during paint_preprocess() if needed + idling = True; + t = paint_preprocess(dpy, list); if (all_damage) { static int paint; diff --git a/src/compton.h b/src/compton.h index 0c6457c..83b7876 100644 --- a/src/compton.h +++ b/src/compton.h @@ -20,12 +20,12 @@ // Whether to enable PCRE regular expression support in blacklists, enabled // by default -#define CONFIG_REGEX_PCRE 1 +// #define CONFIG_REGEX_PCRE 1 // Whether to enable JIT support of libpcre. This may cause problems on PaX // kernels. -#define CONFIG_REGEX_PCRE_JIT 1 +// #define CONFIG_REGEX_PCRE_JIT 1 // Whether to enable parsing of configuration files using libconfig -#define CONFIG_LIBCONFIG 1 +// #define CONFIG_LIBCONFIG 1 // === Includes === @@ -49,6 +49,12 @@ #ifdef CONFIG_REGEX_PCRE #include + +// For compatiblity with extern struct timeval time_start; @@ -168,6 +177,10 @@ typedef struct _win { Bool destroyed; /// Cached width/height of the window including border. int widthb, heightb; + /// Whether the window is bounding-shaped. + Bool bounding_shaped; + /// Whether the window just have rounded corners. + Bool rounded_corners; // Blacklist related members char *name; @@ -222,9 +235,10 @@ typedef struct _win { int shadow_width; /// Height of shadow. Affected by window size and commandline argument. int shadow_height; - /// Alpha mask Picture to render shadow. Affected by window size and - /// shadow opacity. + /// Picture to render shadow. Affected by window size. Picture shadow_pict; + /// Alpha mask Picture to render shadow. Affected by shadow opacity. + Picture shadow_alpha_pict; // Dim-related members /// Whether the window is to be dimmed. @@ -250,6 +264,9 @@ typedef struct _options { Bool mark_ovredir_focused; /// Whether to fork to background. Bool fork_after_register; + /// Whether to detect rounded corners. + Bool detect_rounded_corners; + /// Whether to work under synchronized mode for debugging. Bool synchronize; // Shadow @@ -262,6 +279,8 @@ typedef struct _options { Bool clear_shadow; /// Shadow blacklist. A linked list of conditions. wincond *shadow_blacklist; + /// Whether bounding-shaped window should be ignored. + Bool shadow_ignore_shaped; // Fading Bool wintype_fade[NUM_WINTYPES]; @@ -314,6 +333,8 @@ typedef enum { extern int root_height, root_width; extern Atom atom_client_attr; +extern Bool idling; +extern Bool shape_exists; /** * Functions @@ -555,52 +576,6 @@ free_damage(Display *dpy, Damage *p) { } } -/** - * Determine if a window has a specific attribute. - * - * @param dpy Display to use - * @param w window to check - * @param atom atom of attribute to check - * @return 1 if it has the attribute, 0 otherwise - */ -static inline Bool -win_has_attr(Display *dpy, Window w, Atom atom) { - Atom type = None; - int format; - unsigned long nitems, after; - unsigned char *data; - - if (Success == XGetWindowProperty(dpy, w, atom, 0, 0, False, - AnyPropertyType, &type, &format, &nitems, &after, &data)) { - XFree(data); - if (type) return True; - } - - return False; -} - -/** - * Get the children of a window. - * - * @param dpy Display to use - * @param w window to check - * @param children [out] an array of child window IDs - * @param nchildren [out] number of children - * @return 1 if successful, 0 otherwise - */ -static inline Bool -win_get_children(Display *dpy, Window w, - Window **children, unsigned *nchildren) { - Window troot, tparent; - - if (!XQueryTree(dpy, w, &troot, &tparent, children, nchildren)) { - *nchildren = 0; - return False; - } - - return True; -} - static unsigned long get_time_in_milliseconds(void); @@ -660,6 +635,75 @@ static inline bool is_normal_win(const win *w) { || WINTYPE_UNKNOWN == w->window_type); } +/** + * Determine if a window has a specific attribute. + * + * @param dpy Display to use + * @param w window to check + * @param atom atom of attribute to check + * @return 1 if it has the attribute, 0 otherwise + */ +static inline Bool +wid_has_attr(Display *dpy, Window w, Atom atom) { + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (Success == XGetWindowProperty(dpy, w, atom, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, &after, &data)) { + XFree(data); + if (type) return True; + } + + return False; +} + +/** + * Get the children of a window. + * + * @param dpy Display to use + * @param w window to check + * @param children [out] an array of child window IDs + * @param nchildren [out] number of children + * @return 1 if successful, 0 otherwise + */ +static inline Bool +wid_get_children(Display *dpy, Window w, + Window **children, unsigned *nchildren) { + Window troot, tparent; + + if (!XQueryTree(dpy, w, &troot, &tparent, children, nchildren)) { + *nchildren = 0; + return False; + } + + return True; +} + +/** + * Check if a window is bounding-shaped. + */ +static inline Bool +wid_bounding_shaped(Display *dpy, Window wid) { + if (shape_exists) { + Bool bounding_shaped = False; + Bool clip_shaped; + int x_bounding, y_bounding, x_clip, y_clip; + unsigned int w_bounding, h_bounding, w_clip, h_clip; + + XShapeQueryExtents(dpy, wid, &bounding_shaped, + &x_bounding, &y_bounding, &w_bounding, &h_bounding, + &clip_shaped, &x_clip, &y_clip, &w_clip, &h_clip); + return bounding_shaped; + } + + return False; +} + +static void +win_rounded_corners(Display *dpy, win *w); + static bool win_match_once(win *w, const wincond *cond); @@ -923,7 +967,7 @@ static void fork_after(void); #ifdef CONFIG_LIBCONFIG -static void +static inline void lcfg_lookup_bool(const config_t *config, const char *path, Bool *value) { int ival; @@ -931,6 +975,21 @@ lcfg_lookup_bool(const config_t *config, const char *path, Bool *value) { *value = ival; } +static inline int +lcfg_lookup_int(const config_t *config, const char *path, int *value) { +#ifndef CONFIG_LIBCONFIG_LEGACY + return config_lookup_int(config, path, value); +#else + long lval; + int ret; + + if ((ret = config_lookup_int(config, path, &lval))) + *value = lval; + + return ret; +#endif +} + static FILE * open_config_file(char *cpath, char **path);