diff options
author | Richard Grenville <pyxlcy@gmail.com> | 2013-01-08 08:50:58 +0800 |
---|---|---|
committer | Richard Grenville <pyxlcy@gmail.com> | 2013-01-08 10:19:19 +0800 |
commit | 03ffecb4a0de95300fce6419abda3177db016f0b (patch) | |
tree | 551f650959ebd4c5794f39ecf2f0b21bdba0bec3 /compton.c | |
parent | f4edcb2ec1618b71f09a6b93cdd123583cf3a8c4 (diff) | |
download | tdebase-03ffecb4a0de95300fce6419abda3177db016f0b.tar.gz tdebase-03ffecb4a0de95300fce6419abda3177db016f0b.zip |
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.
Diffstat (limited to 'compton.c')
-rw-r--r-- | compton.c | 519 |
1 files changed, 321 insertions, 198 deletions
@@ -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; - - // 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 (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; + + // 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 - }; - - // 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) - }; +static void +swopti_handle_timeout(session_t *ps, struct timeval *ptv) { + if (!ptv) + return; - // 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; + } +} + +/** + * 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; } +} - return ppoll(&ufd, 1, &next_paint_tmout, NULL); +/** + * NULL libevent callback function. + */ +static void +evcallback_null(evutil_socket_t fd, short what, void *arg) { } /** @@ -4982,6 +5031,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. * * @param ps_old old session, from which the function will take the X @@ -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; - - 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; - } - } + ps->ev_received = false; + + 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); |