From 606844c4bbff1f1069593edf1fd9ad4094f09ef9 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sun, 28 Jan 2024 21:44:19 +0000 Subject: [PATCH 01/16] Update CHANGELOG.md Signed-off-by: Yuxuan Shui --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb8bf7421e..3ef49316e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +# v11.1 (2024-Jan-28) + ## Bug fixes * Fix missing fading on window close for some window managers. (#704) From 71e29c4128725856ab1546a2501823bdac32d819 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 17:44:18 +0000 Subject: [PATCH 02/16] Add .direnv to .gitignore Signed-off-by: Yuxuan Shui --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 20b39d0826..a8330cb8cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Build files .deps +.direnv aclocal.m4 autom4te.cache config.log From f3bdd01dc8afcc1e311ec6e81d999f2ec2b9965a Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 17:44:59 +0000 Subject: [PATCH 03/16] vblank: don't use symbols from backend/gl/glx.h sgi video sync runs in a separate thread, we don't want to have potential races between threads. Signed-off-by: Yuxuan Shui --- src/vblank.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vblank.c b/src/vblank.c index ff83a9a76e..a6d9e03914 100644 --- a/src/vblank.c +++ b/src/vblank.c @@ -18,7 +18,6 @@ #include #include -#include "backend/gl/glx.h" #endif #include "compiler.h" @@ -96,6 +95,8 @@ struct sgi_video_sync_thread_args { pthread_cond_t start_cnd; }; +static PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; + static bool check_sgi_video_sync_extension(Display *dpy, int screen) { const char *glx_ext = glXQueryExtensionsString(dpy, screen); const char *needle = "GLX_SGI_video_sync"; From 8ca66f8a005e7d98545c22c2889c38926d218c8e Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Mon, 29 Jan 2024 23:16:51 +0300 Subject: [PATCH 04/16] win: allow corner-radius-rules without corner-radius check if there is an override in corner-radius-rules even when corner-radius is 0. --- src/win.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/win.c b/src/win.c index b8bfe76093..37f198a15b 100644 --- a/src/win.c +++ b/src/win.c @@ -1139,16 +1139,16 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w) * Determine if a window should have rounded corners. */ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) { - if (ps->o.corner_radius == 0) { - w->corner_radius = 0; - return; - } - void *radius_override = NULL; if (c2_match(ps, w, ps->o.corner_radius_rules, &radius_override)) { log_debug("Matched corner rule! %d", w->corner_radius); } + if (ps->o.corner_radius == 0 && !radius_override) { + w->corner_radius = 0; + return; + } + // Don't round full screen windows & excluded windows, // unless we find a corner override in corner_radius_rules if (!radius_override && ((w && win_is_fullscreen(ps, w)) || From 1bfb1299857dea9b058ba6934529c6e62a59ea29 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 21:02:36 +0000 Subject: [PATCH 05/16] backend: don't choose SGI_video_sync vblank if opengl is not enabled Signed-off-by: Yuxuan Shui --- src/backend/driver.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backend/driver.c b/src/backend/driver.c index f17743a4aa..a70384e1ea 100644 --- a/src/backend/driver.c +++ b/src/backend/driver.c @@ -20,10 +20,13 @@ void apply_driver_workarounds(struct session *ps, enum driver driver) { } enum vblank_scheduler_type choose_vblank_scheduler(enum driver driver) { + enum vblank_scheduler_type type = VBLANK_SCHEDULER_PRESENT; +#ifdef CONFIG_OPENGL if (driver & DRIVER_NVIDIA) { - return VBLANK_SCHEDULER_SGI_VIDEO_SYNC; + type = VBLANK_SCHEDULER_SGI_VIDEO_SYNC; } - return VBLANK_SCHEDULER_PRESENT; +#endif + return type; } enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_window_t window) { From 5fba210ad64b6a15e415c872e552c3b158adc7bc Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 22:07:04 +0000 Subject: [PATCH 06/16] vblank: make schedule fallible Signed-off-by: Yuxuan Shui --- src/vblank.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/vblank.c b/src/vblank.c index a6d9e03914..b29910b996 100644 --- a/src/vblank.c +++ b/src/vblank.c @@ -64,7 +64,7 @@ struct vblank_scheduler_ops { size_t size; void (*init)(struct vblank_scheduler *self); void (*deinit)(struct vblank_scheduler *self); - void (*schedule)(struct vblank_scheduler *self); + bool (*schedule)(struct vblank_scheduler *self); bool (*handle_x_events)(struct vblank_scheduler *self); }; @@ -240,7 +240,7 @@ static void *sgi_video_sync_thread(void *data) { return NULL; } -static void sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) { +static bool sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) { auto self = (struct sgi_video_sync_vblank_scheduler *)base; log_verbose("Requesting vblank event for msc %d", self->last_msc + 1); pthread_mutex_lock(&self->vblank_requested_mtx); @@ -248,6 +248,7 @@ static void sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) { base->vblank_event_requested = true; pthread_cond_signal(&self->vblank_requested_cnd); pthread_mutex_unlock(&self->vblank_requested_mtx); + return true; } static void @@ -309,13 +310,14 @@ static void sgi_video_sync_scheduler_deinit(struct vblank_scheduler *base) { } #endif -static void present_vblank_scheduler_schedule(struct vblank_scheduler *base) { +static bool present_vblank_scheduler_schedule(struct vblank_scheduler *base) { auto self = (struct present_vblank_scheduler *)base; log_verbose("Requesting vblank event for window 0x%08x, msc %" PRIu64, base->target_window, self->last_msc + 1); assert(!base->vblank_event_requested); x_request_vblank_event(base->c, base->target_window, self->last_msc + 1); base->vblank_event_requested = true; + return true; } static void present_vblank_callback(EV_P attr_unused, ev_timer *w, int attr_unused revents) { @@ -440,17 +442,19 @@ static const struct vblank_scheduler_ops vblank_scheduler_ops[LAST_VBLANK_SCHEDU #endif }; -static void vblank_scheduler_schedule_internal(struct vblank_scheduler *self) { +static bool vblank_scheduler_schedule_internal(struct vblank_scheduler *self) { assert(self->type < LAST_VBLANK_SCHEDULER); auto fn = vblank_scheduler_ops[self->type].schedule; assert(fn != NULL); - fn(self); + return fn(self); } bool vblank_scheduler_schedule(struct vblank_scheduler *self, vblank_callback_t vblank_callback, void *user_data) { if (self->callback_count == 0 && self->wind_down == 0) { - vblank_scheduler_schedule_internal(self); + if (!vblank_scheduler_schedule_internal(self)) { + return false; + } } if (self->callback_count == self->callback_capacity) { size_t new_capacity = From 14a345a81755943f85e7e1fa76f2d341633ad2ba Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 22:11:01 +0000 Subject: [PATCH 07/16] vblank: make init fallible Improve error handling in sgi_video_sync_scheduler_init a bit. Signed-off-by: Yuxuan Shui --- src/vblank.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vblank.c b/src/vblank.c index b29910b996..6242c7a170 100644 --- a/src/vblank.c +++ b/src/vblank.c @@ -62,7 +62,7 @@ struct present_vblank_scheduler { struct vblank_scheduler_ops { size_t size; - void (*init)(struct vblank_scheduler *self); + bool (*init)(struct vblank_scheduler *self); void (*deinit)(struct vblank_scheduler *self); bool (*schedule)(struct vblank_scheduler *self); bool (*handle_x_events)(struct vblank_scheduler *self); @@ -263,12 +263,13 @@ sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused vblank_scheduler_invoke_callbacks(&sched->base, &event); } -static void sgi_video_sync_scheduler_init(struct vblank_scheduler *base) { +static bool sgi_video_sync_scheduler_init(struct vblank_scheduler *base) { auto self = (struct sgi_video_sync_vblank_scheduler *)base; auto args = (struct sgi_video_sync_thread_args){ .self = self, .start_status = -1, }; + bool succeeded = true; pthread_mutex_init(&args.start_mtx, NULL); pthread_cond_init(&args.start_cnd, NULL); @@ -288,11 +289,13 @@ static void sgi_video_sync_scheduler_init(struct vblank_scheduler *base) { if (args.start_status != 0) { log_fatal("Failed to start sgi_video_sync_thread, error code: %d", args.start_status); - abort(); + succeeded = false; + } else { + log_info("Started sgi_video_sync_thread"); } pthread_mutex_destroy(&args.start_mtx); pthread_cond_destroy(&args.start_cnd); - log_info("Started sgi_video_sync_thread"); + return succeeded; } static void sgi_video_sync_scheduler_deinit(struct vblank_scheduler *base) { @@ -330,7 +333,7 @@ static void present_vblank_callback(EV_P attr_unused, ev_timer *w, int attr_unus vblank_scheduler_invoke_callbacks(&sched->base, &event); } -static void present_vblank_scheduler_init(struct vblank_scheduler *base) { +static bool present_vblank_scheduler_init(struct vblank_scheduler *base) { auto self = (struct present_vblank_scheduler *)base; base->type = VBLANK_SCHEDULER_PRESENT; ev_timer_init(&self->callback_timer, present_vblank_callback, 0, 0); @@ -342,6 +345,7 @@ static void present_vblank_scheduler_init(struct vblank_scheduler *base) { set_cant_fail_cookie(base->c, select_input); self->event = xcb_register_for_special_xge(base->c->c, &xcb_present_id, self->event_id, NULL); + return true; } static void present_vblank_scheduler_deinit(struct vblank_scheduler *base) { From bacdb919c758d8e9d821c5c49b3ae63b8423c2d4 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 23:55:29 +0000 Subject: [PATCH 08/16] Update CHANGELOG.md Signed-off-by: Yuxuan Shui --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef49316e7..c976959f82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Unreleased +## Bug fixes + +* Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170) + # v11.1 (2024-Jan-28) ## Bug fixes From fdbcd15975fa01efba49c903e35b259a569591f0 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 23:57:11 +0000 Subject: [PATCH 09/16] backend: fix clang warning Signed-off-by: Yuxuan Shui --- src/backend/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/driver.c b/src/backend/driver.c index a70384e1ea..99ea4d7a3a 100644 --- a/src/backend/driver.c +++ b/src/backend/driver.c @@ -19,7 +19,7 @@ void apply_driver_workarounds(struct session *ps, enum driver driver) { } } -enum vblank_scheduler_type choose_vblank_scheduler(enum driver driver) { +enum vblank_scheduler_type choose_vblank_scheduler(enum driver driver attr_unused) { enum vblank_scheduler_type type = VBLANK_SCHEDULER_PRESENT; #ifdef CONFIG_OPENGL if (driver & DRIVER_NVIDIA) { From 0638de5c568dab4215140a37bb7be702301a038b Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Tue, 30 Jan 2024 22:39:03 +0000 Subject: [PATCH 10/16] Update CHANGELOG.md On a second thought, the `corner-radius-rules` is a user noticeable behavioral change, it should be more prominent. Signed-off-by: Yuxuan Shui --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c976959f82..e06f21069f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Unreleased -## Bug fixes +## New features * Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170) From 238c3cc8336fe24370a3ca44ff0d891ca8907c94 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jan 2024 22:28:22 +0000 Subject: [PATCH 11/16] vblank: reset SGI_video_sync scheduler if it's getting nonsense If resetting fails, set a flag so all future schedule calls will fail. Fixes #1168 Signed-off-by: Yuxuan Shui --- CHANGELOG.md | 4 ++++ src/vblank.c | 58 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e06f21069f..a11085678b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ * Allow `corner-radius-rules` to override `corner-radius = 0`. Previously setting corner radius to 0 globally disables rounded corners. (#1170) +## Bug fixes + +* Workaround a NVIDIA problem that causes high CPU usage after suspend/resume (#1172, #1168) + # v11.1 (2024-Jan-28) ## Bug fixes diff --git a/src/vblank.c b/src/vblank.c index 6242c7a170..a9f82116f1 100644 --- a/src/vblank.c +++ b/src/vblank.c @@ -77,13 +77,14 @@ struct sgi_video_sync_vblank_scheduler { // Since glXWaitVideoSyncSGI blocks, we need to run it in a separate thread. // ... and all the thread shenanigans that come with it. - _Atomic unsigned int last_msc; - _Atomic uint64_t last_ust; + _Atomic unsigned int current_msc; + _Atomic uint64_t current_ust; ev_async notify; pthread_t sync_thread; bool running, error; + unsigned int last_msc; - /// Protects `running`, `error` and `base.vblank_event_requested` + /// Protects `running`, and `base.vblank_event_requested` pthread_mutex_t vblank_requested_mtx; pthread_cond_t vblank_requested_cnd; }; @@ -208,8 +209,8 @@ static void *sgi_video_sync_thread(void *data) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - atomic_store(&self->last_msc, last_msc); - atomic_store(&self->last_ust, + atomic_store(&self->current_msc, last_msc); + atomic_store(&self->current_ust, (uint64_t)(now.tv_sec * 1000000 + now.tv_nsec / 1000)); ev_async_send(self->base.loop, &self->notify); pthread_mutex_lock(&self->vblank_requested_mtx); @@ -242,7 +243,10 @@ static void *sgi_video_sync_thread(void *data) { static bool sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) { auto self = (struct sgi_video_sync_vblank_scheduler *)base; - log_verbose("Requesting vblank event for msc %d", self->last_msc + 1); + if (self->error) { + return false; + } + log_verbose("Requesting vblank event for msc %d", self->current_msc + 1); pthread_mutex_lock(&self->vblank_requested_mtx); assert(!base->vblank_event_requested); base->vblank_event_requested = true; @@ -252,16 +256,7 @@ static bool sgi_video_sync_scheduler_schedule(struct vblank_scheduler *base) { } 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 event = (struct vblank_event){ - .msc = atomic_load(&sched->last_msc), - .ust = atomic_load(&sched->last_ust), - }; - sched->base.vblank_event_requested = false; - log_verbose("Received vblank event for msc %lu", event.msc); - vblank_scheduler_invoke_callbacks(&sched->base, &event); -} +sgi_video_sync_scheduler_callback(EV_P attr_unused, ev_async *w, int attr_unused revents); static bool sgi_video_sync_scheduler_init(struct vblank_scheduler *base) { auto self = (struct sgi_video_sync_vblank_scheduler *)base; @@ -293,6 +288,8 @@ static bool sgi_video_sync_scheduler_init(struct vblank_scheduler *base) { } else { log_info("Started sgi_video_sync_thread"); } + self->error = !succeeded; + self->last_msc = 0; pthread_mutex_destroy(&args.start_mtx); pthread_cond_destroy(&args.start_cnd); return succeeded; @@ -311,6 +308,35 @@ static void sgi_video_sync_scheduler_deinit(struct vblank_scheduler *base) { pthread_mutex_destroy(&self->vblank_requested_mtx); pthread_cond_destroy(&self->vblank_requested_cnd); } + +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) { + // 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; + } + auto event = (struct vblank_event){ + .msc = msc, + .ust = atomic_load(&sched->current_ust), + }; + sched->base.vblank_event_requested = false; + sched->last_msc = msc; + log_verbose("Received vblank event for msc %lu", event.msc); + vblank_scheduler_invoke_callbacks(&sched->base, &event); +} #endif static bool present_vblank_scheduler_schedule(struct vblank_scheduler *base) { From 90f5f4ca2944a7705e43b31b680fcf311efb3b4d Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Wed, 31 Jan 2024 06:09:28 +0300 Subject: [PATCH 12/16] fix a bunch of typos in comments --- src/backend/backend.h | 10 +++++----- src/backend/gl/gl_common.c | 4 ++-- src/backend/gl/gl_common.h | 2 +- src/common.h | 6 +++--- src/compiler.h | 2 +- src/config.c | 2 +- src/config.h | 2 +- src/event.c | 8 ++++---- src/file_watch.c | 2 +- src/kernel.c | 2 +- src/opengl.c | 2 +- src/opengl.h | 6 +++--- src/options.c | 8 ++++---- src/picom.c | 12 ++++++------ src/render.c | 4 ++-- src/statistics.c | 4 ---- src/utils.c | 4 ++-- src/utils.h | 2 +- src/win.c | 8 ++++---- src/win.h | 8 ++++---- src/win_defs.h | 2 +- 21 files changed, 48 insertions(+), 52 deletions(-) diff --git a/src/backend/backend.h b/src/backend/backend.h index 1b4df729d0..5896e19d64 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -204,7 +204,7 @@ struct backend_operations { * @param backend_data backend data * @param pixmap X pixmap to bind * @param fmt information of the pixmap's visual - * @param owned whether the ownership of the pixmap is transfered to the backend + * @param owned whether the ownership of the pixmap is transferred to the backend * @return backend internal data structure bound with this pixmap */ void *(*bind_pixmap)(backend_t *backend_data, xcb_pixmap_t pixmap, @@ -220,7 +220,7 @@ struct backend_operations { struct backend_shadow_context *ctx); /// Create a shadow image based on the parameters. Resulting image should have a - /// size of `width + radisu * 2` x `height + radius * 2`. Radius is set when the + /// size of `width + radius * 2` x `height + radius * 2`. Radius is set when the /// shadow context is created. /// Default implementation: default_render_shadow /// @@ -279,9 +279,9 @@ struct backend_operations { bool (*is_image_transparent)(backend_t *backend_data, void *image_data) attr_nonnull(1, 2); - /// Get the age of the buffer content we are currently rendering ontop + /// Get the age of the buffer content we are currently rendering on top /// of. The buffer that has just been `present`ed has a buffer age of 1. - /// Everytime `present` is called, buffers get older. Return -1 if the + /// Every time `present` is called, buffers get older. Return -1 if the /// buffer is empty. /// /// Optional @@ -290,7 +290,7 @@ struct backend_operations { /// Get the render time of the last frame. If the render is still in progress, /// returns false. The time is returned in `ts`. Frames are delimited by the /// present() calls. i.e. after a present() call, last_render_time() should start - /// reporting the time of the just presen1ted frame. + /// reporting the time of the just presented frame. /// /// Optional, if not available, the most conservative estimation will be used. bool (*last_render_time)(backend_t *backend_data, struct timespec *ts); diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 76d4571b08..73bfea9446 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -185,7 +185,7 @@ void gl_destroy_window_shader(backend_t *backend_data attr_unused, void *shader) * @note In order to reduce number of textures which needs to be * allocated and deleted during this recursive render * we reuse the same two textures for render source and - * destination simply by alterating between them. + * destination simply by alternating between them. * Unfortunately on first iteration source_texture might * be read-only. In this case we will select auxiliary_texture as * destination_texture in order not to touch that read-only source @@ -253,7 +253,7 @@ _gl_average_texture_color(backend_t *base, GLuint source_texture, GLuint destina /* * @brief Builds a 1x1 texture which has color corresponding to the average of all - * pixels of img by recursively rendering into texture of quorter the size (half + * pixels of img by recursively rendering into texture of quarter the size (half * width and half height). * Returned texture must not be deleted, since it's owned by the gl_image. It will be * deleted when the gl_image is released. diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index c9cb600e81..a1f396b8d6 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -78,7 +78,7 @@ typedef struct { GLint color_loc; } gl_fill_shader_t; -/// @brief Wrapper of a binded GL texture. +/// @brief Wrapper of a bound GL texture. struct gl_texture { int refcount; bool has_alpha; diff --git a/src/common.h b/src/common.h index 52967e600d..6ba9b4f8a1 100644 --- a/src/common.h +++ b/src/common.h @@ -240,8 +240,8 @@ typedef struct session { /// Either the backend is currently rendering a frame, or a frame has been /// rendered but has yet to be presented. In either case, we should not start /// another render right now. As if we start issuing rendering commands now, we - /// will have to wait for either the the current render to finish, or the current - /// back buffer to be become available again. In either case, we will be wasting + /// will have to wait for either the current render to finish, or the current + /// back buffer to become available again. In either case, we will be wasting /// time. bool backend_busy; /// Whether a render is queued. This generally means there are pending updates @@ -268,7 +268,7 @@ typedef struct session { struct x_convolution_kernel **blur_kerns_cache; /// If we should quit bool quit : 1; - // TODO(yshui) use separate flags for dfferent kinds of updates so we don't + // TODO(yshui) use separate flags for different kinds of updates so we don't // waste our time. /// Whether there are pending updates, like window creation, etc. bool pending_updates : 1; diff --git a/src/compiler.h b/src/compiler.h index 302bc7bbed..544daa559e 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -52,7 +52,7 @@ #else # define attr_warn_unused_result #endif -// An alias for conveninence +// An alias for convenience #define must_use attr_warn_unused_result #if __has_attribute(nonnull) diff --git a/src/config.c b/src/config.c index 22774f7ff7..08d9f62872 100644 --- a/src/config.c +++ b/src/config.c @@ -563,7 +563,7 @@ static char *locate_auxiliary_file_at(const char *base, const char *scope, const } /** - * Get a path of an auxiliary file to read, could be a shader file, or any supplimenrary + * Get a path of an auxiliary file to read, could be a shader file, or any supplementary * file. * * Follows the XDG specification to search for the shader file in configuration locations. diff --git a/src/config.h b/src/config.h index d91dbb4563..3b39887748 100644 --- a/src/config.h +++ b/src/config.h @@ -311,7 +311,7 @@ char **xdg_config_dirs(void); /// Parse a configuration file /// Returns the actually config_file name used, allocated on heap /// Outputs: -/// shadow_enable = whether shaodw is enabled globally +/// shadow_enable = whether shadow is enabled globally /// fading_enable = whether fading is enabled globally /// win_option_mask = whether option overrides for specific window type is set for given /// options diff --git a/src/event.c b/src/event.c index 739540dc9a..28f67d8554 100644 --- a/src/event.c +++ b/src/event.c @@ -29,7 +29,7 @@ /// made the query when those events were already in the queue. so the reply you got is /// more up-to-date than the events). Also, handling events when other client are making /// concurrent requests is not good. Because the server states are changing without you -/// knowning them. This is super racy, and can cause lots of potential problems. +/// knowing them. This is super racy, and can cause lots of potential problems. /// /// All of above mandates we do these things: /// 1. Grab server when handling events @@ -324,7 +324,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t } if (ev->parent == ps->c.screen_info->root) { - // X will generate reparent notifiy even if the parent didn't actually + // X will generate reparent notify even if the parent didn't actually // change (i.e. reparent again to current parent). So we check if that's // the case auto w = find_win(ps, ev->window); @@ -465,7 +465,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t } } - // Unconcerned about any other proprties on root window + // Unconcerned about any other properties on root window return; } @@ -499,7 +499,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t } if (ev->atom == ps->atoms->a_NET_WM_BYPASS_COMPOSITOR) { - // Unnecessay until we remove the queue_redraw in ev_handle + // Unnecessary until we remove the queue_redraw in ev_handle queue_redraw(ps); } diff --git a/src/file_watch.c b/src/file_watch.c index faa8f68933..4532fb6173 100644 --- a/src/file_watch.c +++ b/src/file_watch.c @@ -158,7 +158,7 @@ bool file_watch_add(void *_fwr, const char *filename, file_watch_cb_t cb, void * fflags |= NOTE_CLOSE_WRITE; #else // NOTE_WRITE will receive notification more frequent than necessary, so is less - // preferrable + // preferable fflags |= NOTE_WRITE; #endif struct kevent ev = { diff --git a/src/kernel.c b/src/kernel.c index b5e1a487d5..a9865c9335 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -96,7 +96,7 @@ static inline double estimate_first_row_sum(double size, double r) { // `a` is gaussian at (size, 0) double a = exp(-0.5 * size * size / (r * r)) / sqrt(2 * M_PI) / r; // The sum of the whole kernel is normalized to 1, i.e. each element is divided by - // factor sqaured. So the sum of the first row is a * factor / factor^2 = a / + // factor squared. So the sum of the first row is a * factor / factor^2 = a / // factor return a / factor; } diff --git a/src/opengl.c b/src/opengl.c index 4031e41bd5..7360640ce5 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -1129,7 +1129,7 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, // TODO(bhagwan) this is a mess and needs a more consistent way of getting the border // pixel I tried looking for a notify event for XCB_CW_BORDER_PIXEL (in // xcb_create_window()) or a way to get the pixels from xcb_render_picture_t but the -// documentation for the xcb_xrender extension is literaly non existent... +// documentation for the xcb_xrender extension is literally non existent... // // NOTE(yshui) There is no consistent way to get the "border" color of a X window. From // the WM's perspective there are multiple ways to implement window borders. Using diff --git a/src/opengl.h b/src/opengl.h index affad2499a..cd074ff26e 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -75,7 +75,7 @@ typedef struct glx_session { glx_round_pass_t *round_passes; } glx_session_t; -/// @brief Wrapper of a binded GLX texture. +/// @brief Wrapper of a bound GLX texture. typedef struct _glx_texture { GLuint texture; GLXPixmap glpixmap; @@ -121,9 +121,9 @@ bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, int x, int y, int wi void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2); /** - * Check if a texture is binded, or is binded to the given pixmap. + * Check if a texture is bound, or is bound to the given pixmap. */ -static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) { +static inline bool glx_tex_bound(const glx_texture_t *ptex, xcb_pixmap_t pixmap) { return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap); } diff --git a/src/options.c b/src/options.c index 3637856813..148760cc64 100644 --- a/src/options.c +++ b/src/options.c @@ -316,9 +316,9 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all int o = 0, longopt_idx = -1; - // Pre-parse the commandline arguments to check for --config and invalid + // Pre-parse the command line arguments to check for --config and invalid // switches - // Must reset optind to 0 here in case we reread the commandline + // Must reset optind to 0 here in case we reread the command line // arguments optind = 1; *config_file = NULL; @@ -370,7 +370,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, // instead of commas in atof(). setlocale(LC_NUMERIC, "C"); - // Parse commandline arguments. Range checking will be done later. + // Parse command line arguments. Range checking will be done later. bool failed = false; const char *deprecation_message attr_unused = @@ -722,7 +722,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, opt->blur_strength = atoi(optarg); break; case 333: - // --cornor-radius + // --corner-radius opt->corner_radius = atoi(optarg); break; case 334: diff --git a/src/picom.c b/src/picom.c index 45a033fdad..feac750e4a 100644 --- a/src/picom.c +++ b/src/picom.c @@ -270,7 +270,7 @@ enum vblank_callback_action reschedule_render_at_vblank(struct vblank_event *e, /// is no render currently scheduled. i.e. render_queued == false. /// 2. then, we need to figure out the best time to start rendering. we need to /// at least know when the next vblank will start, as we can't start render -/// before the current rendered frame is diplayed on screen. we have this +/// before the current rendered frame is displayed on screen. we have this /// information from the vblank scheduler, it will notify us when that happens. /// we might also want to delay the rendering even further to reduce latency, /// this is discussed below, in FUTURE WORKS. @@ -1869,7 +1869,7 @@ static void x_event_callback(EV_P attr_unused, ev_io *w, int revents attr_unused /** * Turn on the program reset flag. * - * This will result in the compostior resetting itself after next paint. + * This will result in the compositor resetting itself after next paint. */ static void reset_enable(EV_P_ ev_signal *w attr_unused, int revents attr_unused) { log_info("picom is resetting..."); @@ -1946,11 +1946,11 @@ static bool load_shader_source_for_condition(const c2_lptr_t *cond, void *data) /** * Initialize a session. * - * @param argc number of commandline arguments - * @param argv commandline arguments + * @param argc number of command line arguments + * @param argv command line arguments * @param dpy the X Display * @param config_file the path to the config file - * @param all_xerros whether we should report all X errors + * @param all_xerrors whether we should report all X errors * @param fork whether we will fork after initialization */ static session_t *session_init(int argc, char **argv, Display *dpy, @@ -2496,7 +2496,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ps->server_grabbed = true; // We are going to pull latest information from X server now, events sent by X - // earlier is irrelavant at this point. + // earlier is irrelevant at this point. // A better solution is probably grabbing the server from the very start. But I // think there still could be race condition that mandates discarding the events. x_discard_events(&ps->c); diff --git a/src/render.c b/src/render.c index ec50d8a3ec..fadd833586 100644 --- a/src/render.c +++ b/src/render.c @@ -89,7 +89,7 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h fbcfg = ppaint->fbcfg; } - if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap)) { + if (force || !glx_tex_bound(ppaint->ptex, ppaint->pixmap)) { return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, repeat, fbcfg); } @@ -378,7 +378,7 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { } #ifdef CONFIG_OPENGL - if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE)) { + if (BKEND_GLX == ps->o.backend && !glx_tex_bound(ppaint->ptex, XCB_NONE)) { return false; } #endif diff --git a/src/statistics.c b/src/statistics.c index 11c7466ef6..1a3b335fc4 100644 --- a/src/statistics.c +++ b/src/statistics.c @@ -51,10 +51,6 @@ void render_statistics_add_render_time_sample(struct render_statistics *rs, int } /// How much time budget we should give to the backend for rendering, in microseconds. -/// -/// A `divisor` is also returned, indicating the target framerate. The divisor is -/// the number of vblanks we should wait between each frame. A divisor of 1 means -/// full framerate, 2 means half framerate, etc. unsigned int render_statistics_get_budget(struct render_statistics *rs) { if (rs->render_times.nelem < rs->render_times.window_size) { // No valid render time estimates yet. Assume maximum budget. diff --git a/src/utils.c b/src/utils.c index 5709fa21d2..53766d6d19 100644 --- a/src/utils.c +++ b/src/utils.c @@ -141,10 +141,10 @@ void rolling_max_pop_front(struct rolling_max *rm, int front) { } void rolling_max_push_back(struct rolling_max *rm, int val) { - // Update the prority queue. + // Update the priority queue. // Remove all elements smaller than the new element from the queue. Because // the new element will become the maximum element before them, and since they - // come b1efore the new element, they will have been popped before the new + // come before the new element, they will have been popped before the new // element, so they will never become the maximum element. while (rm->np) { int p_tail = IDX(rm->p_head + rm->np - 1); diff --git a/src/utils.h b/src/utils.h index 446fba8be7..73cb71127e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -222,7 +222,7 @@ allocchk_(const char *func_name, const char *file, unsigned int line, void *ptr) ((type *)allocchk(calloc((size_t)tmp, sizeof(type)))); \ }) -/// @brief Wrapper of ealloc(). +/// @brief Wrapper of realloc(). #define crealloc(ptr, nmemb) \ ({ \ auto tmp = (nmemb); \ diff --git a/src/win.c b/src/win.c index 37f198a15b..c5690b6157 100644 --- a/src/win.c +++ b/src/win.c @@ -954,7 +954,7 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new // Delayed update of shadow image // By setting WIN_FLAGS_SHADOW_STALE, we ask win_process_flags to - // re-create or release the shaodw in based on whether w->shadow + // re-create or release the shadow in based on whether w->shadow // is set. win_set_flags(w, WIN_FLAGS_SHADOW_STALE); @@ -1985,7 +1985,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) { // Add border width because we are using a different origin. // X thinks the top left of the inner window is the origin - // (for the bounding shape, althought xcb_get_geometry thinks + // (for the bounding shape, although xcb_get_geometry thinks // the outer top left (outer means outside of the window // border) is the origin), // We think the top left of the border is the origin @@ -2314,7 +2314,7 @@ bool destroy_win_start(session_t *ps, struct win *w) { HASH_DEL(ps->windows, w); if (!w->managed || mw->state == WSTATE_UNMAPPED) { - // Window is already unmapped, or is an unmanged window, just + // Window is already unmapped, or is an unmanaged window, just // destroy it destroy_win_finish(ps, w); return true; @@ -2717,7 +2717,7 @@ static inline bool rect_is_fullscreen(const session_t *ps, int x, int y, int wid } /** - * Check if a window is fulscreen using EWMH + * Check if a window is full-screen using EWMH * * TODO(yshui) cache this property */ diff --git a/src/win.h b/src/win.h index 51e7f9d32c..c45c7ef88c 100644 --- a/src/win.h +++ b/src/win.h @@ -244,13 +244,13 @@ struct managed_win { 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. + /// X offset of shadow. Affected by command line argument. int shadow_dx; - /// Y offset of shadow. Affected by commandline argument. + /// Y offset of shadow. Affected by command line argument. int shadow_dy; - /// Width of shadow. Affected by window size and commandline argument. + /// Width of shadow. Affected by window size and command line argument. int shadow_width; - /// Height of shadow. Affected by window size and commandline argument. + /// Height of shadow. Affected by window size and command line argument. int shadow_height; /// Picture to render shadow. Affected by window size. paint_t shadow_paint; diff --git a/src/win_defs.h b/src/win_defs.h index e032bc747c..10ad0238a4 100644 --- a/src/win_defs.h +++ b/src/win_defs.h @@ -68,7 +68,7 @@ typedef enum { } winstate_t; enum win_flags { - // Note: *_NONE flags are mostly redudant and meant for detecting logical errors + // Note: *_NONE flags are mostly redundant and meant for detecting logical errors // in the code /// pixmap is out of date, will be update in win_process_flags From 4401666cfb06f9d76a1bf109feda42730a6da9aa Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Thu, 1 Feb 2024 02:31:29 +0300 Subject: [PATCH 13/16] x: add the x_get_visual_for_depth function it returns the first found visual for the given depth --- src/x.c | 15 +++++++++++++++ src/x.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/x.c b/src/x.c index 06c8b939d6..c4de9113f9 100644 --- a/src/x.c +++ b/src/x.c @@ -321,6 +321,21 @@ xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standa return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id); } +xcb_visualid_t x_get_visual_for_depth(struct x_connection *c, uint8_t depth) { + xcb_screen_iterator_t screen_it = xcb_setup_roots_iterator(xcb_get_setup(c->c)); + for (; screen_it.rem; xcb_screen_next(&screen_it)) { + xcb_depth_iterator_t depth_it = + xcb_screen_allowed_depths_iterator(screen_it.data); + for (; depth_it.rem; xcb_depth_next(&depth_it)) { + if (depth_it.data->depth == depth) { + return xcb_depth_visuals_iterator(depth_it.data).data->visual_id; + } + } + } + + return XCB_NONE; +} + xcb_render_pictformat_t x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std) { x_get_server_pictfmts(c); diff --git a/src/x.h b/src/x.h index df45b5cca7..fe44313789 100644 --- a/src/x.h +++ b/src/x.h @@ -408,6 +408,8 @@ struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t vis xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std); +xcb_visualid_t x_get_visual_for_depth(struct x_connection *c, uint8_t depth); + xcb_render_pictformat_t x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std); From a655730e490a57f53bb38a740aa6dbaf8f872ecc Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Thu, 1 Feb 2024 06:25:38 +0300 Subject: [PATCH 14/16] picom: fix binding the root background pixmap in case of depth mismatch if the root background pixmap's depth doesn't match the root window's depth, find a suitable visual for the root background pixmap's depth and use it instead of the root window's visual --- src/picom.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/picom.c b/src/picom.c index feac750e4a..4e7a1b9af5 100644 --- a/src/picom.c +++ b/src/picom.c @@ -1158,14 +1158,43 @@ void root_damaged(session_t *ps) { } auto pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms); if (pixmap != XCB_NONE) { + xcb_get_geometry_reply_t *r = xcb_get_geometry_reply( + ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL); + if (!r) { + goto err; + } + + // We used to assume that pixmaps pointed by the root background + // pixmap atoms are owned by the root window and have the same + // depth and hence the same visual that we can use to bind them. + // However, some applications break this assumption, e.g. the + // Xfce's desktop manager xfdesktop that sets the _XROOTPMAP_ID + // atom to a pixmap owned by it that seems to always have 32 bpp + // depth when the common root window's depth is 24 bpp. So use the + // root window's visual only if the root background pixmap's depth + // matches the root window's depth. Otherwise, find a suitable + // visual for the root background pixmap's depth and use it. + // + // We can't obtain a suitable visual for the root background + // pixmap the same way as the win_bind_pixmap function because it + // requires a window and we have only a pixmap. We also can't not + // bind the root background pixmap in case of depth mismatch + // because some options rely on it's content, e.g. + // transparent-clipping. + xcb_visualid_t visual = + r->depth == ps->c.screen_info->root_depth + ? ps->c.screen_info->root_visual + : x_get_visual_for_depth(&ps->c, r->depth); + free(r); + ps->root_image = ps->backend_data->ops->bind_pixmap( - ps->backend_data, pixmap, - x_get_visual_info(&ps->c, ps->c.screen_info->root_visual), false); + ps->backend_data, pixmap, x_get_visual_info(&ps->c, visual), false); if (ps->root_image) { ps->backend_data->ops->set_image_property( ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE, ps->root_image, (int[]){ps->root_width, ps->root_height}); } else { + err: log_error("Failed to bind root back pixmap"); } } From 4a79e7b7779297db9a622523953a6f207fe38cde Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Thu, 1 Feb 2024 07:13:16 +0300 Subject: [PATCH 15/16] render: fix binding the root background pixmap in case of depth mismatch fix the same issue in the legacy backends, see the previous commit for details. this commit also removes the x_validate_pixmap function because it was used only in the get_root_tile function and the fix pretty much implies and embeds it. --- src/render.c | 20 +++++++++++++------- src/x.c | 21 --------------------- src/x.h | 2 -- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/render.c b/src/render.c index fadd833586..371a9be7d4 100644 --- a/src/render.c +++ b/src/render.c @@ -604,20 +604,27 @@ static bool get_root_tile(session_t *ps) { bool fill = false; xcb_pixmap_t pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms); - // Make sure the pixmap we got is valid - if (pixmap && !x_validate_pixmap(&ps->c, pixmap)) { - pixmap = XCB_NONE; + xcb_get_geometry_reply_t *r; + if (pixmap) { + r = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL); } // Create a pixmap if there isn't any - if (!pixmap) { + xcb_visualid_t visual; + if (!pixmap || !r) { pixmap = x_create_pixmap(&ps->c, (uint8_t)ps->c.screen_info->root_depth, 1, 1); if (pixmap == XCB_NONE) { log_error("Failed to create pixmaps for root tile."); return false; } + visual = ps->c.screen_info->root_visual; fill = true; + } else { + visual = r->depth == ps->c.screen_info->root_depth + ? ps->c.screen_info->root_visual + : x_get_visual_for_depth(&ps->c, r->depth); + free(r); } // Create Picture @@ -625,7 +632,7 @@ static bool get_root_tile(session_t *ps) { .repeat = true, }; ps->root_tile_paint.pict = x_create_picture_with_visual_and_pixmap( - &ps->c, ps->c.screen_info->root_visual, pixmap, XCB_RENDER_CP_REPEAT, &pa); + &ps->c, visual, pixmap, XCB_RENDER_CP_REPEAT, &pa); // Fill pixmap if needed if (fill) { @@ -646,8 +653,7 @@ static bool get_root_tile(session_t *ps) { ps->root_tile_paint.pixmap = pixmap; #ifdef CONFIG_OPENGL if (BKEND_GLX == ps->o.backend) { - return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, - ps->c.screen_info->root_visual, false); + return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, visual, false); } #endif diff --git a/src/x.c b/src/x.c index c4de9113f9..d48ae96ba7 100644 --- a/src/x.c +++ b/src/x.c @@ -704,27 +704,6 @@ xcb_pixmap_t x_create_pixmap(struct x_connection *c, uint8_t depth, int width, i return XCB_NONE; } -/** - * Validate a pixmap. - * - * Detect whether the pixmap is valid with XGetGeometry. Well, maybe there - * are better ways. - */ -bool x_validate_pixmap(struct x_connection *c, xcb_pixmap_t pixmap) { - if (pixmap == XCB_NONE) { - return false; - } - - auto r = xcb_get_geometry_reply(c->c, xcb_get_geometry(c->c, pixmap), NULL); - if (!r) { - return false; - } - - bool ret = r->width && r->height; - free(r); - return ret; -} - /// We don't use the _XSETROOT_ID root window property as a source of the background /// pixmap because it most likely points to a dummy pixmap used to keep the colormap /// associated with the background pixmap alive but we listen for it's changes and update diff --git a/src/x.h b/src/x.h index fe44313789..f320e8696e 100644 --- a/src/x.h +++ b/src/x.h @@ -356,8 +356,6 @@ const char *x_strerror(xcb_generic_error_t *e); xcb_pixmap_t x_create_pixmap(struct x_connection *, uint8_t depth, int width, int height); -bool x_validate_pixmap(struct x_connection *, xcb_pixmap_t pxmap); - /** * Free a winprop_t. * From 5c640ac452f14df027ef1632a69ad024bc46daef Mon Sep 17 00:00:00 2001 From: Reith <35187140+Reith77@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:17:42 +0530 Subject: [PATCH 16/16] Update README.md Updated README.md to include xcb-util-devel package for fedora --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57eb5a4cb0..d569723817 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ libconfig-dev libdbus-1-dev libegl-dev libev-dev libgl-dev libpcre2-dev libpixma On Fedora, the needed packages are ``` -dbus-devel gcc git libconfig-devel libdrm-devel libev-devel libX11-devel libX11-xcb libXext-devel libxcb-devel libGL-devel libEGL-devel meson pcre2-devel pixman-devel uthash-devel xcb-util-image-devel xcb-util-renderutil-devel xorg-x11-proto-devel +dbus-devel gcc git libconfig-devel libdrm-devel libev-devel libX11-devel libX11-xcb libXext-devel libxcb-devel libGL-devel libEGL-devel meson pcre2-devel pixman-devel uthash-devel xcb-util-image-devel xcb-util-renderutil-devel xorg-x11-proto-devel xcb-util-devel ``` To build the documents, you need `asciidoc`