Skip to content

Fix i3status-rs powerline gaps and default status flickering#226

Merged
paperbenni merged 1 commit intomainfrom
fix-i3status-rs-rendering-889909543099433205
Mar 13, 2026
Merged

Fix i3status-rs powerline gaps and default status flickering#226
paperbenni merged 1 commit intomainfrom
fix-i3status-rs-rendering-889909543099433205

Conversation

@paperbenni
Copy link
Copy Markdown
Member

@paperbenni paperbenni commented Mar 13, 2026

Fixes two separate issues regarding status bar rendering:

  1. Powerline gaps: i3status-rs output blocks configured without separators were still having a hardcoded 6-pixel left and right padding added to their internal text width calculation, creating unintended background-colored gaps. Padding is now dynamically omitted if separator: false and separator_block_width: 0.
  2. Status flickering: The background thread responsible for emitting the default status text would periodically overwrite custom external updates if the status_command wasn't explicitly managed through the WM config (e.g. running via autostart scripts). The thread now permanently halts if a custom non-default status is received via IPC.

PR created automatically by Jules for task 889909543099433205 started by @paperbenni

Summary by Sourcery

Fix status bar rendering for i3status-rs blocks and prevent the default status updater from overwriting custom IPC status text.

Bug Fixes:

  • Remove unintended horizontal padding for i3status-rs blocks configured without separators to eliminate background gaps in powerline-style themes.
  • Stop the default status update thread once a non-default custom status is received over IPC to avoid status text flickering and unintended overrides.

Summary by CodeRabbit

  • New Features

    • Added detection for custom status messages.
  • Bug Fixes

    • Improved layout padding calculations for status blocks to ensure proper visual alignment.

- Fix powerline gap rendering by conditionally removing `TEXT_PADDING`
  when a block specifies no separator (`separator: false`) and a
  `separator_block_width` of 0. This allows powerline triangles to
  sit flush against adjacent blocks.
- Fix UI flickering back to "instantwm-VERSION" default text by
  introducing a global atomic flag (`CUSTOM_STATUS_RECEIVED`) that
  halts the default status thread once a custom update is received
  via IPC.

Co-authored-by: paperbenni <15818888+paperbenni@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Mar 13, 2026

Reviewer's Guide

Adjusts i3status-rs block padding logic to remove unintended gaps for powerline-style blocks without separators, and introduces an atomic flag to permanently stop the default status-emitting thread once a custom status is received via IPC, preventing flickering/overwrites.

Sequence diagram for default status thread halting on custom IPC status

sequenceDiagram
    actor User
    participant ExternalStatusProducer
    participant IpcClient
    participant WindowManager as WindowManager_update_status
    participant StatusModule as BarStatusModule
    participant DefaultThread as DefaultStatusThread

    User->>ExternalStatusProducer: Configure custom status command
    ExternalStatusProducer->>IpcClient: Emit custom status text
    IpcClient->>WindowManager: update_status(text)
    alt text does not start with instantwm-
        WindowManager->>BarStatusModule: set CUSTOM_STATUS_RECEIVED = true
    else default instantwm status
        WindowManager->>BarStatusModule: do not modify CUSTOM_STATUS_RECEIVED
    end
    WindowManager->>WindowManager: g.status_text = text

    par default status loop
        loop every 30 seconds
            DefaultThread->>BarStatusModule: load CUSTOM_STATUS_RECEIVED
            alt CUSTOM_STATUS_RECEIVED is true
                DefaultThread-->>DefaultThread: break loop and stop thread
            else CUSTOM_STATUS_RECEIVED is false
                DefaultThread->>WindowManager: send_status_ipc(default_status_text())
            end
        end
    end
Loading

Class diagram for updated status and IPC handling modules

classDiagram
    class BarStatusModule {
        +CUSTOM_STATUS_RECEIVED : AtomicBool
        +spawn_default_status()
        +measure_i3_block_width(block, painter)
        +draw_i3_block(block, painter, x, y)
    }

    class IpcGeneralModule {
        +update_status(wm, text)
    }

    class WindowManager {
        +g_status_text : String
        +backend : Backend
    }

    class Backend {
    }

    class X11Backend {
    }

    Backend <|-- X11Backend
    IpcGeneralModule --> WindowManager : modifies_g_status_text
    IpcGeneralModule --> BarStatusModule : sets_CUSTOM_STATUS_RECEIVED
    BarStatusModule --> WindowManager : send_status_ipc(default_status_text)
Loading

File-Level Changes

Change Details Files
Make text padding conditional so powerline-style blocks without separators no longer render background gaps.
  • Introduce a per-block local padding variable in width measurement and drawing functions based on separator and separator_block_width fields.
  • Use zero padding when separator is disabled and separator_block_width is zero; otherwise fall back to existing TEXT_PADDING.
  • Update block width, inner width, and text area calculations to use the new dynamic padding instead of the hardcoded TEXT_PADDING.
