diff options
-rw-r--r-- | compton.c | 2932 | ||||
-rw-r--r-- | compton.h | 1093 |
2 files changed, 2259 insertions, 1766 deletions
@@ -10,16 +10,18 @@ #include "compton.h" -#define MSTR_(s) #s -#define MSTR(s) MSTR_(s) +// === Macros === + +// #define MSTR_(s) #s +// #define MSTR(s) MSTR_(s) // Use #s here to prevent macro expansion +/// Macro used for shortening some debugging code. #define CASESTRRET(s) case s: return #s -/** - * Shared - */ +// === Global constants === +/// Name strings for window types. const char *WINTYPES[NUM_WINTYPES] = { "unknown", "desktop", @@ -38,207 +40,22 @@ const char *WINTYPES[NUM_WINTYPES] = { "dnd", }; -struct timeval time_start = { 0, 0 }; - -win *list; -Display *dpy = NULL; -int scr; - -/// Root window. -Window root = None; -/// Damage of root window. -Damage root_damage = None; -/// X Composite overlay window. Used if --paint-on-overlay. -Window overlay = None; - -/// Picture of root window. Destination of painting in no-DBE painting -/// mode. -Picture root_picture = None; -/// A Picture acting as the painting target. -Picture tgt_picture = None; -/// Temporary buffer to paint to before sending to display. -Picture tgt_buffer = None; -/// DBE back buffer for root window. Used in DBE painting mode. -XdbeBackBuffer root_dbe = None; - -Picture black_picture; -Picture cshadow_picture; -/// Picture used for dimming inactive windows. -Picture dim_picture = 0; -Picture root_tile; -XserverRegion all_damage; -Bool has_name_pixmap; -int root_height, root_width; -/// A region of the size of the screen. -XserverRegion screen_reg = None; -/// Current active window. Used by EWMH _NET_ACTIVE_WINDOW focus -/// detection. -win *active_win = NULL; -/// Whether all windows are currently redirected. -Bool redirected = False; -/// Whether there's a highest fullscreen window, and all windows could -/// be unredirected. -Bool unredir_possible = False; - -/// Pregenerated alpha pictures. -Picture *alpha_picts = NULL; -/// Whether the program is idling. I.e. no fading, no potential window -/// changes. -Bool idling; -/// Whether all reg_ignore of windows should expire in this paint. -Bool reg_ignore_expire = False; -/// Window ID of the window we register as a symbol. -Window reg_win = 0; - -/// Currently used refresh rate. Used for sw_opti. -short refresh_rate = 0; -/// Interval between refresh in nanoseconds. Used for sw_opti. -unsigned long refresh_intv = 0; -/// Nanosecond-level offset of the first painting. Used for sw_opti. -long paint_tm_offset = 0; - -#ifdef CONFIG_VSYNC_DRM -/// File descriptor of DRI device file. Used for DRM VSync. -int drm_fd = 0; -#endif - -#ifdef CONFIG_VSYNC_OPENGL -/// GLX context. -GLXContext glx_context; - -/// Pointer to glXGetVideoSyncSGI function. Used by OpenGL VSync. -f_GetVideoSync glx_get_video_sync = NULL; - -/// Pointer to glXWaitVideoSyncSGI function. Used by OpenGL VSync. -f_WaitVideoSync glx_wait_video_sync = NULL; -#endif - -/* errors */ -ignore *ignore_head = NULL, **ignore_tail = &ignore_head; -int xfixes_event, xfixes_error; -int damage_event, damage_error; -int composite_event, composite_error; -int render_event, render_error; -int composite_opcode; - -/// Whether X Shape extension exists. -Bool shape_exists = False; -/// Event base number and error base number for X Shape extension. -int shape_event, shape_error; - -/// Whether X RandR extension exists. -Bool randr_exists = False; -/// Event base number and error base number for X RandR extension. -int randr_event, randr_error; - -#ifdef CONFIG_VSYNC_OPENGL -/// Whether X GLX extension exists. -Bool glx_exists = False; -/// Event base number and error base number for X GLX extension. -int glx_event, glx_error; -#endif - -Bool dbe_exists = False; - -/* shadows */ -conv *gaussian_map; - -/* for shadow precomputation */ -int cgsize = -1; -unsigned char *shadow_corner = NULL; -unsigned char *shadow_top = NULL; - -/* for root tile */ -static const char *background_props[] = { +/// Names of root window properties that could point to a pixmap of +/// background. +const char *background_props_str[] = { "_XROOTPMAP_ID", "_XSETROOT_ID", 0, }; -/* for expose events */ -XRectangle *expose_rects = 0; -int size_expose = 0; -int n_expose = 0; - -// atoms -Atom opacity_atom = None; -Atom frame_extents_atom = None; -Atom client_atom = None; -Atom name_atom = None; -Atom name_ewmh_atom = None; -Atom class_atom = None; -Atom transient_atom = None; -Atom ewmh_active_win_atom = None;; -Atom compton_shadow_atom = None; - -Atom win_type_atom; -Atom win_type[NUM_WINTYPES]; +// === Global variables === -/** - * Macros - */ +/// Pointer to current session, as a global variable. Only used by +/// <code>error()</code> and <code>reset_enable()</code>, which could not +/// have a pointer to current session passed in. +session_t *ps_g = NULL; -#define HAS_FRAME_OPACITY(w) \ - (frame_opacity && (w)->top_width) - -/** - * Options - */ - -static options_t opts = { - .display = NULL, - .mark_wmwin_focused = False, - .mark_ovredir_focused = False, - .fork_after_register = False, - .synchronize = False, - .detect_rounded_corners = False, - .paint_on_overlay = False, - .unredir_if_possible = False, - - .refresh_rate = 0, - .sw_opti = False, - .vsync = VSYNC_NONE, - .dbe = False, - .vsync_aggressive = 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, - .respect_attr_shadow = False, - - .wintype_fade = { False }, - .fade_in_step = 0.028 * OPAQUE, - .fade_out_step = 0.03 * OPAQUE, - .fade_delta = 10, - .no_fading_openclose = False, - .fade_blacklist = NULL, - - .wintype_opacity = { 0.0 }, - .inactive_opacity = 0, - .inactive_opacity_override = False, - .frame_opacity = 0.0, - .detect_client_opacity = False, - .inactive_dim = 0.0, - .alpha_step = 0.03, - .use_ewmh_active_win = False, - - .track_focus = False, - .track_wdata = False, -}; - -/** - * Fades - */ - -unsigned long fade_time = 0; +// === Fading === /** * Get the time left before next fading point. @@ -246,8 +63,8 @@ unsigned long fade_time = 0; * In milliseconds. */ static int -fade_timeout(void) { - int diff = opts.fade_delta - get_time_ms() + fade_time; +fade_timeout(session_t *ps) { + int diff = ps->o.fade_delta - get_time_ms() + ps->fade_time; if (diff < 0) diff = 0; @@ -261,7 +78,7 @@ fade_timeout(void) { * @param steps steps of fading */ static void -run_fade(Display *dpy, win *w, unsigned steps) { +run_fade(session_t *ps, win *w, unsigned steps) { // If we have reached target opacity, return if (w->opacity == w->opacity_tgt) { return; @@ -274,16 +91,16 @@ run_fade(Display *dpy, win *w, unsigned steps) { // calculations if (w->opacity < w->opacity_tgt) w->opacity = normalize_d_range( - (double) w->opacity + (double) opts.fade_in_step * steps, + (double) w->opacity + (double) ps->o.fade_in_step * steps, 0.0, w->opacity_tgt); else w->opacity = normalize_d_range( - (double) w->opacity - (double) opts.fade_out_step * steps, + (double) w->opacity - (double) ps->o.fade_out_step * steps, w->opacity_tgt, OPAQUE); } if (w->opacity != w->opacity_tgt) { - idling = False; + ps->idling = false; } } @@ -294,32 +111,30 @@ run_fade(Display *dpy, win *w, unsigned steps) { * @param exec_callback whether the previous callback is to be executed */ static void -set_fade_callback(Display *dpy, win *w, - void (*callback) (Display *dpy, win *w), Bool exec_callback) { - void (*old_callback) (Display *dpy, win *w) = w->fade_callback; +set_fade_callback(session_t *ps, win *w, + void (*callback) (session_t *ps, win *w), bool exec_callback) { + void (*old_callback) (session_t *ps, win *w) = w->fade_callback; w->fade_callback = callback; // Must be the last line as the callback could destroy w! if (exec_callback && old_callback) { - old_callback(dpy, w); + old_callback(ps, w); // Although currently no callback function affects window state on // next paint, it could, in the future - idling = False; + ps->idling = false; } } -/** - * Shadows - */ +// === Shadows === -static double +static double __attribute__((const)) gaussian(double r, double x, double y) { return ((1 / (sqrt(2 * M_PI * r))) * exp((- (x * x + y * y)) / (2 * r * r))); } static conv * -make_gaussian_map(Display *dpy, double r) { +make_gaussian_map(double r) { conv *c; int size = ((int) ceil((r * 3)) + 1) & ~1; int center = size / 2; @@ -334,7 +149,7 @@ make_gaussian_map(Display *dpy, double r) { for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { - g = gaussian(r, (double) (x - center), (double) (y - center)); + g = gaussian(r, x - center, y - center); t += g; c->data[y * size + x] = g; } @@ -420,54 +235,56 @@ sum_gaussian(conv *map, double opacity, to save time for large windows */ static void -presum_gaussian(conv *map) { +presum_gaussian(session_t *ps, conv *map) { int center = map->size / 2; int opacity, x, y; - cgsize = map->size; + ps->cgsize = map->size; - if (shadow_corner) free((void *)shadow_corner); - if (shadow_top) free((void *)shadow_top); + if (ps->shadow_corner) + free(ps->shadow_corner); + if (ps->shadow_top) + free(ps->shadow_top); - shadow_corner = (unsigned char *)(malloc((cgsize + 1) * (cgsize + 1) * 26)); - shadow_top = (unsigned char *)(malloc((cgsize + 1) * 26)); + ps->shadow_corner = malloc((ps->cgsize + 1) * (ps->cgsize + 1) * 26); + ps->shadow_top = malloc((ps->cgsize + 1) * 26); - for (x = 0; x <= cgsize; x++) { - shadow_top[25 * (cgsize + 1) + x] = - sum_gaussian(map, 1, x - center, center, cgsize * 2, cgsize * 2); + for (x = 0; x <= ps->cgsize; x++) { + ps->shadow_top[25 * (ps->cgsize + 1) + x] = + sum_gaussian(map, 1, x - center, center, ps->cgsize * 2, ps->cgsize * 2); for (opacity = 0; opacity < 25; opacity++) { - shadow_top[opacity * (cgsize + 1) + x] = - shadow_top[25 * (cgsize + 1) + x] * opacity / 25; + ps->shadow_top[opacity * (ps->cgsize + 1) + x] = + ps->shadow_top[25 * (ps->cgsize + 1) + x] * opacity / 25; } for (y = 0; y <= x; y++) { - 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]; + ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + y * (ps->cgsize + 1) + x] + = sum_gaussian(map, 1, x - center, y - center, ps->cgsize * 2, ps->cgsize * 2); + ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + x * (ps->cgsize + 1) + y] + = ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + y * (ps->cgsize + 1) + x]; for (opacity = 0; opacity < 25; opacity++) { - 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; + ps->shadow_corner[opacity * (ps->cgsize + 1) * (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x] + = ps->shadow_corner[opacity * (ps->cgsize + 1) * (ps->cgsize + 1) + + x * (ps->cgsize + 1) + y] + = ps->shadow_corner[25 * (ps->cgsize + 1) * (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x] * opacity / 25; } } } } static XImage * -make_shadow(Display *dpy, double opacity, - int width, int height, Bool clear_shadow) { +make_shadow(session_t *ps, double opacity, + int width, int height) { XImage *ximage; unsigned char *data; int ylimit, xlimit; - int swidth = width + cgsize; - int sheight = height + cgsize; - int center = cgsize / 2; + int swidth = width + ps->cgsize; + int sheight = height + ps->cgsize; + int center = ps->cgsize / 2; int x, y; unsigned char d; int x_diff; @@ -476,10 +293,8 @@ make_shadow(Display *dpy, double opacity, data = malloc(swidth * sheight * sizeof(unsigned char)); if (!data) return 0; - ximage = XCreateImage( - dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 8, - ZPixmap, 0, (char *) data, swidth, sheight, 8, - swidth * sizeof(unsigned char)); + ximage = XCreateImage(ps->dpy, ps->vis, 8, + ZPixmap, 0, (char *) data, swidth, sheight, 8, swidth * sizeof(char)); if (!ximage) { free(data); @@ -498,12 +313,12 @@ make_shadow(Display *dpy, double opacity, // 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. - /* if (!(clear_shadow && opts.shadow_offset_x <= 0 && opts.shadow_offset_x >= -cgsize - && opts.shadow_offset_y <= 0 && opts.shadow_offset_y >= -cgsize)) { */ - if (cgsize > 0) { - d = shadow_top[opacity_int * (cgsize + 1) + cgsize]; + /* if (!(clear_shadow && ps->o.shadow_offset_x <= 0 && ps->o.shadow_offset_x >= -ps->cgsize + && ps->o.shadow_offset_y <= 0 && ps->o.shadow_offset_y >= -ps->cgsize)) { */ + if (ps->cgsize > 0) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + ps->cgsize]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, center, center, width, height); } memset(data, d, sheight * swidth); @@ -513,19 +328,19 @@ make_shadow(Display *dpy, double opacity, * corners */ - ylimit = cgsize; + ylimit = ps->cgsize; if (ylimit > sheight / 2) ylimit = (sheight + 1) / 2; - xlimit = cgsize; + xlimit = ps->cgsize; if (xlimit > swidth / 2) xlimit = (swidth + 1) / 2; for (y = 0; y < ylimit; y++) { for (x = 0; x < xlimit; x++) { - if (xlimit == cgsize && ylimit == cgsize) { - d = shadow_corner[opacity_int * (cgsize + 1) * (cgsize + 1) - + y * (cgsize + 1) + x]; + if (xlimit == ps->cgsize && ylimit == ps->cgsize) { + d = ps->shadow_corner[opacity_int * (ps->cgsize + 1) * (ps->cgsize + 1) + + y * (ps->cgsize + 1) + x]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, x - center, y - center, width, height); } data[y * swidth + x] = d; @@ -539,17 +354,17 @@ make_shadow(Display *dpy, double opacity, * top/bottom */ - x_diff = swidth - (cgsize * 2); + x_diff = swidth - (ps->cgsize * 2); if (x_diff > 0 && ylimit > 0) { for (y = 0; y < ylimit; y++) { - if (ylimit == cgsize) { - d = shadow_top[opacity_int * (cgsize + 1) + y]; + if (ylimit == ps->cgsize) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + y]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, center, y - center, width, height); } - memset(&data[y * swidth + cgsize], d, x_diff); - memset(&data[(sheight - y - 1) * swidth + cgsize], d, x_diff); + memset(&data[y * swidth + ps->cgsize], d, x_diff); + memset(&data[(sheight - y - 1) * swidth + ps->cgsize], d, x_diff); } } @@ -558,28 +373,27 @@ make_shadow(Display *dpy, double opacity, */ for (x = 0; x < xlimit; x++) { - if (xlimit == cgsize) { - d = shadow_top[opacity_int * (cgsize + 1) + x]; + if (xlimit == ps->cgsize) { + d = ps->shadow_top[opacity_int * (ps->cgsize + 1) + x]; } else { - d = sum_gaussian(gaussian_map, + d = sum_gaussian(ps->gaussian_map, opacity, x - center, center, width, height); } - for (y = cgsize; y < sheight - cgsize; y++) { + for (y = ps->cgsize; y < sheight - ps->cgsize; y++) { data[y * swidth + x] = d; data[y * swidth + (swidth - x - 1)] = d; } } - assert(!clear_shadow); /* if (clear_shadow) { // Clear the region in the shadow that the window would cover based // on shadow_offset_{x,y} user provides - int xstart = normalize_i_range(- (int) opts.shadow_offset_x, 0, swidth); - int xrange = normalize_i_range(width - (int) opts.shadow_offset_x, + int xstart = normalize_i_range(- (int) ps->o.shadow_offset_x, 0, swidth); + int xrange = normalize_i_range(width - (int) ps->o.shadow_offset_x, 0, swidth) - xstart; - int ystart = normalize_i_range(- (int) opts.shadow_offset_y, 0, sheight); - int yend = normalize_i_range(height - (int) opts.shadow_offset_y, + int ystart = normalize_i_range(- (int) ps->o.shadow_offset_y, 0, sheight); + int yend = normalize_i_range(height - (int) ps->o.shadow_offset_y, 0, sheight); int y; @@ -592,48 +406,50 @@ make_shadow(Display *dpy, double opacity, return ximage; } +/** + * Generate shadow <code>Picture</code> for a window. + */ static Picture -shadow_picture(Display *dpy, double opacity, int width, int height, - Bool clear_shadow) { +shadow_picture(session_t *ps, double opacity, int width, int height) { 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, clear_shadow); + shadow_image = make_shadow(ps, opacity, width, height); if (!shadow_image) return None; - shadow_pixmap = XCreatePixmap(dpy, root, + shadow_pixmap = XCreatePixmap(ps->dpy, ps->root, shadow_image->width, shadow_image->height, 8); - shadow_pixmap_argb = XCreatePixmap(dpy, root, + shadow_pixmap_argb = XCreatePixmap(ps->dpy, ps->root, shadow_image->width, shadow_image->height, 32); if (!shadow_pixmap || !shadow_pixmap_argb) goto shadow_picture_err; - shadow_picture = XRenderCreatePicture(dpy, shadow_pixmap, - XRenderFindStandardFormat(dpy, PictStandardA8), 0, 0); - shadow_picture_argb = XRenderCreatePicture(dpy, shadow_pixmap_argb, - XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0); + shadow_picture = XRenderCreatePicture(ps->dpy, shadow_pixmap, + XRenderFindStandardFormat(ps->dpy, PictStandardA8), 0, 0); + shadow_picture_argb = XRenderCreatePicture(ps->dpy, shadow_pixmap_argb, + XRenderFindStandardFormat(ps->dpy, PictStandardARGB32), 0, 0); if (!shadow_picture || !shadow_picture_argb) goto shadow_picture_err; - gc = XCreateGC(dpy, shadow_pixmap, 0, 0); + gc = XCreateGC(ps->dpy, shadow_pixmap, 0, 0); if (!gc) goto shadow_picture_err; - XPutImage(dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, + XPutImage(ps->dpy, shadow_pixmap, gc, shadow_image, 0, 0, 0, 0, shadow_image->width, shadow_image->height); - XRenderComposite(dpy, PictOpSrc, cshadow_picture, shadow_picture, + XRenderComposite(ps->dpy, PictOpSrc, ps->cshadow_picture, shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width, shadow_image->height); - XFreeGC(dpy, gc); + XFreeGC(ps->dpy, gc); XDestroyImage(shadow_image); - XFreePixmap(dpy, shadow_pixmap); - XFreePixmap(dpy, shadow_pixmap_argb); - XRenderFreePicture(dpy, shadow_picture); + XFreePixmap(ps->dpy, shadow_pixmap); + XFreePixmap(ps->dpy, shadow_pixmap_argb); + XRenderFreePicture(ps->dpy, shadow_picture); return shadow_picture_argb; @@ -641,39 +457,42 @@ shadow_picture_err: if (shadow_image) XDestroyImage(shadow_image); if (shadow_pixmap) - XFreePixmap(dpy, shadow_pixmap); + XFreePixmap(ps->dpy, shadow_pixmap); if (shadow_pixmap_argb) - XFreePixmap(dpy, shadow_pixmap_argb); + XFreePixmap(ps->dpy, shadow_pixmap_argb); if (shadow_picture) - XRenderFreePicture(dpy, shadow_picture); + XRenderFreePicture(ps->dpy, shadow_picture); if (shadow_picture_argb) - XRenderFreePicture(dpy, shadow_picture_argb); + XRenderFreePicture(ps->dpy, shadow_picture_argb); if (gc) - XFreeGC(dpy, gc); + XFreeGC(ps->dpy, gc); return None; } +/** + * Generate a 1x1 <code>Picture</code> of a particular color. + */ static Picture -solid_picture(Display *dpy, Bool argb, double a, +solid_picture(session_t *ps, bool argb, double a, double r, double g, double b) { Pixmap pixmap; Picture picture; XRenderPictureAttributes pa; XRenderColor c; - pixmap = XCreatePixmap(dpy, root, 1, 1, argb ? 32 : 8); + pixmap = XCreatePixmap(ps->dpy, ps->root, 1, 1, argb ? 32 : 8); if (!pixmap) return None; pa.repeat = True; - picture = XRenderCreatePicture(dpy, pixmap, - XRenderFindStandardFormat(dpy, argb + picture = XRenderCreatePicture(ps->dpy, pixmap, + XRenderFindStandardFormat(ps->dpy, argb ? PictStandardARGB32 : PictStandardA8), CPRepeat, &pa); if (!picture) { - XFreePixmap(dpy, pixmap); + XFreePixmap(ps->dpy, pixmap); return None; } @@ -682,25 +501,23 @@ solid_picture(Display *dpy, Bool argb, double a, c.green = g * 0xffff; c.blue = b * 0xffff; - XRenderFillRectangle(dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); - XFreePixmap(dpy, pixmap); + XRenderFillRectangle(ps->dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + XFreePixmap(ps->dpy, pixmap); return picture; } -/** - * Errors - */ +// === Error handling === static void -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; - if (!ignore_head) { - ignore_tail = &ignore_head; +discard_ignore(session_t *ps, unsigned long sequence) { + while (ps->ignore_head) { + if ((long) (sequence - ps->ignore_head->sequence) > 0) { + ignore_t *next = ps->ignore_head->next; + free(ps->ignore_head); + ps->ignore_head = next; + if (!ps->ignore_head) { + ps->ignore_tail = &ps->ignore_head; } } else { break; @@ -709,37 +526,35 @@ discard_ignore(Display *dpy, unsigned long sequence) { } static void -set_ignore(Display *dpy, unsigned long sequence) { - ignore *i = malloc(sizeof(ignore)); +set_ignore(session_t *ps, unsigned long sequence) { + ignore_t *i = malloc(sizeof(ignore_t)); if (!i) return; i->sequence = sequence; i->next = 0; - *ignore_tail = i; - ignore_tail = &i->next; + *ps->ignore_tail = i; + ps->ignore_tail = &i->next; } static int -should_ignore(Display *dpy, unsigned long sequence) { - discard_ignore(dpy, sequence); - return ignore_head && ignore_head->sequence == sequence; +should_ignore(session_t *ps, unsigned long sequence) { + discard_ignore(ps, sequence); + return ps->ignore_head && ps->ignore_head->sequence == sequence; } -/** - * Windows - */ +// === Windows === /** * Check if a window has rounded corners. */ static void -win_rounded_corners(Display *dpy, win *w) { +win_rounded_corners(session_t *ps, win *w) { if (!w->bounding_shaped) return; // Fetch its bounding region if (!w->border_size) - w->border_size = border_size(dpy, w); + w->border_size = border_size(ps, w); // Quit if border_size() returns None if (!w->border_size) @@ -754,7 +569,7 @@ win_rounded_corners(Display *dpy, win *w) { // Get the rectangles in the bounding region int nrects = 0, i; - XRectangle *rects = XFixesFetchRegion(dpy, w->border_size, &nrects); + XRectangle *rects = XFixesFetchRegion(ps->dpy, w->border_size, &nrects); if (!rects) return; @@ -762,12 +577,12 @@ win_rounded_corners(Display *dpy, win *w) { // having rounded corners for (i = 0; i < nrects; ++i) if (rects[i].width >= minwidth && rects[i].height >= minheight) { - w->rounded_corners = True; + w->rounded_corners = true; XFree(rects); return; } - w->rounded_corners = False; + w->rounded_corners = false; XFree(rects); } @@ -777,7 +592,7 @@ win_rounded_corners(Display *dpy, win *w) { * @return true if matched, false otherwise. */ static bool -win_match_once(win *w, const wincond *cond) { +win_match_once(win *w, const wincond_t *cond) { const char *target; bool matched = false; @@ -866,7 +681,7 @@ win_match_once(win *w, const wincond *cond) { * @return true if matched, false otherwise. */ static bool -win_match(win *w, wincond *condlst, wincond **cache) { +win_match(win *w, wincond_t *condlst, wincond_t **cache) { // Check if the cached entry matches firstly if (cache && *cache && win_match_once(w, *cache)) return true; @@ -886,22 +701,22 @@ win_match(win *w, wincond *condlst, wincond **cache) { /** * Add a pattern to a condition linked list. */ -static Bool -condlst_add(wincond **pcondlst, const char *pattern) { +static bool +condlst_add(wincond_t **pcondlst, const char *pattern) { if (!pattern) - return False; + return false; unsigned plen = strlen(pattern); - wincond *cond; + wincond_t *cond; const char *pos; if (plen < 4 || ':' != pattern[1] || !strchr(pattern + 2, ':')) { printf("Pattern \"%s\": Format invalid.\n", pattern); - return False; + return false; } // Allocate memory for the new condition - cond = malloc(sizeof(wincond)); + cond = malloc(sizeof(wincond_t)); // Determine the pattern target switch (pattern[0]) { @@ -918,7 +733,7 @@ condlst_add(wincond **pcondlst, const char *pattern) { printf("Pattern \"%s\": Target \"%c\" invalid.\n", pattern, pattern[0]); free(cond); - return False; + return false; } // Determine the pattern type @@ -944,7 +759,7 @@ condlst_add(wincond **pcondlst, const char *pattern) { printf("Pattern \"%s\": Type \"%c\" invalid.\n", pattern, pattern[2]); free(cond); - return False; + return false; } // Determine the pattern flags @@ -985,7 +800,7 @@ condlst_add(wincond **pcondlst, const char *pattern) { printf("Pattern \"%s\": PCRE regular expression parsing failed on " "offset %d: %s\n", pattern, erroffset, error); free(cond); - return False; + return false; } #ifdef CONFIG_REGEX_PCRE_JIT cond->regex_pcre_extra = pcre_study(cond->regex_pcre, PCRE_STUDY_JIT_COMPILE, &error); @@ -1004,33 +819,39 @@ condlst_add(wincond **pcondlst, const char *pattern) { cond->next = *pcondlst; *pcondlst = cond; - return True; + return true; } +/** + * Determine the event mask for a window. + */ static long -determine_evmask(Display *dpy, Window wid, win_evmode_t mode) { +determine_evmask(session_t *ps, Window wid, win_evmode_t mode) { long evmask = NoEventMask; - if (WIN_EVMODE_FRAME == mode || find_win(wid)) { + if (WIN_EVMODE_FRAME == mode || find_win(ps, wid)) { evmask |= PropertyChangeMask; - if (opts.track_focus && !opts.use_ewmh_active_win) + if (ps->o.track_focus && !ps->o.use_ewmh_active_win) evmask |= FocusChangeMask; } - if (WIN_EVMODE_CLIENT == mode || find_toplevel(wid)) { - if (opts.frame_opacity || opts.track_wdata - || opts.detect_client_opacity) + if (WIN_EVMODE_CLIENT == mode || find_toplevel(ps, wid)) { + if (ps->o.frame_opacity || ps->o.track_wdata + || ps->o.detect_client_opacity) evmask |= PropertyChangeMask; } return evmask; } +/** + * Find a window from window id in window linked list of the session. + */ static win * -find_win(Window id) { +find_win(session_t *ps, Window id) { win *w; - for (w = list; w; w = w->next) { + for (w = ps->list; w; w = w->next) { if (w->id == id && !w->destroyed) return w; } @@ -1045,10 +866,10 @@ find_win(Window id) { * @return struct _win object of the found window, NULL if not found */ static win * -find_toplevel(Window id) { +find_toplevel(session_t *ps, Window id) { win *w; - for (w = list; w; w = w->next) { + for (w = ps->list; w; w = w->next) { if (w->client_win == id && !w->destroyed) return w; } @@ -1059,16 +880,16 @@ find_toplevel(Window id) { /** * Find out the WM frame of a client window by querying X. * - * @param dpy display to use + * @param ps current session * @param w window ID * @return struct _win object of the found window, NULL if not found */ static win * -find_toplevel2(Display *dpy, Window wid) { +find_toplevel2(session_t *ps, Window wid) { win *w = NULL; // We traverse through its ancestors to find out the frame - while (wid && wid != root && !(w = find_win(wid))) { + while (wid && wid != ps->root && !(w = find_win(ps, wid))) { Window troot; Window parent; Window *tchildren; @@ -1077,7 +898,7 @@ find_toplevel2(Display *dpy, Window wid) { // XQueryTree probably fails if you run compton when X is somehow // initializing (like add it in .xinitrc). In this case // just leave it alone. - if (!XQueryTree(dpy, wid, &troot, &parent, &tchildren, + if (!XQueryTree(ps->dpy, wid, &troot, &parent, &tchildren, &tnchildren)) { parent = 0; break; @@ -1093,17 +914,17 @@ find_toplevel2(Display *dpy, Window wid) { /** * Recheck currently focused window and set its <code>w->focused</code> - * to True. + * to true. * - * @param dpy display to use + * @param ps current session * @return struct _win of currently focused window, NULL if not found */ static win * -recheck_focus(Display *dpy) { +recheck_focus(session_t *ps) { // Use EWMH _NET_ACTIVE_WINDOW if enabled - if (opts.use_ewmh_active_win) { - update_ewmh_active_win(dpy); - return active_win; + if (ps->o.use_ewmh_active_win) { + update_ewmh_active_win(ps); + return ps->active_win; } // Determine the currently focused window so we can apply appropriate @@ -1112,16 +933,16 @@ recheck_focus(Display *dpy) { int revert_to; win *w = NULL; - XGetInputFocus(dpy, &wid, &revert_to); + XGetInputFocus(ps->dpy, &wid, &revert_to); // Fallback to the old method if find_toplevel() fails - if (!(w = find_toplevel(wid))) { - w = find_toplevel2(dpy, wid); + if (!(w = find_toplevel(ps, wid))) { + w = find_toplevel2(ps, wid); } // And we set the focus state and opacity here if (w) { - set_focused(dpy, w, True); + set_focused(ps, w, true); return w; } @@ -1129,41 +950,42 @@ recheck_focus(Display *dpy) { } static Picture -root_tile_f(Display *dpy) { +root_tile_f(session_t *ps) { /* - if (opts.paint_on_overlay) { - return root_picture; + if (ps->o.paint_on_overlay) { + return ps->root_picture; } */ Picture picture; Pixmap pixmap; - Bool fill; + bool fill = false; XRenderPictureAttributes pa; int p; pixmap = None; // Get the values of background attributes - for (p = 0; background_props[p]; p++) { - winattr_t attr = wid_get_attr(dpy, root, - XInternAtom(dpy, background_props[p], False), 1L, XA_PIXMAP, 32); - if (attr.nitems) { - pixmap = *((long *) attr.data); - fill = False; - free_winattr(&attr); + for (p = 0; background_props_str[p]; p++) { + winprop_t prop = wid_get_prop(ps, ps->root, + XInternAtom(ps->dpy, background_props_str[p], false), + 1L, XA_PIXMAP, 32); + if (prop.nitems) { + pixmap = *((long *) prop.data); + fill = false; + free_winprop(&prop); break; } - free_winattr(&attr); + free_winprop(&prop); } if (!pixmap) { - pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, scr)); - fill = True; + pixmap = XCreatePixmap(ps->dpy, ps->root, 1, 1, ps->depth); + fill = true; } - pa.repeat = True; + pa.repeat = true; picture = XRenderCreatePicture( - dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + ps->dpy, pixmap, XRenderFindVisualFormat(ps->dpy, ps->vis), CPRepeat, &pa); if (fill) { @@ -1172,29 +994,32 @@ root_tile_f(Display *dpy) { c.red = c.green = c.blue = 0x8080; c.alpha = 0xffff; XRenderFillRectangle( - dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); + ps->dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); } return picture; } +/** + * Paint root window content. + */ static void -paint_root(Display *dpy) { - if (!root_tile) { - root_tile = root_tile_f(dpy); +paint_root(session_t *ps, Picture tgt_buffer) { + if (!ps->root_tile) { + ps->root_tile = root_tile_f(ps); } XRenderComposite( - dpy, PictOpSrc, root_tile, None, + ps->dpy, PictOpSrc, ps->root_tile, None, tgt_buffer, 0, 0, 0, 0, 0, 0, - root_width, root_height); + ps->root_width, ps->root_height); } /** * Get a rectangular region a window occupies, excluding shadow. */ static XserverRegion -win_get_region(Display *dpy, win *w) { +win_get_region(session_t *ps, win *w) { XRectangle r; r.x = w->a.x; @@ -1202,14 +1027,14 @@ win_get_region(Display *dpy, win *w) { r.width = w->widthb; r.height = w->heightb; - return XFixesCreateRegion(dpy, &r, 1); + return XFixesCreateRegion(ps->dpy, &r, 1); } /** * Get a rectangular region a window occupies, excluding frame and shadow. */ static XserverRegion -win_get_region_noframe(Display *dpy, win *w) { +win_get_region_noframe(session_t *ps, win *w) { XRectangle r; r.x = w->a.x + w->a.border_width + w->left_width; @@ -1218,9 +1043,9 @@ win_get_region_noframe(Display *dpy, win *w) { r.height = max_i(w->a.height - w->top_width - w->bottom_width, 0); if (r.width > 0 && r.height > 0) - return XFixesCreateRegion(dpy, &r, 1); + return XFixesCreateRegion(ps->dpy, &r, 1); else - return XFixesCreateRegion(dpy, NULL, 0); + return XFixesCreateRegion(ps->dpy, NULL, 0); } /** @@ -1230,7 +1055,7 @@ win_get_region_noframe(Display *dpy, win *w) { * function. */ static XserverRegion -win_extents(Display *dpy, win *w) { +win_extents(session_t *ps, win *w) { XRectangle r; r.x = w->a.x; @@ -1265,13 +1090,16 @@ win_extents(Display *dpy, win *w) { } } - return XFixesCreateRegion(dpy, &r, 1); + return XFixesCreateRegion(ps->dpy, &r, 1); } +/** + * Retrieve the bounding shape of a window. + */ static XserverRegion -border_size(Display *dpy, win *w) { +border_size(session_t *ps, win *w) { // Start with the window rectangular region - XserverRegion fin = win_get_region(dpy, w); + XserverRegion fin = win_get_region(ps, w); // Only request for a bounding region if the window is shaped if (w->bounding_shaped) { @@ -1284,29 +1112,32 @@ border_size(Display *dpy, win *w) { */ XserverRegion border = XFixesCreateRegionFromWindow( - dpy, w->id, WindowRegionBounding); + ps->dpy, w->id, WindowRegionBounding); if (!border) return fin; // Translate the region to the correct place - XFixesTranslateRegion(dpy, border, + XFixesTranslateRegion(ps->dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); // Intersect the bounding region we got with the window rectangle, to // make sure the bounding region is not bigger than the window // rectangle - XFixesIntersectRegion(dpy, fin, fin, border); - XFixesDestroyRegion(dpy, border); + XFixesIntersectRegion(ps->dpy, fin, fin, border); + XFixesDestroyRegion(ps->dpy, border); } return fin; } +/** + * Look for the client window of a particular window. + */ static Window -find_client_win(Display *dpy, Window w) { - if (wid_has_attr(dpy, w, client_atom)) { +find_client_win(session_t *ps, Window w) { + if (wid_has_attr(ps, w, ps->atom_client)) { return w; } @@ -1315,12 +1146,12 @@ find_client_win(Display *dpy, Window w) { unsigned int i; Window ret = 0; - if (!wid_get_children(dpy, w, &children, &nchildren)) { + if (!wid_get_children(ps, w, &children, &nchildren)) { return 0; } for (i = 0; i < nchildren; ++i) { - if ((ret = find_client_win(dpy, children[i]))) + if ((ret = find_client_win(ps, children[i]))) break; } @@ -1329,60 +1160,70 @@ find_client_win(Display *dpy, Window w) { return ret; } +/** + * Retrieve frame extents from a window. + */ static void -get_frame_extents(Display *dpy, win *w, Window client) { +get_frame_extents(session_t *ps, win *w, Window client) { w->left_width = 0; w->right_width = 0; w->top_width = 0; w->bottom_width = 0; - winattr_t attr = wid_get_attr(dpy, client, frame_extents_atom, + winprop_t prop = wid_get_prop(ps, client, ps->atom_frame_extents, 4L, XA_CARDINAL, 32); - if (4 == attr.nitems) { - long *extents = (long *) attr.data; + if (4 == prop.nitems) { + long *extents = (long *) prop.data; w->left_width = extents[0]; w->right_width = extents[1]; w->top_width = extents[2]; w->bottom_width = extents[3]; - if (opts.frame_opacity) - update_reg_ignore_expire(w); + if (ps->o.frame_opacity) + update_reg_ignore_expire(ps, w); } - free_winattr(&attr); + free_winprop(&prop); } +/** + * Get alpha <code>Picture</code> for an opacity in <code>double</code>. + */ static inline Picture -get_alpha_pict_d(double o) { - assert((lround(normalize_d(o) / opts.alpha_step)) <= lround(1.0 / opts.alpha_step)); - return alpha_picts[lround(normalize_d(o) / opts.alpha_step)]; +get_alpha_pict_d(session_t *ps, double o) { + assert((lround(normalize_d(o) / ps->o.alpha_step)) <= lround(1.0 / ps->o.alpha_step)); + return ps->alpha_picts[lround(normalize_d(o) / ps->o.alpha_step)]; } +/** + * Get alpha <code>Picture</code> for an opacity in + * <code>opacity_t</code>. + */ static inline Picture -get_alpha_pict_o(opacity_t o) { - return get_alpha_pict_d((double) o / OPAQUE); +get_alpha_pict_o(session_t *ps, opacity_t o) { + return get_alpha_pict_d(ps, (double) o / OPAQUE); } static win * -paint_preprocess(Display *dpy, win *list) { +paint_preprocess(session_t *ps, win *list) { // Initialize unredir_possible - unredir_possible = False; + ps->unredir_possible = false; win *w; win *t = NULL, *next = NULL; // Trace whether it's the highest window to paint - Bool is_highest = True; + bool is_highest = true; // Fading step calculation - unsigned steps = (sub_unslong(get_time_ms(), fade_time) - + FADE_DELTA_TOLERANCE * opts.fade_delta) / opts.fade_delta; - fade_time += steps * opts.fade_delta; + unsigned steps = (sub_unslong(get_time_ms(), ps->fade_time) + + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta; + ps->fade_time += steps * ps->o.fade_delta; XserverRegion last_reg_ignore = None; for (w = list; w; w = next) { - Bool to_paint = True; + bool to_paint = true; const winmode mode_old = w->mode; // In case calling the fade callback function destroys this window @@ -1390,123 +1231,123 @@ paint_preprocess(Display *dpy, win *list) { opacity_t opacity_old = w->opacity; // Destroy reg_ignore on all windows if they should expire - if (reg_ignore_expire) - free_region(dpy, &w->reg_ignore); + if (ps->reg_ignore_expire) + free_region(ps, &w->reg_ignore); // Run fading - run_fade(dpy, w, steps); + run_fade(ps, w, steps); // Give up if it's not damaged or invisible, or it's unmapped and its // picture is gone (for example due to a ConfigureNotify) if (!w->damaged || w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 - || w->a.x >= root_width || w->a.y >= root_height - || (IsUnmapped == w->a.map_state && !w->picture)) { - to_paint = False; + || w->a.x >= ps->root_width || w->a.y >= ps->root_height + || ((IsUnmapped == w->a.map_state || w->destroyed) + && !w->picture)) { + to_paint = false; } if (to_paint) { // If opacity changes if (w->opacity != opacity_old) { - determine_mode(dpy, w); - add_damage_win(dpy, w); + determine_mode(ps, w); + add_damage_win(ps, w); } - w->alpha_pict = get_alpha_pict_o(w->opacity); + w->alpha_pict = get_alpha_pict_o(ps, w->opacity); // End the game if we are using the 0 opacity alpha_pict - if (w->alpha_pict == alpha_picts[0]) { - to_paint = False; + if (w->alpha_pict == ps->alpha_picts[0]) { + to_paint = false; } } if (to_paint) { // Fetch bounding region if (!w->border_size) { - w->border_size = border_size(dpy, w); + w->border_size = border_size(ps, w); } // Fetch window extents if (!w->extents) { - w->extents = win_extents(dpy, w); + w->extents = win_extents(ps, w); // 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); + add_damage_win(ps, w); } // Calculate frame_opacity { double frame_opacity_old = w->frame_opacity; - if (opts.frame_opacity && 1.0 != opts.frame_opacity + if (ps->o.frame_opacity && 1.0 != ps->o.frame_opacity && win_has_frame(w)) - w->frame_opacity = get_opacity_percent(dpy, w) * - opts.frame_opacity; + w->frame_opacity = get_opacity_percent(w) * + ps->o.frame_opacity; else w->frame_opacity = 0.0; if (w->to_paint && WINDOW_SOLID == mode_old && (0.0 == frame_opacity_old) != (0.0 == w->frame_opacity)) - reg_ignore_expire = True; + ps->reg_ignore_expire = true; } - w->frame_alpha_pict = get_alpha_pict_d(w->frame_opacity); + w->frame_alpha_pict = get_alpha_pict_d(ps, w->frame_opacity); // Calculate shadow opacity if (w->frame_opacity) - w->shadow_opacity = opts.shadow_opacity * w->frame_opacity; + w->shadow_opacity = ps->o.shadow_opacity * w->frame_opacity; else - w->shadow_opacity = opts.shadow_opacity * get_opacity_percent(dpy, w); + w->shadow_opacity = ps->o.shadow_opacity * get_opacity_percent(w); // Rebuild shadow_pict if necessary if (w->flags & WFLAG_SIZE_CHANGE) - free_picture(dpy, &w->shadow_pict); + free_picture(ps, &w->shadow_pict); if (w->shadow && !w->shadow_pict) { - w->shadow_pict = shadow_picture(dpy, 1, - w->widthb, w->heightb, False); + w->shadow_pict = shadow_picture(ps, 1, w->widthb, w->heightb); } - w->shadow_alpha_pict = get_alpha_pict_d(w->shadow_opacity); + w->shadow_alpha_pict = get_alpha_pict_d(ps, w->shadow_opacity); } if ((to_paint && WINDOW_SOLID == w->mode) != (w->to_paint && WINDOW_SOLID == mode_old)) - reg_ignore_expire = True; + ps->reg_ignore_expire = true; // Add window to damaged area if its painting status changes if (to_paint != w->to_paint) - add_damage_win(dpy, w); + add_damage_win(ps, w); if (to_paint) { // Generate ignore region for painting to reduce GPU load - if (reg_ignore_expire || !w->to_paint) { - free_region(dpy, &w->reg_ignore); + if (ps->reg_ignore_expire || !w->to_paint) { + free_region(ps, &w->reg_ignore); // If the window is solid, we add the window region to the // ignored region if (WINDOW_SOLID == w->mode) { if (!w->frame_opacity) { if (w->border_size) - w->reg_ignore = copy_region(dpy, w->border_size); + w->reg_ignore = copy_region(ps, w->border_size); else - w->reg_ignore = win_get_region(dpy, w); + w->reg_ignore = win_get_region(ps, w); } else { - w->reg_ignore = win_get_region_noframe(dpy, w); + w->reg_ignore = win_get_region_noframe(ps, w); if (w->border_size) - XFixesIntersectRegion(dpy, w->reg_ignore, w->reg_ignore, + XFixesIntersectRegion(ps->dpy, w->reg_ignore, w->reg_ignore, w->border_size); } if (last_reg_ignore) - XFixesUnionRegion(dpy, w->reg_ignore, w->reg_ignore, + XFixesUnionRegion(ps->dpy, w->reg_ignore, w->reg_ignore, last_reg_ignore); } // Otherwise we copy the last region over else if (last_reg_ignore) - w->reg_ignore = copy_region(dpy, last_reg_ignore); + w->reg_ignore = copy_region(ps, last_reg_ignore); else w->reg_ignore = None; } @@ -1514,11 +1355,11 @@ paint_preprocess(Display *dpy, win *list) { last_reg_ignore = w->reg_ignore; if (is_highest && to_paint) { - is_highest = False; + is_highest = false; if (WINDOW_SOLID == w->mode && (!w->frame_opacity || !win_has_frame(w)) - && win_is_fullscreen(w)) - unredir_possible = True; + && win_is_fullscreen(ps, w)) + ps->unredir_possible = true; } // Reset flags @@ -1534,7 +1375,7 @@ paint_preprocess(Display *dpy, win *list) { t = w; } else { - check_fade_fin(dpy, w); + check_fade_fin(ps, w); } if (!destroyed) @@ -1542,15 +1383,15 @@ paint_preprocess(Display *dpy, win *list) { } // If possible, unredirect all windows and stop painting - if (opts.unredir_if_possible && unredir_possible) { - redir_stop(dpy); + if (ps->o.unredir_if_possible && ps->unredir_possible) { + redir_stop(ps); } else { - redir_start(dpy); + redir_start(ps); } // Fetch pictures only if windows are redirected - if (redirected) { + if (ps->redirected) { for (w = t; w; w = w->prev_trans) { // Fetch the picture and pixmap if needed if (!w->picture) { @@ -1558,16 +1399,16 @@ paint_preprocess(Display *dpy, win *list) { XRenderPictFormat *format; Drawable draw = w->id; - if (has_name_pixmap && !w->pixmap) { - set_ignore(dpy, NextRequest(dpy)); - w->pixmap = XCompositeNameWindowPixmap(dpy, w->id); + if (ps->has_name_pixmap && !w->pixmap) { + set_ignore_next(ps); + w->pixmap = XCompositeNameWindowPixmap(ps->dpy, w->id); } if (w->pixmap) draw = w->pixmap; - format = XRenderFindVisualFormat(dpy, w->a.visual); + format = XRenderFindVisualFormat(ps->dpy, w->a.visual); pa.subwindow_mode = IncludeInferiors; w->picture = XRenderCreatePicture( - dpy, draw, format, CPSubwindowMode, &pa); + ps->dpy, draw, format, CPSubwindowMode, &pa); } } } @@ -1579,9 +1420,9 @@ paint_preprocess(Display *dpy, win *list) { * Paint the shadow of a window. */ static inline void -win_paint_shadow(Display *dpy, win *w, Picture tgt_buffer) { +win_paint_shadow(session_t *ps, win *w, Picture tgt_buffer) { XRenderComposite( - dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, + ps->dpy, PictOpOver, w->shadow_pict, w->shadow_alpha_pict, tgt_buffer, 0, 0, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy, w->shadow_width, w->shadow_height); @@ -1591,7 +1432,7 @@ win_paint_shadow(Display *dpy, win *w, Picture tgt_buffer) { * Paint a window itself and dim it if asked. */ static inline void -win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { +win_paint_win(session_t *ps, win *w, Picture tgt_buffer) { int x = w->a.x; int y = w->a.y; int wid = w->widthb; @@ -1601,7 +1442,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { int op = (w->mode == WINDOW_SOLID ? PictOpSrc: PictOpOver); if (!w->frame_opacity) { - XRenderComposite(dpy, op, w->picture, alpha_mask, + XRenderComposite(ps->dpy, op, w->picture, alpha_mask, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); } else { @@ -1611,7 +1452,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { int r = w->right_width; #define COMP_BDR(cx, cy, cwid, chei) \ - XRenderComposite(dpy, PictOpOver, w->picture, w->frame_alpha_pict, \ + XRenderComposite(ps->dpy, PictOpOver, w->picture, w->frame_alpha_pict, \ tgt_buffer, (cx), (cy), 0, 0, x + (cx), y + (cy), (cwid), (chei)) // The following complicated logic is required because some broken @@ -1647,7 +1488,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { pwid = wid - l - pwid; if (pwid > 0) { // body - XRenderComposite(dpy, op, w->picture, alpha_mask, + XRenderComposite(ps->dpy, op, w->picture, alpha_mask, tgt_buffer, l, t, 0, 0, x + l, y + t, pwid, phei); } } @@ -1659,7 +1500,7 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { // Dimming the window if needed if (w->dim) { - XRenderComposite(dpy, PictOpOver, dim_picture, None, + XRenderComposite(ps->dpy, PictOpOver, ps->dim_picture, None, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); } } @@ -1668,14 +1509,14 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) { * Rebuild cached <code>screen_reg</code>. */ static void -rebuild_screen_reg(Display *dpy) { - if (screen_reg) - XFixesDestroyRegion(dpy, screen_reg); - screen_reg = get_screen_region(dpy); +rebuild_screen_reg(session_t *ps) { + if (ps->screen_reg) + XFixesDestroyRegion(ps->dpy, ps->screen_reg); + ps->screen_reg = get_screen_region(ps); } static void -paint_all(Display *dpy, XserverRegion region, win *t) { +paint_all(session_t *ps, XserverRegion region, win *t) { #ifdef DEBUG_REPAINT static struct timespec last_paint = { 0 }; #endif @@ -1684,67 +1525,67 @@ paint_all(Display *dpy, XserverRegion region, win *t) { XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None; if (!region) { - region = get_screen_region(dpy); + region = get_screen_region(ps); } else { // Remove the damaged area out of screen - XFixesIntersectRegion(dpy, region, region, screen_reg); + XFixesIntersectRegion(ps->dpy, region, region, ps->screen_reg); } #ifdef MONITOR_REPAINT // Note: MONITOR_REPAINT cannot work with DBE right now. - tgt_buffer = tgt_picture; + ps->tgt_buffer = ps->tgt_picture; #else - if (!tgt_buffer) { + if (!ps->tgt_buffer) { // DBE painting mode: Directly paint to a Picture of the back buffer - if (opts.dbe) { - tgt_buffer = XRenderCreatePicture(dpy, root_dbe, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + if (ps->o.dbe) { + ps->tgt_buffer = XRenderCreatePicture(ps->dpy, ps->root_dbe, + XRenderFindVisualFormat(ps->dpy, ps->vis), 0, 0); } // No-DBE painting mode: Paint to an intermediate Picture then paint // the Picture to root window else { Pixmap root_pixmap = XCreatePixmap( - dpy, root, root_width, root_height, - DefaultDepth(dpy, scr)); + ps->dpy, ps->root, ps->root_width, ps->root_height, + ps->depth); - tgt_buffer = XRenderCreatePicture(dpy, root_pixmap, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + ps->tgt_buffer = XRenderCreatePicture(ps->dpy, root_pixmap, + XRenderFindVisualFormat(ps->dpy, ps->vis), 0, 0); - XFreePixmap(dpy, root_pixmap); + XFreePixmap(ps->dpy, root_pixmap); } } #endif - XFixesSetPictureClipRegion(dpy, tgt_picture, 0, 0, region); + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_picture, 0, 0, region); #ifdef MONITOR_REPAINT XRenderComposite( - dpy, PictOpSrc, black_picture, None, - tgt_picture, 0, 0, 0, 0, 0, 0, - root_width, root_height); + ps->dpy, PictOpSrc, ps->black_picture, None, + ps->tgt_picture, 0, 0, 0, 0, 0, 0, + ps->root_width, ps->root_height); #endif if (t && t->reg_ignore) { // Calculate the region upon which the root window is to be painted // based on the ignore region of the lowest window, if available - reg_paint = reg_tmp = XFixesCreateRegion(dpy, NULL, 0); - XFixesSubtractRegion(dpy, reg_paint, region, t->reg_ignore); + reg_paint = reg_tmp = XFixesCreateRegion(ps->dpy, NULL, 0); + XFixesSubtractRegion(ps->dpy, reg_paint, region, t->reg_ignore); } else { reg_paint = region; } - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint); + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); - paint_root(dpy); + paint_root(ps, ps->tgt_buffer); // Create temporary regions for use during painting if (!reg_tmp) - reg_tmp = XFixesCreateRegion(dpy, NULL, 0); - reg_tmp2 = XFixesCreateRegion(dpy, NULL, 0); + reg_tmp = XFixesCreateRegion(ps->dpy, NULL, 0); + reg_tmp2 = XFixesCreateRegion(ps->dpy, NULL, 0); for (w = t; w; w = w->prev_trans) { // Painting shadow @@ -1756,28 +1597,28 @@ paint_all(Display *dpy, XserverRegion region, win *t) { // If it's the first cycle and reg_tmp2 is not ready, calculate // the paint region here reg_paint = reg_tmp; - XFixesSubtractRegion(dpy, reg_paint, region, w->reg_ignore); + XFixesSubtractRegion(ps->dpy, reg_paint, region, w->reg_ignore); } else { // Otherwise, used the cached region during last cycle reg_paint = reg_tmp2; } - XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->extents); + XFixesIntersectRegion(ps->dpy, reg_paint, reg_paint, w->extents); } else { reg_paint = reg_tmp; - XFixesIntersectRegion(dpy, reg_paint, region, w->extents); + XFixesIntersectRegion(ps->dpy, reg_paint, region, w->extents); } // Clear the shadow here instead of in make_shadow() for saving GPU // power and handling shaped windows - if (opts.clear_shadow && w->border_size) - XFixesSubtractRegion(dpy, reg_paint, reg_paint, w->border_size); + if (ps->o.clear_shadow && w->border_size) + XFixesSubtractRegion(ps->dpy, reg_paint, reg_paint, w->border_size); // Detect if the region is empty before painting - if (region == reg_paint || !is_region_empty(dpy, reg_paint)) { - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint); + if (region == reg_paint || !is_region_empty(ps, reg_paint)) { + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); - win_paint_shadow(dpy, w, tgt_buffer); + win_paint_shadow(ps, w, ps->tgt_buffer); } } @@ -1785,77 +1626,77 @@ paint_all(Display *dpy, XserverRegion region, win *t) { // window and the bounding region reg_paint = reg_tmp; if (w->prev_trans && w->prev_trans->reg_ignore) { - XFixesSubtractRegion(dpy, reg_paint, region, + XFixesSubtractRegion(ps->dpy, reg_paint, region, w->prev_trans->reg_ignore); // Copy the subtracted region to be used for shadow painting in next // cycle - XFixesCopyRegion(dpy, reg_tmp2, reg_paint); + XFixesCopyRegion(ps->dpy, reg_tmp2, reg_paint); if (w->border_size) - XFixesIntersectRegion(dpy, reg_paint, reg_paint, w->border_size); + XFixesIntersectRegion(ps->dpy, reg_paint, reg_paint, w->border_size); } else { if (w->border_size) - XFixesIntersectRegion(dpy, reg_paint, region, w->border_size); + XFixesIntersectRegion(ps->dpy, reg_paint, region, w->border_size); else reg_paint = region; } - if (!is_region_empty(dpy, reg_paint)) { - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, reg_paint); + if (!is_region_empty(ps, reg_paint)) { + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); // Painting the window - win_paint_win(dpy, w, tgt_buffer); + win_paint_win(ps, w, ps->tgt_buffer); } - check_fade_fin(dpy, w); + check_fade_fin(ps, w); } // Free up all temporary regions - XFixesDestroyRegion(dpy, region); - XFixesDestroyRegion(dpy, reg_tmp); - XFixesDestroyRegion(dpy, reg_tmp2); + XFixesDestroyRegion(ps->dpy, region); + XFixesDestroyRegion(ps->dpy, reg_tmp); + XFixesDestroyRegion(ps->dpy, reg_tmp2); // Do this as early as possible - if (!opts.dbe) - XFixesSetPictureClipRegion(dpy, tgt_buffer, 0, 0, None); + if (!ps->o.dbe) + XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, None); - if (VSYNC_NONE != opts.vsync) { + if (VSYNC_NONE != ps->o.vsync) { // Make sure all previous requests are processed to achieve best // effect - XSync(dpy, False); + XSync(ps->dpy, False); } // Wait for VBlank. We could do it aggressively (send the painting // request and XFlush() on VBlank) or conservatively (send the request // only on VBlank). - if (!opts.vsync_aggressive) - vsync_wait(); + if (!ps->o.vsync_aggressive) + vsync_wait(ps); // DBE painting mode, only need to swap the buffer - if (opts.dbe) { + if (ps->o.dbe) { XdbeSwapInfo swap_info = { - .swap_window = (opts.paint_on_overlay ? overlay: root), + .swap_window = (ps->o.paint_on_overlay ? ps->overlay: ps->root), // Is it safe to use XdbeUndefined? .swap_action = XdbeCopied }; - XdbeSwapBuffers(dpy, &swap_info, 1); + XdbeSwapBuffers(ps->dpy, &swap_info, 1); } // No-DBE painting mode - else if (tgt_buffer != tgt_picture) { + else if (ps->tgt_buffer != ps->tgt_picture) { XRenderComposite( - dpy, PictOpSrc, tgt_buffer, None, - tgt_picture, 0, 0, 0, 0, - 0, 0, root_width, root_height); + ps->dpy, PictOpSrc, ps->tgt_buffer, None, + ps->tgt_picture, 0, 0, 0, 0, + 0, 0, ps->root_width, ps->root_height); } - if (opts.vsync_aggressive) - vsync_wait(); + if (ps->o.vsync_aggressive) + vsync_wait(ps); - XFlush(dpy); + XFlush(ps->dpy); #ifdef DEBUG_REPAINT - print_timestamp(); + print_timestamp(ps); struct timespec now = get_time_timespec(); struct timespec diff = { 0 }; timespec_subtract(&diff, &now, &last_paint); @@ -1870,91 +1711,78 @@ paint_all(Display *dpy, XserverRegion region, win *t) { } static void -add_damage(Display *dpy, XserverRegion damage) { - if (all_damage) { - XFixesUnionRegion(dpy, all_damage, all_damage, damage); - XFixesDestroyRegion(dpy, damage); +add_damage(session_t *ps, XserverRegion damage) { + if (ps->all_damage) { + XFixesUnionRegion(ps->dpy, ps->all_damage, ps->all_damage, damage); + XFixesDestroyRegion(ps->dpy, damage); } else { - all_damage = damage; + ps->all_damage = damage; } } static void -repair_win(Display *dpy, win *w) { +repair_win(session_t *ps, win *w) { XserverRegion parts; if (!w->damaged) { - parts = win_extents(dpy, w); - set_ignore(dpy, NextRequest(dpy)); - XDamageSubtract(dpy, w->damage, None, None); + parts = win_extents(ps, w); + set_ignore_next(ps); + XDamageSubtract(ps->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, + parts = XFixesCreateRegion(ps->dpy, 0, 0); + set_ignore_next(ps); + XDamageSubtract(ps->dpy, w->damage, None, parts); + XFixesTranslateRegion(ps->dpy, parts, w->a.x + w->a.border_width, w->a.y + w->a.border_width); } // Remove the part in the damage area that could be ignored - if (!reg_ignore_expire && w->prev_trans && w->prev_trans->reg_ignore) - XFixesSubtractRegion(dpy, parts, parts, w->prev_trans->reg_ignore); + if (!ps->reg_ignore_expire && w->prev_trans && w->prev_trans->reg_ignore) + XFixesSubtractRegion(ps->dpy, parts, parts, w->prev_trans->reg_ignore); - add_damage(dpy, parts); + add_damage(ps, parts); w->damaged = 1; } -static wintype -get_wintype_prop(Display *dpy, Window wid) { - Atom actual; - int format; - unsigned long n = 0, left, i; - long *data = NULL; - int j; - - 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; - } - - for (i = 0; i < n; ++i) { +static wintype_t +wid_get_prop_wintype(session_t *ps, Window wid) { + int i, j; + + set_ignore_next(ps); + winprop_t prop = wid_get_prop(ps, wid, ps->atom_win_type, 32L, XA_ATOM, 32); + + for (i = 0; i < prop.nitems; ++i) { for (j = 1; j < NUM_WINTYPES; ++j) { - if (win_type[j] == (Atom) data[i]) { - XFree(data); + if (ps->atoms_wintypes[j] == (Atom) ((long *) prop.data)[i]) { + free_winprop(&prop); return j; } } } - XFree(data); + free_winprop(&prop); return WINTYPE_UNKNOWN; } static void -map_win(Display *dpy, Window id, - unsigned long sequence, Bool fade, - Bool override_redirect) { - win *w = find_win(id); +map_win(session_t *ps, Window id, bool override_redirect) { + win *w = find_win(ps, id); // Don't care about window mapping if it's an InputOnly window if (!w || InputOnly == w->a.class) return; - w->focused = False; + w->focused = false; w->a.map_state = IsViewable; // Call XSelectInput() before reading properties so that no property // changes are lost - XSelectInput(dpy, id, determine_evmask(dpy, id, WIN_EVMODE_FRAME)); + XSelectInput(ps->dpy, id, determine_evmask(ps, id, WIN_EVMODE_FRAME)); // Notify compton when the shape of a window changes - if (shape_exists) { - XShapeSelectInput(dpy, id, ShapeNotifyMask); + if (ps->shape_exists) { + XShapeSelectInput(ps->dpy, id, ShapeNotifyMask); } // Detect client window here instead of in add_win() as the client @@ -1963,7 +1791,7 @@ map_win(Display *dpy, Window id, Window cw = 0; // Always recursively look for a window with WM_STATE, as Fluxbox // sets override-redirect flags on all frame windows. - cw = find_client_win(dpy, w->id); + cw = find_client_win(ps, w->id); #ifdef DEBUG_CLIENTWIN printf("find_client_win(%#010lx): client %#010lx\n", w->id, cw); #endif @@ -1976,18 +1804,18 @@ map_win(Display *dpy, Window id, #endif } if (cw) { - mark_client_win(dpy, w, cw); + mark_client_win(ps, w, cw); } } else { // Re-mark client window here - mark_client_win(dpy, w, w->client_win); + mark_client_win(ps, w, w->client_win); } // Workaround for _NET_WM_WINDOW_TYPE for Openbox menus, which is // set on a non-override-redirect window with no WM_STATE either if (!w->client_win && WINTYPE_UNKNOWN == w->window_type) - w->window_type = get_wintype_prop(dpy, w->id); + w->window_type = wid_get_prop_wintype(ps, w->id); #ifdef DEBUG_WINTYPE printf("map_win(%#010lx): type %s\n", @@ -1995,54 +1823,54 @@ map_win(Display *dpy, Window id, #endif // Detect if the window is shaped or has rounded corners - win_update_shape_raw(dpy, w); + win_update_shape_raw(ps, w); // Get window name and class if we are tracking them - if (opts.track_wdata) { - win_get_name(dpy, w); - win_get_class(dpy, w); + if (ps->o.track_wdata) { + win_get_name(ps, w); + win_get_class(ps, w); } - if (opts.track_focus) { + if (ps->o.track_focus) { // 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 // XSelectInput() is called too late. We have to recheck the focused // window here. It makes no sense if we are using EWMH // _NET_ACTIVE_WINDOW. - if (!opts.use_ewmh_active_win) - recheck_focus(dpy); + if (!ps->o.use_ewmh_active_win) + recheck_focus(ps); // Consider a window without client window a WM window and mark it // 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->id == w->client_win)) - w->focused = True; + if ((ps->o.mark_wmwin_focused && !w->client_win) + || (ps->o.mark_ovredir_focused && w->id == w->client_win)) + w->focused = true; } // Check for _COMPTON_SHADOW - if (opts.respect_attr_shadow) - win_update_attr_shadow_raw(dpy, w); + if (ps->o.respect_prop_shadow) + win_update_attr_shadow_raw(ps, w); // Many things above could affect shadow - determine_shadow(dpy, w); + determine_shadow(ps, w); // Fading in - calc_opacity(dpy, w, True); + calc_opacity(ps, w, true); // Set fading state - if (opts.no_fading_openclose) { - set_fade_callback(dpy, w, finish_map_win, True); + if (ps->o.no_fading_openclose) { + set_fade_callback(ps, 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; + w->fade = false; } else { - set_fade_callback(dpy, w, NULL, True); - determine_fade(dpy, w); + set_fade_callback(ps, w, NULL, true); + determine_fade(ps, w); } - calc_dim(dpy, w); + calc_dim(ps, w); w->damaged = 1; @@ -2051,42 +1879,42 @@ map_win(Display *dpy, Window id, the window was unmapped, then configure the window to its correct place */ if (w->need_configure) { - configure_win(dpy, &w->queue_configure); + configure_win(ps, &w->queue_configure); } } static void -finish_map_win(Display *dpy, win *w) { - if (opts.no_fading_openclose) - determine_fade(dpy, w); +finish_map_win(session_t *ps, win *w) { + if (ps->o.no_fading_openclose) + determine_fade(ps, w); } static void -finish_unmap_win(Display *dpy, win *w) { +finish_unmap_win(session_t *ps, win *w) { w->damaged = 0; - update_reg_ignore_expire(w); + update_reg_ignore_expire(ps, w); if (w->extents != None) { /* destroys region */ - add_damage(dpy, w->extents); + add_damage(ps, w->extents); w->extents = None; } - free_pixmap(dpy, &w->pixmap); - free_picture(dpy, &w->picture); - free_region(dpy, &w->border_size); - free_picture(dpy, &w->shadow_pict); + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); + free_region(ps, &w->border_size); + free_picture(ps, &w->shadow_pict); } static void -unmap_callback(Display *dpy, win *w) { - finish_unmap_win(dpy, w); +unmap_callback(session_t *ps, win *w) { + finish_unmap_win(ps, w); } static void -unmap_win(Display *dpy, Window id, Bool fade) { - win *w = find_win(id); +unmap_win(session_t *ps, Window id) { + win *w = find_win(ps, id); if (!w || IsUnmapped == w->a.map_state) return; @@ -2094,48 +1922,36 @@ unmap_win(Display *dpy, Window id, Bool fade) { // Fading out w->opacity_tgt = 0; - set_fade_callback(dpy, w, unmap_callback, False); - if (opts.no_fading_openclose) - w->fade = False; + set_fade_callback(ps, w, unmap_callback, false); + if (ps->o.no_fading_openclose) + w->fade = false; // don't care about properties anymore - // Will get BadWindow if the window is destroyed - set_ignore(dpy, NextRequest(dpy)); - XSelectInput(dpy, w->id, 0); - - if (w->client_win) { - set_ignore(dpy, NextRequest(dpy)); - XSelectInput(dpy, w->client_win, 0); - } + win_ev_stop(ps, w); } static opacity_t -wid_get_opacity_prop(Display *dpy, Window wid, opacity_t def) { - Atom actual; - int format; - unsigned long n, left; +wid_get_opacity_prop(session_t *ps, Window wid, opacity_t def) { + opacity_t val = def; - unsigned char *data; - int result = XGetWindowProperty( - dpy, wid, opacity_atom, 0L, 1L, False, - XA_CARDINAL, &actual, &format, &n, &left, &data); + winprop_t prop = wid_get_prop(ps, wid, ps->atom_opacity, 1L, + XA_CARDINAL, 32); - if (result == Success && data != NULL) { - opacity_t i = *((opacity_t *) data); - XFree(data); - return i; - } + if (prop.nitems) + val = *((long *) prop.data); + + free_winprop(&prop); - return def; + return val; } static double -get_opacity_percent(Display *dpy, win *w) { +get_opacity_percent(win *w) { return ((double) w->opacity) / OPAQUE; } static void -determine_mode(Display *dpy, win *w) { +determine_mode(session_t *ps, win *w) { winmode mode; XRenderPictFormat *format; @@ -2144,7 +1960,7 @@ determine_mode(Display *dpy, win *w) { if (w->a.class == InputOnly) { format = 0; } else { - format = XRenderFindVisualFormat(dpy, w->a.visual); + format = XRenderFindVisualFormat(ps->dpy, w->a.visual); } if (format && format->type == PictTypeDirect @@ -2180,7 +1996,7 @@ determine_mode(Display *dpy, win *w) { * refetched */ static void -calc_opacity(Display *dpy, win *w, Bool refetch_prop) { +calc_opacity(session_t *ps, win *w, bool refetch_prop) { opacity_t opacity; // Do nothing for unmapped window, calc_opacity() will be called @@ -2191,42 +2007,45 @@ calc_opacity(Display *dpy, win *w, Bool refetch_prop) { // Do not refetch the opacity window attribute unless necessary, this // is probably an expensive operation in some cases if (refetch_prop) { - w->opacity_prop = wid_get_opacity_prop(dpy, w->id, OPAQUE); - if (!opts.detect_client_opacity || !w->client_win + w->opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE); + if (!ps->o.detect_client_opacity || !w->client_win || w->id == w->client_win) w->opacity_prop_client = OPAQUE; else - w->opacity_prop_client = wid_get_opacity_prop(dpy, w->client_win, + w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win, OPAQUE); } if (OPAQUE == (opacity = w->opacity_prop) && OPAQUE == (opacity = w->opacity_prop_client)) { - opacity = opts.wintype_opacity[w->window_type] * OPAQUE; + opacity = ps->o.wintype_opacity[w->window_type] * OPAQUE; } // 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; + if (ps->o.inactive_opacity && is_normal_win(w) && false == w->focused + && (OPAQUE == opacity || ps->o.inactive_opacity_override)) { + opacity = ps->o.inactive_opacity; } w->opacity_tgt = opacity; } +/** + * Determine whether a window is to be dimmed. + */ static void -calc_dim(Display *dpy, win *w) { - Bool dim; +calc_dim(session_t *ps, win *w) { + bool dim; - if (opts.inactive_dim && is_normal_win(w) && !(w->focused)) { - dim = True; + if (ps->o.inactive_dim && is_normal_win(w) && !(w->focused)) { + dim = true; } else { - dim = False; + dim = false; } if (dim != w->dim) { w->dim = dim; - add_damage_win(dpy, w); + add_damage_win(ps, w); } } @@ -2234,19 +2053,19 @@ calc_dim(Display *dpy, win *w) { * Determine if a window should fade on opacity change. */ static void -determine_fade(Display *dpy, win *w) { - w->fade = opts.wintype_fade[w->window_type]; +determine_fade(session_t *ps, win *w) { + w->fade = ps->o.wintype_fade[w->window_type]; } /** * Update window-shape. */ static void -win_update_shape_raw(Display *dpy, win *w) { - if (shape_exists) { - w->bounding_shaped = wid_bounding_shaped(dpy, w->id); - if (w->bounding_shaped && opts.detect_rounded_corners) - win_rounded_corners(dpy, w); +win_update_shape_raw(session_t *ps, win *w) { + if (ps->shape_exists) { + w->bounding_shaped = wid_bounding_shaped(ps, w->id); + if (w->bounding_shaped && ps->o.detect_rounded_corners) + win_rounded_corners(ps, w); } } @@ -2254,20 +2073,20 @@ win_update_shape_raw(Display *dpy, win *w) { * Update window-shape related information. */ static void -win_update_shape(Display *dpy, win *w) { - if (shape_exists) { - // Bool bounding_shaped_old = w->bounding_shaped; +win_update_shape(session_t *ps, win *w) { + if (ps->shape_exists) { + // bool bounding_shaped_old = w->bounding_shaped; - win_update_shape_raw(dpy, w); + win_update_shape_raw(ps, w); // Shadow state could be changed - determine_shadow(dpy, w); + determine_shadow(ps, w); /* // If clear_shadow state on the window possibly changed, destroy the old // shadow_pict - if (opts.clear_shadow && w->bounding_shaped != bounding_shaped_old) - free_picture(dpy, &w->shadow_pict); + if (ps->o.clear_shadow && w->bounding_shaped != bounding_shaped_old) + free_picture(ps, &w->shadow_pict); */ } } @@ -2278,18 +2097,18 @@ win_update_shape(Display *dpy, win *w) { * The property must be set on the outermost window, usually the WM frame. */ static void -win_update_attr_shadow_raw(Display *dpy, win *w) { - winattr_t attr = wid_get_attr(dpy, w->id, compton_shadow_atom, 1, +win_update_attr_shadow_raw(session_t *ps, win *w) { + winprop_t prop = wid_get_prop(ps, w->id, ps->atom_compton_shadow, 1, XA_CARDINAL, 32); - - if (!attr.nitems) { - free_winattr(&attr); - w->attr_shadow = -1; - return; + if (!prop.nitems) { + w->attr_shadow = -1; + } + else { + w->attr_shadow = *((long *) prop.data); } - w->attr_shadow = *((long *) attr.data); + free_winprop(&prop); } /** @@ -2297,13 +2116,13 @@ win_update_attr_shadow_raw(Display *dpy, win *w) { * things. */ static void -win_update_attr_shadow(Display *dpy, win *w) { +win_update_attr_shadow(session_t *ps, win *w) { long attr_shadow_old = w->attr_shadow; - win_update_attr_shadow_raw(dpy, w); + win_update_attr_shadow_raw(ps, w); if (w->attr_shadow != attr_shadow_old) - determine_shadow(dpy, w); + determine_shadow(ps, w); } /** @@ -2311,29 +2130,29 @@ win_update_attr_shadow(Display *dpy, win *w) { * on shadow state. */ static void -determine_shadow(Display *dpy, win *w) { - Bool shadow_old = w->shadow; +determine_shadow(session_t *ps, win *w) { + bool shadow_old = w->shadow; - w->shadow = (opts.wintype_shadow[w->window_type] - && !win_match(w, opts.shadow_blacklist, &w->cache_sblst) - && !(opts.shadow_ignore_shaped && w->bounding_shaped + w->shadow = (ps->o.wintype_shadow[w->window_type] + && !win_match(w, ps->o.shadow_blacklist, &w->cache_sblst) + && !(ps->o.shadow_ignore_shaped && w->bounding_shaped && !w->rounded_corners) - && !(opts.respect_attr_shadow && 0 == w->attr_shadow)); + && !(ps->o.respect_prop_shadow && 0 == w->attr_shadow)); // 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); + // calc_shadow_geometry(ps, w); if (w->extents) { // Mark the old extents as damaged if the shadow is removed if (!w->shadow) - add_damage(dpy, w->extents); + add_damage(ps, w->extents); else - free_region(dpy, &w->extents); - w->extents = win_extents(dpy, w); + free_region(ps, &w->extents); + w->extents = win_extents(ps, w); // Mark the new extents as damaged if the shadow is added if (w->shadow) - add_damage_win(dpy, w); + add_damage_win(ps, w); } } } @@ -2343,10 +2162,10 @@ determine_shadow(Display *dpy, win *w) { */ static void -calc_win_size(Display *dpy, win *w) { +calc_win_size(session_t *ps, 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); + calc_shadow_geometry(ps, w); w->flags |= WFLAG_SIZE_CHANGE; } @@ -2354,11 +2173,11 @@ calc_win_size(Display *dpy, win *w) { * Calculate and update geometry of the shadow of a window. */ static void -calc_shadow_geometry(Display *dpy, win *w) { - w->shadow_dx = opts.shadow_offset_x; - w->shadow_dy = opts.shadow_offset_y; - w->shadow_width = w->widthb + gaussian_map->size; - w->shadow_height = w->heightb + gaussian_map->size; +calc_shadow_geometry(session_t *ps, win *w) { + w->shadow_dx = ps->o.shadow_offset_x; + w->shadow_dy = ps->o.shadow_offset_y; + w->shadow_width = w->widthb + ps->gaussian_map->size; + w->shadow_height = w->heightb + ps->gaussian_map->size; } /** @@ -2369,27 +2188,27 @@ calc_shadow_geometry(Display *dpy, win *w) { * @param client window ID of the client window */ static void -mark_client_win(Display *dpy, win *w, Window client) { +mark_client_win(session_t *ps, win *w, Window client) { w->client_win = client; - XSelectInput(dpy, client, determine_evmask(dpy, client, WIN_EVMODE_CLIENT)); + XSelectInput(ps->dpy, client, determine_evmask(ps, client, WIN_EVMODE_CLIENT)); // Get the frame width and monitor further frame width changes on client // window if necessary - if (opts.frame_opacity) { - get_frame_extents(dpy, w, client); + if (ps->o.frame_opacity) { + get_frame_extents(ps, w, client); } // Detect window type here if (WINTYPE_UNKNOWN == w->window_type) - w->window_type = get_wintype_prop(dpy, w->client_win); + w->window_type = wid_get_prop_wintype(ps, w->client_win); // Conform to EWMH standard, if _NET_WM_WINDOW_TYPE is not present, take // override-redirect windows or windows without WM_TRANSIENT_FOR as // _NET_WM_WINDOW_TYPE_NORMAL, otherwise as _NET_WM_WINDOW_TYPE_DIALOG. if (WINTYPE_UNKNOWN == w->window_type) { if (w->a.override_redirect - || !wid_has_attr(dpy, client, transient_atom)) + || !wid_has_attr(ps, client, ps->atom_transient)) w->window_type = WINTYPE_NORMAL; else w->window_type = WINTYPE_DIALOG; @@ -2397,8 +2216,9 @@ mark_client_win(Display *dpy, win *w, Window client) { } static void -add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { - if (find_win(id)) { +add_win(session_t *ps, Window id, Window prev, bool override_redirect) { + // Reject overlay window and already added windows + if (id == ps->overlay || find_win(ps, id)) { return; } @@ -2408,24 +2228,24 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { if (!new) return; if (prev) { - for (p = &list; *p; p = &(*p)->next) { + for (p = &ps->list; *p; p = &(*p)->next) { if ((*p)->id == prev && !(*p)->destroyed) break; } } else { - p = &list; + p = &ps->list; } new->id = id; - set_ignore(dpy, NextRequest(dpy)); + set_ignore_next(ps); - if (!XGetWindowAttributes(dpy, id, &new->a)) { + if (!XGetWindowAttributes(ps->dpy, id, &new->a)) { free(new); return; } new->damaged = 0; - new->to_paint = False; + new->to_paint = false; new->pixmap = None; new->picture = None; @@ -2433,9 +2253,9 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->damage_sequence = 0; new->damage = None; } else { - new->damage_sequence = NextRequest(dpy); - set_ignore(dpy, NextRequest(dpy)); - new->damage = XDamageCreate(dpy, id, XDamageReportNonEmpty); + new->damage_sequence = NextRequest(ps->dpy); + set_ignore_next(ps); + new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty); } new->name = NULL; @@ -2443,13 +2263,13 @@ 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->bounding_shaped = false; + new->rounded_corners = false; new->border_size = None; new->reg_ignore = None; new->extents = None; - new->shadow = False; + new->shadow = false; new->shadow_opacity = 0.0; new->shadow_pict = None; new->shadow_alpha_pict = None; @@ -2461,15 +2281,15 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->opacity_tgt = 0; new->opacity_prop = OPAQUE; new->opacity_prop_client = OPAQUE; - new->fade = False; + new->fade = false; new->fade_callback = NULL; new->alpha_pict = None; new->frame_opacity = 1.0; new->frame_alpha_pict = None; - new->dim = False; - new->focused = False; - new->destroyed = False; - new->need_configure = False; + new->dim = false; + new->focused = false; + new->destroyed = false; + new->need_configure = false; new->window_type = WINTYPE_UNKNOWN; new->mode = WINDOW_TRANS; new->attr_shadow = -1; @@ -2485,21 +2305,21 @@ add_win(Display *dpy, Window id, Window prev, Bool override_redirect) { new->flags = 0; - calc_win_size(dpy, new); + calc_win_size(ps, new); new->next = *p; *p = new; if (new->a.map_state == IsViewable) { - map_win(dpy, id, new->damage_sequence - 1, True, override_redirect); + map_win(ps, id, override_redirect); } } static void -restack_win(Display *dpy, win *w, Window new_above) { +restack_win(session_t *ps, win *w, Window new_above) { Window old_above; - update_reg_ignore_expire(w); + update_reg_ignore_expire(ps, w); if (w->next) { old_above = w->next->id; @@ -2511,14 +2331,14 @@ restack_win(Display *dpy, win *w, Window new_above) { win **prev; /* unhook */ - for (prev = &list; *prev; prev = &(*prev)->next) { + for (prev = &ps->list; *prev; prev = &(*prev)->next) { if ((*prev) == w) break; } *prev = w->next; /* rehook */ - for (prev = &list; *prev; prev = &(*prev)->next) { + for (prev = &ps->list; *prev; prev = &(*prev)->next) { if ((*prev)->id == new_above && !(*prev)->destroyed) break; } @@ -2531,7 +2351,7 @@ restack_win(Display *dpy, win *w, Window new_above) { const char *desc; char *window_name = NULL; bool to_free; - win* c = list; + win* c = ps->list; printf("restack_win(%#010lx, %#010lx): " "Window stack modified. Current stack:\n", w->id, new_above); @@ -2539,7 +2359,7 @@ restack_win(Display *dpy, win *w, Window new_above) { for (; c; c = c->next) { window_name = "(Failed to get title)"; - to_free = ev_window_name(dpy, c->id, &window_name); + to_free = ev_window_name(ps, c->id, &window_name); desc = ""; if (c->destroyed) desc = "(D) "; @@ -2557,21 +2377,21 @@ restack_win(Display *dpy, win *w, Window new_above) { } static void -configure_win(Display *dpy, XConfigureEvent *ce) { - if (ce->window == root) { - if (tgt_buffer) { - XRenderFreePicture(dpy, tgt_buffer); - tgt_buffer = None; +configure_win(session_t *ps, XConfigureEvent *ce) { + if (ce->window == ps->root) { + if (ps->tgt_buffer) { + XRenderFreePicture(ps->dpy, ps->tgt_buffer); + ps->tgt_buffer = None; } - root_width = ce->width; - root_height = ce->height; + ps->root_width = ce->width; + ps->root_height = ce->height; - rebuild_screen_reg(dpy); + rebuild_screen_reg(ps); return; } - win *w = find_win(ce->window); + win *w = find_win(ps, ce->window); XserverRegion damage = None; if (!w) @@ -2579,38 +2399,38 @@ configure_win(Display *dpy, XConfigureEvent *ce) { if (w->a.map_state == IsUnmapped) { /* save the configure event for when the window maps */ - w->need_configure = True; + w->need_configure = true; w->queue_configure = *ce; - restack_win(dpy, w, ce->above); + restack_win(ps, w, ce->above); } else { if (!(w->need_configure)) { - restack_win(dpy, w, ce->above); + restack_win(ps, w, ce->above); } // Windows restack (including window restacks happened when this // window is not mapped) could mess up all reg_ignore - reg_ignore_expire = True; + ps->reg_ignore_expire = true; - w->need_configure = False; + w->need_configure = false; - damage = XFixesCreateRegion(dpy, 0, 0); + damage = XFixesCreateRegion(ps->dpy, 0, 0); if (w->extents != None) { - XFixesCopyRegion(dpy, damage, w->extents); + XFixesCopyRegion(ps->dpy, damage, w->extents); } // If window geometry did not change, don't free extents here if (w->a.x != ce->x || w->a.y != ce->y || w->a.width != ce->width || w->a.height != ce->height) { - free_region(dpy, &w->extents); - free_region(dpy, &w->border_size); + free_region(ps, &w->extents); + free_region(ps, &w->border_size); } w->a.x = ce->x; w->a.y = ce->y; if (w->a.width != ce->width || w->a.height != ce->height) { - free_pixmap(dpy, &w->pixmap); - free_picture(dpy, &w->picture); + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); } if (w->a.width != ce->width || w->a.height != ce->height @@ -2618,19 +2438,19 @@ configure_win(Display *dpy, XConfigureEvent *ce) { w->a.width = ce->width; w->a.height = ce->height; w->a.border_width = ce->border_width; - calc_win_size(dpy, w); + calc_win_size(ps, w); // Rounded corner detection is affected by window size - if (shape_exists && opts.shadow_ignore_shaped - && opts.detect_rounded_corners && w->bounding_shaped) - win_update_shape(dpy, w); + if (ps->shape_exists && ps->o.shadow_ignore_shaped + && ps->o.detect_rounded_corners && w->bounding_shaped) + win_update_shape(ps, w); } if (damage) { - XserverRegion extents = win_extents(dpy, w); - XFixesUnionRegion(dpy, damage, damage, extents); - XFixesDestroyRegion(dpy, extents); - add_damage(dpy, damage); + XserverRegion extents = win_extents(ps, w); + XFixesUnionRegion(ps->dpy, damage, damage, extents); + XFixesDestroyRegion(ps->dpy, extents); + add_damage(ps, damage); } } @@ -2638,40 +2458,35 @@ configure_win(Display *dpy, XConfigureEvent *ce) { } static void -circulate_win(Display *dpy, XCirculateEvent *ce) { - win *w = find_win(ce->window); +circulate_win(session_t *ps, XCirculateEvent *ce) { + win *w = find_win(ps, ce->window); Window new_above; if (!w) return; if (ce->place == PlaceOnTop) { - new_above = list->id; + new_above = ps->list->id; } else { new_above = None; } - restack_win(dpy, w, new_above); + restack_win(ps, w, new_above); } static void -finish_destroy_win(Display *dpy, Window id) { +finish_destroy_win(session_t *ps, Window id) { win **prev, *w; - for (prev = &list; (w = *prev); prev = &w->next) { + for (prev = &ps->list; (w = *prev); prev = &w->next) { if (w->id == id && w->destroyed) { - finish_unmap_win(dpy, w); + finish_unmap_win(ps, w); *prev = w->next; // Clear active_win if it's pointing to the destroyed window - if (active_win) - active_win = NULL; + if (ps->active_win) + ps->active_win = NULL; - free_picture(dpy, &w->shadow_pict); - free_damage(dpy, &w->damage); - free_region(dpy, &w->reg_ignore); - free(w->name); - free(w->class_instance); - free(w->class_general); + free_win_res(ps, w); free(w); break; @@ -2680,67 +2495,72 @@ finish_destroy_win(Display *dpy, Window id) { } static void -destroy_callback(Display *dpy, win *w) { - finish_destroy_win(dpy, w->id); +destroy_callback(session_t *ps, win *w) { + finish_destroy_win(ps, w->id); } static void -destroy_win(Display *dpy, Window id, Bool fade) { - win *w = find_win(id); +destroy_win(session_t *ps, Window id) { + win *w = find_win(ps, id); if (w) { - w->destroyed = True; + w->destroyed = true; // Fading out the window w->opacity_tgt = 0; - set_fade_callback(dpy, w, destroy_callback, False); + set_fade_callback(ps, w, destroy_callback, false); } } static inline void -root_damaged(void) { - if (root_tile) { - XClearArea(dpy, root, 0, 0, 0, 0, True); - // if (root_picture != root_tile) { - XRenderFreePicture(dpy, root_tile); - root_tile = None; +root_damaged(session_t *ps) { + if (ps->root_tile) { + XClearArea(ps->dpy, ps->root, 0, 0, 0, 0, true); + // if (ps->root_picture != ps->root_tile) { + XRenderFreePicture(ps->dpy, ps->root_tile); + ps->root_tile = None; /* } if (root_damage) { - XserverRegion parts = XFixesCreateRegion(dpy, 0, 0); - XDamageSubtract(dpy, root_damage, None, parts); - add_damage(dpy, parts); + XserverRegion parts = XFixesCreateRegion(ps->dpy, 0, 0); + XDamageSubtract(ps->dpy, root_damage, None, parts); + add_damage(ps, parts); } */ } // Mark screen damaged if we are painting on overlay - if (opts.paint_on_overlay) - add_damage(dpy, get_screen_region(dpy)); + if (ps->o.paint_on_overlay) + add_damage(ps, get_screen_region(ps)); } static void -damage_win(Display *dpy, XDamageNotifyEvent *de) { +damage_win(session_t *ps, XDamageNotifyEvent *de) { /* - if (root == de->drawable) { + if (ps->root == de->drawable) { root_damaged(); return; } */ - win *w = find_win(de->drawable); + win *w = find_win(ps, de->drawable); if (!w) return; - repair_win(dpy, w); + repair_win(ps, w); } +/** + * Xlib error handler function. + */ static int error(Display *dpy, XErrorEvent *ev) { + session_t * const ps = ps_g; + int o; const char *name = "Unknown"; - if (should_ignore(dpy, ev->serial)) { + if (should_ignore(ps, ev->serial)) { return 0; } - if (ev->request_code == composite_opcode + if (ev->request_code == ps->composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) { fprintf(stderr, "Another composite manager is already running\n"); exit(1); @@ -2748,17 +2568,17 @@ error(Display *dpy, XErrorEvent *ev) { #define CASESTRRET2(s) case s: name = #s; break - o = ev->error_code - xfixes_error; + o = ev->error_code - ps->xfixes_error; switch (o) { CASESTRRET2(BadRegion); } - o = ev->error_code - damage_error; + o = ev->error_code - ps->damage_error; switch (o) { CASESTRRET2(BadDamage); } - o = ev->error_code - render_error; + o = ev->error_code - ps->render_error; switch (o) { CASESTRRET2(BadPictFormat); CASESTRRET2(BadPicture); @@ -2789,7 +2609,7 @@ error(Display *dpy, XErrorEvent *ev) { #undef CASESTRRET2 - print_timestamp(); + print_timestamp(ps); printf("error %d (%s) request %d minor %d serial %lu\n", ev->error_code, name, ev->request_code, ev->minor_code, ev->serial); @@ -2798,74 +2618,84 @@ error(Display *dpy, XErrorEvent *ev) { } static void -expose_root(Display *dpy, XRectangle *rects, int nrects) { - XserverRegion region = XFixesCreateRegion(dpy, rects, nrects); - add_damage(dpy, region); +expose_root(session_t *ps, XRectangle *rects, int nrects) { + XserverRegion region = XFixesCreateRegion(ps->dpy, rects, nrects); + add_damage(ps, region); } -static Bool -wid_get_text_prop(Display *dpy, Window wid, Atom prop, +/** + * Get the value of a text property of a window. + */ +static bool +wid_get_text_prop(session_t *ps, Window wid, Atom prop, char ***pstrlst, int *pnstr) { XTextProperty text_prop; - if (!(XGetTextProperty(dpy, wid, &text_prop, prop) && text_prop.value)) - return False; + if (!(XGetTextProperty(ps->dpy, wid, &text_prop, prop) && text_prop.value)) + return false; if (Success != - XmbTextPropertyToTextList(dpy, &text_prop, pstrlst, pnstr) + XmbTextPropertyToTextList(ps->dpy, &text_prop, pstrlst, pnstr) || !*pnstr) { *pnstr = 0; if (*pstrlst) XFreeStringList(*pstrlst); - return False; + return false; } - return True; + return true; } -static Bool -wid_get_name(Display *dpy, Window wid, char **name) { +/** + * Get the name of a window from window ID. + */ +static bool +wid_get_name(session_t *ps, 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) + // set_ignore_next(ps); + if (!(XGetTextProperty(ps->dpy, wid, &text_prop, ps->atom_name_ewmh) && text_prop.value)) { - // set_ignore(dpy, NextRequest(dpy)); + // set_ignore_next(ps); #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; + if (!(XGetWMName(ps->dpy, wid, &text_prop) && text_prop.value)) { + return false; } } if (Success != - XmbTextPropertyToTextList(dpy, &text_prop, &strlst, &nstr) + XmbTextPropertyToTextList(ps->dpy, &text_prop, &strlst, &nstr) || !nstr || !strlst) { if (strlst) XFreeStringList(strlst); - return False; + return false; } *name = mstrcpy(strlst[0]); XFreeStringList(strlst); - return True; + return true; } +/** + * Retrieve the name of a window and update its <code>win</code> + * structure. + */ static int -win_get_name(Display *dpy, win *w) { - Bool ret; +win_get_name(session_t *ps, 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; + return false; // Get the name - ret = wid_get_name(dpy, w->client_win, &w->name); + ret = wid_get_name(ps, w->client_win, &w->name); // Return -1 if wid_get_name() failed, 0 if name didn't change, 1 if // it changes @@ -2888,14 +2718,18 @@ win_get_name(Display *dpy, win *w) { return ret; } -static Bool -win_get_class(Display *dpy, win *w) { +/** + * Retrieve the <code>WM_CLASS</code> of a window and update its + * <code>win</code> structure. + */ +static bool +win_get_class(session_t *ps, win *w) { char **strlst = NULL; int nstr = 0; // Can't do anything if there's no client window if (!w->client_win) - return False; + return false; // Free and reset old strings free(w->class_instance); @@ -2904,8 +2738,8 @@ win_get_class(Display *dpy, win *w) { w->class_general = NULL; // Retrieve the property string list - if (!wid_get_text_prop(dpy, w->client_win, class_atom, &strlst, &nstr)) - return False; + if (!wid_get_text_prop(ps, w->client_win, ps->atom_class, &strlst, &nstr)) + return false; // Copy the strings if successful w->class_instance = mstrcpy(strlst[0]); @@ -2921,7 +2755,7 @@ win_get_class(Display *dpy, win *w) { w->id, w->client_win, w->class_instance, w->class_general); #endif - return True; + return true; } #ifdef DEBUG_EVENTS @@ -2934,7 +2768,7 @@ ev_serial(XEvent *ev) { } static const char * -ev_name(XEvent *ev) { +ev_name(session_t *ps, XEvent *ev) { static char buf[128]; switch (ev->type & 0x7f) { CASESTRRET(FocusIn); @@ -2950,11 +2784,11 @@ ev_name(XEvent *ev) { CASESTRRET(PropertyNotify); CASESTRRET(ClientMessage); default: - if (ev->type == damage_event + XDamageNotify) { + if (ev->type == ps->damage_event + XDamageNotify) { return "Damage"; } - if (shape_exists && ev->type == shape_event) { + if (ps->shape_exists && ev->type == ps->shape_event) { return "ShapeNotify"; } @@ -2965,7 +2799,7 @@ ev_name(XEvent *ev) { } static Window -ev_window(XEvent *ev) { +ev_window(session_t *ps, XEvent *ev) { switch (ev->type) { case FocusIn: case FocusOut: @@ -2991,11 +2825,11 @@ ev_window(XEvent *ev) { case ClientMessage: return ev->xclient.window; default: - if (ev->type == damage_event + XDamageNotify) { + if (ev->type == ps->damage_event + XDamageNotify) { return ((XDamageNotifyEvent *)ev)->drawable; } - if (shape_exists && ev->type == shape_event) { + if (ps->shape_exists && ev->type == ps->shape_event) { return ((XShapeEvent *) ev)->window; } @@ -3039,9 +2873,7 @@ ev_focus_report(XFocusChangeEvent* ev) { #endif -/** - * Events - */ +// === Events === /** * Determine whether we should respond to a <code>FocusIn/Out</code> @@ -3054,7 +2886,7 @@ ev_focus_accept(XFocusChangeEvent *ev) { } inline static void -ev_focus_in(XFocusChangeEvent *ev) { +ev_focus_in(session_t *ps, XFocusChangeEvent *ev) { #ifdef DEBUG_EVENTS ev_focus_report(ev); #endif @@ -3062,16 +2894,16 @@ ev_focus_in(XFocusChangeEvent *ev) { if (!ev_focus_accept(ev)) return; - win *w = find_win(ev->window); + win *w = find_win(ps, ev->window); // To deal with events sent from windows just destroyed if (!w) return; - set_focused(dpy, w, True); + set_focused(ps, w, true); } inline static void -ev_focus_out(XFocusChangeEvent *ev) { +ev_focus_out(session_t *ps, XFocusChangeEvent *ev) { #ifdef DEBUG_EVENTS ev_focus_report(ev); #endif @@ -3079,93 +2911,93 @@ ev_focus_out(XFocusChangeEvent *ev) { if (!ev_focus_accept(ev)) return; - win *w = find_win(ev->window); + win *w = find_win(ps, ev->window); // To deal with events sent from windows just destroyed if (!w) return; - set_focused(dpy, w, False); + set_focused(ps, w, false); } inline static void -ev_create_notify(XCreateWindowEvent *ev) { - assert(ev->parent == root); - add_win(dpy, ev->window, 0, ev->override_redirect); +ev_create_notify(session_t *ps, XCreateWindowEvent *ev) { + assert(ev->parent == ps->root); + add_win(ps, ev->window, 0, ev->override_redirect); } inline static void -ev_configure_notify(XConfigureEvent *ev) { +ev_configure_notify(session_t *ps, XConfigureEvent *ev) { #ifdef DEBUG_EVENTS printf(" { send_event: %d, " " above: %#010lx, " " override_redirect: %d }\n", ev->send_event, ev->above, ev->override_redirect); #endif - configure_win(dpy, ev); + configure_win(ps, ev); } inline static void -ev_destroy_notify(XDestroyWindowEvent *ev) { - destroy_win(dpy, ev->window, True); +ev_destroy_notify(session_t *ps, XDestroyWindowEvent *ev) { + destroy_win(ps, ev->window); } inline static void -ev_map_notify(XMapEvent *ev) { - map_win(dpy, ev->window, ev->serial, True, ev->override_redirect); +ev_map_notify(session_t *ps, XMapEvent *ev) { + map_win(ps, ev->window, ev->override_redirect); } inline static void -ev_unmap_notify(XUnmapEvent *ev) { - unmap_win(dpy, ev->window, True); +ev_unmap_notify(session_t *ps, XUnmapEvent *ev) { + unmap_win(ps, ev->window); } inline static void -ev_reparent_notify(XReparentEvent *ev) { - if (ev->parent == root) { - add_win(dpy, ev->window, 0, ev->override_redirect); +ev_reparent_notify(session_t *ps, XReparentEvent *ev) { + if (ev->parent == ps->root) { + add_win(ps, ev->window, 0, ev->override_redirect); } else { - destroy_win(dpy, ev->window, True); + destroy_win(ps, ev->window); // Reset event mask in case something wrong happens - XSelectInput(dpy, ev->window, - determine_evmask(dpy, ev->window, WIN_EVMODE_UNKNOWN)); + XSelectInput(ps->dpy, ev->window, + determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)); /* // Check if the window is a client window of another - win *w_top = find_toplevel2(dpy, ev->window); + win *w_top = find_toplevel2(ps, ev->window); if (w_top && !(w_top->client_win)) { - mark_client_win(dpy, w_top, ev->window); + mark_client_win(ps, w_top, ev->window); } */ } } inline static void -ev_circulate_notify(XCirculateEvent *ev) { - circulate_win(dpy, ev); +ev_circulate_notify(session_t *ps, XCirculateEvent *ev) { + circulate_win(ps, ev); } inline static void -ev_expose(XExposeEvent *ev) { - if (ev->window == root || (overlay && ev->window == overlay)) { +ev_expose(session_t *ps, XExposeEvent *ev) { + if (ev->window == ps->root || (ps->overlay && ev->window == ps->overlay)) { 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; + if (ps->n_expose == ps->size_expose) { + if (ps->expose_rects) { + ps->expose_rects = realloc(ps->expose_rects, + (ps->size_expose + more) * sizeof(XRectangle)); + ps->size_expose += more; } else { - expose_rects = malloc(more * sizeof(XRectangle)); - size_expose = more; + ps->expose_rects = malloc(more * sizeof(XRectangle)); + ps->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++; + ps->expose_rects[ps->n_expose].x = ev->x; + ps->expose_rects[ps->n_expose].y = ev->y; + ps->expose_rects[ps->n_expose].width = ev->width; + ps->expose_rects[ps->n_expose].height = ev->height; + ps->n_expose++; if (ev->count == 0) { - expose_root(dpy, expose_rects, n_expose); - n_expose = 0; + expose_root(ps, ps->expose_rects, ps->n_expose); + ps->n_expose = 0; } } } @@ -3177,46 +3009,47 @@ ev_expose(XExposeEvent *ev) { * returned could not be found. */ static void -update_ewmh_active_win(Display *dpy) { +update_ewmh_active_win(session_t *ps) { // Get the attribute firstly - winattr_t attr = wid_get_attr(dpy, root, ewmh_active_win_atom, + winprop_t prop = wid_get_prop(ps, ps->root, ps->atom_ewmh_active_win, 1L, XA_WINDOW, 32); - if (!attr.nitems) { - free_winattr(&attr); + if (!prop.nitems) { + free_winprop(&prop); return; } - + // Search for the window - Window wid = *((long *) attr.data); + Window wid = *((long *) prop.data); win *w = NULL; - free_winattr(&attr); + free_winprop(&prop); - if (!(w = find_toplevel(wid))) - if (!(w = find_win(wid))) - w = find_toplevel2(dpy, wid); + if (!(w = find_toplevel(ps, wid))) + if (!(w = find_win(ps, wid))) + w = find_toplevel2(ps, wid); // Mark the window focused if (w) { if (!w->focused) - set_focused(dpy, w, True); - if (active_win && w != active_win) - set_focused(dpy, active_win, False); - active_win = w; + set_focused(ps, w, true); + if (ps->active_win && w != ps->active_win) + set_focused(ps, ps->active_win, false); + ps->active_win = w; } } inline static void -ev_property_notify(XPropertyEvent *ev) { - if (root == ev->window) { - if (opts.track_focus && opts.use_ewmh_active_win - && ewmh_active_win_atom == ev->atom) { - update_ewmh_active_win(dpy); +ev_property_notify(session_t *ps, XPropertyEvent *ev) { + if (ps->root == ev->window) { + if (ps->o.track_focus && ps->o.use_ewmh_active_win + && ps->atom_ewmh_active_win == ev->atom) { + update_ewmh_active_win(ps); } else { // Destroy the root "image" if the wallpaper probably changed - for (int p = 0; background_props[p]; p++) { - if (ev->atom == XInternAtom(dpy, background_props[p], False)) { - root_damaged(); + for (int p = 0; background_props_str[p]; p++) { + if (ev->atom == + XInternAtom(ps->dpy, background_props_str[p], false)) { + root_damaged(ps); break; } } @@ -3227,62 +3060,62 @@ ev_property_notify(XPropertyEvent *ev) { } // If _NET_WM_OPACITY changes - if (ev->atom == opacity_atom) { + if (ev->atom == ps->atom_opacity) { win *w = NULL; - if ((w = find_win(ev->window))) - w->opacity_prop = wid_get_opacity_prop(dpy, w->id, OPAQUE); - else if (opts.detect_client_opacity - && (w = find_toplevel(ev->window))) - w->opacity_prop_client = wid_get_opacity_prop(dpy, w->client_win, + if ((w = find_win(ps, ev->window))) + w->opacity_prop = wid_get_opacity_prop(ps, w->id, OPAQUE); + else if (ps->o.detect_client_opacity + && (w = find_toplevel(ps, ev->window))) + w->opacity_prop_client = wid_get_opacity_prop(ps, w->client_win, OPAQUE); if (w) { - calc_opacity(dpy, w, False); + calc_opacity(ps, w, false); } } // If frame extents property changes - if (opts.frame_opacity && ev->atom == frame_extents_atom) { - win *w = find_toplevel(ev->window); + if (ps->o.frame_opacity && ev->atom == ps->atom_frame_extents) { + win *w = find_toplevel(ps, ev->window); if (w) { - get_frame_extents(dpy, w, ev->window); + get_frame_extents(ps, w, ev->window); // If frame extents change, the window needs repaint - add_damage_win(dpy, w); + add_damage_win(ps, w); } } // If name changes - if (opts.track_wdata - && (name_atom == ev->atom || name_ewmh_atom == ev->atom)) { - win *w = find_toplevel(ev->window); - if (w && 1 == win_get_name(dpy, w)) - determine_shadow(dpy, w); + if (ps->o.track_wdata + && (ps->atom_name == ev->atom || ps->atom_name_ewmh == ev->atom)) { + win *w = find_toplevel(ps, ev->window); + if (w && 1 == win_get_name(ps, w)) + determine_shadow(ps, w); } // If class changes - if (opts.track_wdata && class_atom == ev->atom) { - win *w = find_toplevel(ev->window); + if (ps->o.track_wdata && ps->atom_class == ev->atom) { + win *w = find_toplevel(ps, ev->window); if (w) { - win_get_class(dpy, w); - determine_shadow(dpy, w); + win_get_class(ps, w); + determine_shadow(ps, w); } } // If _COMPTON_SHADOW changes - if (opts.respect_attr_shadow && compton_shadow_atom == ev->atom) { - win *w = find_win(ev->window); + if (ps->o.respect_prop_shadow && ps->atom_compton_shadow == ev->atom) { + win *w = find_win(ps, ev->window); if (w) - win_update_attr_shadow(dpy, w); + win_update_attr_shadow(ps, w); } } inline static void -ev_damage_notify(XDamageNotifyEvent *ev) { - damage_win(dpy, ev); +ev_damage_notify(session_t *ps, XDamageNotifyEvent *ev) { + damage_win(ps, ev); } inline static void -ev_shape_notify(XShapeEvent *ev) { - win *w = find_win(ev->window); +ev_shape_notify(session_t *ps, XShapeEvent *ev) { + win *w = find_win(ps, ev->window); if (!w || IsUnmapped == w->a.map_state) return; /* @@ -3293,31 +3126,31 @@ ev_shape_notify(XShapeEvent *ev) { */ if (w->border_size) { // Mark the old border_size as damaged - add_damage(dpy, w->border_size); + add_damage(ps, w->border_size); - w->border_size = border_size(dpy, w); + w->border_size = border_size(ps, w); // Mark the new border_size as damaged - add_damage(dpy, copy_region(dpy, w->border_size)); + add_damage(ps, copy_region(ps, w->border_size)); } // Redo bounding shape detection and rounded corner detection - win_update_shape(dpy, w); + win_update_shape(ps, w); - update_reg_ignore_expire(w); + update_reg_ignore_expire(ps, w); } /** * Handle ScreenChangeNotify events from X RandR extension. */ static void -ev_screen_change_notify(XRRScreenChangeNotifyEvent *ev) { - if (!opts.refresh_rate) { - update_refresh_rate(dpy); - if (!refresh_rate) { +ev_screen_change_notify(session_t *ps, XRRScreenChangeNotifyEvent *ev) { + if (!ps->o.refresh_rate) { + update_refresh_rate(ps); + if (!ps->refresh_rate) { fprintf(stderr, "ev_screen_change_notify(): Refresh rate detection " "failed, software VSync disabled."); - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } } } @@ -3327,26 +3160,26 @@ ev_screen_change_notify(XRRScreenChangeNotifyEvent *ev) { * Get a window's name from window ID. */ static bool -ev_window_name(Display *dpy, Window wid, char **name) { +ev_window_name(session_t *ps, Window wid, char **name) { bool to_free = false; *name = ""; if (wid) { *name = "(Failed to get title)"; - if (root == wid) + if (ps->root == wid) *name = "(Root window)"; - else if (overlay == wid) + else if (ps->overlay == wid) *name = "(Overlay)"; else { - win *w = find_win(wid); + win *w = find_win(ps, wid); if (!w) - w = find_toplevel(wid); + w = find_toplevel(ps, wid); if (w && w->name) *name = w->name; else if (!(w && w->client_win - && (to_free = wid_get_name(dpy, w->client_win, name)))) - to_free = wid_get_name(dpy, wid, name); + && (to_free = wid_get_name(ps, w->client_win, name)))) + to_free = wid_get_name(ps, wid, name); } } @@ -3355,22 +3188,22 @@ ev_window_name(Display *dpy, Window wid, char **name) { #endif static void -ev_handle(XEvent *ev) { +ev_handle(session_t *ps, XEvent *ev) { if ((ev->type & 0x7f) != KeymapNotify) { - discard_ignore(dpy, ev->xany.serial); + discard_ignore(ps, ev->xany.serial); } #ifdef DEBUG_EVENTS - if (ev->type != damage_event + XDamageNotify) { - Window wid = ev_window(ev); + if (ev->type != ps->damage_event + XDamageNotify) { + Window wid = ev_window(ps, ev); char *window_name = NULL; - Bool to_free = false; + bool to_free = false; - to_free = ev_window_name(dpy, wid, &window_name); + to_free = ev_window_name(ps, wid, &window_name); - print_timestamp(); + print_timestamp(ps); printf("event %10.10s serial %#010x window %#010lx \"%s\"\n", - ev_name(ev), ev_serial(ev), wid, window_name); + ev_name(ps, ev), ev_serial(ev), wid, window_name); if (to_free) { XFree(window_name); @@ -3382,57 +3215,55 @@ ev_handle(XEvent *ev) { switch (ev->type) { case FocusIn: - ev_focus_in((XFocusChangeEvent *)ev); + ev_focus_in(ps, (XFocusChangeEvent *)ev); break; case FocusOut: - ev_focus_out((XFocusChangeEvent *)ev); + ev_focus_out(ps, (XFocusChangeEvent *)ev); break; case CreateNotify: - ev_create_notify((XCreateWindowEvent *)ev); + ev_create_notify(ps, (XCreateWindowEvent *)ev); break; case ConfigureNotify: - ev_configure_notify((XConfigureEvent *)ev); + ev_configure_notify(ps, (XConfigureEvent *)ev); break; case DestroyNotify: - ev_destroy_notify((XDestroyWindowEvent *)ev); + ev_destroy_notify(ps, (XDestroyWindowEvent *)ev); break; case MapNotify: - ev_map_notify((XMapEvent *)ev); + ev_map_notify(ps, (XMapEvent *)ev); break; case UnmapNotify: - ev_unmap_notify((XUnmapEvent *)ev); + ev_unmap_notify(ps, (XUnmapEvent *)ev); break; case ReparentNotify: - ev_reparent_notify((XReparentEvent *)ev); + ev_reparent_notify(ps, (XReparentEvent *)ev); break; case CirculateNotify: - ev_circulate_notify((XCirculateEvent *)ev); + ev_circulate_notify(ps, (XCirculateEvent *)ev); break; case Expose: - ev_expose((XExposeEvent *)ev); + ev_expose(ps, (XExposeEvent *)ev); break; case PropertyNotify: - ev_property_notify((XPropertyEvent *)ev); + ev_property_notify(ps, (XPropertyEvent *)ev); break; default: - if (shape_exists && ev->type == shape_event) { - ev_shape_notify((XShapeEvent *) ev); + if (ps->shape_exists && ev->type == ps->shape_event) { + ev_shape_notify(ps, (XShapeEvent *) ev); break; } - if (randr_exists && ev->type == (randr_event + RRScreenChangeNotify)) { - ev_screen_change_notify((XRRScreenChangeNotifyEvent *) ev); + if (ps->randr_exists && ev->type == (ps->randr_event + RRScreenChangeNotify)) { + ev_screen_change_notify(ps, (XRRScreenChangeNotifyEvent *) ev); break; } - if (ev->type == damage_event + XDamageNotify) { - ev_damage_notify((XDamageNotifyEvent *)ev); + if (ev->type == ps->damage_event + XDamageNotify) { + ev_damage_notify(ps, (XDamageNotifyEvent *)ev); } break; } } -/** - * Main - */ +// === Main === /** * Print usage text and exit. @@ -3541,7 +3372,7 @@ usage(void) { "--use-ewmh-active-win\n" " Use _NET_WM_ACTIVE_WINDOW on the root window to determine which\n" " window is focused instead of using FocusIn/Out events.\n" - "--respect-attr-shadow\n" + "--respect-prop-shadow\n" " Respect _COMPTON_SHADOW. This a prototype-level feature, which\n" " you must not rely on.\n" "--unredir-if-possible\n" @@ -3573,7 +3404,7 @@ usage(void) { * Register a window as symbol, and initialize GLX context if wanted. */ static void -register_cm(Bool want_glxct) { +register_cm(session_t *ps, bool want_glxct) { Atom a; char *buf; int len, s; @@ -3582,10 +3413,10 @@ register_cm(Bool want_glxct) { // Create a window with the wanted GLX visual if (want_glxct) { XVisualInfo *pvi = NULL; - Bool ret = False; + bool ret = false; // Get visual for the window int attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None }; - pvi = glXChooseVisual(dpy, scr, attribs); + pvi = glXChooseVisual(ps->dpy, ps->scr, attribs); if (!pvi) { fprintf(stderr, "register_cm(): Failed to choose visual required " @@ -3594,28 +3425,28 @@ register_cm(Bool want_glxct) { else { // Create the window XSetWindowAttributes swa = { - .colormap = XCreateColormap(dpy, root, pvi->visual, AllocNone), + .colormap = XCreateColormap(ps->dpy, ps->root, pvi->visual, AllocNone), .border_pixel = 0, }; - pvi->screen = scr; - reg_win = XCreateWindow(dpy, root, 0, 0, 1, 1, 0, pvi->depth, + pvi->screen = ps->scr; + ps->reg_win = XCreateWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0, pvi->depth, InputOutput, pvi->visual, CWBorderPixel | CWColormap, &swa); - if (!reg_win) + if (!ps->reg_win) fprintf(stderr, "register_cm(): Failed to create window required " "by fake OpenGL VSync. OpenGL VSync turned off.\n"); else { // Get GLX context - glx_context = glXCreateContext(dpy, pvi, None, GL_TRUE); - if (!glx_context) { + ps->glx_context = glXCreateContext(ps->dpy, pvi, None, GL_TRUE); + if (!ps->glx_context) { fprintf(stderr, "register_cm(): Failed to get GLX context. " "OpenGL VSync turned off.\n"); - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } else { // Attach GLX context - if (!(ret = glXMakeCurrent(dpy, reg_win, glx_context))) + if (!(ret = glXMakeCurrent(ps->dpy, ps->reg_win, ps->glx_context))) fprintf(stderr, "register_cm(): Failed to attach GLX context." " OpenGL VSync turned off.\n"); } @@ -3625,20 +3456,19 @@ register_cm(Bool want_glxct) { XFree(pvi); if (!ret) - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } #endif - - if (!reg_win) - reg_win = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, + + if (!ps->reg_win) + ps->reg_win = XCreateSimpleWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0, None, None); - Xutf8SetWMProperties( - dpy, reg_win, "xcompmgr", "xcompmgr", + Xutf8SetWMProperties(ps->dpy, ps->reg_win, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); len = strlen(REGISTER_PROP) + 2; - s = scr; + s = ps->scr; while (s >= 10) { ++len; @@ -3646,14 +3476,17 @@ register_cm(Bool want_glxct) { } buf = malloc(len); - snprintf(buf, len, REGISTER_PROP"%d", scr); + snprintf(buf, len, REGISTER_PROP"%d", ps->scr); - a = XInternAtom(dpy, buf, False); + a = XInternAtom(ps->dpy, buf, false); free(buf); - XSetSelectionOwner(dpy, a, reg_win, 0); + XSetSelectionOwner(ps->dpy, a, ps->reg_win, 0); } +/** + * Fork program to background and disable all I/O streams. + */ static void fork_after(void) { if (getppid() == 1) return; @@ -3769,7 +3602,7 @@ open_config_file(char *cpath, char **ppath) { * Parse a VSync option argument. */ static inline void -parse_vsync(const char *optarg) { +parse_vsync(session_t *ps, const char *optarg) { const static char * const vsync_str[] = { "none", // VSYNC_NONE "drm", // VSYNC_DRM @@ -3780,7 +3613,7 @@ parse_vsync(const char *optarg) { for (i = 0; i < (sizeof(vsync_str) / sizeof(vsync_str[0])); ++i) if (!strcasecmp(optarg, vsync_str[i])) { - opts.vsync = i; + ps->o.vsync = i; break; } if ((sizeof(vsync_str) / sizeof(vsync_str[0])) == i) { @@ -3792,7 +3625,7 @@ parse_vsync(const char *optarg) { * Parse a configuration file from default location. */ static void -parse_config(char *cpath, struct options_tmp *pcfgtmp) { +parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) { char *path = NULL; FILE *f; config_t cfg; @@ -3830,31 +3663,31 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { // -D (fade_delta) if (lcfg_lookup_int(&cfg, "fade-delta", &ival)) - opts.fade_delta = ival; + ps->o.fade_delta = ival; // -I (fade_in_step) if (config_lookup_float(&cfg, "fade-in-step", &dval)) - opts.fade_in_step = normalize_d(dval) * OPAQUE; + ps->o.fade_in_step = normalize_d(dval) * OPAQUE; // -O (fade_out_step) if (config_lookup_float(&cfg, "fade-out-step", &dval)) - opts.fade_out_step = normalize_d(dval) * OPAQUE; + ps->o.fade_out_step = normalize_d(dval) * OPAQUE; // -r (shadow_radius) - lcfg_lookup_int(&cfg, "shadow-radius", &opts.shadow_radius); + lcfg_lookup_int(&cfg, "shadow-radius", &ps->o.shadow_radius); // -o (shadow_opacity) - config_lookup_float(&cfg, "shadow-opacity", &opts.shadow_opacity); + config_lookup_float(&cfg, "shadow-opacity", &ps->o.shadow_opacity); // -l (shadow_offset_x) - lcfg_lookup_int(&cfg, "shadow-offset-x", &opts.shadow_offset_x); + lcfg_lookup_int(&cfg, "shadow-offset-x", &ps->o.shadow_offset_x); // -t (shadow_offset_y) - lcfg_lookup_int(&cfg, "shadow-offset-y", &opts.shadow_offset_y); + lcfg_lookup_int(&cfg, "shadow-offset-y", &ps->o.shadow_offset_y); // -i (inactive_opacity) if (config_lookup_float(&cfg, "inactive-opacity", &dval)) - opts.inactive_opacity = normalize_d(dval) * OPAQUE; + ps->o.inactive_opacity = normalize_d(dval) * OPAQUE; // -e (frame_opacity) - config_lookup_float(&cfg, "frame-opacity", &opts.frame_opacity); + config_lookup_float(&cfg, "frame-opacity", &ps->o.frame_opacity); // -z (clear_shadow) - lcfg_lookup_bool(&cfg, "clear-shadow", &opts.clear_shadow); + lcfg_lookup_bool(&cfg, "clear-shadow", &ps->o.clear_shadow); // -c (shadow_enable) if (config_lookup_bool(&cfg, "shadow", &ival) && ival) - wintype_arr_enable(opts.wintype_shadow); + wintype_arr_enable(ps->o.wintype_shadow); // -C (no_dock_shadow) lcfg_lookup_bool(&cfg, "no-dock-shadow", &pcfgtmp->no_dock_shadow); // -G (no_dnd_shadow) @@ -3863,53 +3696,53 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { 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); + wintype_arr_enable(ps->o.wintype_fade); // --no-fading-open-close - lcfg_lookup_bool(&cfg, "no-fading-openclose", &opts.no_fading_openclose); + lcfg_lookup_bool(&cfg, "no-fading-openclose", &ps->o.no_fading_openclose); // --shadow-red - config_lookup_float(&cfg, "shadow-red", &opts.shadow_red); + config_lookup_float(&cfg, "shadow-red", &ps->o.shadow_red); // --shadow-green - config_lookup_float(&cfg, "shadow-green", &opts.shadow_green); + config_lookup_float(&cfg, "shadow-green", &ps->o.shadow_green); // --shadow-blue - config_lookup_float(&cfg, "shadow-blue", &opts.shadow_blue); + config_lookup_float(&cfg, "shadow-blue", &ps->o.shadow_blue); // --inactive-opacity-override lcfg_lookup_bool(&cfg, "inactive-opacity-override", - &opts.inactive_opacity_override); + &ps->o.inactive_opacity_override); // --inactive-dim - config_lookup_float(&cfg, "inactive-dim", &opts.inactive_dim); + config_lookup_float(&cfg, "inactive-dim", &ps->o.inactive_dim); // --mark-wmwin-focused - lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &opts.mark_wmwin_focused); + lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &ps->o.mark_wmwin_focused); // --mark-ovredir-focused lcfg_lookup_bool(&cfg, "mark-ovredir-focused", - &opts.mark_ovredir_focused); + &ps->o.mark_ovredir_focused); // --shadow-ignore-shaped lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", - &opts.shadow_ignore_shaped); + &ps->o.shadow_ignore_shaped); // --detect-rounded-corners lcfg_lookup_bool(&cfg, "detect-rounded-corners", - &opts.detect_rounded_corners); + &ps->o.detect_rounded_corners); // --detect-client-opacity lcfg_lookup_bool(&cfg, "detect-client-opacity", - &opts.detect_client_opacity); + &ps->o.detect_client_opacity); // --refresh-rate - lcfg_lookup_int(&cfg, "refresh-rate", &opts.refresh_rate); + lcfg_lookup_int(&cfg, "refresh-rate", &ps->o.refresh_rate); // --vsync if (config_lookup_string(&cfg, "vsync", &sval)) - parse_vsync(sval); + parse_vsync(ps, sval); // --alpha-step - config_lookup_float(&cfg, "alpha-step", &opts.alpha_step); + config_lookup_float(&cfg, "alpha-step", &ps->o.alpha_step); // --dbe - lcfg_lookup_bool(&cfg, "dbe", &opts.dbe); + lcfg_lookup_bool(&cfg, "dbe", &ps->o.dbe); // --paint-on-overlay - lcfg_lookup_bool(&cfg, "paint-on-overlay", &opts.paint_on_overlay); + lcfg_lookup_bool(&cfg, "paint-on-overlay", &ps->o.paint_on_overlay); // --sw-opti - lcfg_lookup_bool(&cfg, "sw-opti", &opts.sw_opti); + lcfg_lookup_bool(&cfg, "sw-opti", &ps->o.sw_opti); // --use-ewmh-active-win lcfg_lookup_bool(&cfg, "use-ewmh-active-win", - &opts.use_ewmh_active_win); + &ps->o.use_ewmh_active_win); // --unredir-if-possible lcfg_lookup_bool(&cfg, "unredir-if-possible", - &opts.unredir_if_possible); + &ps->o.unredir_if_possible); // --shadow-exclude { config_setting_t *setting = @@ -3919,20 +3752,20 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { if (config_setting_is_array(setting)) { int i = config_setting_length(setting); while (i--) { - condlst_add(&opts.shadow_blacklist, + condlst_add(&ps->o.shadow_blacklist, config_setting_get_string_elem(setting, i)); } } // Treat it as a single pattern if it's a string else if (CONFIG_TYPE_STRING == config_setting_type(setting)) { - condlst_add(&opts.shadow_blacklist, + condlst_add(&ps->o.shadow_blacklist, config_setting_get_string(setting)); } } } // Wintype settings { - wintype i; + wintype_t i; for (i = 0; i < NUM_WINTYPES; ++i) { char *str = mstrjoin("wintypes.", WINTYPES[i]); @@ -3940,11 +3773,11 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { free(str); if (setting) { if (config_setting_lookup_bool(setting, "shadow", &ival)) - opts.wintype_shadow[i] = (Bool) ival; + ps->o.wintype_shadow[i] = (bool) ival; if (config_setting_lookup_bool(setting, "fade", &ival)) - opts.wintype_fade[i] = (Bool) ival; + ps->o.wintype_fade[i] = (bool) ival; config_setting_lookup_float(setting, "opacity", - &opts.wintype_opacity[i]); + &ps->o.wintype_opacity[i]); } } } @@ -3957,7 +3790,7 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) { * Process arguments and configuration files. */ static void -get_cfg(int argc, char *const *argv) { +get_cfg(session_t *ps, 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 }, @@ -3981,30 +3814,33 @@ get_cfg(int argc, char *const *argv) { { "sw-opti", no_argument, NULL, 274 }, { "vsync-aggressive", no_argument, NULL, 275 }, { "use-ewmh-active-win", no_argument, NULL, 276 }, - { "respect-attr-shadow", no_argument, NULL, 277 }, + { "respect-prop-shadow", no_argument, NULL, 277 }, { "unredir-if-possible", no_argument, NULL, 278 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; struct options_tmp cfgtmp = { - .no_dock_shadow = False, - .no_dnd_shadow = False, + .no_dock_shadow = false, + .no_dnd_shadow = false, .menu_opacity = 1.0, }; - Bool shadow_enable = False, fading_enable = False; + bool shadow_enable = false, fading_enable = false; int o, longopt_idx, i; char *config_file = NULL; char *lc_numeric_old = mstrcpy(setlocale(LC_NUMERIC, NULL)); for (i = 0; i < NUM_WINTYPES; ++i) { - opts.wintype_fade[i] = False; - opts.wintype_shadow[i] = False; - opts.wintype_opacity[i] = 1.0; + ps->o.wintype_fade[i] = false; + ps->o.wintype_shadow[i] = false; + ps->o.wintype_opacity[i] = 1.0; } // Pre-parse the commandline arguments to check for --config and invalid // switches + // Must reset optind to 0 here in case we reread the commandline + // arguments + optind = 1; while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) { if (256 == o) @@ -4014,7 +3850,7 @@ get_cfg(int argc, char *const *argv) { } #ifdef CONFIG_LIBCONFIG - parse_config(config_file, &cfgtmp); + parse_config(ps, config_file, &cfgtmp); #endif // Parse commandline arguments. Range checking will be done later. @@ -4029,56 +3865,56 @@ get_cfg(int argc, char *const *argv) { switch (o) { // Short options case 'd': - opts.display = optarg; + ps->o.display = mstrcpy(optarg); break; case 'D': - opts.fade_delta = atoi(optarg); + ps->o.fade_delta = atoi(optarg); break; case 'I': - opts.fade_in_step = normalize_d(atof(optarg)) * OPAQUE; + ps->o.fade_in_step = normalize_d(atof(optarg)) * OPAQUE; break; case 'O': - opts.fade_out_step = normalize_d(atof(optarg)) * OPAQUE; + ps->o.fade_out_step = normalize_d(atof(optarg)) * OPAQUE; break; case 'c': - shadow_enable = True; + shadow_enable = true; break; case 'C': - cfgtmp.no_dock_shadow = True; + cfgtmp.no_dock_shadow = true; break; case 'G': - cfgtmp.no_dnd_shadow = True; + cfgtmp.no_dnd_shadow = true; break; case 'm': cfgtmp.menu_opacity = atof(optarg); break; case 'f': case 'F': - fading_enable = True; + fading_enable = true; break; case 'S': - opts.synchronize = True; + ps->o.synchronize = true; break; case 'r': - opts.shadow_radius = atoi(optarg); + ps->o.shadow_radius = atoi(optarg); break; case 'o': - opts.shadow_opacity = atof(optarg); + ps->o.shadow_opacity = atof(optarg); break; case 'l': - opts.shadow_offset_x = atoi(optarg); + ps->o.shadow_offset_x = atoi(optarg); break; case 't': - opts.shadow_offset_y = atoi(optarg); + ps->o.shadow_offset_y = atoi(optarg); break; case 'i': - opts.inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE); + ps->o.inactive_opacity = (normalize_d(atof(optarg)) * OPAQUE); break; case 'e': - opts.frame_opacity = atof(optarg); + ps->o.frame_opacity = atof(optarg); break; case 'z': - opts.clear_shadow = True; + ps->o.clear_shadow = true; break; case 'n': case 'a': @@ -4087,7 +3923,7 @@ get_cfg(int argc, char *const *argv) { "-n, -a, and -s have been removed.\n"); break; case 'b': - opts.fork_after_register = True; + ps->o.fork_after_register = true; break; // Long options case 256: @@ -4095,95 +3931,94 @@ get_cfg(int argc, char *const *argv) { break; case 257: // --shadow-red - opts.shadow_red = atof(optarg); + ps->o.shadow_red = atof(optarg); break; case 258: // --shadow-green - opts.shadow_green = atof(optarg); + ps->o.shadow_green = atof(optarg); break; case 259: // --shadow-blue - opts.shadow_blue = atof(optarg); + ps->o.shadow_blue = atof(optarg); break; case 260: // --inactive-opacity-override - opts.inactive_opacity_override = True; + ps->o.inactive_opacity_override = true; break; case 261: // --inactive-dim - opts.inactive_dim = atof(optarg); + ps->o.inactive_dim = atof(optarg); break; case 262: // --mark-wmwin-focused - opts.mark_wmwin_focused = True; + ps->o.mark_wmwin_focused = true; break; case 263: // --shadow-exclude - condlst_add(&opts.shadow_blacklist, optarg); + condlst_add(&ps->o.shadow_blacklist, optarg); break; case 264: // --mark-ovredir-focused - opts.mark_ovredir_focused = True; + ps->o.mark_ovredir_focused = true; break; case 265: // --no-fading-openclose - opts.no_fading_openclose = True; + ps->o.no_fading_openclose = true; break; case 266: // --shadow-ignore-shaped - opts.shadow_ignore_shaped = True; + ps->o.shadow_ignore_shaped = true; break; case 267: // --detect-rounded-corners - opts.detect_rounded_corners = True; + ps->o.detect_rounded_corners = true; break; case 268: // --detect-client-opacity - opts.detect_client_opacity = True; + ps->o.detect_client_opacity = true; break; case 269: // --refresh-rate - opts.refresh_rate = atoi(optarg); + ps->o.refresh_rate = atoi(optarg); break; case 270: // --vsync - parse_vsync(optarg); + parse_vsync(ps, optarg); break; case 271: // --alpha-step - opts.alpha_step = atof(optarg); + ps->o.alpha_step = atof(optarg); break; case 272: // --dbe - opts.dbe = True; + ps->o.dbe = true; break; case 273: // --paint-on-overlay - opts.paint_on_overlay = True; + ps->o.paint_on_overlay = true; break; case 274: // --sw-opti - opts.sw_opti = True; + ps->o.sw_opti = true; break; case 275: // --vsync-aggressive - opts.vsync_aggressive = True; + ps->o.vsync_aggressive = true; break; case 276: // --use-ewmh-active-win - opts.use_ewmh_active_win = True; + ps->o.use_ewmh_active_win = true; break; case 277: - // --respect-attr-shadow - opts.respect_attr_shadow = True; + // --respect-prop-shadow + ps->o.respect_prop_shadow = true; break; case 278: // --unredir-if-possible - opts.unredir_if_possible = True; + ps->o.unredir_if_possible = true; break; default: usage(); - break; } } @@ -4192,88 +4027,91 @@ get_cfg(int argc, char *const *argv) { free(lc_numeric_old); // Range checking and option assignments - 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); + ps->o.fade_delta = max_i(ps->o.fade_delta, 1); + ps->o.shadow_radius = max_i(ps->o.shadow_radius, 1); + ps->o.shadow_red = normalize_d(ps->o.shadow_red); + ps->o.shadow_green = normalize_d(ps->o.shadow_green); + ps->o.shadow_blue = normalize_d(ps->o.shadow_blue); + ps->o.inactive_dim = normalize_d(ps->o.inactive_dim); + ps->o.frame_opacity = normalize_d(ps->o.frame_opacity); + ps->o.shadow_opacity = normalize_d(ps->o.shadow_opacity); cfgtmp.menu_opacity = normalize_d(cfgtmp.menu_opacity); - opts.refresh_rate = normalize_i_range(opts.refresh_rate, 0, 300); - opts.alpha_step = normalize_d_range(opts.alpha_step, 0.01, 1.0); - if (OPAQUE == opts.inactive_opacity) { - opts.inactive_opacity = 0; + ps->o.refresh_rate = normalize_i_range(ps->o.refresh_rate, 0, 300); + ps->o.alpha_step = normalize_d_range(ps->o.alpha_step, 0.01, 1.0); + if (OPAQUE == ps->o.inactive_opacity) { + ps->o.inactive_opacity = 0; } if (shadow_enable) - wintype_arr_enable(opts.wintype_shadow); - opts.wintype_shadow[WINTYPE_DESKTOP] = False; + wintype_arr_enable(ps->o.wintype_shadow); + ps->o.wintype_shadow[WINTYPE_DESKTOP] = false; if (cfgtmp.no_dock_shadow) - opts.wintype_shadow[WINTYPE_DOCK] = False; + ps->o.wintype_shadow[WINTYPE_DOCK] = false; if (cfgtmp.no_dnd_shadow) - opts.wintype_shadow[WINTYPE_DND] = False; + ps->o.wintype_shadow[WINTYPE_DND] = false; if (fading_enable) - wintype_arr_enable(opts.wintype_fade); + wintype_arr_enable(ps->o.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; + ps->o.wintype_opacity[WINTYPE_DROPDOWN_MENU] = cfgtmp.menu_opacity; + ps->o.wintype_opacity[WINTYPE_POPUP_MENU] = cfgtmp.menu_opacity; } // Other variables determined by options // Determine whether we need to track focus changes - if (opts.inactive_opacity || opts.inactive_dim) { - opts.track_focus = True; + if (ps->o.inactive_opacity || ps->o.inactive_dim) { + ps->o.track_focus = true; } // Determine whether we need to track window name and class - if (opts.shadow_blacklist || opts.fade_blacklist) - opts.track_wdata = True; + if (ps->o.shadow_blacklist || ps->o.fade_blacklist) + ps->o.track_wdata = true; } +/** + * Fetch all required atoms and save them to a session. + */ static void -get_atoms(void) { - opacity_atom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False); - frame_extents_atom = XInternAtom(dpy, "_NET_FRAME_EXTENTS", False); - client_atom = XInternAtom(dpy, "WM_STATE", False); - name_atom = XA_WM_NAME; - name_ewmh_atom = XInternAtom(dpy, "_NET_WM_NAME", False); - class_atom = XA_WM_CLASS; - transient_atom = XA_WM_TRANSIENT_FOR; - ewmh_active_win_atom = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); - compton_shadow_atom = XInternAtom(dpy, "_COMPTON_SHADOW", False); - - win_type_atom = XInternAtom(dpy, +init_atoms(session_t *ps) { + ps->atom_opacity = XInternAtom(ps->dpy, "_NET_WM_WINDOW_OPACITY", False); + ps->atom_frame_extents = XInternAtom(ps->dpy, "_NET_FRAME_EXTENTS", False); + ps->atom_client = XInternAtom(ps->dpy, "WM_STATE", False); + ps->atom_name = XA_WM_NAME; + ps->atom_name_ewmh = XInternAtom(ps->dpy, "_NET_WM_NAME", False); + ps->atom_class = XA_WM_CLASS; + ps->atom_transient = XA_WM_TRANSIENT_FOR; + ps->atom_ewmh_active_win = XInternAtom(ps->dpy, "_NET_ACTIVE_WINDOW", False); + ps->atom_compton_shadow = XInternAtom(ps->dpy, "_COMPTON_SHADOW", False); + + ps->atom_win_type = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE", False); - win_type[WINTYPE_UNKNOWN] = 0; - win_type[WINTYPE_DESKTOP] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0; + ps->atoms_wintypes[WINTYPE_DESKTOP] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); - win_type[WINTYPE_DOCK] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DOCK] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); - win_type[WINTYPE_TOOLBAR] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_TOOLBAR] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); - win_type[WINTYPE_MENU] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_MENU] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_MENU", False); - win_type[WINTYPE_UTILITY] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_UTILITY] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); - win_type[WINTYPE_SPLASH] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_SPLASH] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); - win_type[WINTYPE_DIALOG] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DIALOG] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - win_type[WINTYPE_NORMAL] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_NORMAL] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); - win_type[WINTYPE_DROPDOWN_MENU] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DROPDOWN_MENU] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False); - win_type[WINTYPE_POPUP_MENU] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_POPUP_MENU] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False); - win_type[WINTYPE_TOOLTIP] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_TOOLTIP] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False); - win_type[WINTYPE_NOTIFY] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_NOTIFY] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False); - win_type[WINTYPE_COMBO] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_COMBO] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_COMBO", False); - win_type[WINTYPE_DND] = XInternAtom(dpy, + ps->atoms_wintypes[WINTYPE_DND] = XInternAtom(ps->dpy, "_NET_WM_WINDOW_TYPE_DND", False); } @@ -4281,49 +4119,49 @@ get_atoms(void) { * Update refresh rate info with X Randr extension. */ static void -update_refresh_rate(Display *dpy) { +update_refresh_rate(session_t *ps) { XRRScreenConfiguration* randr_info; - if (!(randr_info = XRRGetScreenInfo(dpy, root))) + if (!(randr_info = XRRGetScreenInfo(ps->dpy, ps->root))) return; - refresh_rate = XRRConfigCurrentRate(randr_info); + ps->refresh_rate = XRRConfigCurrentRate(randr_info); XRRFreeScreenConfigInfo(randr_info); - if (refresh_rate) - refresh_intv = NS_PER_SEC / refresh_rate; + if (ps->refresh_rate) + ps->refresh_intv = NS_PER_SEC / ps->refresh_rate; else - refresh_intv = 0; + ps->refresh_intv = 0; } /** * Initialize refresh-rated based software optimization. * - * @return True for success, False otherwise + * @return true for success, false otherwise */ -static Bool -sw_opti_init(void) { +static bool +sw_opti_init(session_t *ps) { // Prepare refresh rate // Check if user provides one - refresh_rate = opts.refresh_rate; - if (refresh_rate) - refresh_intv = NS_PER_SEC / refresh_rate; + ps->refresh_rate = ps->o.refresh_rate; + if (ps->refresh_rate) + ps->refresh_intv = NS_PER_SEC / ps->refresh_rate; // Auto-detect refresh rate otherwise - if (!refresh_rate && randr_exists) { - update_refresh_rate(dpy); + if (!ps->refresh_rate && ps->randr_exists) { + update_refresh_rate(ps); } // Turn off vsync_sw if we can't get the refresh rate - if (!refresh_rate) - return False; + if (!ps->refresh_rate) + return false; // Monitor screen changes only if vsync_sw is enabled and we are using // an auto-detected refresh rate - if (randr_exists && !opts.refresh_rate) - XRRSelectInput(dpy, root, RRScreenChangeNotify); + if (ps->randr_exists && !ps->o.refresh_rate) + XRRSelectInput(ps->dpy, ps->root, RRScreenChangeNotify); - return True; + return true; } /** @@ -4353,18 +4191,23 @@ lceil_ntimes(long dividend, long divisor) { * problems */ static int -evpoll(struct pollfd *fd, int timeout) { +evpoll(session_t *ps, int timeout) { + struct pollfd ufd = { + .fd = ConnectionNumber(ps->dpy), + .events = POLLIN + }; + // Always wait infinitely if asked so, to minimize CPU usage if (timeout < 0) { - int ret = poll(fd, 1, timeout); - // Reset fade_time so the fading steps during idling are not counted - fade_time = get_time_ms(); + int ret = poll(&ufd, 1, timeout); + // Reset ps->fade_time so the fading steps during idling are not counted + ps->fade_time = get_time_ms(); return ret; } // Just do a poll() if we are not using optimization - if (!opts.sw_opti) - return poll(fd, 1, timeout); + if (!ps->o.sw_opti) + return poll(&ufd, 1, timeout); // Convert the old timeout to struct timespec struct timespec next_paint_tmout = { @@ -4374,7 +4217,7 @@ evpoll(struct pollfd *fd, int timeout) { // Get the nanosecond offset of the time when the we reach the timeout // I don't think a 32-bit long could overflow here. - long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - paint_tm_offset) % NS_PER_SEC; + long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - ps->paint_tm_offset) % NS_PER_SEC; if (target_relative_offset < 0) target_relative_offset += NS_PER_SEC; @@ -4383,39 +4226,39 @@ evpoll(struct pollfd *fd, int timeout) { // If the target time is sufficiently close to a refresh time, don't add // an offset, to avoid certain blocking conditions. if ((target_relative_offset % NS_PER_SEC) < SW_OPTI_TOLERANCE) - return poll(fd, 1, timeout); + return poll(&ufd, 1, timeout); // Add an offset so we wait until the next refresh after timeout - next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, refresh_intv) - target_relative_offset; + next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, ps->refresh_intv) - target_relative_offset; if (next_paint_tmout.tv_nsec > NS_PER_SEC) { next_paint_tmout.tv_nsec -= NS_PER_SEC; ++next_paint_tmout.tv_sec; } - return ppoll(fd, 1, &next_paint_tmout, NULL); + return ppoll(&ufd, 1, &next_paint_tmout, NULL); } /** * Initialize DRM VSync. * - * @return True for success, False otherwise + * @return true for success, false otherwise */ -static Bool -vsync_drm_init(void) { +static bool +vsync_drm_init(session_t *ps) { #ifdef CONFIG_VSYNC_DRM // Should we always open card0? - if ((drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) { + if ((ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) { fprintf(stderr, "vsync_drm_init(): Failed to open device.\n"); - return False; + return false; } - if (vsync_drm_wait()) - return False; + if (vsync_drm_wait(ps)) + return false; - return True; + return true; #else fprintf(stderr, "Program not compiled with DRM VSync support.\n"); - return False; + return false; #endif } @@ -4426,7 +4269,7 @@ vsync_drm_init(void) { * Stolen from: https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp */ static int -vsync_drm_wait(void) { +vsync_drm_wait(session_t *ps) { int ret = -1; drm_wait_vblank_t vbl; @@ -4434,7 +4277,7 @@ vsync_drm_wait(void) { vbl.request.sequence = 1; do { - ret = ioctl(drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl); + ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl); vbl.request.type &= ~_DRM_VBLANK_RELATIVE; } while (ret && errno == EINTR); @@ -4443,7 +4286,7 @@ vsync_drm_wait(void) { "unimplemented in this drmver?\n"); return ret; - + } #endif @@ -4453,26 +4296,26 @@ vsync_drm_wait(void) { * Stolen from: http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e * Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html * - * @return True for success, False otherwise + * @return true for success, false otherwise */ -static Bool -vsync_opengl_init(void) { +static bool +vsync_opengl_init(session_t *ps) { #ifdef CONFIG_VSYNC_OPENGL // Get video sync functions - glx_get_video_sync = (f_GetVideoSync) + ps->glx_get_video_sync = (f_GetVideoSync) glXGetProcAddress ((const GLubyte *) "glXGetVideoSyncSGI"); - glx_wait_video_sync = (f_WaitVideoSync) + ps->glx_wait_video_sync = (f_WaitVideoSync) glXGetProcAddress ((const GLubyte *) "glXWaitVideoSyncSGI"); - if (!glx_wait_video_sync || !glx_get_video_sync) { + if (!ps->glx_wait_video_sync || !ps->glx_get_video_sync) { fprintf(stderr, "vsync_opengl_init(): " "Failed to get glXWait/GetVideoSyncSGI function.\n"); - return False; + return false; } - - return True; + + return true; #else fprintf(stderr, "Program not compiled with OpenGL VSync support.\n"); - return False; + return false; #endif } @@ -4481,11 +4324,11 @@ vsync_opengl_init(void) { * Wait for next VSync, OpenGL method. */ static void -vsync_opengl_wait(void) { +vsync_opengl_wait(session_t *ps) { unsigned vblank_count; - glx_get_video_sync(&vblank_count); - glx_wait_video_sync(2, (vblank_count + 1) % 2, &vblank_count); + ps->glx_get_video_sync(&vblank_count); + ps->glx_wait_video_sync(2, (vblank_count + 1) % 2, &vblank_count); // I see some code calling glXSwapIntervalSGI(1) afterwards, is it required? } #endif @@ -4494,20 +4337,20 @@ vsync_opengl_wait(void) { * Wait for next VSync. */ static void -vsync_wait(void) { - if (VSYNC_NONE == opts.vsync) +vsync_wait(session_t *ps) { + if (VSYNC_NONE == ps->o.vsync) return; #ifdef CONFIG_VSYNC_DRM - if (VSYNC_DRM == opts.vsync) { - vsync_drm_wait(); + if (VSYNC_DRM == ps->o.vsync) { + vsync_drm_wait(ps); return; } #endif #ifdef CONFIG_VSYNC_OPENGL - if (VSYNC_OPENGL == opts.vsync) { - vsync_opengl_wait(); + if (VSYNC_OPENGL == ps->o.vsync) { + vsync_opengl_wait(ps); return; } #endif @@ -4522,18 +4365,18 @@ vsync_wait(void) { * Pregenerate alpha pictures. */ static void -init_alpha_picts(Display *dpy) { +init_alpha_picts(session_t *ps) { int i; - int num = lround(1.0 / opts.alpha_step) + 1; + int num = lround(1.0 / ps->o.alpha_step) + 1; - alpha_picts = malloc(sizeof(Picture) * num); + ps->alpha_picts = malloc(sizeof(Picture) * num); for (i = 0; i < num; ++i) { - double o = i * opts.alpha_step; - if ((1.0 - o) > opts.alpha_step) - alpha_picts[i] = solid_picture(dpy, False, o, 0, 0, 0); + double o = i * ps->o.alpha_step; + if ((1.0 - o) > ps->o.alpha_step) + ps->alpha_picts[i] = solid_picture(ps, false, o, 0, 0, 0); else - alpha_picts[i] = None; + ps->alpha_picts[i] = None; } } @@ -4541,12 +4384,12 @@ init_alpha_picts(Display *dpy) { * Initialize double buffer. */ static void -init_dbe(void) { - if (!(root_dbe = XdbeAllocateBackBufferName(dpy, - (opts.paint_on_overlay ? overlay: root), XdbeCopied))) { +init_dbe(session_t *ps) { + if (!(ps->root_dbe = XdbeAllocateBackBufferName(ps->dpy, + (ps->o.paint_on_overlay ? ps->overlay: ps->root), XdbeCopied))) { fprintf(stderr, "Failed to create double buffer. Double buffering " "turned off.\n"); - opts.dbe = False; + ps->o.dbe = false; return; } } @@ -4555,27 +4398,27 @@ init_dbe(void) { * Initialize X composite overlay window. */ static void -init_overlay(void) { - overlay = XCompositeGetOverlayWindow(dpy, root); - if (overlay) { +init_overlay(session_t *ps) { + ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root); + if (ps->overlay) { // Set window region of the overlay window, code stolen from // compiz-0.8.8 - XserverRegion region = XFixesCreateRegion (dpy, NULL, 0); - XFixesSetWindowShapeRegion(dpy, overlay, ShapeBounding, 0, 0, 0); - XFixesSetWindowShapeRegion(dpy, overlay, ShapeInput, 0, 0, region); - XFixesDestroyRegion (dpy, region); + XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0); + XFixesSetWindowShapeRegion(ps->dpy, ps->overlay, ShapeBounding, 0, 0, 0); + XFixesSetWindowShapeRegion(ps->dpy, ps->overlay, ShapeInput, 0, 0, region); + XFixesDestroyRegion(ps->dpy, region); // Listen to Expose events on the overlay - XSelectInput(dpy, overlay, ExposureMask); + XSelectInput(ps->dpy, ps->overlay, ExposureMask); // Retrieve DamageNotify on root window if we are painting on an // overlay - // root_damage = XDamageCreate(dpy, root, XDamageReportNonEmpty); + // root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty); } else { fprintf(stderr, "Cannot get X Composite overlay window. Falling " "back to painting on root window.\n"); - opts.paint_on_overlay = False; + ps->o.paint_on_overlay = false; } } @@ -4583,23 +4426,23 @@ init_overlay(void) { * Redirect all windows. */ static void -redir_start(Display *dpy) { - if (!redirected) { +redir_start(session_t *ps) { + if (!ps->redirected) { #ifdef DEBUG_REDIR printf("redir_start(): Screen redirected.\n"); #endif // Map overlay window. Done firstly according to this: // https://bugzilla.gnome.org/show_bug.cgi?id=597014 - if (overlay) - XMapWindow(dpy, overlay); + if (ps->overlay) + XMapWindow(ps->dpy, ps->overlay); - XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); + XCompositeRedirectSubwindows(ps->dpy, ps->root, CompositeRedirectManual); // Must call XSync() here - XSync(dpy, False); + XSync(ps->dpy, False); - redirected = True; + ps->redirected = true; } } @@ -4607,103 +4450,252 @@ redir_start(Display *dpy) { * Unredirect all windows. */ static void -redir_stop(Display *dpy) { - if (redirected) { +redir_stop(session_t *ps) { + if (ps->redirected) { #ifdef DEBUG_REDIR printf("redir_stop(): Screen unredirected.\n"); #endif // Destroy all Pictures as they expire once windows are unredirected // If we don't destroy them here, looks like the resources are just // kept inaccessible somehow - for (win *w = list; w; w = w->next) { - free_pixmap(dpy, &w->pixmap); - free_picture(dpy, &w->picture); + for (win *w = ps->list; w; w = w->next) { + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); } - XCompositeUnredirectSubwindows(dpy, root, CompositeRedirectManual); - + XCompositeUnredirectSubwindows(ps->dpy, ps->root, CompositeRedirectManual); // Unmap overlay window - if (overlay) - XUnmapWindow(dpy, overlay); + if (ps->overlay) + XUnmapWindow(ps->dpy, ps->overlay); // Must call XSync() here - XSync(dpy, False); - - redirected = False; + XSync(ps->dpy, False); + ps->redirected = 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, ""); +/** + * Initialize a session. + * + * @param ps_old old session, from which the function will take the X + * connection, then free it + * @param argc number of commandline arguments + * @param argv commandline arguments + */ +static session_t * +session_init(session_t *ps_old, int argc, char **argv) { + const static session_t s_def = { + .dpy = NULL, + .scr = 0, + .vis = NULL, + .depth = 0, + .root = None, + .root_height = 0, + .root_width = 0, + // .root_damage = None, + .overlay = None, + .root_tile = None, + .screen_reg = None, + .tgt_picture = None, + .tgt_buffer = None, + .root_dbe = None, + .reg_win = None, + .o = { + .display = NULL, + .mark_wmwin_focused = false, + .mark_ovredir_focused = false, + .fork_after_register = false, + .synchronize = false, + .detect_rounded_corners = false, + .paint_on_overlay = false, + .unredir_if_possible = false, + + .refresh_rate = 0, + .sw_opti = false, + .vsync = VSYNC_NONE, + .dbe = false, + .vsync_aggressive = 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, + .respect_prop_shadow = false, + + .wintype_fade = { false }, + .fade_in_step = 0.028 * OPAQUE, + .fade_out_step = 0.03 * OPAQUE, + .fade_delta = 10, + .no_fading_openclose = false, + .fade_blacklist = NULL, + + .wintype_opacity = { 0.0 }, + .inactive_opacity = 0, + .inactive_opacity_override = false, + .frame_opacity = 0.0, + .detect_client_opacity = false, + .inactive_dim = 0.0, + .alpha_step = 0.03, + .use_ewmh_active_win = false, + + .track_focus = false, + .track_wdata = false, + }, + + .all_damage = None, + .time_start = { 0, 0 }, + .redirected = false, + .unredir_possible = false, + .alpha_picts = NULL, + .reg_ignore_expire = false, + .idling = false, + .fade_time = 0, + .ignore_head = NULL, + .ignore_tail = NULL, + .reset = false, + + .expose_rects = NULL, + .size_expose = 0, + .n_expose = 0, + + .list = NULL, + .active_win = NULL, + .black_picture = None, + .dim_picture = None, + .cshadow_picture = None, + .gaussian_map = NULL, + .cgsize = 0, + .shadow_corner = NULL, + .shadow_top = NULL, + + .refresh_rate = 0, + .refresh_intv = 0UL, + .paint_tm_offset = 0L, + + .drm_fd = 0, + + .glx_context = None, + .glx_get_video_sync = NULL, + .glx_wait_video_sync = NULL, + + .xfixes_event = 0, + .xfixes_error = 0, + .damage_event = 0, + .damage_error = 0, + .render_event = 0, + .render_error = 0, + .composite_event = 0, + .composite_error = 0, + .composite_opcode = 0, + .has_name_pixmap = false, + .shape_exists = false, + .shape_event = 0, + .shape_error = 0, + .randr_exists = 0, + .randr_event = 0, + .randr_error = 0, + .glx_exists = false, + .glx_event = 0, + .glx_error = 0, + .dbe_exists = false, + + .atom_opacity = None, + .atom_frame_extents = None, + .atom_client = None, + .atom_name = None, + .atom_name_ewmh = None, + .atom_class = None, + .atom_transient = None, + .atom_ewmh_active_win = None, + .atom_compton_shadow = None, + .atom_win_type = None, + .atoms_wintypes = { 0 } + }; - get_cfg(argc, argv); + int i; - dpy = XOpenDisplay(opts.display); - if (!dpy) { - fprintf(stderr, "Can't open display\n"); - exit(1); + // Allocate a session and copy default values into it + session_t *ps = malloc(sizeof(session_t)); + memcpy(ps, &s_def, sizeof(session_t)); + ps_g = ps; + ps->ignore_tail = &ps->ignore_head; + gettimeofday(&ps->time_start, NULL); + + get_cfg(ps, argc, argv); + + // Inherit old Display if possible, primarily for resource leak checking + if (ps_old && ps_old->dpy) + ps->dpy = ps_old->dpy; + + // Open Display + if (!ps->dpy) { + ps->dpy = XOpenDisplay(ps->o.display); + if (!ps->dpy) { + fprintf(stderr, "Can't open display\n"); + exit(1); + } } XSetErrorHandler(error); - if (opts.synchronize) { - XSynchronize(dpy, 1); + if (ps->o.synchronize) { + XSynchronize(ps->dpy, 1); } - scr = DefaultScreen(dpy); - root = RootWindow(dpy, scr); + ps->scr = DefaultScreen(ps->dpy); + ps->root = RootWindow(ps->dpy, ps->scr); - if (!XRenderQueryExtension(dpy, &render_event, &render_error)) { + ps->vis = DefaultVisual(ps->dpy, ps->scr); + ps->depth = DefaultDepth(ps->dpy, ps->scr); + + if (!XRenderQueryExtension(ps->dpy, + &ps->render_event, &ps->render_error)) { fprintf(stderr, "No render extension\n"); exit(1); } - if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, - &composite_event, &composite_error)) { + if (!XQueryExtension(ps->dpy, COMPOSITE_NAME, &ps->composite_opcode, + &ps->composite_event, &ps->composite_error)) { fprintf(stderr, "No composite extension\n"); exit(1); } - XCompositeQueryVersion(dpy, &composite_major, &composite_minor); + { + int composite_major = 0, composite_minor = 0; + + XCompositeQueryVersion(ps->dpy, &composite_major, &composite_minor); - if (composite_major > 0 || composite_minor >= 2) { - has_name_pixmap = True; + if (composite_major > 0 || composite_minor >= 2) { + ps->has_name_pixmap = true; + } } - if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) { + if (!XDamageQueryExtension(ps->dpy, &ps->damage_event, &ps->damage_error)) { fprintf(stderr, "No damage extension\n"); exit(1); } - if (!XFixesQueryExtension(dpy, &xfixes_event, &xfixes_error)) { + if (!XFixesQueryExtension(ps->dpy, &ps->xfixes_event, &ps->xfixes_error)) { fprintf(stderr, "No XFixes extension\n"); exit(1); } // Query X Shape - if (XShapeQueryExtension(dpy, &shape_event, &shape_error)) { - shape_exists = True; + if (XShapeQueryExtension(ps->dpy, &ps->shape_event, &ps->shape_error)) { + ps->shape_exists = true; } // Query X RandR - if (opts.sw_opti && !opts.refresh_rate) { - if (XRRQueryExtension(dpy, &randr_event, &randr_error)) - randr_exists = True; + if (ps->o.sw_opti && !ps->o.refresh_rate) { + if (XRRQueryExtension(ps->dpy, &ps->randr_event, &ps->randr_error)) + ps->randr_exists = true; else fprintf(stderr, "No XRandR extension, automatic refresh rate " "detection impossible.\n"); @@ -4711,170 +4703,368 @@ main(int argc, char **argv) { #ifdef CONFIG_VSYNC_OPENGL // Query X GLX extension - if (VSYNC_OPENGL == opts.vsync) { - if (glXQueryExtension(dpy, &glx_event, &glx_error)) - glx_exists = True; + if (VSYNC_OPENGL == ps->o.vsync) { + if (glXQueryExtension(ps->dpy, &ps->glx_event, &ps->glx_error)) + ps->glx_exists = true; else { fprintf(stderr, "No GLX extension, OpenGL VSync impossible.\n"); - opts.vsync = VSYNC_NONE; + ps->o.vsync = VSYNC_NONE; } } #endif // Query X DBE extension - if (opts.dbe) { + if (ps->o.dbe) { int dbe_ver_major = 0, dbe_ver_minor = 0; - if (XdbeQueryExtension(dpy, &dbe_ver_major, &dbe_ver_minor)) + if (XdbeQueryExtension(ps->dpy, &dbe_ver_major, &dbe_ver_minor)) if (dbe_ver_major >= 1) - dbe_exists = True; + ps->dbe_exists = true; else fprintf(stderr, "DBE extension version too low. Double buffering " "impossible.\n"); else { fprintf(stderr, "No DBE extension. Double buffering impossible.\n"); } - if (!dbe_exists) - opts.dbe = False; + if (!ps->dbe_exists) + ps->o.dbe = false; } - register_cm((VSYNC_OPENGL == opts.vsync)); + register_cm(ps, (VSYNC_OPENGL == ps->o.vsync)); // Initialize software optimization - if (opts.sw_opti) - opts.sw_opti = sw_opti_init(); + if (ps->o.sw_opti) + ps->o.sw_opti = sw_opti_init(ps); // Initialize DRM/OpenGL VSync - if ((VSYNC_DRM == opts.vsync && !vsync_drm_init()) - || (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init())) - opts.vsync = VSYNC_NONE; + if ((VSYNC_DRM == ps->o.vsync && !vsync_drm_init(ps)) + || (VSYNC_OPENGL == ps->o.vsync && !vsync_opengl_init(ps))) + ps->o.vsync = VSYNC_NONE; // Overlay must be initialized before double buffer - if (opts.paint_on_overlay) - init_overlay(); + if (ps->o.paint_on_overlay) + init_overlay(ps); - if (opts.dbe) - init_dbe(); + if (ps->o.dbe) + init_dbe(ps); - if (opts.fork_after_register) fork_after(); + if (ps->o.fork_after_register) fork_after(); - get_atoms(); - init_alpha_picts(dpy); + init_atoms(ps); + init_alpha_picts(ps); - pa.subwindow_mode = IncludeInferiors; + ps->gaussian_map = make_gaussian_map(ps->o.shadow_radius); + presum_gaussian(ps, ps->gaussian_map); - gaussian_map = make_gaussian_map(dpy, opts.shadow_radius); - presum_gaussian(gaussian_map); + ps->root_width = DisplayWidth(ps->dpy, ps->scr); + ps->root_height = DisplayHeight(ps->dpy, ps->scr); - root_width = DisplayWidth(dpy, scr); - root_height = DisplayHeight(dpy, scr); + rebuild_screen_reg(ps); - rebuild_screen_reg(dpy); + { + XRenderPictureAttributes pa; + pa.subwindow_mode = IncludeInferiors; - root_picture = XRenderCreatePicture(dpy, root, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), - CPSubwindowMode, &pa); - if (opts.paint_on_overlay) { - tgt_picture = XRenderCreatePicture(dpy, overlay, - XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)), + ps->root_picture = XRenderCreatePicture(ps->dpy, ps->root, + XRenderFindVisualFormat(ps->dpy, ps->vis), CPSubwindowMode, &pa); - } - else { - tgt_picture = root_picture; + if (ps->o.paint_on_overlay) { + ps->tgt_picture = XRenderCreatePicture(ps->dpy, ps->overlay, + XRenderFindVisualFormat(ps->dpy, ps->vis), + CPSubwindowMode, &pa); + } + else { + ps->tgt_picture = ps->root_picture; + } } - black_picture = solid_picture(dpy, True, 1, 0, 0, 0); + ps->black_picture = solid_picture(ps, true, 1, 0, 0, 0); // Generates another Picture for shadows if the color is modified by // user - if (!opts.shadow_red && !opts.shadow_green && !opts.shadow_blue) { - cshadow_picture = black_picture; + if (!ps->o.shadow_red && !ps->o.shadow_green && !ps->o.shadow_blue) { + ps->cshadow_picture = ps->black_picture; } else { - cshadow_picture = solid_picture(dpy, True, 1, - opts.shadow_red, opts.shadow_green, opts.shadow_blue); + ps->cshadow_picture = solid_picture(ps, true, 1, + ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue); } // Generates a picture for inactive_dim - if (opts.inactive_dim) { - dim_picture = solid_picture(dpy, True, opts.inactive_dim, 0, 0, 0); + if (ps->o.inactive_dim) { + ps->dim_picture = solid_picture(ps, true, ps->o.inactive_dim, 0, 0, 0); } - all_damage = None; - XGrabServer(dpy); + ps->all_damage = None; + XGrabServer(ps->dpy); - redir_start(dpy); + redir_start(ps); - XSelectInput(dpy, root, + XSelectInput(ps->dpy, ps->root, SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); - XQueryTree(dpy, root, &root_return, - &parent_return, &children, &nchildren); + { + Window root_return, parent_return; + Window *children; + unsigned int nchildren; + + XQueryTree(ps->dpy, ps->root, &root_return, + &parent_return, &children, &nchildren); + + for (i = 0; i < nchildren; i++) { + add_win(ps, children[i], i ? children[i-1] : None, false); + } - for (i = 0; i < nchildren; i++) { - add_win(dpy, children[i], i ? children[i-1] : None, False); + XFree(children); } - XFree(children); - if (opts.track_focus) { - recheck_focus(dpy); + if (ps->o.track_focus) { + recheck_focus(ps); } - XUngrabServer(dpy); + XUngrabServer(ps->dpy); + + // Free the old session + if (ps_old) + free(ps_old); + + return ps; +} + +/** + * Destroy a session. + * + * Does not close the X connection or free the <code>session_t</code> + * structure, though. + * + * @param ps session to destroy + */ +static void +session_destroy(session_t *ps) { + redir_stop(ps); + + // Stop listening to events on root window + XSelectInput(ps->dpy, ps->root, 0); - ufd.fd = ConnectionNumber(dpy); - ufd.events = POLLIN; + // Free window linked list + { + win *next = NULL; + for (win *w = ps->list; w; w = next) { + // Must be put here to avoid segfault + next = w->next; - if (opts.sw_opti) - paint_tm_offset = get_time_timespec().tv_nsec; + if (IsViewable == w->a.map_state && !w->destroyed) + win_ev_stop(ps, w); - reg_ignore_expire = True; + free_win_res(ps, w); + free(w); + } - fade_time = get_time_ms(); + ps->list = NULL; + } - t = paint_preprocess(dpy, list); + // Free alpha_picts + { + const int max = lround(1.0 / ps->o.alpha_step) + 1; + for (int i = 0; i < max; ++i) + free_picture(ps, &ps->alpha_picts[i]); + free(ps->alpha_picts); + ps->alpha_picts = NULL; + } + + // Free blacklists + free_wincondlst(&ps->o.shadow_blacklist); + free_wincondlst(&ps->o.fade_blacklist); + + // Free ignore linked list + { + ignore_t *next = NULL; + for (ignore_t *ign = ps->ignore_head; ign; ign = next) { + next = ign->next; - if (redirected) - paint_all(dpy, None, t); + free(ign); + } + + // Reset head and tail + ps->ignore_head = NULL; + ps->ignore_tail = &ps->ignore_head; + } + + // Free cshadow_picture and black_picture + if (ps->cshadow_picture == ps->black_picture) + ps->cshadow_picture = None; + else + free_picture(ps, &ps->cshadow_picture); + + free_picture(ps, &ps->black_picture); + + // Free tgt_{buffer,picture} and root_picture + if (ps->tgt_buffer == ps->tgt_picture) + ps->tgt_buffer = None; + else + free_picture(ps, &ps->tgt_buffer); + + if (ps->tgt_picture == ps->root_picture) + ps->tgt_picture = None; + else + free_picture(ps, &ps->tgt_picture); + + free_picture(ps, &ps->root_picture); + + // Free other X resources + free_picture(ps, &ps->dim_picture); + free_picture(ps, &ps->root_tile); + free_region(ps, &ps->screen_reg); + free_region(ps, &ps->all_damage); + free(ps->expose_rects); + free(ps->shadow_corner); + free(ps->shadow_top); + free(ps->gaussian_map); + free(ps->o.display); + + // Free reg_win and glx_context + if (ps->reg_win) { + XDestroyWindow(ps->dpy, ps->reg_win); + ps->reg_win = None; + } + if (ps->glx_context) { + glXDestroyContext(ps->dpy, ps->glx_context); + ps->glx_context = None; + } + + // Free double buffer + if (ps->root_dbe) { + XdbeDeallocateBackBufferName(ps->dpy, ps->root_dbe); + ps->root_dbe = None; + } + + // Close file opened for DRM VSync + if (ps->drm_fd) { + close(ps->drm_fd); + ps->drm_fd = 0; + } + + // Release overlay window + if (ps->overlay) { + XCompositeReleaseOverlayWindow(ps->dpy, ps->overlay); + ps->overlay = None; + } + + // Flush all events + XSync(ps->dpy, True); + + if (ps == ps_g) + ps_g = NULL; +} + +/** + * Do the actual work. + * + * @param ps current session + */ +static void +session_run(session_t *ps) { + win *t; + + if (ps->o.sw_opti) + ps->paint_tm_offset = get_time_timespec().tv_nsec; + + ps->reg_ignore_expire = true; + + ps->fade_time = get_time_ms(); + + t = paint_preprocess(ps, ps->list); + + if (ps->redirected) + paint_all(ps, None, t); // Initialize idling - idling = False; + ps->idling = false; // Main loop - while (1) { - Bool ev_received = False; + while (!ps->reset) { + bool ev_received = false; - while (XEventsQueued(dpy, QueuedAfterReading) - || (evpoll(&ufd, - (ev_received ? 0: (idling ? -1: fade_timeout()))) > 0)) { + while (XEventsQueued(ps->dpy, QueuedAfterReading) + || (evpoll(ps, + (ev_received ? 0: (ps->idling ? -1: fade_timeout(ps)))) > 0)) { // Sometimes poll() returns 1 but no events are actually read, // causing XNextEvent() to block, I have no idea what's wrong, so we // check for the number of events here - if (XEventsQueued(dpy, QueuedAfterReading)) { - XNextEvent(dpy, &ev); - ev_handle((XEvent *) &ev); - ev_received = True; + if (XEventsQueued(ps->dpy, QueuedAfterReading)) { + XEvent ev; + + XNextEvent(ps->dpy, &ev); + ev_handle(ps, &ev); + ev_received = true; } } // idling will be turned off during paint_preprocess() if needed - idling = True; + ps->idling = true; - t = paint_preprocess(dpy, list); + t = paint_preprocess(ps, ps->list); // If the screen is unredirected, free all_damage to stop painting - if (!redirected) - free_region(dpy, &all_damage); + if (!ps->redirected) + free_region(ps, &ps->all_damage); - if (all_damage && !is_region_empty(dpy, all_damage)) { + if (ps->all_damage && !is_region_empty(ps, ps->all_damage)) { static int paint; - paint_all(dpy, all_damage, t); - reg_ignore_expire = False; + paint_all(ps, ps->all_damage, t); + ps->reg_ignore_expire = false; paint++; - XSync(dpy, False); - all_damage = None; + XSync(ps->dpy, False); + ps->all_damage = None; } } } + +/** + * Turn on the program reset flag. + * + * This will result in compton resetting itself after next paint. + */ +static void +reset_enable(int __attribute__((unused)) signum) { + session_t * const ps = ps_g; + + ps->reset = true; +} + +/** + * The function that everybody knows. + */ +int +main(int argc, char **argv) { + // Set locale so window names with special characters are interpreted + // correctly + setlocale(LC_ALL, ""); + + // Set up SIGUSR1 signal handler to reset program + { + sigset_t block_mask; + sigemptyset(&block_mask); + const struct sigaction action= { + .sa_handler = reset_enable, + .sa_mask = block_mask, + .sa_flags = 0 + }; + sigaction(SIGUSR1, &action, NULL); + } + + // Main loop + session_t *ps_old = ps_g; + while (1) { + ps_g = session_init(ps_old, argc, argv); + session_run(ps_g); + ps_old = ps_g; + session_destroy(ps_g); + } + + free(ps_g); + + return 0; +} @@ -15,6 +15,7 @@ // #define DEBUG_WINDATA 1 // #define DEBUG_WINMATCH 1 // #define DEBUG_REDIR 1 +// #define DEBUG_ALLOC_REG 1 // #define MONITOR_REPAINT 1 // Whether to enable PCRE regular expression support in blacklists, enabled @@ -48,8 +49,8 @@ #include <stdbool.h> #include <locale.h> #include <assert.h> - #include <fnmatch.h> +#include <signal.h> #ifdef CONFIG_REGEX_PCRE #include <pcre.h> @@ -75,6 +76,7 @@ #include <X11/extensions/shape.h> #include <X11/extensions/Xrandr.h> #include <X11/extensions/Xdbe.h> +#include <time.h> #ifdef CONFIG_VSYNC_DRM #include <fcntl.h> @@ -90,58 +92,6 @@ #include <GL/glx.h> #endif -static void -print_timestamp(void); - -#ifdef DEBUG_ALLOC_REG - -#include <execinfo.h> -#define BACKTRACE_SIZE 5 - -/** - * Print current backtrace, excluding the first two items. - * - * Stolen from glibc manual. - */ -static inline void -print_backtrace(void) { - void *array[BACKTRACE_SIZE]; - size_t size; - char **strings; - - size = backtrace(array, BACKTRACE_SIZE); - strings = backtrace_symbols(array, size); - - for (size_t i = 2; i < size; i++) - printf ("%s\n", strings[i]); - - free(strings); -} - -static inline XserverRegion -XFixesCreateRegion_(Display *dpy, XRectangle *p, int n, - const char *func, int line) { - XserverRegion reg = XFixesCreateRegion(dpy, p, n); - print_timestamp(); - printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line); - print_backtrace(); - fflush(stdout); - return reg; -} - -static inline void -XFixesDestroyRegion_(Display *dpy, XserverRegion reg, - const char *func, int line) { - XFixesDestroyRegion(dpy, reg); - print_timestamp(); - printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line); - fflush(stdout); -} - -#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__) -#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__) -#endif - // === Constants === #if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2) #error libXcomposite version unsupported @@ -150,10 +100,6 @@ XFixesDestroyRegion_(Display *dpy, XserverRegion reg, #define ROUNDED_PERCENT 0.05 #define ROUNDED_PIXELS 10 -// For printing timestamps -#include <time.h> -extern struct timeval time_start; - #define OPAQUE 0xffffffff #define REGISTER_PROP "_NET_WM_CM_S" @@ -194,7 +140,7 @@ typedef enum { WINTYPE_COMBO, WINTYPE_DND, NUM_WINTYPES -} wintype; +} wintype_t; typedef enum { WINDOW_SOLID, @@ -204,13 +150,13 @@ typedef enum { typedef struct { unsigned char *data; - int nitems; -} winattr_t; + unsigned long nitems; +} winprop_t; typedef struct _ignore { struct _ignore *next; unsigned long sequence; -} ignore; +} ignore_t; enum wincond_target { CONDTGT_NAME, @@ -238,8 +184,311 @@ typedef struct _wincond { #endif int16_t flags; struct _wincond *next; -} wincond; +} wincond_t; + +/// VSync modes. +typedef enum { + VSYNC_NONE, + VSYNC_DRM, + VSYNC_OPENGL, +} vsync_t; + +#ifdef CONFIG_VSYNC_OPENGL +typedef int (*f_WaitVideoSync) (int, int, unsigned *); +typedef int (*f_GetVideoSync) (unsigned *); +#endif + +typedef struct { + int size; + double *data; +} conv; + +struct _win; +/// Structure representing all options. +typedef struct { + // === General === + char *display; + /// Whether to try to detect WM windows and mark them as focused. + bool mark_wmwin_focused; + /// Whether to mark override-redirect windows as focused. + bool mark_ovredir_focused; + /// Whether to fork to background. + bool fork_after_register; + /// Whether to detect rounded corners. + bool detect_rounded_corners; + /// Whether to paint on X Composite overlay window instead of root + /// window. + bool paint_on_overlay; + /// Whether to unredirect all windows if a full-screen opaque window + /// is detected. + bool unredir_if_possible; + /// Whether to work under synchronized mode for debugging. + bool synchronize; + + // === VSync & software optimization === + /// User-specified refresh rate. + int refresh_rate; + /// Whether to enable refresh-rate-based software optimization. + bool sw_opti; + /// VSync method to use; + vsync_t vsync; + /// Whether to enable double buffer. + bool dbe; + /// Whether to do VSync aggressively. + bool vsync_aggressive; + + // === Shadow === + bool wintype_shadow[NUM_WINTYPES]; + /// Red, green and blue tone of the shadow. + double shadow_red, shadow_green, shadow_blue; + int shadow_radius; + int shadow_offset_x, shadow_offset_y; + double shadow_opacity; + bool clear_shadow; + /// Shadow blacklist. A linked list of conditions. + wincond_t *shadow_blacklist; + /// Whether bounding-shaped window should be ignored. + bool shadow_ignore_shaped; + /// Whether to respect _COMPTON_SHADOW. + bool respect_prop_shadow; + + // === Fading === + bool wintype_fade[NUM_WINTYPES]; + /// How much to fade in in a single fading step. + opacity_t fade_in_step; + /// How much to fade out in a single fading step. + opacity_t fade_out_step; + unsigned long fade_delta; + /// Whether to disable fading on window open/close. + bool no_fading_openclose; + /// Fading blacklist. A linked list of conditions. + wincond_t *fade_blacklist; + + // === Opacity === + double wintype_opacity[NUM_WINTYPES]; + /// Default opacity for inactive windows. + /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for + /// not enabled, default. + opacity_t inactive_opacity; + /// Whether inactive_opacity overrides the opacity set by window + /// attributes. + bool inactive_opacity_override; + /// Frame opacity. Relative to window opacity, also affects shadow + /// opacity. + double frame_opacity; + /// Whether to detect _NET_WM_OPACITY on client windows. Used on window + /// managers that don't pass _NET_WM_OPACITY to frame windows. + bool detect_client_opacity; + /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable. + double inactive_dim; + /// Step for pregenerating alpha pictures. 0.01 - 1.0. + double alpha_step; + /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window. + bool use_ewmh_active_win; + + // === Calculated === + /// Whether compton needs to track focus changes. + bool track_focus; + /// Whether compton needs to track window name and class. + bool track_wdata; + +} options_t; + +/// Structure containing all necessary data for a compton session. +typedef struct { + // === Display related === + /// Display in use. + Display *dpy; + /// Default screen. + int scr; + /// Default visual. + Visual *vis; + /// Default depth. + int depth; + /// Root window. + Window root; + /// Height of root window. + int root_height; + /// Width of root window. + int root_width; + // Damage of root window. + // Damage root_damage; + /// X Composite overlay window. Used if <code>--paint-on-overlay</code>. + Window overlay; + /// Picture of the root window background. + Picture root_tile; + /// A region of the size of the screen. + XserverRegion screen_reg; + /// Picture of root window. Destination of painting in no-DBE painting + /// mode. + Picture root_picture; + /// A Picture acting as the painting target. + Picture tgt_picture; + /// Temporary buffer to paint to before sending to display. + Picture tgt_buffer; + /// DBE back buffer for root window. Used in DBE painting mode. + XdbeBackBuffer root_dbe; + /// Window ID of the window we register as a symbol. + Window reg_win; + + // === Operation related === + /// Program options. + options_t o; + /// Program start time. + struct timeval time_start; + /// The region needs to painted on next paint. + XserverRegion all_damage; + /// Whether all windows are currently redirected. + bool redirected; + /// Whether there's a highest full-screen window, and all windows could + /// be unredirected. + bool unredir_possible; + /// Pre-generated alpha pictures. + Picture *alpha_picts; + /// Whether all reg_ignore of windows should expire in this paint. + bool reg_ignore_expire; + /// Whether the program is idling. I.e. no fading, no potential window + /// changes. + bool idling; + /// Time of last fading. In milliseconds. + unsigned long fade_time; + /// Head pointer of the error ignore linked list. + ignore_t *ignore_head; + /// Pointer to the <code>next</code> member of tail element of the error + /// ignore linked list. + ignore_t **ignore_tail; + /// Reset program after next paint. + bool reset; + + // === Expose event related === + /// Pointer to an array of <code>XRectangle</code>-s of exposed region. + XRectangle *expose_rects; + /// Number of <code>XRectangle</code>-s in <code>expose_rects</code>. + int size_expose; + /// Index of the next free slot in <code>expose_rects</code>. + int n_expose; + + // === Window related === + /// Linked list of all windows. + struct _win *list; + /// Current active window. Used by EWMH _NET_ACTIVE_WINDOW focus + /// detection. + struct _win *active_win; + + // === Shadow/dimming related === + /// 1x1 black Picture. + Picture black_picture; + /// Picture used for dimming inactive windows. + Picture dim_picture; + /// 1x1 Picture of the shadow color. + Picture cshadow_picture; + /// Gaussian map of shadow. + conv *gaussian_map; + // for shadow precomputation + /// Shadow depth on one side. + int cgsize; + /// Pre-computed color table for corners of shadow. + unsigned char *shadow_corner; + /// Pre-computed color table for a side of shadow. + unsigned char *shadow_top; + + // === Software-optimization-related === + /// Currently used refresh rate. + short refresh_rate; + /// Interval between refresh in nanoseconds. + unsigned long refresh_intv; + /// Nanosecond offset of the first painting. + long paint_tm_offset; + + #ifdef CONFIG_VSYNC_DRM + // === DRM VSync related === + /// File descriptor of DRI device file. Used for DRM VSync. + int drm_fd; + #endif + + #ifdef CONFIG_VSYNC_OPENGL + // === OpenGL VSync related === + /// GLX context. + GLXContext glx_context; + /// Pointer to glXGetVideoSyncSGI function. + f_GetVideoSync glx_get_video_sync; + /// Pointer to glXWaitVideoSyncSGI function. + f_WaitVideoSync glx_wait_video_sync; + #endif + + // === X extension related === + /// Event base number for X Fixes extension. + int xfixes_event; + /// Error base number for X Fixes extension. + int xfixes_error; + /// Event base number for X Damage extension. + int damage_event; + /// Error base number for X Damage extension. + int damage_error; + /// Event base number for X Render extension. + int render_event; + /// Error base number for X Render extension. + int render_error; + /// Event base number for X Composite extension. + int composite_event; + /// Error base number for X Composite extension. + int composite_error; + /// Major opcode for X Composite extension. + int composite_opcode; + /// Whether X Composite NameWindowPixmap is available. Aka if X + /// Composite version >= 0.2. + bool has_name_pixmap; + /// Whether X Shape extension exists. + bool shape_exists; + /// Event base number for X Shape extension. + int shape_event; + /// Error base number for X Shape extension. + int shape_error; + /// Whether X RandR extension exists. + bool randr_exists; + /// Event base number for X RandR extension. + int randr_event; + /// Error base number for X RandR extension. + int randr_error; + #ifdef CONFIG_VSYNC_OPENGL + /// Whether X GLX extension exists. + bool glx_exists; + /// Event base number for X GLX extension. + int glx_event; + /// Error base number for X GLX extension. + int glx_error; + #endif + /// Whether X DBE extension exists. + bool dbe_exists; + + // === Atoms === + /// Atom of property <code>_NET_WM_OPACITY</code>. + Atom atom_opacity; + /// Atom of <code>_NET_FRAME_EXTENTS</code>. + Atom atom_frame_extents; + /// Property atom to identify top-level frame window. Currently + /// <code>WM_STATE</code>. + Atom atom_client; + /// Atom of property <code>WM_NAME</code>. + Atom atom_name; + /// Atom of property <code>_NET_WM_NAME</code>. + Atom atom_name_ewmh; + /// Atom of property <code>WM_CLASS</code>. + Atom atom_class; + /// Atom of property <code>WM_TRANSIENT_FOR</code>. + Atom atom_transient; + /// Atom of property <code>_NET_ACTIVE_WINDOW</code>. + Atom atom_ewmh_active_win; + /// Atom of property <code>_COMPTON_SHADOW</code>. + Atom atom_compton_shadow; + /// Atom of property <code>_NET_WM_WINDOW_TYPE</code>. + Atom atom_win_type; + /// Array of atoms of all possible window types. + Atom atoms_wintypes[NUM_WINTYPES]; +} session_t; + +/// Structure representing a top-level window compton manages. typedef struct _win { struct _win *next; Window id; @@ -253,25 +502,26 @@ typedef struct _win { XserverRegion border_size; XserverRegion extents; // Type of the window. - wintype window_type; + wintype_t window_type; /// Whether the window is focused. - Bool focused; - Bool destroyed; + bool focused; + /// Whether the window has been destroyed. + bool destroyed; /// Cached width/height of the window including border. int widthb, heightb; /// Whether the window is bounding-shaped. - Bool bounding_shaped; + bool bounding_shaped; /// Whether the window just have rounded corners. - Bool rounded_corners; - /// Whether this window is to be painted - Bool to_paint; + bool rounded_corners; + /// Whether this window is to be painted. + bool to_paint; // Blacklist related members char *name; char *class_instance; char *class_general; - wincond *cache_sblst; - wincond *cache_fblst; + wincond_t *cache_sblst; + wincond_t *cache_fblst; // Opacity-related members /// Current window opacity. @@ -290,9 +540,9 @@ typedef struct _win { // Fading-related members /// Do not fade if it's false. Change on window type change. /// Used by fading blacklist in the future. - Bool fade; + bool fade; /// Callback to be called after fading completed. - void (*fade_callback) (Display *dpy, struct _win *w); + void (*fade_callback) (session_t *ps, struct _win *w); // Frame-opacity-related members /// Current window frame opacity. Affected by window opacity. @@ -304,7 +554,7 @@ typedef struct _win { // Shadow-related members /// Whether a window has shadow. Affected by window type. - Bool shadow; + bool shadow; /// Opacity of the shadow. Affected by window opacity and frame opacity. double shadow_opacity; /// X offset of shadow. Affected by commandline argument. @@ -325,14 +575,17 @@ typedef struct _win { // Dim-related members /// Whether the window is to be dimmed. - Bool dim; + bool dim; /// Window flags. Definitions above. int_fast16_t flags; unsigned long damage_sequence; /* sequence when damage was created */ - Bool need_configure; + /// Whether there's a pending <code>ConfigureNotify</code> happening + /// when the window is unmapped. + bool need_configure; + /// Queued <code>ConfigureNotify</code> when the window is unmapped. XConfigureEvent queue_configure; /// Region to be ignored when painting. Basically the region where /// higher opaque windows will paint upon. Depends on window frame @@ -343,132 +596,83 @@ typedef struct _win { struct _win *prev_trans; } win; -/// VSync modes. -typedef enum { - VSYNC_NONE, - VSYNC_DRM, - VSYNC_OPENGL, -} vsync_t; - -#ifdef CONFIG_VSYNC_OPENGL -typedef int (*f_WaitVideoSync) (int, int, unsigned *); -typedef int (*f_GetVideoSync) (unsigned *); -#endif - -typedef struct { - // General - char *display; - /// Whether to try to detect WM windows and mark them as focused. - Bool mark_wmwin_focused; - /// Whether to mark override-redirect windows as focused. - Bool mark_ovredir_focused; - /// Whether to fork to background. - Bool fork_after_register; - /// Whether to detect rounded corners. - Bool detect_rounded_corners; - /// Whether to paint on X Composite overlay window instead of root - /// window. - Bool paint_on_overlay; - /// Whether to unredirect all windows if a full-screen opaque window - /// is detected. - Bool unredir_if_possible; - /// Whether to work under synchronized mode for debugging. - Bool synchronize; - - // VSync and software optimization - /// User-specified refresh rate. - int refresh_rate; - /// Whether to enable refresh-rate-based software optimization. - Bool sw_opti; - /// VSync method to use; - vsync_t vsync; - /// Whether to enable double buffer. - Bool dbe; - /// Whether to do VSync aggressively. - Bool vsync_aggressive; - - // Shadow - Bool wintype_shadow[NUM_WINTYPES]; - /// Red, green and blue tone of the shadow. - double shadow_red, shadow_green, shadow_blue; - int shadow_radius; - int shadow_offset_x, shadow_offset_y; - double shadow_opacity; - Bool clear_shadow; - /// Shadow blacklist. A linked list of conditions. - wincond *shadow_blacklist; - /// Whether bounding-shaped window should be ignored. - Bool shadow_ignore_shaped; - /// Whether to respect _COMPTON_SHADOW. - Bool respect_attr_shadow; - - // Fading - Bool wintype_fade[NUM_WINTYPES]; - /// How much to fade in in a single fading step. - opacity_t fade_in_step; - /// How much to fade out in a single fading step. - opacity_t fade_out_step; - unsigned long fade_delta; - Bool no_fading_openclose; - /// Fading blacklist. A linked list of conditions. - wincond *fade_blacklist; - - // Opacity - double wintype_opacity[NUM_WINTYPES]; - /// Default opacity for inactive windows. - /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for - /// not enabled, default. - opacity_t inactive_opacity; - /// Whether inactive_opacity overrides the opacity set by window - /// attributes. - Bool inactive_opacity_override; - /// Frame opacity. Relative to window opacity, also affects shadow - /// opacity. - double frame_opacity; - /// Whether to detect _NET_WM_OPACITY on client windows. Used on window - /// managers that don't pass _NET_WM_OPACITY to frame windows. - Bool detect_client_opacity; - /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable. - double inactive_dim; - /// Step for pregenerating alpha pictures. 0.01 - 1.0. - double alpha_step; - /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window. - Bool use_ewmh_active_win; - - // Calculated - /// Whether compton needs to track focus changes. - Bool track_focus; - /// Whether compton needs to track window name and class. - Bool track_wdata; - -} options_t; - +/// Temporary structure used for communication between +/// <code>get_cfg()</code> and <code>parse_config()</code>. struct options_tmp { - Bool no_dock_shadow; - Bool no_dnd_shadow; + bool no_dock_shadow; + bool no_dnd_shadow; double menu_opacity; }; -typedef struct _conv { - int size; - double *data; -} conv; - typedef enum { WIN_EVMODE_UNKNOWN, WIN_EVMODE_FRAME, WIN_EVMODE_CLIENT } win_evmode_t; -extern int root_height, root_width; -extern Atom atom_client_attr; -extern Bool idling; -extern Bool shape_exists; -extern Bool reg_ignore_expire; +extern const char *WINTYPES[NUM_WINTYPES]; +extern session_t *ps_g; + +// == Debugging code == +static void +print_timestamp(session_t *ps); + +#ifdef DEBUG_ALLOC_REG + +#include <execinfo.h> +#define BACKTRACE_SIZE 5 + +/** + * Print current backtrace, excluding the first two items. + * + * Stolen from glibc manual. + */ +static inline void +print_backtrace(void) { + void *array[BACKTRACE_SIZE]; + size_t size; + char **strings; + + size = backtrace(array, BACKTRACE_SIZE); + strings = backtrace_symbols(array, size); + + for (size_t i = 2; i < size; i++) + printf ("%s\n", strings[i]); + + free(strings); +} + +/** + * Wrapper of <code>XFixesCreateRegion</code>, for debugging. + */ +static inline XserverRegion +XFixesCreateRegion_(Display *dpy, XRectangle *p, int n, + const char *func, int line) { + XserverRegion reg = XFixesCreateRegion(dpy, p, n); + print_timestamp(ps_g); + printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line); + print_backtrace(); + fflush(stdout); + return reg; +} /** - * Functions + * Wrapper of <code>XFixesDestroyRegion</code>, for debugging. */ +static inline void +XFixesDestroyRegion_(Display *dpy, XserverRegion reg, + const char *func, int line) { + XFixesDestroyRegion(dpy, reg); + print_timestamp(ps_g); + printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line); + fflush(stdout); +} + +#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__) +#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__) +#endif + +// == Functions == // inline functions must be made static to compile correctly under clang: // http://clang.llvm.org/compatibility.html#inline @@ -476,40 +680,45 @@ extern Bool reg_ignore_expire; // Helper functions static void -discard_ignore(Display *dpy, unsigned long sequence); +discard_ignore(session_t *ps, unsigned long sequence); static void -set_ignore(Display *dpy, unsigned long sequence); +set_ignore(session_t *ps, unsigned long sequence); + +static inline void +set_ignore_next(session_t *ps) { + set_ignore(ps, NextRequest(ps->dpy)); +} static int -should_ignore(Display *dpy, unsigned long sequence); +should_ignore(session_t *ps, unsigned long sequence); /** * Subtract two unsigned long values. * * Truncate to 0 if the result is negative. */ -static inline unsigned long +static inline unsigned long __attribute__((const)) sub_unslong(unsigned long a, unsigned long b) { return (a > b) ? a - b : 0; } /** - * Set a Bool array of all wintypes to true. + * Set a <code>bool</code> array of all wintypes to true. */ static void -wintype_arr_enable(Bool arr[]) { - wintype i; +wintype_arr_enable(bool arr[]) { + wintype_t i; for (i = 0; i < NUM_WINTYPES; ++i) { - arr[i] = True; + arr[i] = true; } } /** * Allocate the space and copy a string. */ -static inline char * +static inline char * __attribute__((const)) mstrcpy(const char *src) { char *str = malloc(sizeof(char) * (strlen(src) + 1)); @@ -521,7 +730,7 @@ mstrcpy(const char *src) { /** * Allocate the space and join two strings. */ -static inline char * +static inline char * __attribute__((const)) mstrjoin(const char *src1, const char *src2) { char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2) + 1)); @@ -534,7 +743,7 @@ mstrjoin(const char *src1, const char *src2) { /** * Allocate the space and join two strings; */ -static inline char * +static inline char * __attribute__((const)) mstrjoin3(const char *src1, const char *src2, const char *src3) { char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2) + strlen(src3) + 1)); @@ -554,7 +763,7 @@ mstrjoin3(const char *src1, const char *src2, const char *src3) { * @param max maximum value * @return normalized value */ -static inline int +static inline int __attribute__((const)) normalize_i_range(int i, int min, int max) { if (i > max) return max; if (i < min) return min; @@ -564,7 +773,7 @@ normalize_i_range(int i, int min, int max) { /** * Select the larger integer of two. */ -static inline int +static inline int __attribute__((const)) max_i(int a, int b) { return (a > b ? a : b); } @@ -572,7 +781,7 @@ max_i(int a, int b) { /** * Select the smaller integer of two. */ -static inline int +static inline int __attribute__((const)) min_i(int a, int b) { return (a > b ? b : a); } @@ -585,7 +794,7 @@ min_i(int a, int b) { * @param max maximum value * @return normalized value */ -static inline double +static inline double __attribute__((const)) normalize_d_range(double d, double min, double max) { if (d > max) return max; if (d < min) return min; @@ -598,7 +807,7 @@ normalize_d_range(double d, double min, double max) { * @param d double value to normalize * @return normalized value */ -static inline double +static inline double __attribute__((const)) normalize_d(double d) { return normalize_d_range(d, 0.0, 1.0); } @@ -610,15 +819,15 @@ normalize_d(double d) { * @param count amount of elements in the array * @param wid window ID to search for */ -static inline Bool +static inline bool array_wid_exists(const Window *arr, int count, Window wid) { while (count--) { if (arr[count] == wid) { - return True; + return true; } } - return False; + return false; } /* @@ -695,9 +904,9 @@ timespec_subtract(struct timespec *result, * * Note its starting time is unspecified. */ -static inline struct timespec +static inline struct timespec __attribute__((const)) get_time_timespec(void) { - struct timespec tm = { 0 }; + struct timespec tm = { 0, 0 }; clock_gettime(CLOCK_MONOTONIC, &tm); @@ -711,12 +920,12 @@ get_time_timespec(void) { * Used for debugging. */ static void -print_timestamp(void) { +print_timestamp(session_t *ps) { struct timeval tm, diff; if (gettimeofday(&tm, NULL)) return; - timeval_subtract(&diff, &tm, &time_start); + timeval_subtract(&diff, &tm, &ps->time_start); printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000); } @@ -724,9 +933,9 @@ print_timestamp(void) { * Destroy a <code>XserverRegion</code>. */ inline static void -free_region(Display *dpy, XserverRegion *p) { +free_region(session_t *ps, XserverRegion *p) { if (*p) { - XFixesDestroyRegion(dpy, *p); + XFixesDestroyRegion(ps->dpy, *p); *p = None; } } @@ -735,9 +944,9 @@ free_region(Display *dpy, XserverRegion *p) { * Destroy a <code>Picture</code>. */ inline static void -free_picture(Display *dpy, Picture *p) { +free_picture(session_t *ps, Picture *p) { if (*p) { - XRenderFreePicture(dpy, *p); + XRenderFreePicture(ps->dpy, *p); *p = None; } } @@ -746,9 +955,9 @@ free_picture(Display *dpy, Picture *p) { * Destroy a <code>Pixmap</code>. */ inline static void -free_pixmap(Display *dpy, Pixmap *p) { +free_pixmap(session_t *ps, Pixmap *p) { if (*p) { - XFreePixmap(dpy, *p); + XFreePixmap(ps->dpy, *p); *p = None; } } @@ -757,16 +966,65 @@ free_pixmap(Display *dpy, Pixmap *p) { * Destroy a <code>Damage</code>. */ inline static void -free_damage(Display *dpy, Damage *p) { +free_damage(session_t *ps, Damage *p) { if (*p) { // BadDamage will be thrown if the window is destroyed - set_ignore(dpy, NextRequest(dpy)); - XDamageDestroy(dpy, *p); + set_ignore_next(ps); + XDamageDestroy(ps->dpy, *p); *p = None; } } /** + * Destroy a <code>wincond_t</code>. + */ +inline static void +free_wincond(wincond_t *cond) { + if (cond->pattern) + free(cond->pattern); +#ifdef CONFIG_REGEX_PCRE + if (cond->regex_pcre_extra) + pcre_free_study(cond->regex_pcre_extra); + if (cond->regex_pcre) + pcre_free(cond->regex_pcre); +#endif + free(cond); +} + +/** + * Destroy a linked list of <code>wincond_t</code>. + */ +inline static void +free_wincondlst(wincond_t **cond_lst) { + wincond_t *next = NULL; + + for (wincond_t *cond = *cond_lst; cond; cond = next) { + next = cond->next; + + free_wincond(cond); + } + + *cond_lst = NULL; +} + +/** + * Destroy all resources in a <code>struct _win</code>. + */ +inline static void +free_win_res(session_t *ps, win *w) { + free_region(ps, &w->extents); + free_pixmap(ps, &w->pixmap); + free_picture(ps, &w->picture); + free_region(ps, &w->border_size); + free_picture(ps, &w->shadow_pict); + free_damage(ps, &w->damage); + free_region(ps, &w->reg_ignore); + free(w->name); + free(w->class_instance); + free(w->class_general); +} + +/** * Get current system clock in milliseconds. * * The return type must be unsigned long because so many milliseconds have @@ -782,53 +1040,51 @@ get_time_ms(void) { } static int -fade_timeout(void); +fade_timeout(session_t *ps); static void -run_fade(Display *dpy, win *w, unsigned steps); +run_fade(session_t *ps, win *w, unsigned steps); static void -set_fade_callback(Display *dpy, win *w, - void (*callback) (Display *dpy, win *w), Bool exec_callback); +set_fade_callback(session_t *ps, win *w, + void (*callback) (session_t *ps, win *w), bool exec_callback); /** * Execute fade callback of a window if fading finished. */ static inline void -check_fade_fin(Display *dpy, win *w) { +check_fade_fin(session_t *ps, win *w) { if (w->fade_callback && w->opacity == w->opacity_tgt) { // Must be the last line as the callback could destroy w! - set_fade_callback(dpy, w, NULL, True); + set_fade_callback(ps, w, NULL, true); } } static void -set_fade_callback(Display *dpy, win *w, - void (*callback) (Display *dpy, win *w), Bool exec_callback); +set_fade_callback(session_t *ps, win *w, + void (*callback) (session_t *ps, win *w), bool exec_callback); static double gaussian(double r, double x, double y); static conv * -make_gaussian_map(Display *dpy, double r); +make_gaussian_map(double r); static unsigned char sum_gaussian(conv *map, double opacity, int x, int y, int width, int height); static void -presum_gaussian(conv *map); +presum_gaussian(session_t *ps, conv *map); static XImage * -make_shadow(Display *dpy, double opacity, - int width, int height, Bool clear_shadow); +make_shadow(session_t *ps, double opacity, int width, int height); static Picture -shadow_picture(Display *dpy, double opacity, int width, int height, - Bool clear_shadow); +shadow_picture(session_t *ps, double opacity, int width, int height); static Picture -solid_picture(Display *dpy, Bool argb, double a, +solid_picture(session_t *ps, bool argb, double a, double r, double g, double b); static inline bool is_normal_win(const win *w) { @@ -839,25 +1095,25 @@ static inline bool is_normal_win(const win *w) { /** * Determine if a window has a specific attribute. * - * @param dpy Display to use + * @param session_t current session * @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) { +static inline bool +wid_has_attr(const session_t *ps, 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, + if (Success == XGetWindowProperty(ps->dpy, w, atom, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data)) { XFree(data); - if (type) return True; + if (type) return true; } - return False; + return false; } /** @@ -866,17 +1122,17 @@ wid_has_attr(Display *dpy, Window w, Atom atom) { * Returns a blank structure if the returned type and format does not * match the requested type and format. * - * @param dpy Display to use + * @param session_t current session * @param w window * @param atom atom of attribute to fetch * @param length length to read * @param rtype atom of the requested type * @param rformat requested format - * @return a <code>winattr_t</code> structure containing the attribute + * @return a <code>winprop_t</code> structure containing the attribute * and number of items. A blank one on failure. */ -static winattr_t -wid_get_attr(Display *dpy, Window w, Atom atom, long length, +static winprop_t +wid_get_prop(const session_t *ps, Window w, Atom atom, long length, Atom rtype, int rformat) { Atom type = None; int format = 0; @@ -884,10 +1140,10 @@ wid_get_attr(Display *dpy, Window w, Atom atom, long length, unsigned char *data = NULL; // Use two if statements to deal with the sequence point issue. - if (Success == XGetWindowProperty(dpy, w, atom, 0L, length, False, + if (Success == XGetWindowProperty(ps->dpy, w, atom, 0L, length, False, rtype, &type, &format, &nitems, &after, &data)) { if (type == rtype && format == rformat) { - return (winattr_t) { + return (winprop_t) { .data = data, .nitems = nitems }; @@ -896,83 +1152,102 @@ wid_get_attr(Display *dpy, Window w, Atom atom, long length, XFree(data); - return (winattr_t) { + return (winprop_t) { .data = NULL, .nitems = 0 }; } /** - * Free a <code>winattr_t</code>. + * Free a <code>winprop_t</code>. * - * @param pattr pointer to the <code>winattr_t</code> to free. + * @param pprop pointer to the <code>winprop_t</code> to free. */ static inline void -free_winattr(winattr_t *pattr) { +free_winprop(winprop_t *pprop) { // Empty the whole structure to avoid possible issues - if (pattr->data) { - XFree(pattr->data); - pattr->data = NULL; + if (pprop->data) { + XFree(pprop->data); + pprop->data = NULL; + } + pprop->nitems = 0; +} + +/** + * Stop listening for events on a particular window. + */ +static inline void +win_ev_stop(session_t *ps, win *w) { + // Will get BadWindow if the window is destroyed + set_ignore_next(ps); + XSelectInput(ps->dpy, w->id, 0); + + if (w->client_win) { + set_ignore_next(ps); + XSelectInput(ps->dpy, w->client_win, 0); + } + + if (ps->shape_exists) { + set_ignore_next(ps); + XShapeSelectInput(ps->dpy, w->id, 0); } - pattr->nitems = 0; } /** * Get the children of a window. * - * @param dpy Display to use + * @param session_t current session * @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, +static inline bool +wid_get_children(session_t *ps, Window w, Window **children, unsigned *nchildren) { Window troot, tparent; - if (!XQueryTree(dpy, w, &troot, &tparent, children, nchildren)) { + if (!XQueryTree(ps->dpy, w, &troot, &tparent, children, nchildren)) { *nchildren = 0; - return False; + return false; } - return True; + 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; +static inline bool +wid_bounding_shaped(const session_t *ps, Window wid) { + if (ps->shape_exists) { + Bool bounding_shaped = False, clip_shaped = False; int x_bounding, y_bounding, x_clip, y_clip; unsigned int w_bounding, h_bounding, w_clip, h_clip; - XShapeQueryExtents(dpy, wid, &bounding_shaped, + XShapeQueryExtents(ps->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; + + return false; } /** - * Determine if a window change affects reg_ignore and set - * reg_ignore_expire accordingly. + * Determine if a window change affects <code>reg_ignore</code> and set + * <code>reg_ignore_expire</code> accordingly. */ static inline void -update_reg_ignore_expire(const win *w) { +update_reg_ignore_expire(session_t *ps, const win *w) { if (w->to_paint && WINDOW_SOLID == w->mode) - reg_ignore_expire = True; + ps->reg_ignore_expire = true; } /** * Check whether a window has WM frames. */ -static inline bool +static inline bool __attribute__((const)) win_has_frame(const win *w) { return w->top_width || w->left_width || w->right_width || w->bottom_width; @@ -984,261 +1259,261 @@ win_has_frame(const win *w) { * It's not using w->border_size for performance measures. */ static inline bool -win_is_fullscreen(const win *w) { - return (w->a.x <= 0 && w->a.y <= 0 && (w->a.x + w->widthb) >= root_width - && (w->a.y + w->heightb) >= root_height && !w->bounding_shaped); +win_is_fullscreen(session_t *ps, const win *w) { + return (w->a.x <= 0 && w->a.y <= 0 + && (w->a.x + w->widthb) >= ps->root_width + && (w->a.y + w->heightb) >= ps->root_height + && !w->bounding_shaped); } static void -win_rounded_corners(Display *dpy, win *w); +win_rounded_corners(session_t *ps, win *w); static bool -win_match_once(win *w, const wincond *cond); +win_match_once(win *w, const wincond_t *cond); static bool -win_match(win *w, wincond *condlst, wincond * *cache); +win_match(win *w, wincond_t *condlst, wincond_t * *cache); -static Bool -condlst_add(wincond **pcondlst, const char *pattern); +static bool +condlst_add(wincond_t **pcondlst, const char *pattern); static long -determine_evmask(Display *dpy, Window wid, win_evmode_t mode); +determine_evmask(session_t *ps, Window wid, win_evmode_t mode); static win * -find_win(Window id); +find_win(session_t *ps, Window id); static win * -find_toplevel(Window id); +find_toplevel(session_t *ps, Window id); static win * -find_toplevel2(Display *dpy, Window wid); +find_toplevel2(session_t *ps, Window wid); static win * -recheck_focus(Display *dpy); +recheck_focus(session_t *ps); static Picture -root_tile_f(Display *dpy); +root_tile_f(session_t *ps); static void -paint_root(Display *dpy); +paint_root(session_t *ps, Picture tgt_buffer); static XserverRegion -win_extents(Display *dpy, win *w); +win_extents(session_t *ps, win *w); static XserverRegion -border_size(Display *dpy, win *w); +border_size(session_t *ps, win *w); static Window -find_client_win(Display *dpy, Window w); +find_client_win(session_t *ps, Window w); static void -get_frame_extents(Display *dpy, win *w, Window client); +get_frame_extents(session_t *ps, win *w, Window client); static win * -paint_preprocess(Display *dpy, win *list); +paint_preprocess(session_t *ps, win *list); static void -paint_all(Display *dpy, XserverRegion region, win *t); +paint_all(session_t *ps, XserverRegion region, win *t); static void -add_damage(Display *dpy, XserverRegion damage); +add_damage(session_t *ps, XserverRegion damage); static void -repair_win(Display *dpy, win *w); +repair_win(session_t *ps, win *w); -static wintype -get_wintype_prop(Display * dpy, Window w); +static wintype_t +wid_get_prop_wintype(session_t *ps, Window w); static void -map_win(Display *dpy, Window id, - unsigned long sequence, Bool fade, - Bool override_redirect); +map_win(session_t *ps, Window id, bool override_redirect); static void -finish_map_win(Display *dpy, win *w); +finish_map_win(session_t *ps, win *w); static void -finish_unmap_win(Display *dpy, win *w); +finish_unmap_win(session_t *ps, win *w); static void -unmap_callback(Display *dpy, win *w); +unmap_callback(session_t *ps, win *w); static void -unmap_win(Display *dpy, Window id, Bool fade); +unmap_win(session_t *ps, Window id); static opacity_t -wid_get_opacity_prop(Display *dpy, Window wid, opacity_t def); +wid_get_opacity_prop(session_t *ps, Window wid, opacity_t def); static double -get_opacity_percent(Display *dpy, win *w); +get_opacity_percent(win *w); static void -determine_mode(Display *dpy, win *w); +determine_mode(session_t *ps, win *w); static void -calc_opacity(Display *dpy, win *w, Bool refetch_prop); +calc_opacity(session_t *ps, win *w, bool refetch_prop); static void -calc_dim(Display *dpy, win *w); +calc_dim(session_t *ps, win *w); static inline void -set_focused(Display *dpy, win *w, Bool focused) { +set_focused(session_t *ps, win *w, bool focused) { w->focused = focused; - calc_opacity(dpy, w, False); - calc_dim(dpy, w); + calc_opacity(ps, w, false); + calc_dim(ps, w); } static void -determine_fade(Display *dpy, win *w); +determine_fade(session_t *ps, win *w); static void -win_update_shape_raw(Display *dpy, win *w); +win_update_shape_raw(session_t *ps, win *w); static void -win_update_shape(Display *dpy, win *w); +win_update_shape(session_t *ps, win *w); static void -win_update_attr_shadow_raw(Display *dpy, win *w); +win_update_attr_shadow_raw(session_t *ps, win *w); static void -win_update_attr_shadow(Display *dpy, win *w); +win_update_attr_shadow(session_t *ps, win *w); static void -determine_shadow(Display *dpy, win *w); +determine_shadow(session_t *ps, win *w); static void -calc_win_size(Display *dpy, win *w); +calc_win_size(session_t *ps, win *w); static void -calc_shadow_geometry(Display *dpy, win *w); +calc_shadow_geometry(session_t *ps, win *w); static void -mark_client_win(Display *dpy, win *w, Window client); +mark_client_win(session_t *ps, win *w, Window client); static void -add_win(Display *dpy, Window id, Window prev, Bool override_redirect); +add_win(session_t *ps, Window id, Window prev, bool override_redirect); static void -restack_win(Display *dpy, win *w, Window new_above); +restack_win(session_t *ps, win *w, Window new_above); static void -configure_win(Display *dpy, XConfigureEvent *ce); +configure_win(session_t *ps, XConfigureEvent *ce); static void -circulate_win(Display *dpy, XCirculateEvent *ce); +circulate_win(session_t *ps, XCirculateEvent *ce); static void -finish_destroy_win(Display *dpy, Window id); +finish_destroy_win(session_t *ps, Window id); static void -destroy_callback(Display *dpy, win *w); +destroy_callback(session_t *ps, win *w); static void -destroy_win(Display *dpy, Window id, Bool fade); +destroy_win(session_t *ps, Window id); static void -damage_win(Display *dpy, XDamageNotifyEvent *de); +damage_win(session_t *ps, XDamageNotifyEvent *de); static int error(Display *dpy, XErrorEvent *ev); static void -expose_root(Display *dpy, XRectangle *rects, int nrects); +expose_root(session_t *ps, XRectangle *rects, int nrects); -static Bool -wid_get_text_prop(Display *dpy, Window wid, Atom prop, +static bool +wid_get_text_prop(session_t *ps, Window wid, Atom prop, char ***pstrlst, int *pnstr); -static Bool -wid_get_name(Display *dpy, Window w, char **name); +static bool +wid_get_name(session_t *ps, Window w, char **name); static int -win_get_name(Display *dpy, win *w); +win_get_name(session_t *ps, win *w); -static Bool -win_get_class(Display *dpy, win *w); +static bool +win_get_class(session_t *ps, win *w); #ifdef DEBUG_EVENTS static int ev_serial(XEvent *ev); static const char * -ev_name(XEvent *ev); +ev_name(session_t *ps, XEvent *ev); static Window -ev_window(XEvent *ev); +ev_window(session_t *ps, XEvent *ev); #endif -static void +static void __attribute__ ((noreturn)) usage(void); static void -register_cm(Bool want_glxct); +register_cm(session_t *ps, bool want_glxct); inline static void -ev_focus_in(XFocusChangeEvent *ev); +ev_focus_in(session_t *ps, XFocusChangeEvent *ev); inline static void -ev_focus_out(XFocusChangeEvent *ev); +ev_focus_out(session_t *ps, XFocusChangeEvent *ev); inline static void -ev_create_notify(XCreateWindowEvent *ev); +ev_create_notify(session_t *ps, XCreateWindowEvent *ev); inline static void -ev_configure_notify(XConfigureEvent *ev); +ev_configure_notify(session_t *ps, XConfigureEvent *ev); inline static void -ev_destroy_notify(XDestroyWindowEvent *ev); +ev_destroy_notify(session_t *ps, XDestroyWindowEvent *ev); inline static void -ev_map_notify(XMapEvent *ev); +ev_map_notify(session_t *ps, XMapEvent *ev); inline static void -ev_unmap_notify(XUnmapEvent *ev); +ev_unmap_notify(session_t *ps, XUnmapEvent *ev); inline static void -ev_reparent_notify(XReparentEvent *ev); +ev_reparent_notify(session_t *ps, XReparentEvent *ev); inline static void -ev_circulate_notify(XCirculateEvent *ev); +ev_circulate_notify(session_t *ps, XCirculateEvent *ev); inline static void -ev_expose(XExposeEvent *ev); +ev_expose(session_t *ps, XExposeEvent *ev); static void -update_ewmh_active_win(Display *dpy); +update_ewmh_active_win(session_t *ps); inline static void -ev_property_notify(XPropertyEvent *ev); +ev_property_notify(session_t *ps, XPropertyEvent *ev); inline static void -ev_damage_notify(XDamageNotifyEvent *ev); +ev_damage_notify(session_t *ps, XDamageNotifyEvent *ev); inline static void -ev_shape_notify(XShapeEvent *ev); +ev_shape_notify(session_t *ps, XShapeEvent *ev); /** * Get a region of the screen size. */ inline static XserverRegion -get_screen_region(Display *dpy) { +get_screen_region(session_t *ps) { XRectangle r; r.x = 0; r.y = 0; - r.width = root_width; - r.height = root_height; - return XFixesCreateRegion(dpy, &r, 1); + r.width = ps->root_width; + r.height = ps->root_height; + return XFixesCreateRegion(ps->dpy, &r, 1); } /** * Copies a region */ inline static XserverRegion -copy_region(Display *dpy, XserverRegion oldregion) { - XserverRegion region = XFixesCreateRegion(dpy, NULL, 0); +copy_region(const session_t *ps, XserverRegion oldregion) { + XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0); - XFixesCopyRegion(dpy, region, oldregion); + XFixesCopyRegion(ps->dpy, region, oldregion); return region; } @@ -1247,9 +1522,9 @@ copy_region(Display *dpy, XserverRegion oldregion) { * Dump a region. */ static inline void -dump_region(Display *dpy, XserverRegion region) { +dump_region(const session_t *ps, XserverRegion region) { int nrects = 0, i; - XRectangle *rects = XFixesFetchRegion(dpy, region, &nrects); + XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects); if (!rects) return; @@ -1265,11 +1540,14 @@ dump_region(Display *dpy, XserverRegion region) { * * Keith Packard said this is slow: * http://lists.freedesktop.org/archives/xorg/2007-November/030467.html + * + * @param ps current session + * @param region region to check for */ -static inline Bool -is_region_empty(Display *dpy, XserverRegion region) { +static inline bool +is_region_empty(const session_t *ps, XserverRegion region) { int nrects = 0; - XRectangle *rects = XFixesFetchRegion(dpy, region, &nrects); + XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects); XFree(rects); @@ -1279,36 +1557,49 @@ is_region_empty(Display *dpy, XserverRegion region) { /** * Add a window to damaged area. * - * @param dpy display in use + * @param ps current session * @param w struct _win element representing the window */ static inline void -add_damage_win(Display *dpy, win *w) { +add_damage_win(session_t *ps, win *w) { if (w->extents) { - add_damage(dpy, copy_region(dpy, w->extents)); + add_damage(ps, copy_region(ps, w->extents)); } } #if defined(DEBUG_EVENTS) || defined(DEBUG_RESTACK) static bool -ev_window_name(Display *dpy, Window wid, char **name); +ev_window_name(session_t *ps, Window wid, char **name); #endif inline static void -ev_handle(XEvent *ev); +ev_handle(session_t *ps, XEvent *ev); static void fork_after(void); #ifdef CONFIG_LIBCONFIG +/** + * Wrapper of libconfig's <code>config_lookup_int</code>. + * + * To convert <code>int</code> value <code>config_lookup_bool</code> + * returns to <code>bool</code>. + */ static inline void -lcfg_lookup_bool(const config_t *config, const char *path, Bool *value) { +lcfg_lookup_bool(const config_t *config, const char *path, + bool *value) { int ival; if (config_lookup_bool(config, path, &ival)) *value = ival; } +/** + * Wrapper of libconfig's <code>config_lookup_int</code>. + * + * To deal with the different value types <code>config_lookup_int</code> + * returns in libconfig-1.3 and libconfig-1.4. + */ static inline int lcfg_lookup_int(const config_t *config, const char *path, int *value) { #ifndef CONFIG_LIBCONFIG_LEGACY @@ -1328,54 +1619,66 @@ static FILE * open_config_file(char *cpath, char **path); static void -parse_config(char *cpath, struct options_tmp *pcfgtmp); +parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp); #endif static void -get_cfg(int argc, char *const *argv); +get_cfg(session_t *ps, int argc, char *const *argv); static void -get_atoms(void); +init_atoms(session_t *ps); static void -update_refresh_rate(Display *dpy); +update_refresh_rate(session_t *ps); -static Bool -sw_opti_init(void); +static bool +sw_opti_init(session_t *ps); static int -evpoll(struct pollfd *fd, int timeout); +evpoll(session_t *ps, int timeout); -static Bool -vsync_drm_init(void); +static bool +vsync_drm_init(session_t *ps); #ifdef CONFIG_VSYNC_DRM static int -vsync_drm_wait(void); +vsync_drm_wait(session_t *ps); #endif -static Bool -vsync_opengl_init(void); +static bool +vsync_opengl_init(session_t *ps); #ifdef CONFIG_VSYNC_OPENGL static void -vsync_opengl_wait(void); +vsync_opengl_wait(session_t *ps); #endif static void -vsync_wait(void); +vsync_wait(session_t *ps); + +static void +init_alpha_picts(session_t *ps); static void -init_alpha_picts(Display *dpy); +init_dbe(session_t *ps); static void -init_dbe(void); +init_overlay(session_t *ps); + +static void +redir_start(session_t *ps); + +static void +redir_stop(session_t *ps); + +static session_t * +session_init(session_t *ps_old, int argc, char **argv); static void -init_overlay(void); +session_destroy(session_t *ps); static void -redir_start(Display *dpy); +session_run(session_t *ps); static void -redir_stop(Display *dpy); +reset_enable(int __attribute__((unused)) signum); |