From 3521f10a978d5a82234eec2b24f92a4144014ec6 Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Tue, 8 Jan 2013 08:50:58 +0800 Subject: [PATCH] Improvement #74: Use libevent for main loop - Use libevent for main loop. I will explain the reasons in #56 later. The preferred libevent version is 2.x, yet 1.4.x should work as well. - As a result, compton now should build fine on *BSD. Thanks to DachiChang for the FreeBSD build issue report. - Another consequence is we now use microsecond-level timing all the way. Nanosecond-level code will be dropped soon. Start using long instead of unsigned long to represent time in milliseconds, as both can't hold the full epoch time in ms, anyway, and a signed type requires less care in subtraction. Wrap the epoch time in ms to 15 days. - Fix broken NO_VSYNC_DRM and NO_VSYNC_OPENGL compile-time options. - Use git revision number for versioning in Makefile, and other small improvements. - Reorganize struct _win. Drop unused w->damaged_sequence. w->damaged is turned to bool. - Add type and format to winprop_t, as preparation for the new condition format. - Add w->shadow_force and w->focus_force, to prepare for D-Bus support. - Rename wid_get_prop() to wid_get_prop_adv() with more options. Add wrapper function wid_get_prop(). - Add some extra helper functions, for D-Bus support later. - Make some functions return a bool value to indicate if it's successful. - Modify add_win(), use a static const structure to initialize the new struct _win. - Add some helper macros, like printf_err(f)(q). Make some errors fatal. - Rename some types, constants, and functions. Code clean-up. - Check for time disorder in paint_preprocess() when calculating fading steps. - Rename evpoll() to swopti_handle_timeout(), and partially rewrite it. - Make -h / --help legal. - Known issue: compton segfaults on FreeBSD with nvidia-drivers, unless NO_VSYNC_OPENGL is used. Will look into it later. Thamls to DachiChang for reporting. --- Makefile | 72 +++++-- README.md | 1 + src/compton.c | 513 +++++++++++++++++++++++++++++++------------------- src/compton.h | 314 ++++++++++++++++++++++-------- 4 files changed, 614 insertions(+), 286 deletions(-) diff --git a/Makefile b/Makefile index 10e6f17..ba47769 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# Use tab to indent recipe lines, spaces to indent other lines, otherwise +# GNU make may get unhappy. + CC ?= gcc PREFIX ?= /usr @@ -8,44 +11,79 @@ PACKAGES = x11 xcomposite xfixes xdamage xrender xext xrandr LIBS = -lm -lrt INCS = -# Parse configuration flags +# === Configuration flags === CFG = +# ==== libevent ==== +# Seemingly, libevent1 has no pkg-config file! +# FreeBSD 9.1 probably has issues handling --atleast-version in pkg-config. +ifeq "$(shell pkg-config --modversion --print-errors libevent)" "" + $(warning libevent-2.0 not found, assuming libevent-1.4.x.) + CFG += -DCONFIG_LIBEVENT_LEGACY + LIBS += -levent +else + # Using pkg-config for linking with libevent will result in linking with + # libevent.so instead of the smaller libevent_core.so. But FreeBSD keeps + # libevent2 .so files at a separate place, and we must learn it from + # pkg-config. + LIBS += $(shell pkg-config --libs libevent) + INCS += $(shell pkg-config --cflags libevent) +endif + +# ==== libconfig ==== ifeq "$(NO_LIBCONFIG)" "" - CFG += -DCONFIG_LIBCONFIG - PACKAGES += libconfig + CFG += -DCONFIG_LIBCONFIG + PACKAGES += libconfig - # libconfig-1.3* does not define LIBCONFIG_VER* macros, so we use - # pkg-config to determine its version here - CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY') + # libconfig-1.3* does not define LIBCONFIG_VER* macros, so we use + # pkg-config to determine its version here + CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY') endif +# ==== PCRE regular expression ==== ifeq "$(NO_REGEX_PCRE)" "" - CFG += -DCONFIG_REGEX_PCRE - LIBS += $(shell pcre-config --libs) - INCS += $(shell pcre-config --cflags) - ifeq "$(NO_REGEX_PCRE_JIT)" "" - CFG += -DCONFIG_REGEX_PCRE_JIT - endif + CFG += -DCONFIG_REGEX_PCRE + LIBS += $(shell pcre-config --libs) + INCS += $(shell pcre-config --cflags) + ifeq "$(NO_REGEX_PCRE_JIT)" "" + CFG += -DCONFIG_REGEX_PCRE_JIT + endif endif +# ==== DRM VSync ==== ifeq "$(NO_VSYNC_DRM)" "" - CFG += -DCONFIG_VSYNC_DRM + CFG += -DCONFIG_VSYNC_DRM endif +# ==== OpenGL VSync ==== ifeq "$(NO_VSYNC_OPENGL)" "" - CFG += -DCONFIG_VSYNC_OPENGL - LIBS += -lGL + CFG += -DCONFIG_VSYNC_OPENGL + LIBS += -lGL endif -CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 +# ==== D-Bus ==== +# ifeq "$(NO_DBUS)" "" +# CFG += -DCONFIG_DBUS +# PACKAGES += dbus-1 +# endif + +# === Version string === +COMPTON_VERSION ?= git-$(shell git describe --always) +CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\"" + +LDFLAGS ?= -Wl,-O1 -Wl,--as-needed +CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2 $(LDFLAGS) CFLAGS += $(CFG) LIBS += $(shell pkg-config --libs $(PACKAGES)) INCS += $(shell pkg-config --cflags $(PACKAGES)) + CFLAGS += -Wall -std=c99 OBJS = compton.o +# === Recipes === +.DEFAULT_GOAL := compton + %.o: src/%.c src/%.h $(CC) $(CFLAGS) $(INCS) -c src/$*.c @@ -75,4 +113,4 @@ uninstall: clean: @rm -f $(OBJS) compton -.PHONY: uninstall clean +.PHONY: uninstall clean docs diff --git a/README.md b/README.md index 5d77134..f2d3a8a 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ __R__ for runtime * libdrm (B) (Will probably be made optional soon) * libGL (B,R) (Will probably be made optional soon) * asciidoc (B) (if you wish to run `make docs`) +* libevent (B,R) ### How to build diff --git a/src/compton.c b/src/compton.c index eff195f..7707126 100644 --- a/src/compton.c +++ b/src/compton.c @@ -1196,15 +1196,19 @@ paint_preprocess(session_t *ps, win *list) { bool is_highest = true; // Fading step calculation - unsigned steps = (sub_unslong(get_time_ms(), ps->fade_time) - + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta; + time_ms_t steps = ((get_time_ms() - ps->fade_time) + FADE_DELTA_TOLERANCE * ps->o.fade_delta) / ps->o.fade_delta; + if (steps < 0L) { + // Time disorder + ps->fade_time = get_time_ms(); + steps = 0; + } ps->fade_time += steps * ps->o.fade_delta; XserverRegion last_reg_ignore = None; for (w = list; w; w = next) { bool to_paint = true; - const winmode mode_old = w->mode; + const winmode_t mode_old = w->mode; // In case calling the fade callback function destroys this window next = w->next; @@ -1274,7 +1278,7 @@ paint_preprocess(session_t *ps, win *list) { else w->frame_opacity = 0.0; - if (w->to_paint && WINDOW_SOLID == mode_old + if (w->to_paint && WMODE_SOLID == mode_old && (0.0 == frame_opacity_old) != (0.0 == w->frame_opacity)) ps->reg_ignore_expire = true; } @@ -1308,8 +1312,8 @@ paint_preprocess(session_t *ps, win *list) { } - if ((to_paint && WINDOW_SOLID == w->mode) - != (w->to_paint && WINDOW_SOLID == mode_old)) + if ((to_paint && WMODE_SOLID == w->mode) + != (w->to_paint && WMODE_SOLID == mode_old)) ps->reg_ignore_expire = true; // Add window to damaged area if its painting status changes @@ -1323,7 +1327,7 @@ paint_preprocess(session_t *ps, win *list) { // If the window is solid, we add the window region to the // ignored region - if (WINDOW_SOLID == w->mode) { + if (WMODE_SOLID == w->mode) { if (!w->frame_opacity) { if (w->border_size) w->reg_ignore = copy_region(ps, w->border_size); @@ -1352,7 +1356,7 @@ paint_preprocess(session_t *ps, win *list) { if (is_highest && to_paint) { is_highest = false; - if (WINDOW_SOLID == w->mode + if (WMODE_SOLID == w->mode && (!w->frame_opacity || !win_has_frame(w)) && win_is_fullscreen(ps, w)) ps->unredir_possible = true; @@ -1473,7 +1477,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer, // Minimize the region we try to blur, if the window itself is not // opaque, only the frame is. - if (WINDOW_SOLID == w->mode && w->frame_opacity) { + if (WMODE_SOLID == w->mode && w->frame_opacity) { XserverRegion reg_all = border_size(ps, w, false); XserverRegion reg_noframe = win_get_region_noframe(ps, w, false); XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe); @@ -1506,7 +1510,7 @@ win_paint_win(session_t *ps, win *w, Picture tgt_buffer) { int hei = w->heightb; Picture alpha_mask = (OPAQUE == w->opacity ? None: w->alpha_pict); - int op = (w->mode == WINDOW_SOLID ? PictOpSrc: PictOpOver); + int op = (w->mode == WMODE_SOLID ? PictOpSrc: PictOpOver); if (!w->frame_opacity) { XRenderComposite(ps->dpy, op, w->picture, alpha_mask, @@ -1713,7 +1717,7 @@ paint_all(session_t *ps, XserverRegion region, win *t) { if (!is_region_empty(ps, reg_paint)) { XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer, 0, 0, reg_paint); // Blur window background - if ((ps->o.blur_background && WINDOW_SOLID != w->mode) + if ((ps->o.blur_background && WMODE_SOLID != w->mode) || (ps->o.blur_background_frame && w->frame_opacity)) { win_blur_background(ps, w, ps->tgt_buffer, reg_paint); } @@ -1815,7 +1819,7 @@ repair_win(session_t *ps, win *w) { XFixesSubtractRegion(ps->dpy, parts, parts, w->prev_trans->reg_ignore); add_damage(ps, parts); - w->damaged = 1; + w->damaged = true; } static wintype_t @@ -1916,7 +1920,7 @@ map_win(session_t *ps, Window id) { // Check for _COMPTON_SHADOW if (ps->o.respect_prop_shadow) - win_update_attr_shadow_raw(ps, w); + win_update_prop_shadow_raw(ps, w); // Many things above could affect shadow determine_shadow(ps, w); @@ -1933,7 +1937,7 @@ map_win(session_t *ps, Window id) { determine_fade(ps, w); } - w->damaged = 1; + w->damaged = true; /* if any configure events happened while @@ -1952,7 +1956,7 @@ finish_map_win(session_t *ps, win *w) { static void finish_unmap_win(session_t *ps, win *w) { - w->damaged = 0; + w->damaged = false; update_reg_ignore_expire(ps, w); @@ -2016,7 +2020,7 @@ get_opacity_percent(win *w) { static void determine_mode(session_t *ps, win *w) { - winmode mode; + winmode_t mode = WMODE_SOLID; XRenderPictFormat *format; /* if trans prop == -1 fall back on previous tests */ @@ -2029,11 +2033,11 @@ determine_mode(session_t *ps, win *w) { if (format && format->type == PictTypeDirect && format->direct.alphaMask) { - mode = WINDOW_ARGB; + mode = WMODE_ARGB; } else if (w->opacity != OPAQUE) { - mode = WINDOW_TRANS; + mode = WMODE_TRANS; } else { - mode = WINDOW_SOLID; + mode = WMODE_SOLID; } w->mode = mode; @@ -2153,15 +2157,15 @@ win_update_shape(session_t *ps, win *w) { * The property must be set on the outermost window, usually the WM frame. */ static void -win_update_attr_shadow_raw(session_t *ps, win *w) { +win_update_prop_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 (!prop.nitems) { - w->attr_shadow = -1; + w->prop_shadow = -1; } else { - w->attr_shadow = *prop.data.p32; + w->prop_shadow = *prop.data.p32; } free_winprop(&prop); @@ -2172,12 +2176,12 @@ win_update_attr_shadow_raw(session_t *ps, win *w) { * things. */ static void -win_update_attr_shadow(session_t *ps, win *w) { - long attr_shadow_old = w->attr_shadow; +win_update_prop_shadow(session_t *ps, win *w) { + long attr_shadow_old = w->prop_shadow; - win_update_attr_shadow_raw(ps, w); + win_update_prop_shadow_raw(ps, w); - if (w->attr_shadow != attr_shadow_old) + if (w->prop_shadow != attr_shadow_old) determine_shadow(ps, w); } @@ -2189,11 +2193,13 @@ static void determine_shadow(session_t *ps, win *w) { bool shadow_old = w->shadow; - 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) - && !(ps->o.respect_prop_shadow && 0 == w->attr_shadow)); + w->shadow = (UNSET == w->shadow_force ? + (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) + && !(ps->o.respect_prop_shadow && 0 == w->prop_shadow)) + : w->shadow_force); // Window extents need update on shadow state change if (w->shadow != shadow_old) { @@ -2340,18 +2346,98 @@ win_recheck_client(session_t *ps, win *w) { win_mark_client(ps, w, cw); } -static void +static bool add_win(session_t *ps, Window id, Window prev) { + const static win win_def = { + .next = NULL, + .prev_trans = NULL, + + .id = None, + .a = { }, + .mode = WMODE_TRANS, + .damaged = false, + .damage = None, + .pixmap = None, + .picture = None, + .border_size = None, + .extents = None, + .flags = 0, + .need_configure = false, + .queue_configure = { }, + .reg_ignore = None, + .destroyed = false, + .widthb = 0, + .heightb = 0, + .bounding_shaped = false, + .rounded_corners = false, + .to_paint = false, + + .client_win = None, + .window_type = WINTYPE_UNKNOWN, + .wmwin = false, + .leader = None, + .cache_leader = None, + + .focused = false, + .focused_force = UNSET, + .focused_real = false, + + .name = NULL, + .class_instance = NULL, + .class_general = NULL, + .role = NULL, + .cache_sblst = NULL, + .cache_fblst = NULL, + .cache_fcblst = NULL, + + .opacity = 0, + .opacity_tgt = 0, + .opacity_prop = OPAQUE, + .opacity_prop_client = OPAQUE, + .alpha_pict = None, + + .fade = false, + .fade_callback = NULL, + + .frame_opacity = 0.0, + .frame_alpha_pict = None, + .left_width = 0, + .right_width = 0, + .top_width = 0, + .bottom_width = 0, + + .shadow = false, + .shadow_force = UNSET, + .shadow_opacity = 0.0, + .shadow_dx = 0, + .shadow_dy = 0, + .shadow_width = 0, + .shadow_height = 0, + .shadow_pict = None, + .shadow_alpha_pict = None, + .prop_shadow = -1, + + .dim = false, + .dim_alpha_pict = None, + }; + // Reject overlay window and already added windows if (id == ps->overlay || find_win(ps, id)) { - return; + return false; } + // Allocate and initialize the new win structure win *new = malloc(sizeof(win)); - win **p; - if (!new) return; + if (!new) { + printf_errf("(%#010lx): Failed to allocate memory for the new window.", id); + return false; + } + memcpy(new, &win_def, sizeof(win)); + + // Find window insertion point + win **p = NULL; if (prev) { for (p = &ps->list; *p; p = &(*p)->next) { if ((*p)->id == prev && !(*p)->destroyed) @@ -2361,12 +2447,15 @@ add_win(session_t *ps, Window id, Window prev) { p = &ps->list; } + // Fill structure new->id = id; set_ignore_next(ps); if (!XGetWindowAttributes(ps->dpy, id, &new->a)) { + // Failed to get window attributes. Which probably means, the window + // is gone already. free(new); - return; + return false; } // Delay window mapping @@ -2374,76 +2463,12 @@ add_win(session_t *ps, Window id, Window prev) { assert(IsViewable == map_state || IsUnmapped == map_state); new->a.map_state = IsUnmapped; - new->damaged = 0; - new->to_paint = false; - new->pixmap = None; - new->picture = None; - - if (new->a.class == InputOnly) { - new->damage_sequence = 0; - new->damage = None; - } else { - new->damage_sequence = NextRequest(ps->dpy); + // Create Damage for window + if (InputOutput == new->a.class) { set_ignore_next(ps); new->damage = XDamageCreate(ps->dpy, id, XDamageReportNonEmpty); } - new->name = NULL; - new->class_instance = NULL; - new->class_general = NULL; - new->role = NULL; - new->cache_sblst = NULL; - new->cache_fblst = NULL; - new->cache_fcblst = NULL; - new->bounding_shaped = false; - new->rounded_corners = false; - - new->border_size = None; - new->reg_ignore = None; - new->extents = None; - new->shadow = false; - new->shadow_opacity = 0.0; - new->shadow_pict = None; - new->shadow_alpha_pict = None; - new->shadow_dx = 0; - new->shadow_dy = 0; - new->shadow_width = 0; - new->shadow_height = 0; - new->opacity = 0; - new->opacity_tgt = 0; - new->opacity_prop = OPAQUE; - new->opacity_prop_client = OPAQUE; - 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->dim_alpha_pict = None; - - new->focused = false; - new->focused_real = false; - new->leader = None; - new->cache_leader = None; - new->destroyed = false; - new->need_configure = false; - new->window_type = WINTYPE_UNKNOWN; - new->mode = WINDOW_TRANS; - new->attr_shadow = -1; - - new->prev_trans = NULL; - - new->left_width = 0; - new->right_width = 0; - new->top_width = 0; - new->bottom_width = 0; - - new->client_win = 0; - new->wmwin = false; - - new->flags = 0; - calc_win_size(ps, new); new->next = *p; @@ -2452,6 +2477,8 @@ add_win(session_t *ps, Window id, Window prev) { if (map_state == IsViewable) { map_win(ps, id); } + + return true; } static void @@ -2790,22 +2817,27 @@ static void win_update_focused(session_t *ps, win *w) { bool focused_old = w->focused; - w->focused = w->focused_real; + if (UNSET != w->focused_force) { + w->focused = w->focused_force; + } + else { + w->focused = w->focused_real; - // Use wintype_focus, and treat WM windows and override-redirected - // windows specially - if (ps->o.wintype_focus[w->window_type] - || (ps->o.mark_wmwin_focused && w->wmwin) - || (ps->o.mark_ovredir_focused - && w->id == w->client_win && !w->wmwin) - || win_match(w, ps->o.focus_blacklist, &w->cache_fcblst)) - w->focused = true; + // Use wintype_focus, and treat WM windows and override-redirected + // windows specially + if (ps->o.wintype_focus[w->window_type] + || (ps->o.mark_wmwin_focused && w->wmwin) + || (ps->o.mark_ovredir_focused + && w->id == w->client_win && !w->wmwin) + || win_match(w, ps->o.focus_blacklist, &w->cache_fcblst)) + w->focused = true; - // If window grouping detection is enabled, mark the window active if - // its group is - if (ps->o.track_leader && ps->active_leader - && win_get_leader(ps, w) == ps->active_leader) { - w->focused = true; + // If window grouping detection is enabled, mark the window active if + // its group is + if (ps->o.track_leader && ps->active_leader + && win_get_leader(ps, w) == ps->active_leader) { + w->focused = true; + } } if (w->focused != focused_old) @@ -3471,7 +3503,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) { 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(ps, w); + win_update_prop_shadow(ps, w); } // If a leader property changes @@ -3649,7 +3681,7 @@ ev_handle(session_t *ps, XEvent *ev) { static void usage(void) { const static char *usage_text = - "compton (development version)\n" + "compton (" COMPTON_VERSION ")\n" "usage: compton [options]\n" "Options:\n" "\n" @@ -3888,15 +3920,16 @@ register_cm(session_t *ps, bool want_glxct) { /** * Fork program to background and disable all I/O streams. */ -static void +static bool fork_after(void) { - if (getppid() == 1) return; + if (getppid() == 1) + return true; int pid = fork(); - if (pid == -1) { - fprintf(stderr, "Fork failed\n"); - return; + if (-1 == pid) { + printf_errf("(): fork() failed."); + return false; } if (pid > 0) _exit(0); @@ -3906,11 +3939,17 @@ fork_after(void) { // Mainly to suppress the _FORTIFY_SOURCE warning bool success = freopen("/dev/null", "r", stdin); success = freopen("/dev/null", "w", stdout) && success; - if (!success) - fprintf(stderr, "fork_after(): freopen() failed."); + if (!success) { + printf_errf("(): freopen() failed."); + return false; + } success = freopen("/dev/null", "w", stderr); - if (!success) - fprintf(stderr, "fork_after(): freopen() failed."); + if (!success) { + printf_errf("(): freopen() failed."); + return false; + } + + return true; } #ifdef CONFIG_LIBCONFIG @@ -4059,7 +4098,7 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) { f = open_config_file(cpath, &path); if (!f) { if (cpath) - printf("Failed to read the specified configuration file.\n"); + printf_errfq(1, "(): Failed to read the specified configuration file."); return; } @@ -4223,8 +4262,9 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) { */ static void 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 char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:hscnfFCaSzGb"; const static struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, { "config", required_argument, NULL, 256 }, { "shadow-red", required_argument, NULL, 257 }, { "shadow-green", required_argument, NULL, 258 }, @@ -4255,6 +4295,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) { { "blur-background", no_argument, NULL, 283 }, { "blur-background-frame", no_argument, NULL, 284 }, { "blur-background-fixed", no_argument, NULL, 285 }, + { "dbus", no_argument, NULL, 286 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -4303,6 +4344,9 @@ get_cfg(session_t *ps, int argc, char *const *argv) { (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) { switch (o) { // Short options + case 'h': + usage(); + break; case 'd': ps->o.display = mstrcpy(optarg); break; @@ -4484,6 +4528,10 @@ get_cfg(session_t *ps, int argc, char *const *argv) { // --blur-background-fixed ps->o.blur_background_fixed = true; break; + case 286: + // --dbus + ps->o.dbus = true; + break; default: usage(); } @@ -4609,7 +4657,7 @@ update_refresh_rate(session_t *ps) { XRRFreeScreenConfigInfo(randr_info); if (ps->refresh_rate) - ps->refresh_intv = NS_PER_SEC / ps->refresh_rate; + ps->refresh_intv = US_PER_SEC / ps->refresh_rate; else ps->refresh_intv = 0; } @@ -4620,12 +4668,12 @@ update_refresh_rate(session_t *ps) { * @return true for success, false otherwise */ static bool -sw_opti_init(session_t *ps) { +swopti_init(session_t *ps) { // Prepare refresh rate // Check if user provides one ps->refresh_rate = ps->o.refresh_rate; if (ps->refresh_rate) - ps->refresh_intv = NS_PER_SEC / ps->refresh_rate; + ps->refresh_intv = US_PER_SEC / ps->refresh_rate; // Auto-detect refresh rate otherwise if (!ps->refresh_rate && ps->randr_exists) { @@ -4661,61 +4709,62 @@ lceil_ntimes(long dividend, long divisor) { } /** - * Wait for events until next paint. + * Modify a struct timeval timeout value to render at a fixed pace. * - * Optionally use refresh-rate based optimization to reduce painting. - * - * @param fd struct pollfd used for poll() - * @param timeout second timeout (fading timeout) - * @return > 0 if we get some events, 0 if timeout is reached, < 0 on - * problems + * @param ps current session + * @param[in,out] ptv pointer to the timeout */ -static int -evpoll(session_t *ps, int timeout) { - struct pollfd ufd = { - .fd = ConnectionNumber(ps->dpy), - .events = POLLIN - }; +static void +swopti_handle_timeout(session_t *ps, struct timeval *ptv) { + if (!ptv) + return; - // Always wait infinitely if asked so, to minimize CPU usage - if (timeout < 0) { - 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 (!ps->o.sw_opti) - return poll(&ufd, 1, timeout); - - // Convert the old timeout to struct timespec - struct timespec next_paint_tmout = { - .tv_sec = timeout / MS_PER_SEC, - .tv_nsec = timeout % MS_PER_SEC * (NS_PER_SEC / MS_PER_SEC) - }; - - // Get the nanosecond offset of the time when the we reach the timeout + // Get the microsecond 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 - ps->paint_tm_offset) % NS_PER_SEC; - if (target_relative_offset < 0) - target_relative_offset += NS_PER_SEC; + long offset = (ptv->tv_usec + get_time_timeval().tv_usec - ps->paint_tm_offset) % ps->refresh_intv; + if (offset < 0) + offset += ps->refresh_intv; - assert(target_relative_offset >= 0); + assert(offset >= 0 && offset < ps->refresh_intv); // 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(&ufd, 1, timeout); + if (offset < SWOPTI_TOLERANCE + || offset > ps->refresh_intv - SWOPTI_TOLERANCE) + return; // Add an offset so we wait until the next refresh after timeout - 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; + ptv->tv_usec += ps->refresh_intv - offset; + if (ptv->tv_usec > US_PER_SEC) { + ptv->tv_usec -= US_PER_SEC; + ++ptv->tv_sec; } +} - return ppoll(&ufd, 1, &next_paint_tmout, NULL); +/** + * Libevent callback function to handle X events. + */ +static void +evcallback_x(evutil_socket_t fd, short what, void *arg) { + session_t *ps = ps_g; + + // 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(ps->dpy, QueuedAfterReading)) { + XEvent ev = { }; + + XNextEvent(ps->dpy, &ev); + ev_handle(ps, &ev); + ps->ev_received = true; + } +} + +/** + * NULL libevent callback function. + */ +static void +evcallback_null(evutil_socket_t fd, short what, void *arg) { } /** @@ -4981,6 +5030,45 @@ redir_stop(session_t *ps) { } } +/** + * Main loop. + */ +static bool +mainloop(session_t *ps) { + bool infinite_wait = false; + + // Process existing events + if (XEventsQueued(ps->dpy, QueuedAfterReading)) { + evcallback_x(ConnectionNumber(ps->dpy), 0, NULL); + return true; + } + + // Add timeout + if (ps->ev_received || !ps->idling) { + struct timeval tv = ms_to_tv(ps->ev_received ? 0: fade_timeout(ps)); + if (ps->o.sw_opti) + swopti_handle_timeout(ps, &tv); + assert(tv.tv_sec >= 0 && tv.tv_usec >= 0); + if (timeval_isempty(tv)) + return false; + evtimer_add(ps->ev_tmout, &tv); + } + else { + infinite_wait = true; + } + + // Run libevent main loop + if (event_base_loop(ps->ev_base, EVLOOP_ONCE)) + printf_errfq(1, "(): Unexpected error when running event loop."); + + evtimer_del(ps->ev_tmout); + + if (infinite_wait) + ps->fade_time = get_time_ms(); + + return true; +} + /** * Initialize a session. * @@ -5097,11 +5185,15 @@ session_init(session_t *ps_old, int argc, char **argv) { .refresh_intv = 0UL, .paint_tm_offset = 0L, +#ifdef CONFIG_VSYNC_DRM .drm_fd = 0, +#endif +#ifdef CONFIG_VSYNC_OPENGL .glx_context = None, .glx_get_video_sync = NULL, .glx_wait_video_sync = NULL, +#endif .xfixes_event = 0, .xfixes_error = 0, @@ -5119,9 +5211,11 @@ session_init(session_t *ps_old, int argc, char **argv) { .randr_exists = 0, .randr_event = 0, .randr_error = 0, +#ifdef CONFIG_VSYNC_OPENGL .glx_exists = false, .glx_event = 0, .glx_error = 0, +#endif .dbe_exists = false, .xrfilter_convolution_exists = false, @@ -5255,7 +5349,7 @@ session_init(session_t *ps_old, int argc, char **argv) { // Initialize software optimization if (ps->o.sw_opti) - ps->o.sw_opti = sw_opti_init(ps); + ps->o.sw_opti = swopti_init(ps); // Initialize DRM/OpenGL VSync if ((VSYNC_DRM == ps->o.vsync && !vsync_drm_init(ps)) @@ -5269,8 +5363,6 @@ session_init(session_t *ps_old, int argc, char **argv) { if (ps->o.dbe) init_dbe(ps); - if (ps->o.fork_after_register) fork_after(); - init_atoms(ps); init_alpha_picts(ps); @@ -5313,6 +5405,24 @@ session_init(session_t *ps_old, int argc, char **argv) { } ps->all_damage = None; + + // Build event base + if (!(ps->ev_base = +#ifndef CONFIG_LIBEVENT_LEGACY + event_base_new() +#else + event_init() +#endif + )) + printf_errfq(1, "(): Failed to build event base."); + if (!(ps->ev_x = EVENT_NEW(ps->ev_base, ConnectionNumber(ps->dpy), + EV_READ | EV_PERSIST, evcallback_x, NULL))) + printf_errfq(1, "(): Failed to build event."); + if (event_add(ps->ev_x, NULL)) + printf_errfq(1, "(): Failed to add event."); + if (!(ps->ev_tmout = evtimer_new(ps->ev_base, evcallback_null, NULL))) + printf_errfq(1, "(): Failed to build event."); + XGrabServer(ps->dpy); redir_start(ps); @@ -5345,6 +5455,18 @@ session_init(session_t *ps_old, int argc, char **argv) { XUngrabServer(ps->dpy); + // Fork to background, if asked + if (ps->o.fork_after_register) { + if (!fork_after()) { + session_destroy(ps); + return NULL; + } + + // Reinitialize event base + if (event_reinit(ps->ev_base) < 0) + printf_errfq(1, "Failed to reinitialize event base."); + } + // Free the old session if (ps_old) free(ps_old); @@ -5447,10 +5569,12 @@ session_destroy(session_t *ps) { XDestroyWindow(ps->dpy, ps->reg_win); ps->reg_win = None; } +#ifdef CONFIG_VSYNC_OPENGL if (ps->glx_context) { glXDestroyContext(ps->dpy, ps->glx_context); ps->glx_context = None; } +#endif // Free double buffer if (ps->root_dbe) { @@ -5458,11 +5582,13 @@ session_destroy(session_t *ps) { ps->root_dbe = None; } +#ifdef CONFIG_VSYNC_DRM // Close file opened for DRM VSync if (ps->drm_fd) { close(ps->drm_fd); ps->drm_fd = 0; } +#endif // Release overlay window if (ps->overlay) { @@ -5470,6 +5596,11 @@ session_destroy(session_t *ps) { ps->overlay = None; } + // Free libevent things + event_free(ps->ev_x); + event_free(ps->ev_tmout); + event_base_free(ps->ev_base); + // Flush all events XSync(ps->dpy, True); @@ -5487,7 +5618,7 @@ session_run(session_t *ps) { win *t; if (ps->o.sw_opti) - ps->paint_tm_offset = get_time_timespec().tv_nsec; + ps->paint_tm_offset = get_time_timeval().tv_usec; ps->reg_ignore_expire = true; @@ -5503,22 +5634,10 @@ session_run(session_t *ps) { // Main loop while (!ps->reset) { - bool ev_received = false; + ps->ev_received = false; - 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(ps->dpy, QueuedAfterReading)) { - XEvent ev; - - XNextEvent(ps->dpy, &ev); - ev_handle(ps, &ev); - ev_received = true; - } - } + while (mainloop(ps)) + continue; // idling will be turned off during paint_preprocess() if needed ps->idling = true; @@ -5530,7 +5649,7 @@ session_run(session_t *ps) { free_region(ps, &ps->all_damage); if (ps->all_damage && !is_region_empty(ps, ps->all_damage)) { - static int paint; + static int paint = 0; paint_all(ps, ps->all_damage, t); ps->reg_ignore_expire = false; paint++; @@ -5577,6 +5696,10 @@ main(int argc, char **argv) { session_t *ps_old = ps_g; while (1) { ps_g = session_init(ps_old, argc, argv); + if (!ps_g) { + printf_errf("Failed to create new session."); + return 1; + } session_run(ps_g); ps_old = ps_g; session_destroy(ps_g); diff --git a/src/compton.h b/src/compton.h index 66ed396..c7d65d3 100644 --- a/src/compton.h +++ b/src/compton.h @@ -54,6 +54,21 @@ #include #include +// libevent +#ifndef CONFIG_LIBEVENT_LEGACY +#include +#else +#include +typedef int evutil_socket_t; +typedef void(* event_callback_fn)(evutil_socket_t, short, void *); +#define event_free(ev) (event_del((ev)), free((ev))) +#endif + +#ifndef evtimer_new +#define evtimer_new(b, cb, arg) EVENT_NEW((b), -1, 0, (cb), (arg)) +#endif + +// libpcre #ifdef CONFIG_REGEX_PCRE #include @@ -72,6 +87,10 @@ #include #endif +#ifdef CONFIG_DBUS +#include +#endif + #include #include #include @@ -109,9 +128,11 @@ #define REGISTER_PROP "_NET_WM_CM_S" #define FADE_DELTA_TOLERANCE 0.2 -#define SW_OPTI_TOLERANCE 1000 +#define SWOPTI_TOLERANCE 1000 #define WIN_GET_LEADER_MAX_RECURSION 20 +#define SEC_WRAP (15L * 24L * 60L * 60L) + #define NS_PER_SEC 1000000000L #define US_PER_SEC 1000000L #define MS_PER_SEC 1000 @@ -134,10 +155,27 @@ // #define MSTR_(s) #s // #define MSTR(s) MSTR_(s) +/// Print out an error message. +#define printf_err(format, ...) \ + fprintf(stderr, format "\n", ## __VA_ARGS__) + +/// Print out an error message with function name. +#define printf_errf(format, ...) \ + printf_err("%s" format, __func__, ## __VA_ARGS__) + +/// Print out an error message with function name, and quit with a +/// specific exit code. +#define printf_errfq(code, format, ...) { \ + printf_err("%s" format, __func__, ## __VA_ARGS__); \ + exit(code); \ +} + +/// Print out a debug message. #define printf_dbg(format, ...) \ printf(format, ## __VA_ARGS__); \ fflush(stdout) +/// Print out a debug message with function name. #define printf_dbgf(format, ...) \ printf_dbg("%s" format, __func__, ## __VA_ARGS__) @@ -148,6 +186,7 @@ // === Types === typedef uint32_t opacity_t; +typedef long time_ms_t; typedef enum { WINTYPE_UNKNOWN, @@ -175,12 +214,14 @@ typedef enum { UNSET } switch_t; +/// Enumeration type of window painting mode. typedef enum { - WINDOW_SOLID, - WINDOW_TRANS, - WINDOW_ARGB -} winmode; + WMODE_TRANS, + WMODE_SOLID, + WMODE_ARGB +} winmode_t; +/// Structure representing Window property value. typedef struct { // All pointers have the same length, right? // I wanted to use anonymous union but it's a GNU extension... @@ -190,6 +231,8 @@ typedef struct { long *p32; } data; unsigned long nitems; + Atom type; + int format; } winprop_t; typedef struct _ignore { @@ -263,6 +306,8 @@ typedef struct { /// Whether to unredirect all windows if a full-screen opaque window /// is detected. bool unredir_if_possible; + /// Whether to enable D-Bus support. + bool dbus; /// Whether to work under synchronized mode for debugging. bool synchronize; @@ -301,7 +346,8 @@ typedef struct { opacity_t fade_in_step; /// How much to fade out in a single fading step. opacity_t fade_out_step; - unsigned long fade_delta; + /// Fading time delta. In milliseconds. + time_ms_t fade_delta; /// Whether to disable fading on window open/close. bool no_fading_openclose; /// Fading blacklist. A linked list of conditions. @@ -401,6 +447,17 @@ typedef struct { // === Operation related === /// Program options. options_t o; + /// Libevent event base. + struct event_base *ev_base; + /// Libevent event for X connection. + struct event *ev_x; + /// Libevent event for timeout. + struct event *ev_tmout; + /// Whether we have received an event in this cycle. + bool ev_received; + /// Whether the program is idling. I.e. no fading, no potential window + /// changes. + bool idling; /// Program start time. struct timeval time_start; /// The region needs to painted on next paint. @@ -414,11 +471,8 @@ typedef struct { 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; + time_ms_t fade_time; /// Head pointer of the error ignore linked list. ignore_t *ignore_head; /// Pointer to the next member of tail element of the error @@ -566,35 +620,42 @@ typedef struct { /// Structure representing a top-level window compton manages. typedef struct _win { - // Next structure in the linked list. + /// Pointer to the next structure in the linked list. struct _win *next; + /// Pointer to the next higher window to paint. + struct _win *prev_trans; - // ID of the top-level frame window. + // Core members + /// ID of the top-level frame window. Window id; - /// ID of the top-level client window of the window. - Window client_win; - /// Whether it looks like a WM window. We consider a window WM window if - /// it does not have a decedent with WM_STATE and it is not override- - /// redirected itself. - bool wmwin; - Pixmap pixmap; + /// Window attributes. XWindowAttributes a; - winmode mode; - int damaged; + /// Window painting mode. + winmode_t mode; + /// Whether the window has been damaged at least once. + bool damaged; + /// Damage of the window. Damage damage; + /// NameWindowPixmap of the window. + Pixmap pixmap; + /// Picture of the window. Picture picture; + /// Bounding shape of the window. XserverRegion border_size; + /// Region of the whole window, shadow region included. XserverRegion extents; - // Type of the window. - wintype_t window_type; - /// Whether the window is to be considered focused. - bool focused; - /// Whether the window is actually focused. - bool focused_real; - /// Leader window ID of the window. - Window leader; - /// Cached topmost window ID of the window. - Window cache_leader; + /// Window flags. Definitions above. + int_fast16_t flags; + /// Whether there's a pending ConfigureNotify happening + /// when the window is unmapped. + bool need_configure; + /// Queued ConfigureNotify 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 + /// opacity state, window geometry, window mapped/unmapped state, + /// window mode, of this and all higher windows. + XserverRegion reg_ignore; /// Whether the window has been destroyed. bool destroyed; /// Cached width/height of the window including border. @@ -606,6 +667,28 @@ typedef struct _win { /// Whether this window is to be painted. bool to_paint; + // Client window related members + /// ID of the top-level client window of the window. + Window client_win; + /// Type of the window. + wintype_t window_type; + /// Whether it looks like a WM window. We consider a window WM window if + /// it does not have a decedent with WM_STATE and it is not override- + /// redirected itself. + bool wmwin; + /// Leader window ID of the window. + Window leader; + /// Cached topmost window ID of the window. + Window cache_leader; + + // Focus-related members + /// Whether the window is to be considered focused. + bool focused; + /// Override value of window focus state. Set by D-Bus method calls. + switch_t focused_force; + /// Whether the window is actually focused. + bool focused_real; + // Blacklist related members /// Name of the window. char *name; @@ -649,8 +732,10 @@ typedef struct _win { unsigned int left_width, right_width, top_width, bottom_width; // Shadow-related members - /// Whether a window has shadow. Affected by window type. + /// Whether a window has shadow. Calculated. bool shadow; + /// Override value of window shadow state. Set by D-Bus method calls. + switch_t shadow_force; /// Opacity of the shadow. Affected by window opacity and frame opacity. double shadow_opacity; /// X offset of shadow. Affected by commandline argument. @@ -667,7 +752,7 @@ typedef struct _win { Picture shadow_alpha_pict; /// The value of _COMPTON_SHADOW attribute of the window. Below 0 for /// none. - long attr_shadow; + long prop_shadow; // Dim-related members /// Whether the window is to be dimmed. @@ -675,24 +760,6 @@ typedef struct _win { /// Picture for dimming. Affected by user-specified inactive dim /// opacity and window opacity. Picture dim_alpha_pict; - - /// Window flags. Definitions above. - int_fast16_t flags; - - unsigned long damage_sequence; /* sequence when damage was created */ - - /// Whether there's a pending ConfigureNotify happening - /// when the window is unmapped. - bool need_configure; - /// Queued ConfigureNotify 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 - /// opacity state, window geometry, window mapped/unmapped state, - /// window mode, of this and all higher windows. - XserverRegion reg_ignore; - - struct _win *prev_trans; } win; /// Temporary structure used for communication between @@ -773,6 +840,22 @@ XFixesDestroyRegion_(Display *dpy, XserverRegion reg, // == Functions == +/** + * Wrapper of libevent event_new(), for compatibility with libevent-1\.x. + */ +static inline struct event * +EVENT_NEW(struct event_base *base, evutil_socket_t fd, + short what, event_callback_fn cb, void *arg) { +#ifndef CONFIG_LIBEVENT_LEGACY + return event_new(base, fd, what, cb, arg); +#else + struct event *pev = malloc(sizeof(struct event)); + if (pev) + event_set(pev, fd, what, cb, arg); + return pev; +#endif +} + // inline functions must be made static to compile correctly under clang: // http://clang.llvm.org/compatibility.html#inline @@ -784,6 +867,9 @@ discard_ignore(session_t *ps, unsigned long sequence); static void set_ignore(session_t *ps, unsigned long sequence); +/** + * Ignore X errors caused by next X request. + */ static inline void set_ignore_next(session_t *ps) { set_ignore(ps, NextRequest(ps->dpy)); @@ -792,6 +878,14 @@ set_ignore_next(session_t *ps) { static int should_ignore(session_t *ps, unsigned long sequence); +/** + * Wrapper of XInternAtom() for convience. + */ +static inline Atom +get_atom(session_t *ps, char *atom_name) { + return XInternAtom(ps->dpy, atom_name, False); +} + /** * Return the painting target window. */ @@ -957,6 +1051,14 @@ array_wid_exists(const Window *arr, int count, Window wid) { return false; } +/** + * Return whether a struct timeval value is empty. + */ +static inline bool +timeval_isempty(struct timeval tv) { + return tv.tv_sec <= 0 && tv.tv_usec <= 0; +} + /* * Subtracting two struct timeval values. * @@ -1026,6 +1128,19 @@ timespec_subtract(struct timespec *result, return x->tv_sec < y->tv_sec; } +/** + * Get current time in struct timeval. + */ +static inline struct timeval __attribute__((const)) +get_time_timeval(void) { + struct timeval tv = { 0, 0 }; + + gettimeofday(&tv, NULL); + + // Return a time of all 0 if the call fails + return tv; +} + /** * Get current time in struct timespec. * @@ -1154,18 +1269,25 @@ free_win_res(session_t *ps, win *w) { /** * Get current system clock in milliseconds. - * - * The return type must be unsigned long because so many milliseconds have - * passed since the epoch. */ -static unsigned long +static inline time_ms_t get_time_ms(void) { struct timeval tv; gettimeofday(&tv, NULL); - return (unsigned long) tv.tv_sec * 1000 - + (unsigned long) tv.tv_usec / 1000; + return tv.tv_sec % SEC_WRAP * 1000 + tv.tv_usec / 1000; +} + +/** + * Convert time from milliseconds to struct timeval. + */ +static inline struct timeval +ms_to_tv(int timeout) { + return (struct timeval) { + .tv_sec = timeout / MS_PER_SEC, + .tv_usec = timeout % MS_PER_SEC * (US_PER_SEC / MS_PER_SEC) + }; } static int @@ -1255,33 +1377,68 @@ wid_has_prop(const session_t *ps, Window w, Atom atom) { * @return a winprop_t structure containing the attribute * and number of items. A blank one on failure. */ +// TODO: Move to compton.c static winprop_t -wid_get_prop(const session_t *ps, Window w, Atom atom, long length, - Atom rtype, int rformat) { +wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset, + long length, Atom rtype, int rformat) { Atom type = None; int format = 0; unsigned long nitems = 0, after = 0; unsigned char *data = NULL; - // Use two if statements to deal with the sequence point issue. - if (Success == XGetWindowProperty(ps->dpy, w, atom, 0L, length, False, - rtype, &type, &format, &nitems, &after, &data)) { - if (type == rtype && format == rformat) { + if (Success == XGetWindowProperty(ps->dpy, w, atom, offset, length, + False, rtype, &type, &format, &nitems, &after, &data) + && nitems && (AnyPropertyType == type || type == rtype) + && (!format || format == rformat) + && (8 == format || 16 == format || 32 == format)) { return (winprop_t) { .data.p8 = data, - .nitems = nitems + .nitems = nitems, + .type = type, + .format = format, }; - } } XFree(data); return (winprop_t) { .data.p8 = NULL, - .nitems = 0 + .nitems = 0, + .type = AnyPropertyType, + .format = 0 }; } +/** + * Wrapper of wid_get_prop_adv(). + */ +static inline winprop_t +wid_get_prop(const session_t *ps, Window wid, Atom atom, long length, + Atom rtype, int rformat) { + return wid_get_prop_adv(ps, wid, atom, 0L, length, rtype, rformat); +} + +/** + * Get the numeric property value from a win_prop_t. + */ +static inline long +winprop_get_int(winprop_t prop) { + long tgt = 0; + + if (!prop.nitems) + return 0; + + switch (prop.format) { + case 8: tgt = *(prop.data.p8); break; + case 16: tgt = *(prop.data.p16); break; + case 32: tgt = *(prop.data.p32); break; + default: assert(0); + break; + } + + return tgt; +} + /** * Free a winprop_t. * @@ -1364,7 +1521,7 @@ wid_bounding_shaped(const session_t *ps, Window wid) { */ static inline void update_reg_ignore_expire(session_t *ps, const win *w) { - if (w->to_paint && WINDOW_SOLID == w->mode) + if (w->to_paint && WMODE_SOLID == w->mode) ps->reg_ignore_expire = true; } @@ -1616,10 +1773,10 @@ static void win_update_shape(session_t *ps, win *w); static void -win_update_attr_shadow_raw(session_t *ps, win *w); +win_update_prop_shadow_raw(session_t *ps, win *w); static void -win_update_attr_shadow(session_t *ps, win *w); +win_update_prop_shadow(session_t *ps, win *w); static void determine_shadow(session_t *ps, win *w); @@ -1639,7 +1796,7 @@ win_unmark_client(session_t *ps, win *w); static void win_recheck_client(session_t *ps, win *w); -static void +static bool add_win(session_t *ps, Window id, Window prev); static void @@ -1855,7 +2012,7 @@ ev_window_name(session_t *ps, Window wid, char **name); inline static void ev_handle(session_t *ps, XEvent *ev); -static void +static bool fork_after(void); #ifdef CONFIG_LIBCONFIG @@ -1916,10 +2073,16 @@ static void update_refresh_rate(session_t *ps); static bool -sw_opti_init(session_t *ps); +swopti_init(session_t *ps); -static int -evpoll(session_t *ps, int timeout); +static void +swopti_handle_timeout(session_t *ps, struct timeval *ptv); + +static void +evcallback_x(evutil_socket_t fd, short what, void *arg); + +static void +evcallback_null(evutil_socket_t fd, short what, void *arg); static bool vsync_drm_init(session_t *ps); @@ -1955,6 +2118,9 @@ redir_start(session_t *ps); static void redir_stop(session_t *ps); +static bool +mainloop(session_t *ps); + static session_t * session_init(session_t *ps_old, int argc, char **argv);