src/bar/status.rs
Stop the default status background thread once a non-default custom status is received to avoid flickering and overwrites.
  • Add a global AtomicBool CUSTOM_STATUS_RECEIVED to track whether a custom status has been seen.
  • In spawn_default_status, check the atomic flag each loop iteration and break out when it is set, halting further default status IPC updates.
  • In the IPC update_status handler, set the atomic flag when the incoming status text does not start with the default 'instantwm-' prefix, distinguishing real custom statuses from internal defaults.
src/bar/status.rs
src/ipc/general.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@paperbenni paperbenni merged commit d38adba into main Mar 13, 2026
2 of 4 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 13, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e0f80f1-cf6f-4024-abd3-c372ff960fd4

📥 Commits

Reviewing files that changed from the base of the PR and between c4922bb and e296f72.

📒 Files selected for processing (2)
  • src/bar/status.rs
  • src/ipc/general.rs

📝 Walkthrough

Walkthrough

The changes introduce a new atomic flag (CUSTOM_STATUS_RECEIVED) to track when custom status text arrives via IPC, allowing the default status spawner to exit early. Dynamic padding logic is added to i3-block layout calculations, and the IPC handler now signals the flag when non-default status text is received.

Changes

Cohort / File(s) Summary
Status monitoring and i3-block layout
src/bar/status.rs
Introduces CUSTOM_STATUS_RECEIVED atomic flag, refines padding logic in measure_i3_block_width and draw_i3_block to compute conditional padding based on separator presence, and updates spawn_default_status to poll the flag and exit early when custom status is detected.
IPC status updates
src/ipc/general.rs
Modifies update_status to set the CUSTOM_STATUS_RECEIVED flag to true when status text does not start with "instantwm-".

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 A flag so atomic, a signal so true,
When custom status arrives, the spawner breaks through,
Padding flows gently in i3-styled blocks,
No more default spam—the control flow unlocks! ✨

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-i3status-rs-rendering-889909543099433205
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • The CUSTOM_STATUS_RECEIVED AtomicBool is declared as a public static; consider making it module-private (or exposing a small API) to avoid leaking this synchronization detail outside bar::status.
  • The padding computation if !block.separator && block.separator_block_width == 0 { 0 } else { TEXT_PADDING } is duplicated in both measure_i3_block_width and draw_i3_block; factoring this into a small helper will reduce the risk of these diverging in future changes.
  • The "instantwm-" string used to detect custom status in update_status is a magic prefix; consider extracting it into a named constant so future changes to the default status format remain centralized.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `CUSTOM_STATUS_RECEIVED` `AtomicBool` is declared as a public static; consider making it module-private (or exposing a small API) to avoid leaking this synchronization detail outside `bar::status`.
- The padding computation `if !block.separator && block.separator_block_width == 0 { 0 } else { TEXT_PADDING }` is duplicated in both `measure_i3_block_width` and `draw_i3_block`; factoring this into a small helper will reduce the risk of these diverging in future changes.
- The `"instantwm-"` string used to detect custom status in `update_status` is a magic prefix; consider extracting it into a named constant so future changes to the default status format remain centralized.

## Individual Comments

### Comment 1
<location path="src/bar/status.rs" line_range="14" />
<code_context>
 pub(crate) const TEXT_PADDING: i32 = 6;
 const DEFAULT_SEPARATOR_BLOCK_WIDTH: i32 = 9;

+pub static CUSTOM_STATUS_RECEIVED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
+
 #[derive(Debug, Clone)]
</code_context>
<issue_to_address>
**suggestion:** Consider avoiding a public global mutable state for the status flag

Public mutable `pub static` state makes the code harder to reason about as usage grows. Consider keeping this `AtomicBool` private to the module and exposing functions like `set_custom_status_received()` / `custom_status_received()` so the synchronization details remain encapsulated and can be changed later without impacting callers.

Suggested implementation:

```rust
pub(crate) const TEXT_PADDING: i32 = 6;
const DEFAULT_SEPARATOR_BLOCK_WIDTH: i32 = 9;

use std::sync::atomic::{AtomicBool, Ordering};

static CUSTOM_STATUS_RECEIVED: AtomicBool = AtomicBool::new(false);

pub(crate) fn set_custom_status_received() {
    CUSTOM_STATUS_RECEIVED.store(true, Ordering::Relaxed);
}

pub(crate) fn clear_custom_status_received() {
    CUSTOM_STATUS_RECEIVED.store(false, Ordering::Relaxed);
}

pub(crate) fn custom_status_received() -> bool {
    CUSTOM_STATUS_RECEIVED.load(Ordering::Relaxed)
}

#[derive(Debug, Clone)]
pub(crate) enum StatusItem {

```

1. Replace any external uses of `CUSTOM_STATUS_RECEIVED` (e.g. reads with `.load(...)`) with calls to `custom_status_received()`.
2. Replace any external writes to `CUSTOM_STATUS_RECEIVED` (e.g. `.store(true/false, ...)` or `.swap(...)`) with the appropriate helper: `set_custom_status_received()` or `clear_custom_status_received()`. If there are more complex update patterns, add additional helper functions in this module instead of exposing the static.
3. Once all external uses are replaced, ensure `CUSTOM_STATUS_RECEIVED` is not re-exported elsewhere (e.g. via `pub use`), to keep the synchronization details encapsulated in this module.
</issue_to_address>

