Skip to content

Run the Windows port on Linux - #294

Open
arlindovs wants to merge 2 commits into
vinzdg:mainfrom
arlindovs:linux-support
Open

arlindovs wants to merge 2 commits into
vinzdg:mainfrom
arlindovs:linux-support

Conversation

@arlindovs

Copy link
Copy Markdown

The Rust port under windows/ builds and runs on Linux with fairly little
persuasion — every Win32 call was already behind cfg(windows), so what was
left was the handful of places where a Windows mechanism was the only one on
offer, plus a PNG icon and a launcher.

Tested on Ubuntu 26.04 / GNOME 49 (Wayland), against a live Claude Code
install: cargo test --locked passes (121 tests), codenotch doctor reads the
Claude credential and finds the standalone CLI, and the notch draws on the
screen edge and tracks running sessions through the watcher.

What changed

Mechanisms that had no Linux equivalent

Was Now
HKCU\...\Run value written with reg.exe an XDG autostart entry — same bargain: per user, no administrator rights, still --silent
GetUserDefaultLocaleName, GetLocaleInfoEx, the taskbar-clock registry value LC_ALL/LC_MESSAGES/LANG, and the 12/24-hour question from the locale's own t_fmt, translated to the letters the LOCALE_* patterns use so is_24h_pattern keeps reading both
explorer, cmd /C start xdg-open
claude.exe / claude.cmd only suffixes chosen per platform, plus ~/.npm-global/bin and ~/.bun/bin; Codex's vendored native binary matched by linux rather than windows
Claude sign-in in a PowerShell window the same script in a terminal emulator, found from the usual candidates. The CLI path still travels in the environment, so a path with quotes in it is never parsed

Build and packaging

tauri::generate_context! will not build without a PNG icon, so the icon set
grows the four sizes Tauri looks for, generated from the existing icon.ico
and listed beside it. Windows bundling is untouched — NSIS still takes the
.ico. tauri.linux.conf.json is merged only on Linux: deb and appimage, and
an updater with no endpoints, because the feed describes an NSIS installer.

scripts/run-linux.sh

