Skip to content

Bugfix: Unresponsive native window controls on Linux#160

Open
pettijohn wants to merge 2 commits into
erictli:mainfrom
pettijohn:bugfix-linux-chrome
Open

Bugfix: Unresponsive native window controls on Linux#160
pettijohn wants to merge 2 commits into
erictli:mainfrom
pettijohn:bugfix-linux-chrome

Conversation

@pettijohn

@pettijohn pettijohn commented Jun 4, 2026

Copy link
Copy Markdown

Issue / Repro

On Linux (Ubuntu 26.04 with 7.0.0-22 kernel on amd64), the native window controls were broken on first launch: minimize, maximize, and close didn’t respond, even though the window could still be resized and double-clicking the titlebar would maximize it. Once the window was maximized, the native buttons started working normally.

Repro was just:

  1. Launch the app on Linux
  2. Try the native titlebar buttons before maximizing
  3. Observe that they don’t respond until after a maximize

Root Cause

The main window was being created hidden and then shown later during startup. On Linux, that hidden-then-show flow was leaving the native window chrome in a bad initial state, so the caption buttons didn’t receive clicks until the window was reconfigured by maximizing.

There was also some macOS-specific titlebar config living in the shared Tauri config, which wasn’t related to the main Linux bug but didn’t belong in cross-platform window settings.

Fix

Linux now starts the main window visible instead of creating it hidden and showing it afterward. I also skipped the redundant normal-startup show() calls on Linux so it stays on that visible-from-creation path.

Separately, I split the macOS titlebar settings into a dedicated tauri.macos.conf.json so overlay titlebar options stay macOS-only and don’t leak into Linux/Windows config.

I only verified the fix on Ubuntu 26.04, not on Windows or Linux.

Dev Container