### Comment 2
<location path="src/bar/status.rs" line_range="878-882" />
<code_context>

         thread::sleep(Duration::from_millis(500));

         loop {
+            if CUSTOM_STATUS_RECEIVED.load(Ordering::Relaxed) {
+                break;
+            }
             send_status_ipc(&default_status_text());
             thread::sleep(Duration::from_secs(30));
         }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** There may be an extra default status update after a custom status arrives

Because the flag is only checked at the top of the loop, a custom status arriving after the `load` but before `send_status_ipc` will still result in one extra default update. If you want to stop sending immediately once the custom status is set, either re-check the flag right before `send_status_ipc`, or move the send to the end of the loop and guard it with a flag check before each send.
</issue_to_address>

### Comment 3
<location path="src/bar/status.rs" line_range="587-595" />
<code_context>
         None => 0,
     };

+    let padding = if !block.separator && block.separator_block_width == 0 {
+        0
+    } else {
+        TEXT_PADDING
+    };
+
     let content_width = text_width.max(min_width).max(0);
     let border_width = block.border_left + block.border_right;
-    let block_width = border_width + TEXT_PADDING * 2 + content_width;
+    let block_width = border_width + padding * 2 + content_width;

     let separator_width = if block.separator {
</code_context>
<issue_to_address>
**suggestion:** The padding calculation is duplicated and could be centralized

The `padding` condition (`if !block.separator && block.separator_block_width == 0 { 0 } else { TEXT_PADDING }`) is repeated in `measure_i3_block_width` and `draw_i3_block`. Please extract it into a helper (e.g., `fn block_padding(block: &I3Block) -> i32`) to keep the behavior consistent and avoid future divergence.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/bar/status.rs
pub(crate) const TEXT_PADDING: i32 = 6;
const DEFAULT_SEPARATOR_BLOCK_WIDTH: i32 = 9;

pub static CUSTOM_STATUS_RECEIVED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider avoiding a public global mutable state for the status flag

Public mutable pub static state makes the code harder to reason about as usage grows. Consider keeping this AtomicBool private to the module and exposing functions like set_custom_status_received() / custom_status_received() so the synchronization details remain encapsulated and can be changed later without impacting callers.

Suggested implementation:

pub(crate) const TEXT_PADDING: i32 = 6;
const DEFAULT_SEPARATOR_BLOCK_WIDTH: i32 = 9;

use std::sync::atomic::{AtomicBool, Ordering};

static CUSTOM_STATUS_RECEIVED: AtomicBool = AtomicBool::new(false);

pub(crate) fn set_custom_status_received() {
    CUSTOM_STATUS_RECEIVED.store(true, Ordering::Relaxed);
}

pub(crate) fn clear_custom_status_received() {
    CUSTOM_STATUS_RECEIVED.store(false, Ordering::Relaxed);
}

pub(crate) fn custom_status_received() -> bool {
    CUSTOM_STATUS_RECEIVED.load(Ordering::Relaxed)
}

#[derive(Debug, Clone)]
pub(crate) enum StatusItem {
  1. Replace any external uses of CUSTOM_STATUS_RECEIVED (e.g. reads with .load(...)) with calls to custom_status_received().
  2. Replace any external writes to CUSTOM_STATUS_RECEIVED (e.g. .store(true/false, ...) or .swap(...)) with the appropriate helper: set_custom_status_received() or clear_custom_status_received(). If there are more complex update patterns, add additional helper functions in this module instead of exposing the static.
  3. Once all external uses are replaced, ensure CUSTOM_STATUS_RECEIVED is not re-exported elsewhere (e.g. via pub use), to keep the synchronization details encapsulated in this module.

Comment thread src/bar/status.rs
Comment on lines 878 to 882
loop {
if CUSTOM_STATUS_RECEIVED.load(Ordering::Relaxed) {
break;
}
send_status_ipc(&default_status_text());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): There may be an extra default status update after a custom status arrives

Because the flag is only checked at the top of the loop, a custom status arriving after the load but before send_status_ipc will still result in one extra default update. If you want to stop sending immediately once the custom status is set, either re-check the flag right before send_status_ipc, or move the send to the end of the loop and guard it with a flag check before each send.

Comment thread src/bar/status.rs
Comment on lines +587 to +595
let padding = if !block.separator && block.separator_block_width == 0 {
0
} else {
TEXT_PADDING
};

let content_width = text_width.max(min_width).max(0);
let border_width = block.border_left + block.border_right;
let block_width = border_width + TEXT_PADDING * 2 + content_width;
let block_width = border_width + padding * 2 + content_width;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The padding calculation is duplicated and could be centralized

The padding condition (if !block.separator && block.separator_block_width == 0 { 0 } else { TEXT_PADDING }) is repeated in measure_i3_block_width and draw_i3_block. Please extract it into a helper (e.g., fn block_padding(block: &I3Block) -> i32) to keep the behavior consistent and avoid future divergence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant