diff --git a/.clang-tidy b/.clang-tidy index d28a1322..69e0b17a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -32,20 +32,16 @@ Checks: ' ' CheckOptions: - - key: modernize-loop-convert.NamingStyle - value: lower_case - - key: readability-identifier-naming.ClassCase - value: lower_case - - key: readability-identifier-naming.ClassConstantCase - value: UPPER_CASE - - key: readability-identifier-naming.ClassMethodCase - value: lower_case - - key: readability-identifier-naming.MemberCase - value: lower_case - - key: readability-identifier-naming.ProtectedMemberPrefix - value: 'm_' - - key: readability-identifier-naming.PrivateMemberPrefix - value: 'm_' + cppcoreguidelines-avoid-do-while.IgnoreMacros: true + modernize-loop-convert.NamingStyle: lower_case + readability-identifier-naming.ClassCase: lower_case + readability-identifier-naming.ClassConstantCase: UPPER_CASE + readability-identifier-naming.ClassMethodCase: lower_case + readability-identifier-naming.MemberCase: lower_case + readability-identifier-naming.ProtectedMemberPrefix: 'm_' + readability-identifier-naming.PrivateMemberPrefix: 'm_' + readability-simplify-boolean-expr.SimplifyDeMorgan: false + HeaderFilterRegex: '' WarningsAsErrors: '' AnalyzeTemporaryDtors: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5eb3a6d..5a94d398 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: env: COLOR: "ON" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.ref }} - name: Install Dependencies @@ -48,7 +48,7 @@ jobs: python3-xcbgen \ libuv1-dev \ xcb-proto - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true ref: ${{ github.event.inputs.ref }} @@ -115,7 +115,7 @@ jobs: if [ "$POLYBAR_BUILD_TYPE" = "tests" ]; then sudo apt-get install -y lcov fi - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true ref: ${{ github.event.inputs.ref }} @@ -144,14 +144,20 @@ jobs: lcov --remove cov_total.info "${PWD}/build/*" "${PWD}/tests/*" "${PWD}/lib/*" -o cov.info - name: Upload Coverage if: ${{ matrix.polybar_build_type == 'tests' }} - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: + token: ${{ secrets.CODECOV_TOKEN }} flags: unittests + # We provide our own coverage files + disable_search: true + # Disable all plugins, we handle all preparations ourselves + plugins: noop files: ./cov.info fail_ci_if_error: true + verbose: true - name: Upload Logs if: failure() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: cmake path: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a0c408d7..1fd317c8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,7 @@ jobs: } >> "$GITHUB_ENV" # Checks out the target tag - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: ref: ${{ env.RELEASE_TAG }} submodules: true @@ -55,7 +55,7 @@ jobs: - name: Get Upload URL id: get_upload_url - uses: actions/github-script@v3 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -83,7 +83,7 @@ jobs: # Adds a download section to the beginning of the release body - name: Update Release Body - uses: actions/github-script@v3 + uses: actions/github-script@v7 env: # Existing release body, fetched in the get_upload_url step. RELEASE_BODY: ${{ env.RELEASE_BODY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index d54387e6..dc2aba11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `internal/i3`: module errors when i3 has negative gaps ([`#2888`](https://github.com/polybar/polybar/issues/2888), [`#2889`](https://github.com/polybar/polybar/pull/2889)) - `wm-restack = bspwm`: bar may become unclickable if there are overlapping monitors ([`#2873`](https://github.com/polybar/polybar/issues/2873), [`#2961`](https://github.com/polybar/polybar/pull/2961)) +## [3.7.2] - 2024-08-17 +### Fixed +- `custom/script`: When a script with `tail = true` received multiple lines quickly, only the first would get displayed ([`#3117`](https://github.com/polybar/polybar/issues/3117), [`#3119`](https://github.com/polybar/polybar/pull/3119)) by [@Isak05](https://github.com/Isak05) +- Token min-length calculations would behave differently when non-ASCII characters appear in the token ([`#3074`](https://github.com/polybar/polybar/issues/3074), [`#3087`](https://github.com/polybar/polybar/pull/3087)) by [@nklloyd](https://github.com/nklloyd) +- i3: Fix duplicated rendering for non-full-width bars ([`#3091`](https://github.com/polybar/polybar/pull/3091), [`#3060`](https://github.com/polybar/polybar/issues/3060)) +- `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 - Fixed missing header when using `libc++` in clang 15 and below @@ -313,7 +323,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Empty color values are no longer treated as invalid and no longer produce an error. -[Unreleased]: https://github.com/polybar/polybar/compare/3.7.1...HEAD +[Unreleased]: https://github.com/polybar/polybar/compare/3.7.2...HEAD +[3.7.2]: https://github.com/polybar/polybar/releases/tag/3.7.2 [3.7.1]: https://github.com/polybar/polybar/releases/tag/3.7.1 [3.7.0]: https://github.com/polybar/polybar/releases/tag/3.7.0 [3.6.3]: https://github.com/polybar/polybar/releases/tag/3.6.3 diff --git a/doc/config.ini b/doc/config.ini index b514e00c..df1361c1 100644 --- a/doc/config.ini +++ b/doc/config.ini @@ -64,6 +64,14 @@ enable-ipc = true ; override-redirect = true +; This module is not active by default (to enable it, add it to one of the +; modules-* list above). +; Please note that only a single tray can exist at any time. If you launch +; multiple bars with this module, only a single one will show it, the others +; will produce a warning. Which bar gets the module is timing dependent and can +; be quite random. +; For more information, see the documentation page for this module: +; https://polybar.readthedocs.io/en/stable/user/modules/tray.html [module/systray] type = internal/tray diff --git a/doc/requirements.txt b/doc/requirements.txt index d7dc4cb5..12b5ef3b 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -4,4 +4,4 @@ sphinx~=7.2.6 sphinx-rtd-theme~=2.0.0rc2 sphinx-notfound-page~=1.0.0 -readthedocs-sphinx-search~=0.3.1 +readthedocs-sphinx-search~=0.3.2 diff --git a/doc/user/modules/tray.rst b/doc/user/modules/tray.rst index 9a6314f7..9f405081 100644 --- a/doc/user/modules/tray.rst +++ b/doc/user/modules/tray.rst @@ -15,14 +15,16 @@ the Dropbox application). Polybar is only responsible for embedding the windows in the bar and positioning them correctly. -.. note:: +.. attention:: Only a single instance of this module can be active at the same time (across - all polybar instances). + all polybar instances in the same graphical session). The way the `system tray protocol `_ works, at most one tray can exist at any time. Polybar will produce a warning if additional tray instances are created. + This also applies when another tray application (e.g. ``stalonetray``) is + active. For transparent background colors, the tray will use pseudo-transparency, true transparency is not possible for the tray icons. diff --git a/include/modules/backlight.hpp b/include/modules/backlight.hpp index 685814dd..f878643d 100644 --- a/include/modules/backlight.hpp +++ b/include/modules/backlight.hpp @@ -67,7 +67,12 @@ namespace modules { brightness_handle m_val; brightness_handle m_max; - int m_percentage = 0; + /** + * Initial value set to a negative number so that any value read from the backlight file triggers an update during + * the first read. + * Otherwise, tokens may not be replaced + */ + int m_percentage = -1; chrono::duration m_interval{}; chrono::steady_clock::time_point m_lastpoll; diff --git a/include/modules/meta/base.inl b/include/modules/meta/base.inl index f80c7782..8a647d45 100644 --- a/include/modules/meta/base.inl +++ b/include/modules/meta/base.inl @@ -119,7 +119,7 @@ namespace modules { template string module::contents() { - if (m_changed) { + if (m_changed.exchange(false)) { m_log.info("%s: Rebuilding cache", name()); m_cache = CAST_MOD(Impl)->get_output(); // Make sure builder is really empty @@ -129,7 +129,6 @@ namespace modules { m_builder->control(tags::controltag::R); m_cache += m_builder->flush(); } - m_changed = false; } return m_cache; } diff --git a/include/utils/command.hpp b/include/utils/command.hpp index 322984c8..919ba86a 100644 --- a/include/utils/command.hpp +++ b/include/utils/command.hpp @@ -92,6 +92,7 @@ class command : private command cb); string readline(); + bool wait_for_data(int timeout_ms); int get_stdout(int c); int get_stdin(int c); diff --git a/src/adapters/script_runner.cpp b/src/adapters/script_runner.cpp index c7ffb26a..5cfe68a3 100644 --- a/src/adapters/script_runner.cpp +++ b/src/adapters/script_runner.cpp @@ -155,7 +155,7 @@ script_runner::interval script_runner::run_tail() { assert(fd != -1); while (!m_stopping && cmd.is_running() && !io_util::poll(fd, POLLHUP, 0)) { - if (io_util::poll_read(fd, 250)) { + if (cmd.wait_for_data(250)) { auto changed = set_output(cmd.readline()); if (changed) { diff --git a/src/components/renderer.cpp b/src/components/renderer.cpp index fbedb8d6..8b5c75c4 100644 --- a/src/components/renderer.cpp +++ b/src/components/renderer.cpp @@ -86,14 +86,6 @@ renderer::renderer(connection& conn, signal_emitter& sig, const config& conf, co { m_pixmap = m_connection.generate_id(); m_connection.create_pixmap(m_depth, m_pixmap, m_window, m_bar.size.w, m_bar.size.h); - - uint32_t configure_mask = 0; - std::array configure_values{}; - xcb_params_cw_t configure_params{}; - - XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, back_pixmap, m_pixmap); - connection::pack_values(configure_mask, &configure_params, configure_values); - m_connection.change_window_attributes_checked(m_window, configure_mask, configure_values.data()); } m_log.trace("renderer: Allocate graphic contexts"); @@ -372,8 +364,8 @@ void renderer::flush() { highlight_clickable_areas(); m_surface->flush(); - // Clear entire window so that the new pixmap is shown - m_connection.clear_area(0, m_window, 0, 0, m_bar.size.w, m_bar.size.h); + // Copy pixmap onto the window + m_connection.copy_area(m_pixmap, m_window, m_gcontext, 0, 0, 0, 0, m_bar.size.w, m_bar.size.h); m_connection.flush(); if (!m_snapshot_dst.empty()) { diff --git a/src/drawtypes/label.cpp b/src/drawtypes/label.cpp index e5ba8911..4b58deae 100644 --- a/src/drawtypes/label.cpp +++ b/src/drawtypes/label.cpp @@ -82,14 +82,15 @@ namespace drawtypes { for (auto&& tok : m_tokens) { string repl{replacement}; + size_t len = string_util::char_len(repl); if (token == tok.token) { - if (tok.max != 0_z && string_util::char_len(repl) > tok.max) { + if (tok.max != 0_z && len > tok.max) { repl = string_util::utf8_truncate(std::move(repl), tok.max) + tok.suffix; - } else if (tok.min != 0_z && repl.length() < tok.min) { + } else if (tok.min != 0_z && len < tok.min) { if (tok.rpadding) { - repl.append(tok.min - repl.length(), ' '); + repl.append(tok.min - len, ' '); } else { - repl.insert(0_z, tok.min - repl.length(), tok.zpad ? '0' : ' '); + repl.insert(0_z, tok.min - len, tok.zpad ? '0' : ' '); } } diff --git a/src/modules/ipc.cpp b/src/modules/ipc.cpp index 9e337020..144bb404 100644 --- a/src/modules/ipc.cpp +++ b/src/modules/ipc.cpp @@ -79,6 +79,8 @@ namespace modules { this->module::start(); m_mainthread = thread([&] { m_log.trace("%s: Thread id = %i", this->name(), concurrency_util::thread_id(this_thread::get_id())); + // Initial update to start with an empty output until the initial hook finishes + update_output(); update(); broadcast(); }); diff --git a/src/utils/command.cpp b/src/utils/command.cpp index a4571215..a0b57569 100644 --- a/src/utils/command.cpp +++ b/src/utils/command.cpp @@ -201,6 +201,14 @@ string command::readline() { return s; } +/** + * Wait until there is data in the output stream or until timeout_ms milliseconds + */ +bool command::wait_for_data(int timeout_ms) { + return (m_stdout_reader && m_stdout_reader->rdbuf()->in_avail() > 0) || + io_util::poll_read(get_stdout(PIPE_READ), timeout_ms); +} + /** * Get command output channel */ 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() { diff --git a/src/x11/tray_manager.cpp b/src/x11/tray_manager.cpp index 058d04f1..3a47c1fe 100644 --- a/src/x11/tray_manager.cpp +++ b/src/x11/tray_manager.cpp @@ -502,7 +502,8 @@ void manager::remove_client(const client& c) { void manager::remove_client(xcb_window_t win) { auto old_size = m_clients.size(); m_clients.erase( - std::remove_if(m_clients.begin(), m_clients.end(), [win](const auto& client) { return client->match(win); })); + std::remove_if(m_clients.begin(), m_clients.end(), [win](const auto& client) { return client->match(win); }), + m_clients.end()); if (old_size != m_clients.size()) { reconfigure(); @@ -518,7 +519,8 @@ void manager::remove_client(xcb_window_t win) { */ void manager::clean_clients() { m_clients.erase( - std::remove_if(m_clients.begin(), m_clients.end(), [](const auto& client) { return client.get() == nullptr; })); + std::remove_if(m_clients.begin(), m_clients.end(), [](const auto& client) { return client.get() == nullptr; }), + m_clients.end()); } bool manager::change_visibility(bool visible) { diff --git a/version.txt b/version.txt index 650ff681..f1d711af 100644 --- a/version.txt +++ b/version.txt @@ -1,4 +1,4 @@ # Polybar version information # Update this on every release # This is used to create the version string if a git repo is not available -3.7.1 +3.7.2