Separately, this branch includes a devcontainer since I don't have these dev tools on my local machine. If you don't want it in main, exclude .devcontainer/**

Summary by CodeRabbit

  • Bug Fixes

    • Improved window show/focus behavior during CLI and preview workflows to avoid unwanted window pop-ups on specific platforms.
  • Chores

    • Added platform-specific window configurations for macOS and Linux for consistent sizing and title-bar behavior.
    • Simplified Windows title bar settings for a cleaner, more native appearance.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7761c9f2-31ec-4f0b-b2ca-b8cb2c7a544a

📥 Commits

Reviewing files that changed from the base of the PR and between d7c616e and a9e3b8d.

📒 Files selected for processing (2)
  • src-tauri/src/lib.rs
  • src-tauri/tauri.linux.conf.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • src-tauri/tauri.linux.conf.json
  • src-tauri/src/lib.rs

📝 Walkthrough

Walkthrough

The PR conditionally disables main-window show/focus on Linux via three #[cfg(not(target_os = "linux"))] guards and adds per-platform Tauri window configuration files: Linux (new visible window), macOS (overlay title bar + traffic light position), and a simplified Windows window preset.

Changes

Platform-Specific Window Management

Layer / File(s) Summary
Conditional window display for non-Linux platforms
src-tauri/src/lib.rs
Three #[cfg(not(target_os = "linux"))] compile-time guards wrap main-window show()/set_focus() calls in the CLI init error branch, the no-files-opened path, and the startup visibility decision, preventing those calls on Linux.
Platform-specific Tauri window configurations
src-tauri/tauri.conf.json, src-tauri/tauri.linux.conf.json, src-tauri/tauri.macos.conf.json
Windows preset removes titleBarStyle/hiddenTitle/trafficLightPosition. New tauri.linux.conf.json defines a visible, resizable, decorated window. New tauri.macos.conf.json sets titleBarStyle: "Overlay", hiddenTitle: true, and trafficLightPosition: {x:16,y:24}.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • erictli/scratch#57: Related modification to window show/focus behavior in src-tauri/src/lib.rs based on opened_preview and notes-folder state.

Suggested reviewers

  • erictli

Poem

🐇 A little hop through cfg and config bright,

Linux stays quiet in the moonlit night.
macOS lights the traffic lights with care,
Windows keeps it simple — curtains bare.
A rabbit cheers: "Each platform gets its light!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: addressing unresponsive native window controls on Linux by conditionally handling window visibility. The changes support this primary objective across multiple configuration and source files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src-tauri/src/lib.rs (1)

3541-3541: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Linux: also guard main_window.show() in try_select_in_notes_folder()

try_select_in_notes_folder() unconditionally calls main_window.show() when a note inside the configured notes folder is selected (CLI/Open With/DragDrop). Other main_window.show() calls are wrapped with #[cfg(not(target_os = "linux"))], and the Tauri main window is configured with "visible": false, so this unguarded call is inconsistent and can reintroduce the Linux window-chrome issue. Add the same Linux guard around show() (keep set_focus() consistent with the surrounding patterns).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/lib.rs` at line 3541, In try_select_in_notes_folder(), the
unguarded call to main_window.show() can reintroduce the Linux window-chrome
issue; wrap that show() call with the same conditional compilation used
elsewhere (i.e. #[cfg(not(target_os = "linux"))]) so it only runs on non-Linux
builds, and leave main_window.set_focus() following the existing pattern (keep
set_focus() as-is or guarded the same way if surrounding calls do so) to match
surrounding code paths and maintain consistency with other main_window.show()
usages.
🧹 Nitpick comments (6)
.devcontainer/devcontainer.json (3)

28-29: ⚡ Quick win

Cross-platform compatibility concern with bind mount paths.

The bind mounts on lines 28-29 use paths that are Unix/Linux/macOS specific:

  • ${localEnv:HOME}/.codex
  • ${localEnv:HOME}/.config/Code/User/globalStorage

These mounts will fail or have incorrect paths on Windows hosts, where VS Code's global storage is typically at %APPDATA%\Code\User\globalStorage. If your team includes Windows developers, consider either:

  1. Removing these bind mounts and accepting that settings won't persist
  2. Using platform-specific devcontainer configs
  3. Documenting that the devcontainer is Linux/macOS-only

Additionally, these bind mounts combined with updateRemoteUserUID: false (line 10) may cause permission issues if the host user's UID ≠ 1000.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/devcontainer.json around lines 28 - 29, The devcontainer bind
mounts use Unix-only HOME paths and will break on Windows; update
.devcontainer/devcontainer.json to either remove the two bind entries
("source=${localEnv:HOME}/.codex,..." and
"source=${localEnv:HOME}/.config/Code/User/globalStorage,..."), replace them
with platform-specific alternatives (use a Windows conditional config that maps
%APPDATA%\Code\User\globalStorage for Windows hosts), or document that the
devcontainer is Linux/macOS-only; also address potential UID mapping by setting
updateRemoteUserUID to true or adding documentation/instructions so host UID
mismatches do not cause permission issues.

20-20: 💤 Low value

Verify that the ChatGPT extension should be in the shared devcontainer config.

The openai.chatgpt extension is included in the shared devcontainer configuration. While this may be intentional for team collaboration, AI assistant extensions are often a personal preference. Consider whether this should be in the shared config or left to individual developers to install via their personal VS Code settings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/devcontainer.json at line 20, The shared devcontainer
currently includes the AI extension "openai.chatgpt"; decide whether this is
intentional—if not, remove "openai.chatgpt" from the devcontainer extensions
array in devcontainer.json so it is not forced for all developers, or
alternatively make it optional by documenting it in the repo README (or a dev
setup doc) so developers can install "openai.chatgpt" individually; update
devcontainer.json to remove the extension or add a comment pointing to the
documentation and commit that change.

10-10: Potential UID/GID permission mismatch with updateRemoteUserUID: false (bind mounts into /home/vscode/...)

  • .devcontainer/Dockerfile creates the vscode user with default USER_UID=1000 / USER_GID=1000, and .devcontainer/devcontainer.json sets "remoteUser": "vscode" + "updateRemoteUserUID": false, so the container user stays UID 1000.
  • The bind mounts from ${localEnv:HOME} into /home/vscode/.codex and /home/vscode/.vscode-server/data/User/globalStorage may be unwritable when the host’s HOME files are owned by a different UID than 1000.

Set "updateRemoteUserUID" to true (or omit it) unless all developers consistently use UID 1000 or the host mount permissions are compatible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/devcontainer.json at line 10, The devcontainer sets
"remoteUser": "vscode" while leaving "updateRemoteUserUID": false which can
cause host bind-mounted HOME files under /home/vscode/.codex and
/home/vscode/.vscode-server to be unwritable if the host UID differs from 1000;
update the devcontainer.json to set "updateRemoteUserUID": true (or remove the
setting so it defaults to true) so the container adjusts the vscode user's
UID/GID to match the host and avoid permission issues with the bind mounts
referenced (/home/vscode/.codex,
/home/vscode/.vscode-server/data/User/globalStorage).
.devcontainer/Dockerfile (2)

71-71: ⚡ Quick win

Clarify the purpose of the .codex directory.

The .codex directory is created in the container and mounted from the host (per devcontainer.json line 28), but its purpose is not documented. Consider adding a comment explaining what this directory is used for.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/Dockerfile at line 71, Add a short comment above the line
creating/mounting "/home/${USERNAME}/.codex" in the Dockerfile explaining the
directory's purpose and why it's mounted from the host (e.g., cache for models,
local tool state, credentials, or workspace artifacts); reference the ".codex"
directory name and the corresponding mount configured in devcontainer.json so
future readers know what data lives there and why it must be persisted on the
host.

80-80: ⚡ Quick win

Consider pinning the Rust toolchain version for reproducibility.

Using --default-toolchain stable installs the latest stable Rust version at build time, which can change and cause reproducibility issues. Consider pinning to a specific version (e.g., 1.70 to match the README minimum, or a more recent stable version) to ensure consistent builds across time and developers.

📌 Example: Pin to a specific Rust version
 RUN curl https://sh.rustup.rs -sSf \
-    | sh -s -- -y --profile minimal --default-toolchain stable \
+    | sh -s -- -y --profile minimal --default-toolchain 1.83.0 \
   && chmod -R a+w ${CARGO_HOME} ${RUSTUP_HOME}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/Dockerfile at line 80, The Dockerfile currently uses the
rustup installer flag `--default-toolchain stable`; change this to pin a
specific toolchain (for example `1.70` or a chosen patch-level like `1.70.0`) so
builds are reproducible—update the `sh -s -- -y --profile minimal
--default-toolchain stable \` invocation to use the pinned version (or read a
build ARG and use that value) so the Rust toolchain is deterministic across
builds.
src-tauri/tauri.macos.conf.json (1)

5-7: ⚡ Quick win

Verify consistency between main window and preview window titlebar configuration.

This config sets trafficLightPosition for the main window, but the preview window creation code at lines 3590-3592 in lib.rs only sets title_bar_style and hidden_title for macOS—no traffic light positioning. This might cause visual inconsistency between the main window and preview windows on macOS.

Consider either:

  1. Adding trafficLightPosition to preview windows in lib.rs, or
  2. Documenting why preview windows intentionally use default positioning
Suggested alignment for preview windows
 #[cfg(target_os = "macos")]
 let builder = builder
     .title_bar_style(tauri::TitleBarStyle::Overlay)
-    .hidden_title(true);
+    .hidden_title(true)
+    .traffic_light_position(tauri::LogicalPosition { x: 16.0, y: 24.0 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tauri.macos.conf.json` around lines 5 - 7, The macOS main window
JSON sets trafficLightPosition but the preview window creation in lib.rs only
sets title_bar_style and hidden_title, causing visual inconsistency; locate the
preview window creation function (the code that constructs the preview window in
lib.rs—e.g., the function that calls WindowBuilder or sets
title_bar_style/hidden_title for preview windows) and either add a matching
traffic_light_position with {x: 16, y: 24} to its macOS WindowBuilder options to
mirror the main window, or add a one-line comment/docstring near that preview
window creation explaining why the preview intentionally omits
traffic_light_position so reviewers understand this is deliberate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devcontainer/Dockerfile:
- Line 81: Remove the insecure world-writable permission on the Rust directories
by deleting (or replacing) the chmod -R a+w ${CARGO_HOME} ${RUSTUP_HOME} step;
since ownership is already set with chown -R "${USER_UID}:${USER_GID}", either
remove the chmod line entirely or change it to a more restrictive permission
change (e.g., grant only the owner write permission) on CARGO_HOME and
RUSTUP_HOME to avoid making them writable by all users.

In `@src-tauri/src/lib.rs`:
- Around line 3664-3666: In handle_cli_args ensure Linux focus handling matches
show(): either wrap main_window.set_focus() with the same #[cfg(not(target_os =
"linux"))] attribute used for main_window.show(), or add a concise comment on
why calling main_window.set_focus() on Linux is safe when the window is hidden;
locate the calls to main_window.show() and main_window.set_focus() in
handle_cli_args and apply the same conditional guard (or add the rationale)
consistently in both the "directory-open" and "no files were opened" paths.

In `@src-tauri/tauri.linux.conf.json`:
- Around line 1-9: The Linux override is replacing the entire app.windows array
so you lose base window settings; instead of setting app.windows to a single
anonymous entry, patch only the main window’s visible property (e.g., target the
"main" window entry) so you preserve title, width/height, minWidth/minHeight,
resizable, and decorations from the base tauri.conf.json; update
src-tauri/tauri.linux.conf.json to modify app.windows["main"].visible (or the
array element keyed as "main") rather than replacing the whole app.windows
array.

---

Outside diff comments:
In `@src-tauri/src/lib.rs`:
- Line 3541: In try_select_in_notes_folder(), the unguarded call to
main_window.show() can reintroduce the Linux window-chrome issue; wrap that
show() call with the same conditional compilation used elsewhere (i.e.
#[cfg(not(target_os = "linux"))]) so it only runs on non-Linux builds, and leave
main_window.set_focus() following the existing pattern (keep set_focus() as-is
or guarded the same way if surrounding calls do so) to match surrounding code
paths and maintain consistency with other main_window.show() usages.

---

Nitpick comments:
In @.devcontainer/devcontainer.json:
- Around line 28-29: The devcontainer bind mounts use Unix-only HOME paths and
will break on Windows; update .devcontainer/devcontainer.json to either remove
the two bind entries ("source=${localEnv:HOME}/.codex,..." and
"source=${localEnv:HOME}/.config/Code/User/globalStorage,..."), replace them
with platform-specific alternatives (use a Windows conditional config that maps
%APPDATA%\Code\User\globalStorage for Windows hosts), or document that the
devcontainer is Linux/macOS-only; also address potential UID mapping by setting
updateRemoteUserUID to true or adding documentation/instructions so host UID
mismatches do not cause permission issues.
- Line 20: The shared devcontainer currently includes the AI extension
"openai.chatgpt"; decide whether this is intentional—if not, remove
"openai.chatgpt" from the devcontainer extensions array in devcontainer.json so
it is not forced for all developers, or alternatively make it optional by
documenting it in the repo README (or a dev setup doc) so developers can install
"openai.chatgpt" individually; update devcontainer.json to remove the extension
or add a comment pointing to the documentation and commit that change.
- Line 10: The devcontainer sets "remoteUser": "vscode" while leaving
"updateRemoteUserUID": false which can cause host bind-mounted HOME files under
/home/vscode/.codex and /home/vscode/.vscode-server to be unwritable if the host
UID differs from 1000; update the devcontainer.json to set
"updateRemoteUserUID": true (or remove the setting so it defaults to true) so
the container adjusts the vscode user's UID/GID to match the host and avoid
permission issues with the bind mounts referenced (/home/vscode/.codex,
/home/vscode/.vscode-server/data/User/globalStorage).

In @.devcontainer/Dockerfile:
- Line 71: Add a short comment above the line creating/mounting
"/home/${USERNAME}/.codex" in the Dockerfile explaining the directory's purpose
and why it's mounted from the host (e.g., cache for models, local tool state,
credentials, or workspace artifacts); reference the ".codex" directory name and
the corresponding mount configured in devcontainer.json so future readers know
what data lives there and why it must be persisted on the host.
- Line 80: The Dockerfile currently uses the rustup installer flag
`--default-toolchain stable`; change this to pin a specific toolchain (for
example `1.70` or a chosen patch-level like `1.70.0`) so builds are
reproducible—update the `sh -s -- -y --profile minimal --default-toolchain
stable \` invocation to use the pinned version (or read a build ARG and use that
value) so the Rust toolchain is deterministic across builds.

In `@src-tauri/tauri.macos.conf.json`:
- Around line 5-7: The macOS main window JSON sets trafficLightPosition but the
preview window creation in lib.rs only sets title_bar_style and hidden_title,
causing visual inconsistency; locate the preview window creation function (the
code that constructs the preview window in lib.rs—e.g., the function that calls
WindowBuilder or sets title_bar_style/hidden_title for preview windows) and
either add a matching traffic_light_position with {x: 16, y: 24} to its macOS
WindowBuilder options to mirror the main window, or add a one-line
comment/docstring near that preview window creation explaining why the preview
intentionally omits traffic_light_position so reviewers understand this is
deliberate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03239157-5b2c-48d5-8fbd-b01ad8596f5d

📥 Commits

Reviewing files that changed from the base of the PR and between a638f02 and 561bcd7.

📒 Files selected for processing (6)
  • .devcontainer/Dockerfile
  • .devcontainer/devcontainer.json
  • src-tauri/src/lib.rs
  • src-tauri/tauri.conf.json
  • src-tauri/tauri.linux.conf.json
  • src-tauri/tauri.macos.conf.json
💤 Files with no reviewable changes (1)
  • src-tauri/tauri.conf.json

Comment thread .devcontainer/Dockerfile Outdated
Comment thread src-tauri/src/lib.rs Outdated
Comment thread src-tauri/tauri.linux.conf.json
@pettijohn pettijohn force-pushed the bugfix-linux-chrome branch from 561bcd7 to d7c616e Compare June 4, 2026 15:38
@pettijohn

Copy link
Copy Markdown
Author

I deleted the devcontainer from the branch and addressed the two other coderabbit concerns.

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