Two things the desktop will not do by itself:

  • Wayland does not let a client place its own windows, and the notch has to
    sit on a screen edge — so it runs as an X11 client under XWayland.
  • A shell started from a snap (Ubuntu's VS Code, for one) exports that
    snap's library paths, and a binary built against the system glibc then dies
    before main with
    symbol lookup error: … undefined symbol: __libc_pthread_init, version GLIBC_PRIVATE.

The script unsets those and sets GDK_BACKEND=x11. Launched from the desktop
rather than from such a shell, the binary runs on its own.

CI

The Windows workflow grows a Linux job, for the reason that workflow exists at
all: a change that compiles on one of the two says nothing about the other. It
is build-and-test only — there is no runner with a desktop to show a notch on.

What does not work yet

Documented in the README rather than hidden. Each degrades quietly instead of
misbehaving:

  • Dragging the pill along its edge — follows the mouse through
    GetAsyncKeyState; needs an X11 pointer query.
  • Seen-clears-it, and jumping back to the terminal — focus.rs reads the
    foreground window and the process tree through Toolhelp. /proc plus a
    window-manager call would replace it.
  • Antigravity — its credential comes from the Windows Credential Manager;
    libsecret is the equivalent.
  • App icons taken from an installed .exe — the built-in provider SVGs
    cover every provider, so little is lost.

Everything else behaves as on Windows: all other providers, the hover card, the
settings window, the tray menu, hooks, and start at sign-in. The tray itself
needs GNOME's AppIndicator Support extension, as every Tauri tray does there.

Two things for you to decide

  1. Where this belongs. The README says this tree is developed at
    Im-Midi/codenotch-windows and offered here. I opened it here because the
    README also says a pull request touching the tree is built and tested here.
    Happy to move it, or to mirror it there.
  2. The name. A Linux port living under windows/ is odd, and the crate's
    description still says "Codenotch for Windows". I left both alone rather
    than making that call inside a contribution — say the word and I will follow
    whatever you prefer.

I am glad to close the remaining gaps in follow-ups if the direction is welcome.

🤖 Generated with Claude Code

arlindovs and others added 2 commits September 20, 2026 14:52
Every Win32 call already sat behind cfg(windows), so what stopped the crate on
Linux was the handful of places where a Windows mechanism was the only one:

- autostart: an HKCU\...\Run value becomes an XDG autostart entry, which is the
  same bargain — per user, no administrator rights, and the command still
  carries --silent.
- i18n: the locale comes from LC_ALL/LC_MESSAGES/LANG, and the 12/24-hour
  question from the locale's own t_fmt, since there is no taskbar clock setting
  to read. The pattern is translated to the letters the LOCALE_* patterns use so
  is_24h_pattern keeps reading both.
- explorer and `cmd /C start` become xdg-open.
- CLI discovery looked only for claude.exe / claude.cmd. The suffixes are now
  chosen per platform, and the places a Linux install lands (~/.npm-global/bin,
  ~/.bun/bin) are searched. Codex's vendored native binary is matched by
  "linux" rather than "windows" on the same grounds.
- Claude sign-in ran a PowerShell window. On Linux it runs the same script in a
  terminal emulator, found from the usual candidates, with the CLI path travelling
  in the environment exactly as before so a path with quotes in it is never parsed.

Verified on Ubuntu 26.04 / GNOME: cargo test passes, doctor reads the Claude
credential and finds the standalone CLI, and the notch draws and tracks sessions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tauri::generate_context! refuses to build without a PNG icon, so the icon set
grows the four sizes Tauri looks for, generated from the existing icon.ico and
listed beside it. Windows bundling is unaffected: NSIS still takes the .ico.

tauri.linux.conf.json is merged only on Linux; it points the bundler at deb and
appimage and leaves the updater without endpoints, because the feed describes
an NSIS installer.

scripts/run-linux.sh carries the two things the desktop will not do by itself —
running as an X11 client, because Wayland does not let a client place its own
windows and the notch has to sit on an edge, and dropping the library paths a
snap-launched shell exports, which otherwise kill the binary before main.

The Windows workflow grows a Linux job for the same reason it exists at all: a
change that compiles on one of the two says nothing about the other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@arlindovs
arlindovs requested a review from vinzdg as a code owner September 20, 2026 18:00
@vinzdg

vinzdg commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Thanks @arlindovs. You should know there is a second Linux port open — #269 by @heliorosadoneto — and the two take opposite approaches, so I'm reviewing them against each other rather than in isolation. Tagging you both so neither is working blind.

Yours is the cheaper shape. It keeps windows/ where it is, adds tauri.linux.conf.json beside the existing config, adds no dependencies, no packaging path, and is based on today's main. It breaks no open PR and commits me to nothing. #269 is better-engineered Linux code — a real 10-function platform facade — but it renames windows/ → desktop/, which invalidates every branch written against those paths, and its own branch predates 1.16.0.

Things to fix here regardless of what I decide about Linux:

  • tauri.conf.json:37-43 — the PNGs are prepended to the shared icon list, so generate_context! embeds a PNG window icon on Windows too. Move them into tauri.linux.conf.json; Tauri merges it at build time. (Good news: targets stays ["nsis"] and createUpdaterArtifacts is untouched, so unlike Linux desktop port (Mint / Cinnamon / X11) #269 there's no leak into the Windows installer. That matters — the installer target is now switched on from the workflow when a signing key is present.)
  • hooks_install.rs:71 still joins codenotch-hook.exe, so Install hooks fails on Linux with a missing-file error. Both the PR body and your windows/README.md edit say hooks behave as on Windows; they don't yet.
  • claude_auth.rs terminal_emulator() passes ["-e","sh","-c",script]. That's right for xterm/konsole/alacritty, but gnome-terminal dropped multi-arg -e in GNOME 42+ and kgx never had it — and on Ubuntu x-terminal-emulator resolves to gnome-terminal first. So Claude sign-in likely fails on the desktop the PR says it was tested on. Use -- with a fallback.
  • tauri.linux.conf.json:8 sets updater.endpoints: []. Once a signing key exists, app.updater() will return EmptyEndpoints and Settings will show an error on Linux. Better to gate the check off entirely on non-Windows — see src/updater.rs, which already has a configured() guard you can extend.

Smaller: find_cli() gains ~/.npm-global/bin and ~/.bun/bin un-gated (harmless, but it's a shared path), codex.rs:133 still pushes codex.exe on Linux, and there's ~330 KB of PNGs including a 230 KB icon.png where Tauri needs only 32/128/128@2x.

On the decision itself: I haven't made it, and I won't pretend the holdup is code quality. The code cost of Linux is small and getting smaller. The support cost is permanent — a third packaging path, and bug reports from X11/Wayland desktops I don't run and can't reproduce on. Once a .deb ships it also needs its own update story, because the Tauri feed added in 1.16.0 only describes an NSIS installer.

I'd rather tell you that plainly than leave this open for weeks. Fix the four items above and it's a reversible first step I can say yes to; the facade work in #269 can fold in on top later.

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.

2 participants