From c0d3d7a3e74b4be9a854480fb57acf765236e6a9 Mon Sep 17 00:00:00 2001 From: patrick96 Date: Sun, 18 Feb 2024 19:05:02 +0100 Subject: [PATCH] fix(render): Deal with incomplete wallpapers If the root pixmap does not fully cover the bar window, some pseudo-transparent areas were filled with unitialized data, causing pixelation or other rendering artifacts. Now, ovserved background slices are first filled with black to make sure this does not happen and they print an error if not the full pixmap can be filled. Fixes #3041 --- .clang-tidy | 1 + CHANGELOG.md | 1 + src/x11/background_manager.cpp | 37 +++++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index a763ee6d..69e0b17a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -40,6 +40,7 @@ CheckOptions: readability-identifier-naming.MemberCase: lower_case readability-identifier-naming.ProtectedMemberPrefix: 'm_' readability-identifier-naming.PrivateMemberPrefix: 'm_' + readability-simplify-boolean-expr.SimplifyDeMorgan: false HeaderFilterRegex: '' WarningsAsErrors: '' diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a85716c..26d3f01c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `internal/backlight`: Module could display the literal `%percentage%` token if the backlight reports a value of 0 at startup ([`#3081`](https://github.com/polybar/polybar/pull/3081)) by [@unclechu](https://github.com/unclechu) - `internal/tray`: Fix crash during restarting, when tray icons were not removed proberly ([`#3111`](https://github.com/polybar/polybar/issues/3111), [`#3112`](https://github.com/polybar/polybar/pull/3112)) - `custom/ipc`: Module would display the literal `%output%` token before the initial hook finished executing ([`#3131`](https://github.com/polybar/polybar/issues/3131), [`#3140`](https://github.com/polybar/polybar/pull/3140)) +- renderer: Pseudo-transparency rendering artifacts when wallpaper does not fill entire screen ([`#3096`](https://github.com/polybar/polybar/pull/3096), [`#3041`](https://github.com/polybar/polybar/issues/3041)) ## [3.7.1] - 2023-11-27 ### Build diff --git a/src/x11/background_manager.cpp b/src/x11/background_manager.cpp index 62027d92..b6047b27 100644 --- a/src/x11/background_manager.cpp +++ b/src/x11/background_manager.cpp @@ -220,13 +220,34 @@ void bg_slice::copy(xcb_pixmap_t root_pixmap, int depth, xcb_rectangle_t geom, x ensure_resources(depth, visual); assert(m_pixmap); - // fill the slice + auto pixmap_end_x = int16_t(geom.x + geom.width); + auto pixmap_end_y = int16_t(geom.y + geom.height); + auto translated = m_connection.translate_coordinates(m_window, m_connection.screen()->root, m_rect.x, m_rect.y); - // Coordinates of the slice in the root pixmap - auto src_x = math_util::cap(translated->dst_x, geom.x, int16_t(geom.x + geom.width)); - auto src_y = math_util::cap(translated->dst_y, geom.y, int16_t(geom.y + geom.height)); + + /* + * If the slice is not fully contained in the root pixmap, we will be missing at least some background pixels. For + * those areas, nothing is copied over and a simple black background is shown. + * This can happen when connecting new monitors without updating the root pixmap. + */ + if (!(translated->dst_x >= geom.x && translated->dst_x + m_rect.width <= pixmap_end_x && + translated->dst_y >= geom.y && translated->dst_y + m_rect.height <= pixmap_end_y)) { + m_log.err( + "background_manager: Root pixmap does not fully cover transparent areas. " + "Pseudo-transparency may not fully work and instead just show a black background. " + "Make sure you have a wallpaper set on all of your screens"); + } + + /* + * Coordinates of the slice in the root pixmap. The rectangle is capped so that it is contained in the root pixmap to + * avoid copying areas not covered by the pixmap. + */ + auto src_x = math_util::cap(translated->dst_x, geom.x, pixmap_end_x); + auto src_y = math_util::cap(translated->dst_y, geom.y, pixmap_end_x); auto w = math_util::cap(m_rect.width, uint16_t(0), uint16_t(geom.width - (src_x - geom.x))); auto h = math_util::cap(m_rect.height, uint16_t(0), uint16_t(geom.height - (src_y - geom.y))); + + // fill the slice m_log.trace( "background_manager: Copying from root pixmap (0x%x:%d) %dx%d+%d+%d", root_pixmap, depth, w, h, src_x, src_y); m_connection.copy_area_checked(root_pixmap, m_pixmap, m_gcontext, src_x, src_y, 0, 0, w, h); @@ -257,12 +278,18 @@ void bg_slice::allocate_resources(xcb_visualtype_t* visual) { XCB_AUX_ADD_PARAM(&mask, ¶ms, foreground, black_pixel); XCB_AUX_ADD_PARAM(&mask, ¶ms, background, black_pixel); XCB_AUX_ADD_PARAM(&mask, ¶ms, graphics_exposures, 0); - m_connection.pack_values(mask, ¶ms, value_list); + connection::pack_values(mask, ¶ms, value_list); m_gcontext = m_connection.generate_id(); m_connection.create_gc(m_gcontext, m_pixmap, mask, value_list.data()); m_log.trace("background_manager: Allocating cairo surface"); m_surface = make_unique(m_connection, m_pixmap, visual, m_rect.width, m_rect.height); + + /* + * Fill pixmap with black in case it is not fully filled by the root pixmap. Otherwise we may render uninitialized + * memory + */ + m_connection.poly_fill_rectangle(m_pixmap, m_gcontext, 1, &m_rect); } void bg_slice::free_resources() {