Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package picom for openSUSE:Factory checked in at 2024-11-17 16:41:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/picom (Old) and /work/SRC/openSUSE:Factory/.picom.new.2017 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "picom" Sun Nov 17 16:41:37 2024 rev:13 rq:1224526 version:12.5 Changes: -------- --- /work/SRC/openSUSE:Factory/picom/picom.changes 2024-10-17 18:40:00.939968584 +0200 +++ /work/SRC/openSUSE:Factory/.picom.new.2017/picom.changes 2024-11-17 16:41:43.164530239 +0100 @@ -1,0 +2,17 @@ +Fri Nov 15 11:03:35 UTC 2024 - Michael Pujos <[email protected]> + +- Update to version 12.5: + * Bug fixes + - Fix assertion failure when running with some window managers (e.g. qtile) and no window is focused (#1384) +- Update to version 12.4: + * Improvements + - Better workaround for a NVIDIA quirk, fix high CPU usage when + screen is off (#1265) + - Avoid using xrender convolution in all cases, should improve + shadow performance for most users (#1349) + * Bug fixes + - Fix leak of saved window images + * Build fixes + - Fix build on arm32 (#1355) + +------------------------------------------------------------------- Old: ---- picom-12.3.tar.gz New: ---- picom-12.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ picom.spec ++++++ --- /var/tmp/diff_new_pack.OPHpbG/_old 2024-11-17 16:41:43.684551839 +0100 +++ /var/tmp/diff_new_pack.OPHpbG/_new 2024-11-17 16:41:43.688552005 +0100 @@ -17,7 +17,7 @@ Name: picom -Version: 12.3 +Version: 12.5 Release: 0 Summary: Stand-alone compositor for X11 License: MIT AND MPL-2.0 ++++++ picom-12.3.tar.gz -> picom-12.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/CHANGELOG.md new/picom-12.5/CHANGELOG.md --- old/picom-12.3/CHANGELOG.md 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/CHANGELOG.md 2024-11-13 07:48:38.000000000 +0100 @@ -1,3 +1,24 @@ +# 12.5 (2024-Nov-13) + +## Bug fixes + +* Fix assertion failure when running with some window managers (e.g. qtile) and no window is focused (#1384) + +# 12.4 (2024-Nov-09) + +## Improvements + +* Better workaround for a NVIDIA qurik, fix high CPU usage when screen is off (#1265) +* Avoid using xrender convolution in all cases, should improve shadow performance for most users. (#1349) + +# Bug fixes + +* Fix leak of saved window images. + +## Build fixes + +* Fix build on arm32 (#1355) + # 12.3 (2024-Oct-14) ## Improvements diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/meson.build new/picom-12.5/meson.build --- old/picom-12.3/meson.build 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/meson.build 2024-11-13 07:48:38.000000000 +0100 @@ -1,4 +1,4 @@ -project('picom', 'c', version: '12.3', +project('picom', 'c', version: '12.5', default_options: ['c_std=c11', 'warning_level=1']) cc = meson.get_compiler('c') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/backend/backend_common.c new/picom-12.5/src/backend/backend_common.c --- old/picom-12.3/src/backend/backend_common.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/backend/backend_common.c 2024-11-13 07:48:38.000000000 +0100 @@ -197,7 +197,7 @@ */ bool build_shadow(struct x_connection *c, double opacity, const int width, const int height, const conv *kernel, xcb_render_picture_t shadow_pixel, - xcb_pixmap_t *pixmap, xcb_render_picture_t *pict) { + xcb_pixmap_t *pixmap) { xcb_image_t *shadow_image = NULL; xcb_pixmap_t shadow_pixmap = XCB_NONE, shadow_pixmap_argb = XCB_NONE; xcb_render_picture_t shadow_picture = XCB_NONE, shadow_picture_argb = XCB_NONE; @@ -262,12 +262,12 @@ shadow_image->height); *pixmap = shadow_pixmap_argb; - *pict = shadow_picture_argb; xcb_free_gc(c->c, gc); xcb_image_destroy(shadow_image); xcb_free_pixmap(c->c, shadow_pixmap); x_free_picture(c, shadow_picture); + x_free_picture(c, shadow_picture_argb); return true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/backend/backend_common.h new/picom-12.5/src/backend/backend_common.h --- old/picom-12.3/src/backend/backend_common.h 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/backend/backend_common.h 2024-11-13 07:48:38.000000000 +0100 @@ -28,8 +28,7 @@ xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity, int width, int height); bool build_shadow(struct x_connection *, double opacity, int width, int height, - const conv *kernel, xcb_render_picture_t shadow_pixel, - xcb_pixmap_t *pixmap, xcb_render_picture_t *pict); + const conv *kernel, xcb_render_picture_t shadow_pixel, xcb_pixmap_t *pixmap); xcb_render_picture_t solid_picture(struct x_connection *, bool argb, double a, double r, double g, double b); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/backend/xrender/xrender.c new/picom-12.5/src/backend/xrender/xrender.c --- old/picom-12.3/src/backend/xrender/xrender.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/backend/xrender/xrender.c 2024-11-13 07:48:38.000000000 +0100 @@ -956,12 +956,7 @@ xd->curr_back = 0; xd->back_image.pict = xd->vsync ? xd->back[xd->curr_back] : xd->target; - auto drivers = detect_driver(xd->base.c->c, &xd->base, xd->target_win); - if (drivers & (DRIVER_MODESETTING | DRIVER_NVIDIA | DRIVER_NOUVEAU | - DRIVER_AMDGPU | DRIVER_RADEON | DRIVER_FGLRX)) { - // I believe xf86-video-intel have accelerated convolution? - xd->quirks |= BACKEND_QUIRK_SLOW_BLUR; - } + xd->quirks |= BACKEND_QUIRK_SLOW_BLUR; return &xd->base; err: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/config.h new/picom-12.5/src/config.h --- old/picom-12.3/src/config.h 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/config.h 2024-11-13 07:48:38.000000000 +0100 @@ -199,9 +199,6 @@ struct win_script animations[ANIMATION_TRIGGER_COUNT]; }; -// Make sure `window_options` has no implicit padding. -#pragma GCC diagnostic push -#pragma GCC diagnostic error "-Wpadded" /// Like `window_maybe_options`, but all fields are guaranteed to be set. struct window_options { double opacity; @@ -220,13 +217,18 @@ struct win_script animations[ANIMATION_TRIGGER_COUNT]; }; -#pragma GCC diagnostic pop static inline bool win_options_no_damage(const struct window_options *a, const struct window_options *b) { // Animation changing does not immediately change how window is rendered, so - // they don't cause damage. - return memcmp(a, b, offsetof(struct window_options, animations)) == 0; + // they don't cause damage; all other options do. + return a->opacity == b->opacity && a->dim == b->dim && + a->corner_radius == b->corner_radius && a->unredir == b->unredir && + a->transparent_clipping == b->transparent_clipping && + a->shadow == b->shadow && a->invert_color == b->invert_color && + a->blur_background == b->blur_background && a->fade == b->fade && + a->clip_shadow_above == b->clip_shadow_above && a->paint == b->paint && + a->full_shadow == b->full_shadow && a->shader == b->shader; } /// Structure representing all options. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/log.h new/picom-12.5/src/log.h --- old/picom-12.3/src/log.h 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/log.h 2024-11-13 07:48:38.000000000 +0100 @@ -33,12 +33,13 @@ } \ } while (0) -#define LOG(level, x, ...) \ - do { \ - if (LOG_LEVEL_##level >= log_get_level_tls()) { \ - log_printf(tls_logger, LOG_LEVEL_##level, __func__, x, ##__VA_ARGS__); \ - } \ +#define LOG_(level, x, ...) \ + do { \ + if (level >= log_get_level_tls()) { \ + log_printf(tls_logger, level, __func__, x, ##__VA_ARGS__); \ + } \ } while (0) +#define LOG(level, x, ...) LOG_(LOG_LEVEL_##level, x, ##__VA_ARGS__) #define log_trace(x, ...) LOG_UNLIKELY(TRACE, x, ##__VA_ARGS__) #define log_verbose(x, ...) LOG_UNLIKELY(VERBOSE, x, ##__VA_ARGS__) #define log_debug(x, ...) LOG_UNLIKELY(DEBUG, x, ##__VA_ARGS__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/picom.c new/picom-12.5/src/picom.c --- old/picom-12.3/src/picom.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/picom.c 2024-11-13 07:48:38.000000000 +0100 @@ -1450,18 +1450,10 @@ static void handle_x_events(struct session *ps) { uint32_t latest_completed = ps->c.latest_completed_request; while (true) { - // Flush because if we go into sleep when there is still requests - // in the outgoing buffer, they will not be sent for an indefinite - // amount of time. Use XFlush here too, we might still use some - // Xlib functions because OpenGL. - // - // Also note, `xcb_flush`/`XFlush` may _read_ more events from the server - // (yes, this is ridiculous, I know). But since we are polling for events - // in a loop, this should be fine - if we read events here, they will be - // handled below; and if some requests is sent later in this loop, we will - // set `needs_flush` and loop once more and get here to flush them. - XFlush(ps->c.dpy); - xcb_flush(ps->c.c); + if (!x_prepare_for_sleep(&ps->c)) { + log_fatal("X connection broke."); + exit(1); + } // If we send any new requests, we should loop again to flush them. There // is no direct way to do this from xcb. So if we called `ev_handle`, or @@ -1694,9 +1686,7 @@ w->running_animation_instance = NULL; w->in_openclose = false; if (w->saved_win_image != NULL) { - ps->backend_data->ops.release_image(ps->backend_data, - w->saved_win_image); - w->saved_win_image = NULL; + win_release_saved_win_image(ps->backend_data, w); } if (w->state == WSTATE_UNMAPPED) { unmap_win_finish(ps, w); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/renderer/renderer.c new/picom-12.5/src/renderer/renderer.c --- old/picom-12.3/src/renderer/renderer.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/renderer/renderer.c 2024-11-13 07:48:38.000000000 +0100 @@ -351,10 +351,8 @@ renderer_bind_shadow(struct renderer *r, struct backend_base *backend, struct win *w) { if (backend->ops.quirks(backend) & BACKEND_QUIRK_SLOW_BLUR) { xcb_pixmap_t shadow = XCB_NONE; - xcb_render_picture_t pict = XCB_NONE; - if (!build_shadow(backend->c, r->shadow_color.alpha, w->widthb, w->heightb, - (void *)r->shadow_kernel, r->shadow_pixel, &shadow, &pict)) { + (void *)r->shadow_kernel, r->shadow_pixel, &shadow)) { return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/vblank.c new/picom-12.5/src/vblank.c --- old/picom-12.3/src/vblank.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/vblank.c 2024-11-13 07:48:38.000000000 +0100 @@ -87,6 +87,21 @@ pthread_t sync_thread; bool running, error, vblank_requested; unsigned int last_msc; + /// Number of synthesized vblank event. Currently these are being inserted when + /// the driver reports duplicate msc to us. + /// + /// This is because the NVIDIA driver has been observed to recover from a + /// duplicated msc loop by us rendering a new frame. So we insert a fake vblank + /// event so the render loop can progress, but doing so makes our msc desync from + /// the driver's msc. An hypothetical sequence of events go like this: + /// + /// - driver -> msc 1, we report msc 1 + /// - driver -> msc 1 (duplicate msc! if we don't render a new frame, we'll + /// be stuck here forever) + /// - we report msc 2 + /// - new frame rendered, driver recover + /// - driver -> msc 2, but we already reported msc 2, so we have to report msc 3 + unsigned int vblank_inserted; /// Protects `running`, and `vblank_requested` pthread_mutex_t vblank_requested_mtx; @@ -199,6 +214,8 @@ pthread_cond_signal(&args->start_cnd); pthread_mutex_unlock(&args->start_mtx); + unsigned int last_msc = 0; + pthread_mutex_lock(&self->vblank_requested_mtx); while (self->running) { if (!self->vblank_requested) { @@ -208,10 +225,9 @@ } pthread_mutex_unlock(&self->vblank_requested_mtx); - unsigned int last_msc; glXWaitVideoSyncSGI(1, 0, &last_msc); - struct timespec now; + struct timespec now = {}; clock_gettime(CLOCK_MONOTONIC, &now); atomic_store(&self->current_msc, last_msc); atomic_store(&self->current_ust, @@ -323,28 +339,33 @@ static void sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused revents) { auto sched = container_of(w, struct sgi_video_sync_vblank_scheduler, notify); - auto msc = atomic_load(&sched->current_msc); - if (sched->last_msc == msc) { + auto msc = atomic_load(&sched->current_msc) + sched->vblank_inserted; + auto ust = atomic_load(&sched->current_ust); + if (sched->last_msc >= msc) { // NVIDIA spams us with duplicate vblank events after a suspend/resume - // cycle. Recreating the X connection and GLX context seems to fix this. - // Oh NVIDIA. - log_warn("Duplicate vblank event found with msc %d. Possible NVIDIA bug?", msc); - log_warn("Resetting the vblank scheduler"); - sgi_video_sync_scheduler_deinit(&sched->base); - sched->base.vblank_event_requested = false; - if (!sgi_video_sync_scheduler_init(&sched->base)) { - log_error("Failed to reset the vblank scheduler"); - } else { - sgi_video_sync_scheduler_schedule(&sched->base); - } - return; + // cycle, or when the monitor turns off. + // Fake a vblank event in this case. See comments on `vblank_inserted` + // for more details. + enum log_level level = + sched->vblank_inserted == 0 ? LOG_LEVEL_WARN : LOG_LEVEL_DEBUG; + LOG_(level, + "Duplicate vblank event found with msc %d. Possible NVIDIA bug? " + "Number of duplicates so far: %d", + msc, sched->vblank_inserted); + sched->last_msc++; + sched->vblank_inserted++; + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + ust = (uint64_t)(now.tv_sec * 1000000 + now.tv_nsec / 1000); + } else { + sched->last_msc = msc; } auto event = (struct vblank_event){ - .msc = msc, - .ust = atomic_load(&sched->current_ust), + .msc = sched->last_msc, + .ust = ust, }; sched->base.vblank_event_requested = false; - sched->last_msc = msc; log_verbose("Received vblank event for msc %" PRIu64, event.msc); vblank_scheduler_invoke_callbacks(&sched->base, &event); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/wm/win.c new/picom-12.5/src/wm/win.c --- old/picom-12.3/src/wm/win.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/wm/win.c 2024-11-13 07:48:38.000000000 +0100 @@ -235,10 +235,14 @@ } } -static inline void win_release_saved_win_image(backend_t *base, struct win *w) { +void win_release_saved_win_image(backend_t *base, struct win *w) { if (w->saved_win_image) { - base->ops.release_image(base, w->saved_win_image); + xcb_pixmap_t pixmap = XCB_NONE; + pixmap = base->ops.release_image(base, w->saved_win_image); w->saved_win_image = NULL; + if (pixmap != XCB_NONE) { + xcb_free_pixmap(base->c->c, pixmap); + } } } @@ -1937,9 +1941,7 @@ if (win_check_flags_any(w, WIN_FLAGS_PIXMAP_STALE)) { // Grab the old pixmap, animations might need it if (w->saved_win_image) { - ps->backend_data->ops.release_image(ps->backend_data, - w->saved_win_image); - w->saved_win_image = NULL; + win_release_saved_win_image(ps->backend_data, w); } if (ps->drivers & DRIVER_NVIDIA) { if (w->win_image != NULL) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/wm/win.h new/picom-12.5/src/wm/win.h --- old/picom-12.3/src/wm/win.h 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/wm/win.h 2024-11-13 07:48:38.000000000 +0100 @@ -419,6 +419,7 @@ /// because of fading and such. void win_destroy_start(session_t *ps, struct win *w); void win_map_start(struct session *ps, struct win *w); +void win_release_saved_win_image(backend_t *base, struct win *w); /// Release images bound with a window, set the *_NONE flags on the window. Only to be /// used when de-initializing the backend outside of win.c void win_release_images(struct backend_base *backend, struct win *w); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/wm/wm.c new/picom-12.5/src/wm/wm.c --- old/picom-12.3/src/wm/wm.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/wm/wm.c 2024-11-13 07:48:38.000000000 +0100 @@ -187,7 +187,9 @@ struct wm_ref *wm_find_by_client(const struct wm *wm, xcb_window_t client) { auto node = wm_tree_find(&wm->tree, client); - if (node == NULL) { + if (node == NULL || node->parent == NULL) { + // If `client` is the root window, we return NULL too, technically + // the root window doesn't have a client window. return NULL; } auto toplevel = wm_tree_find_toplevel_for(&wm->tree, node); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/x.c new/picom-12.5/src/x.c --- old/picom-12.3/src/x.c 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/x.c 2024-11-13 07:48:38.000000000 +0100 @@ -166,12 +166,6 @@ /// This function logs X errors, or aborts the program based on severity of the error. static void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev) { x_discard_pending_errors(c, ev->full_sequence); - if (c->event_sync_sent && ev->full_sequence == c->event_sync) { - // This is the error for our event sync request we have been - // expecting. - c->event_sync_sent = false; - return; - } struct pending_x_error *first_error_action = NULL; if (!list_is_empty(&c->pending_x_errors)) { first_error_action = @@ -206,6 +200,48 @@ ev->error_code)); } +struct x_generic_async_request { + struct x_async_request_base base; + enum x_error_action error_action; + const char *func; + const char *file; + int line; +}; + +static void x_generic_async_callback(struct x_connection * /*c*/, + struct x_async_request_base *req_base, + const xcb_raw_generic_event_t *reply_or_error) { + auto req = (struct x_generic_async_request *)req_base; + auto error_action = req->error_action; + auto func = req->func == NULL ? "(unknown)" : req->func; + auto file = req->file == NULL ? "(unknown)" : req->file; + auto line = req->line; + free(req); + + if (reply_or_error == NULL || reply_or_error->response_type != 0) { + return; + } + + auto error = (xcb_generic_error_t *)reply_or_error; + if (error_action != PENDING_REPLY_ACTION_IGNORE) { + log_error("X error for request in %s at %s:%d: %s", func, file, line, + x_error_code_to_string(error->full_sequence, error->major_code, + error->minor_code, error->error_code)); + } else { + log_debug("Expected X error for request in %s at %s:%d: %s", func, file, line, + x_error_code_to_string(error->full_sequence, error->major_code, + error->minor_code, error->error_code)); + } + switch (error_action) { + case PENDING_REPLY_ACTION_ABORT: + log_fatal("An unrecoverable X error occurred, " + "aborting..."); + abort(); + case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break; + case PENDING_REPLY_ACTION_IGNORE: break; + } +} + /** * Xlib error handler function. */ @@ -238,7 +274,6 @@ c->screen = DefaultScreen(dpy); c->screen_info = xcb_aux_get_screen(c->c, c->screen); - c->event_sync_sent = false; // Do a round trip to fetch the current sequence number auto cookie = xcb_get_input_focus(c->c); @@ -1063,15 +1098,36 @@ return x_ingest_event(c, e); } +bool x_prepare_for_sleep(struct x_connection *c) { + if (!list_is_empty(&c->pending_x_requests)) { + auto last = list_entry(c->pending_x_requests.prev, + struct x_async_request_base, siblings); + if (c->event_sync != last->sequence) { + // Send an async request that is guaranteed to error, see comments + // on `event_sync` for why. + auto req = ccalloc(1, struct x_generic_async_request); + req->func = __func__; + req->file = __FILE__; + req->line = __LINE__; + req->error_action = PENDING_REPLY_ACTION_IGNORE; + req->base.sequence = xcb_free_pixmap(c->c, XCB_NONE).sequence; + req->base.callback = x_generic_async_callback; + req->base.no_reply = true; + c->event_sync = req->base.sequence; + x_await_request(c, &req->base); + log_trace("Sending event sync request to catch response to " + "pending request, last sequence: %u, event sync: %u", + last->sequence, c->event_sync); + } + } + XFlush(c->dpy); + xcb_flush(c->c); + return true; +} + xcb_generic_event_t *x_poll_for_event(struct x_connection *c, bool queued) { xcb_raw_generic_event_t *ret = NULL; while (true) { - if (!list_is_empty(&c->pending_x_requests) && !c->event_sync_sent) { - // Send a request that is guaranteed to error, see comments on - // `event_sync` for why. - c->event_sync = xcb_free_pixmap(c->c, XCB_NONE).sequence; - c->event_sync_sent = true; - } ret = x_poll_for_event_impl(c, queued); if (ret == NULL || ret->response_type != 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/picom-12.3/src/x.h new/picom-12.5/src/x.h --- old/picom-12.3/src/x.h 2024-10-14 17:25:35.000000000 +0200 +++ new/picom-12.5/src/x.h 2024-11-13 07:48:38.000000000 +0100 @@ -112,7 +112,6 @@ /// events. The only problem, if no events are coming, we will be stuck /// indefinitely, so we have to make our own events. uint32_t event_sync; - bool event_sync_sent; }; /// Monitor info @@ -474,6 +473,16 @@ list_insert_before(&c->pending_x_requests, &req->siblings); } +/// Flush all X buffers to ensure we don't sleep with outgoing messages not sent. +/// +/// If there are requests pending replies, an event sync request will +/// be sent if necessary. See comments on `event_sync` for more information. MUST be +/// called before sleep to ensure we can handle replies/events in a timely manner. This +/// function MIGHT read data from X into xcb buffer (because `xcb_flush` might read, +/// ridiculous, I know), so `x_poll_for_event(queued = true)` MUST be called after this to +/// drain the buffer. +bool x_prepare_for_sleep(struct x_connection *c); + /// Poll for the next X event. This is like `xcb_poll_for_event`, but also includes /// machinery for handling async replies. Calling `xcb_poll_for_event` directly will /// cause replies to async requests to be lost, so that should never be called.
