From 5c8191e82f8b7ed7814272c5d9b9e57e3c726f58 Mon Sep 17 00:00:00 2001 From: Aaddrick Date: Fri, 1 May 2026 02:47:16 -0400 Subject: [PATCH] feat(linux): hybrid titlebar mode for clickable in-app topbar (#538) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(linux): hybrid titlebar mode for clickable in-app topbar Default `CLAUDE_TITLEBAR_STYLE` is now `hybrid`: native OS frame plus a BrowserView preload shim that convinces claude.ai's bundle to render its in-app topbar (hamburger / sidebar / search / nav / Cowork ghost). Stacked layout instead of Windows's combined bar, but every button is clickable. Why not the upstream `frame:false` + WCO config: investigation (see docs/learnings/linux-topbar-shim.md) ruled out `titleBarOverlay`, `titleBarStyle:'hidden'`, and the `.draggable` CSS class as the source of the topbar click-eating drag region. The remaining cause is a Chromium-level implicit drag region for `frame:false` windows that exists on both X11 and Wayland and has no Electron-API knob. With `frame:true` the OS handles dragging and Chromium pushes no drag-region map, so the buttons receive mouse events normally. Modes: - `hybrid` (default) — system frame + shim, topbar visible and clickable - `native` — system frame, no shim, no in-app topbar - `hidden` — frameless + WCO config, matches Windows/macOS upstream; topbar visible but not clickable on Linux. Kept for Wayland comparison and future investigation Tests: tests/launcher-common.bats grew 16 cases covering `_resolve_titlebar_style`, `build_electron_args` flag selection per mode, and `setup_electron_env` env-var wiring per mode. `claude-desktop --doctor` now reports the resolved mode and warns when `hidden` is set. Co-Authored-By: Claude * docs(learnings): add hybrid-mode screenshot Visual reference of the stacked layout: DE-drawn titlebar on top with native window controls, claude.ai's in-app topbar (hamburger / search / back-forward) immediately below it. Co-Authored-By: Claude * docs(learnings): fix codespell hit (Pre-emptive → Preemptive) Codespell flags hyphenated "Pre-emptive" as a misspelling of "Preemptive". Drops the hyphen to clear the spellcheck CI gate on PR #538. Co-Authored-By: Claude --------- Co-authored-by: Claude --- .claude/agents/electron-linux-specialist.md | 4 +- .claude/agents/issue-triage.md | 4 +- CLAUDE.md | 1 + build.sh | 4 +- docs/CONFIGURATION.md | 23 ++ docs/learnings/images/linux-topbar-hybrid.png | Bin 0 -> 90466 bytes docs/learnings/linux-topbar-shim.md | 367 ++++++++++++++++++ scripts/doctor.sh | 23 ++ scripts/frame-fix-wrapper.js | 178 ++++++++- scripts/launcher-common.sh | 40 +- scripts/patches/app-asar.sh | 10 +- scripts/patches/titlebar.sh | 44 --- scripts/patches/wco-shim.sh | 40 ++ scripts/wco-shim.js | 267 +++++++++++++ tests/launcher-common.bats | 108 +++++- 15 files changed, 1053 insertions(+), 60 deletions(-) create mode 100644 docs/learnings/images/linux-topbar-hybrid.png create mode 100644 docs/learnings/linux-topbar-shim.md delete mode 100644 scripts/patches/titlebar.sh create mode 100644 scripts/patches/wco-shim.sh create mode 100644 scripts/wco-shim.js diff --git a/.claude/agents/electron-linux-specialist.md b/.claude/agents/electron-linux-specialist.md index 3cfb758..3333d31 100644 --- a/.claude/agents/electron-linux-specialist.md +++ b/.claude/agents/electron-linux-specialist.md @@ -101,7 +101,7 @@ claude-desktop-debian/ │ ├── patches/ # sed/regex patches on minified JS (per-subsystem) │ │ ├── _common.sh # extract_electron_variable, fix_native_theme_references │ │ ├── app-asar.sh # Asar repack, frame-fix wrapper injection -│ │ ├── titlebar.sh +│ │ ├── wco-shim.sh # Inlines WCO/UA shim into mainView.js preload │ │ ├── tray.sh # Tray menu handler + icon selection │ │ ├── quick-window.sh │ │ ├── claude-code.sh @@ -121,7 +121,7 @@ claude-desktop-debian/ | Function | File | Purpose | |----------|------|---------| | `patch_app_asar()` | `scripts/patches/app-asar.sh` | Extracts asar, injects frame-fix wrapper, repacks | -| `patch_titlebar_detection()` | `scripts/patches/titlebar.sh` | Removes `!` from `if(!isWindows && isMainWindow)` to enable titlebar | +| `patch_wco_shim()` | `scripts/patches/wco-shim.sh` | Inlines `scripts/wco-shim.js` at the top of `mainView.js` (the BrowserView preload) so claude.ai's bundle sees Windows-like UA + matchMedia and renders the in-app topbar on Linux | | `extract_electron_variable()` | `scripts/patches/_common.sh` | Finds the minified variable name for `require("electron")` | | `fix_native_theme_references()` | `scripts/patches/_common.sh` | Fixes wrong `*.nativeTheme` references to use the correct electron var | | `patch_tray_menu_handler()` | `scripts/patches/tray.sh` | Makes tray rebuild async, adds mutex guard, DBus cleanup delay, startup skip | diff --git a/.claude/agents/issue-triage.md b/.claude/agents/issue-triage.md index 77810e6..f0a1b11 100644 --- a/.claude/agents/issue-triage.md +++ b/.claude/agents/issue-triage.md @@ -48,7 +48,7 @@ Use this when you're not confident enough to triage automatically. Examples: sec ## INVESTIGATION RULES ### All bugs are ours to fix -This project's goal is to take a working Anthropic product and make it work on Linux. Every bug is something we can investigate and potentially patch. Check `scripts/patches/*.sh` first for bugs in patched areas (`cowork.sh`, `tray.sh`, `app-asar.sh`, `titlebar.sh`, `quick-window.sh`, `claude-code.sh`). Read the relevant `patch_` function and trace what it modifies. If a behavior difference exists between the Windows/macOS app and our Linux build, that's a gap in our patching, not someone else's problem. +This project's goal is to take a working Anthropic product and make it work on Linux. Every bug is something we can investigate and potentially patch. Check `scripts/patches/*.sh` first for bugs in patched areas (`cowork.sh`, `tray.sh`, `app-asar.sh`, `wco-shim.sh`, `quick-window.sh`, `claude-code.sh`). Read the relevant `patch_` function and trace what it modifies. If a behavior difference exists between the Windows/macOS app and our Linux build, that's a gap in our patching, not someone else's problem. ### Verify before stating Only state facts you verified by reading actual code or running commands. Never claim code exists, functions behave a certain way, or patterns match without finding them in the source. If you cannot find evidence, say so explicitly rather than speculating. @@ -80,7 +80,7 @@ When investigating bugs, search these files based on the issue category: | Category | Files to check | |----------|---------------| | Build failures | `build.sh` (orchestrator), `scripts/setup/`, `.github/workflows/ci.yml`, `build-amd64.yml`, `build-arm64.yml` | -| Window/frame issues | `scripts/frame-fix-wrapper.js`, `scripts/patches/titlebar.sh`, `scripts/patches/app-asar.sh`, reference source for `BrowserWindow` | +| Window/frame issues | `scripts/frame-fix-wrapper.js`, `scripts/wco-shim.js`, `scripts/patches/wco-shim.sh`, `scripts/patches/app-asar.sh`, reference source for `BrowserWindow` | | Tray icon issues | `scripts/patches/tray.sh`, reference source for `Tray`, `StatusNotifier` | | Packaging (deb) | `scripts/packaging/deb.sh`, `scripts/launcher-common.sh` | | Packaging (rpm) | `scripts/packaging/rpm.sh`, `scripts/launcher-common.sh` | diff --git a/CLAUDE.md b/CLAUDE.md index d1c557c..0aceec9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,6 +14,7 @@ The [`docs/learnings/`](docs/learnings/) directory contains hard-won technical k - [`apt-worker-architecture.md`](docs/learnings/apt-worker-architecture.md) — APT/DNF binary distribution via Cloudflare Worker + GitHub Releases, redirect chain, credential ownership, heartbeat runbook - [`tray-rebuild-race.md`](docs/learnings/tray-rebuild-race.md) — why destroy + recreate on `nativeTheme` updates briefly duplicates the tray icon on KDE Plasma, and the in-place `setImage` + `setContextMenu` fast-path that avoids the SNI re-registration race - [`mcp-double-spawn.md`](docs/learnings/mcp-double-spawn.md) — Stdio MCPs spawn 2× when chat and Code/Agent panels are both active, root cause in upstream session managers, MCP-author workaround +- [`linux-topbar-shim.md`](docs/learnings/linux-topbar-shim.md) — why claude.ai's in-app topbar is missing on Linux, the four gates that hide it, why the upstream `frame:false` + WCO config has unclickable buttons on X11 (Chromium-level implicit drag region), and the resolution: hybrid mode (system frame + UA-spoof shim → stacked layout, full button functionality) ## Code Style diff --git a/build.sh b/build.sh index 0569b7c..30db739 100755 --- a/build.sh +++ b/build.sh @@ -52,8 +52,6 @@ source "$script_dir/scripts/setup/download.sh" source "$script_dir/scripts/patches/_common.sh" # shellcheck source=scripts/patches/app-asar.sh source "$script_dir/scripts/patches/app-asar.sh" -# shellcheck source=scripts/patches/titlebar.sh -source "$script_dir/scripts/patches/titlebar.sh" # shellcheck source=scripts/patches/tray.sh source "$script_dir/scripts/patches/tray.sh" # shellcheck source=scripts/patches/quick-window.sh @@ -62,6 +60,8 @@ source "$script_dir/scripts/patches/quick-window.sh" source "$script_dir/scripts/patches/claude-code.sh" # shellcheck source=scripts/patches/cowork.sh source "$script_dir/scripts/patches/cowork.sh" +# shellcheck source=scripts/patches/wco-shim.sh +source "$script_dir/scripts/patches/wco-shim.sh" # shellcheck source=scripts/staging/electron.sh source "$script_dir/scripts/staging/electron.sh" # shellcheck source=scripts/staging/icons.sh diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 7761dd8..1cd9b87 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -15,6 +15,7 @@ Model Context Protocol settings are stored in: |----------|---------|-------------| | `CLAUDE_USE_WAYLAND` | unset | Set to `1` to use native Wayland instead of XWayland. Note: Global hotkeys won't work in native Wayland mode. | | `CLAUDE_MENU_BAR` | unset (`auto`) | Controls menu bar behavior: `auto` (hidden, Alt toggles), `visible` / `1` (always shown), `hidden` / `0` (always hidden, Alt disabled). See [Menu Bar](#menu-bar) below. | +| `CLAUDE_TITLEBAR_STYLE` | unset (`hybrid`) | Controls window decoration style: `hybrid` (system frame + in-app topbar), `native` (system frame, no in-app topbar), `hidden` (frameless WCO — broken on X11, kept for diagnostics). See [Titlebar Style](#titlebar-style) below. | | `COWORK_VM_BACKEND` | unset (auto-detect) | Force a specific Cowork isolation backend: `kvm` (full VM), `bwrap` (bubblewrap namespace sandbox), or `host` (no isolation). See [Cowork Backend](#cowork-backend) below. | ### Wayland Support @@ -49,6 +50,28 @@ CLAUDE_MENU_BAR=visible claude-desktop export CLAUDE_MENU_BAR=visible ``` +### Titlebar Style + +Claude Desktop's web UI includes a custom topbar (hamburger menu, sidebar toggle, search, back/forward, Cowork ghost). On Windows / macOS the bundle gates rendering on `display-mode: window-controls-overlay`; on Linux a shim convinces the bundle to render anyway. Use `CLAUDE_TITLEBAR_STYLE` to choose the layout: + +| Value | Frame | In-app topbar | Window controls drawn by | Notes | +|-------|-------|--------------|--------------------------|-------| +| unset / `hybrid` | system | Yes | Desktop environment | **Default.** Stacked layout — DE-drawn titlebar on top, in-app topbar below. Topbar buttons clickable. | +| `native` | system | No | Desktop environment | When the stacked layout looks wrong on your DE, or you don't need the in-app topbar. | +| `hidden` | frameless | Yes | Chromium (WCO region) | Matches Windows / macOS upstream config. **Broken on Linux X11** — topbar buttons unresponsive due to a Chromium-level implicit drag region for `frame:false` windows. Kept for diagnostic / Wayland investigation; see [docs/learnings/linux-topbar-shim.md](learnings/linux-topbar-shim.md). | + +```bash +# Switch to the bare native experience (no in-app topbar) +CLAUDE_TITLEBAR_STYLE=native claude-desktop + +# Or add to your environment permanently +export CLAUDE_TITLEBAR_STYLE=native +``` + +This setting applies to the main window only. The Quick Entry and About windows are always frameless. + +Run `claude-desktop --doctor` to confirm the resolved titlebar style. The doctor output also flags `hidden` mode as broken on Linux and unrecognized values as fallbacks to `hybrid`. + ## Cowork Backend Cowork mode auto-detects the best available isolation backend: diff --git a/docs/learnings/images/linux-topbar-hybrid.png b/docs/learnings/images/linux-topbar-hybrid.png new file mode 100644 index 0000000000000000000000000000000000000000..5b95f40b71ce218e7e54aead6f2117ca83e77088 GIT binary patch literal 90466 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 z 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�Cy0jZx%d*zHZas@h^KZh&ePEBc_ny+Xk}$Z zGVNo^^_s;A8dvk$%k^wE1DH^sKlg-)!pmKyV8Cmu9Jp9NE^?Bh=Ehgt9$&LOEs-X_ z5<56#5>wgdemd$k4%x zlfCye-ew!vy9XN@3{l;=9#0w=9CS@hWujyoW#Jng+qKWAH{V(|6pzPoW$B)3^j)PM zLO~sA`G7!7EiIpZ+&|)Rj)CFzP)$%1tblXugSV zqBkKR_|6-%dvOV82Q6=1>&Y#(h7ryC;DtWH&}VnO6V!s4WncdPkqs8@IQ6cQ%diHIqG#bLpu(+C6Jd_SE=|- zC3_si;GBqJOSs2C^46^#6+S_Zl+nI$Vw)WtPVKbw2XKOK)pF$|*>$J6LkMT>9fiJ8 zkDdEw%rjBptEnp4@qO+!h_M(y$O++}E6wOiF>jLid7J;svBtB2`5h zzC9#2VN(Q^6IS{ipR%=T6(L_}YG(EkwMde39#jucfy2eyIB9o?lIJ|L7=NbCQBzM8xB_ ze#;FBGD5(O1$PHSsbz<_yiTs?C(PR{G!ux>hI*}`1j`;6oVm4!_1zr$qsBaIV}uc` zR7S9V3(=3|mzT&fw_VSYLS(InkDvDm&CIkIWt1jeLU*V=_ zwIDft{nz+>>Ln+z9q4Z8HUGuI@j!Q?o6{Y9f!hsMa>})UE&Y(AY01hyViv ze|TN;-eSvp@Q)K>qjQCMPEc32u{tn{jn#wA%KwDJ=PP^d)U?ww(v4<&{kPK{%8WsY znGWNxk=rQuU*`X+e@1h*sI0S-f~4^1)hk!7uQ402E=R}r%S$y+NNzLYd5wrD)(E$= z&CFYrSja!{Iz5SSP*_G?sU9i6u37iLheOA|@n;wG?<}S|1I{{!+!GL(-Q86DbU$2^ ze&__>KSxJ*|EqGVB)9vC9`|Uv>1dv=D~YO3!AEYo9jLRI?k0D^_#XTjAYNg5UuMo&i+oy$jFfBi~0gvFQNpwRBssCrKK@zXlc!L8RuSMa0gBwlb?mp?SV~_ zLln*0rS4wikw@G-Jofg%tqgEXq-ba-!7FdLw$v6(zSXhV4h^kdX{NcGSk@)jFA}}K z(G<|>`SRtHq3Qv%hroISs{EVL#t`A~Rc9II7G*?&lS32|Y8mV*$Z+F^OwYp4)1q2{ zyD1lWAJB=0h;IqNt67?F8B8nRckdo3DpnahTpO&vc5P6Fg{At`?mrx>Fdki zqBLPBK`(oKv-9#lcRl?cnaRM^lo#GLK_>%4p>XG|d*t&qO#HjV(X&Ng!36FCtGCfJsvVpaB9?^kT_Y1ljTuQ)K4`s(oh{j$~p z9g%lDf_ZFNk`*(7L&jWs8npKE&;2pjg;!4rc)h9-_Af^;_wVweoJhCv7eGrO3*0P^ z#g>e$ZI25zZ*B&fQNL(6MrA=cBX(nIqh@O+_vr8hnR(W6dw)Xb+U@Oa1Vc|l`3xhQJf@OCR0x)s&KE!*`veL)1vE3Q=c<4qXCs(QF)ZU`zY~_!&_S|Ey^^~aS;di zahv>d!Ej!7qv+Z6^6x6Y05fGYE@~Kk3(_*(`FDcoWm3vEl6l4o1_)H%!9N<96d=OX zNQQ;na+>N+ft@8Dm?xWS1M{K1eWp~sGlZmIb9gx&{Cl{P{;zv_Ch7cLTX_YACs;0G zYkC=fwv=y^1xR+pvBlF;H3@Bw*@hDpr&F5VbG1C}=lRoL8QP!+m_nbhy6l43^+iK+zPZqMB4Fa&m1r?c%sD>EFf7%q-xj zhugH{aZfIPv+@Ck#J$@JvoN3scK`GiTd;>F&I_^-u?rl&8={3E6ZTb0$a$(S^`Ob0 z`S}aiK0n2ANLI`>(<|EE%F7j+{p8T~KArnJftyP~)uaEtu? zci)7okp+6Vbj_NUQu(yoL9>_W>0g26nPxphjhSa8^-{4<>AKAOO})CoIVutueO^{D z`40+N5By^L=6#2CtUVW$@<6J(RQfUcxVD50qKnx^D3`@N5d z-RQJfF4PQ)QgyDE&)hlE*chFA<@n*lhcR&&OVJz$C3CE|z{AXW)lB*5^MV52nf&>z z4u*=*5Gr!k;X_GDNf99k*+7cl1_gPbVQGqS6ci9}uSz-%sko3Q6S6%Tk8q*^`R3TY z@a->EB>;Zn{%3xH13^T{3W5QTq@#plWs~27Lb(ri?upa%nOBu8qM5Or`qg1|PMPks zT#|f>|4uWI2bySmevg+94-F;nKJjjSpQgTkp>VA$7ayBZbHOP%Q$c^8HF$Bb(l_cN z-2|-<0B{)qg}N+K5T2^3s&3qqyD-&t-?ktTAb~HAAF825e|F|i;V#QiFSNcT@z~n! zfF{F{k3n!3j}ggjyZ`v{F388W+@X#`FuN^rQz@L!5olTToShWwM%R%uYn~F}kti(& zCMSR3I|O$hA`g^f4dN{C>Df#>pn<^LJxPT_dgi+xiE*AqRYp{zPRr7x#nELVns8SQg>)vj$s3AhNT?)yy^d2|#}gHuz<-By+b_K!>8jvCA^#(wNK zG~_TN0%J%2`WWUKl~9VS3E|{NV{yne+LD~)`~?xQ10HT}JN(~u3kfmQ8G*!U*OABU zkec@8I&Z@sf=&A@j45|uuj4novM*fuk(1s_ z-^5f=q0oW6o_F~Q%KJM}4FE)M3Ja59RC$hv=TY!qjP-1nOU-vxR#u9q%%w_15f^Q+ zsPcZV{9PsG|AS&1#S$TIv9UE;M?9{B|b!<@!4X`uv?zW#4PnKU#{fM zGQYw^*-gD>XZE$t$GW;(=3W9(T_fYaT!exe0}SZV9HTOoS|f0P07SF*QN@0V-{nzb z?=T7mker~=qkJ3R+7Fgbsr1&84!d+Pvl|l@^_(L|d1kRCli)%0XKfKdyeQosPmQ=KDw;=H;^cPp|%R zJpz|DFNvb$RloN$w>OV&gk!|6V+3Ej%%m){8Ugv&Ye3?qm7fyC2SBt)C05u z<_tdruyhEg1P-zEvPlm>!y@OhfEold!JitBLqo2mJ}xBSI3}1$9E9Waehx0K#*g=Q zBOVTa-`}H=0EtIJ)q?ahh!P=xZ9EagC5Em%yG44i5KPR>&hzARZf$L0OhC|X1XJV( zpD01mNyTwd6Yx%ijuP5z0foH_U>7|U?!NWl0rrrm(YF5tY>%`0038+7;6}h9fVS#8 z!YmiA8xn!FH8p@A&wyALW2V{mv4TPr!R!@nUU)3ZDX{eB8-9{{>|(2Szl@OVoi6_>@EKYvUJjE(~bE&>{GTw9<8==pTl2^;Jx z#3{CX$nJe#iEc1Ja~U!B!Goi)YD4qWfF2u^7i>fhW5TArFxrL(WpHCvnqJQ8USdmQ zq8t;5QlW&+F^e3O-b;YJLloU-ayMA&{lOzrKV5edj%L1*mRTl)cXV>tMm?s17d73)#f7j*ehV$V zs))2P(ZZ$pj5Y-3Xid5VH?_b=XS@Zjg zW70|T$3O-{)$>rWGdX`5<7o9Kkq1RTXJlMp%VGun=Hj)_e1PY*H&)WF8+AViVsm+< z5)71vEJLN%B!$wcu3SfP3J?gv<2!cxbS2856&UBX-0=i;gm6`G)Ud#G5%uDQ``+U5 zZx6y`5pkuLpt%hY06?iwV0LwFZM0}87ep)vhld5gqa<9&0{aRK?^EISS%n=g53ELg zQM`&(`GxV8gUPM#FkFk)5&qg{8+*OtE-*^GHT0S91q0}PF`7YbetDBnh0a#kq5g;$ zkKBoe0sKwP+V`25GWl^LUF{|&2HVmHe&q-(=&tt2$;sh>=Ge~D^0;i8G0CN9{EWJ9 zjT;L~-t9|6QO(ocRTpqRL6?}Vq6<&RBOT&A+_K(SS{jOH;)A2`P!BR|<;dgl#Y$ep z958r9dvX_vJ|hKJy^VfUpg1@GF9x01z>I3Hff~9yNp@aIQhMo2zR@y-5wciH(O^MO zVgi$knFPK3<0m^#@!Bsl2zRE*kn4=U7B)99oN5-i&69?WSX}$;s@htaXE&RRE|)!@ z?pZsuE}X0y)!^SA7MYj);UfcQrs9-xs{D!D8#6z}vI5Hs>X<%Gp28>){_rieulApy zWibw0P25(>@>Kg({QP(aReE~*J6`+4;ZAGu4R>w5D0UE7UnpJDzI?fO;esm&;0S2o z=#SvmVIg!m$86|T!x|BG)>bg4!nT-PCxKr1a_o^>dieRBAj0Hdt0piRm~ur3hv_qDb$X%uy|knFjt5_q z|Bc-6!BWC!n1fShW8@t=aDBHm=LuUqkd#DcC1o8zpm4b#K9iu)(7JYE!T zhvn&t}al@|e&x8QRYn~ssi_p_5pKp@1U8*U_NBQ^MBl|Df)5A{Qcg)x4zP~(SF@93LdFd|#>_5lpzetr#MonD@nu8bG4+LAD z#b%-?C&DN=JkC&QKHA|>va8=xvVu zvd6x8f)0cA5Fu!eOAXf^GuXl`tw0z94)=;6euYWsssN53*y***;Q?vs_%XL zH-l|D3+#``rE0}_T&AM3kb409hrw`JQ6Lpf4U#fCqZ(X6&1wo$ejXkk^p>T_LEP4J zklfafXWhBFwuW8c*C^D$Ho$gfqQ^UFOqv8h46pj}<2Ue>@szwqo$Gk1fk7!!5R_9? z3iPZbyWSv01Ka$B0kpsWNjwt)g};712JK8_%MkJQs^XVlE3+r84~66e0n}DAG^~BP z%Q-$z7zAQ+IBOxKY1aQ?r8^^rdT*x8qD+U=+XaQ^{!jp69(z|4( z*W1f1W%cz(fY>d~@JCFu)PSV|h+9oxzsC2%ePQD0U@$~vC0xcw8%#?De7rpaR`TU1t7(lf}mu%tZZvz z11;}*#7R!8$#)%|Y%!RqNM>kVMak0vGkOVC(Be>otQgxC@LyWCH)5$MEp^3+P2JG& z4g?oKAe1^H;jdlvE{c1b+xM*`ONK`zAYAZF9>tj3+Ip8(l=W>=p=HD>^bOm?1e|Q^ zgh=k}fk>|WOa{l~#WwTtr1LmT&SgjVfBeSr6Mnytm5a#>;U6pB?oK59X<+7$ zb$<4TgR%`nU;hVj3%iN52?H(9U{+^o>-~fu_}5SEJ4Y=gJ5K!1{|}gI1DX9`T=)<@ zqI|A}?pHy@|N7>uIGca}KXP`QOBt~>I)h_OTULNmGF|p4;R<{QTstTszs3b4|Ian}=eqstyL>$VeFOgYkG!}q@UPqV|Gb}n|J?Tr7yk3k|M|WD zx`n>JkMUst=Ux8ur`gH}|8sHv>*Z`T{(t-!0lEDTr2xeZZ_BretrLw{-gULp&{>jP!|8OHWsvZ?I|7Z+ZnDeJ06#O)7)5_;95LN z)Y!y?VpeswWZk&`_wNUZfmh`hClrY=F^PNB;f4YA1EIV)m6OKCVt6ZNvjdv=f%v@H zrMXX9SDg(q6}_psORD^|J;T&D?J^tW^?u6hMT|1bCB@ZQW1)xpxo9ycNG|69y9hQK!l$3xtxooy9tE|Z` z>*C+$pz^S;9eQkReE;Un8?F*GLmDGyzei0iSu^#Bf63MEP4+r8QWyL7t=gLHe_#87 z{*3hWi@72v7sp#=haFL+aD>}E75R{DzBFmOc-|)j`CcZ`4umOnv)sVT!+3{yF-mbp*Q*-md{MFWzLr$4` ze0WCw;_2@3EZ5Wo;V)zlh+AE8%Kv?Pjs!u>V{?7!drjg2WZMyh4!{_L3T3;(6I2!^ znnF9w$;`GK-rF_YuWo2~T3C>0+JBpi)j1?~`qZ}vr9c0omo}l*+`h$T&`p?DEgqfS zXF1h)4E4p<{481b*9+vL&uzMSBueOy9TPzzq&AsTwM-iKksY`u-^SyeSHFGW`TUp^ zJb}`mH;J$>l`zewTUy@el}CoYSitl2v+QiTSkZ9J`f11RA3rW~YG&>nM3`f=r( z()CE$S|WE6+gG5G9~aqe_uXpR#m{fo#8&%vJVg8SPu_m;VAsF^*TA$ya51qZumfLL z5AWkt-7d6Vci<@RuYTVrW7-D>N914M`j(8h(Cm78<*H>v8->szfJ0K9yu7?C%cH(J zcrd9r%L{)ORThSdY_3`E+rR%e!c}EeRewGIGG(&Z|GEVURD2@tey8q|pUT!NX9iR3{cprYGw^s$>->=G#U$%M+%#Bb8_PGCibCZJoux3-t6s)BV zxV(6wrIU%Vdv=uuMZwekj(}l8_#6X|@P))|)Uq2t)TsQmMIbBe*k$JzGDim9C!1nx zt85Ln%@UKW*O!#@HyW>DH$x~R=83~f!*#%j#E@4$Zap`L{DJHGi`P{KK;kzHE}Lsf zZ0M=IqTOqPQvVDlsroNH-DO#S;qsVRj5FsQ-M-JJ3?NejM$tV^yb$>I=6_|x?-za# zPVFh)+C?)WZ8h0_=LY{-%M38Yo{qOTm|9t#=iOwX6Adezu-?GilTIDJKUB@wo#R_o zB^4_~`anGSJrh)^i9jMH{1I(o&#>AWO;j2|YdK}|SwZL-tkRhePuhYs?^!;|$I)IiNXQbYh|K^Rx&)i+GHQf$)=CJ7Nzp{*swrTKWV5s>`asr-p#_kYyWd zn{Rx-Jfx;&UL&ulh(JNGbnvF)tqWiv7f|o%egyVVd3opi<}a@W$WA1J!zG!SK&KKW zlYAagJYa{$xHJQNzQP)5`%|ll3R&Y!xOMsZZ_6PIw##BTo*3J z%Ec&XehuWl)=tjdH1!T|%-YVjU@DVZfRh82vpCeFmAijadKf?gz6Ar(ICW;$w@>b+891LT`?2r~AW< zfRHs^X{PHC4=qQZ_GaOmH^hiFx15~#RE3$G@>Nu1;$&E{=W}~_Gyg%s>Abf~ zjYAIhpq}nKkWkTEaC!XPf1TXtHv1M%tioP4F0Zn-Rbb4?+8K$|YD&rWER!x~4cA$LcvVQiIVAfu{CQDKj%mD#h8kB>Ww zyU6O_@tIB&nAk-usJsPT#GJDxTe| zi65W3ml5Md^gyi0;AE2IKL?iLz~Kb3d95ean{k!H)lBNRr_NOe=HPN=p6nbPm$5BxYIXTpGTvFU_ z7AutQq-@6bzq6tl_LN#Ws{zF%0YfXRERxZ)K8gA?QA+?8u-jxN8p@~NoT8*B^XxLcP*BPM2okUZuP<8=()7+vl**$eLNFU> zr0Jn_k0cy~$%m2Z6*_p$pncFUV)J(2Q(4<^&vW?XCfldO?w1de1qqUnZ=580eJc6a zmlDcbQ=Pefc3N7rhEYoNQ|?!;SQx*%p|>LRzxtus7gXF%Z&7Gm*QI*pm3d?Dk+WA# z&m}2(SS9a2bm;eJ+6lOr_`Dtqic=^JKh-ayL)r6IDLZ3zB6UFcDyE+2v&^{(u|4a% zGIrL9jc4eu8+O0>`G#0tzIeQE>sqIKq;1ial7^C}?R8U?l{w`z`s_C)v`Bfk$DMZX zX&r1FVt`m$Xoj{_yi^`B-fJUcF3m_?%v-1Um1hI(@0O6748(*XK(yK3(baJ2`U`9( zG^Q9b1YT*;tYj|(km2NL4<34LYGRw|=ue5oqkg&NmY=X`pJmil6*$>X$N;?X6u=uk*Xx-!<6O-D^_^eI~T_pitc-MIlG zQ;Iv9lg8?$HtkvFE5iS^LZ>|0lP$)M(MiYph!ZNj{wW!^r70!##Fn{{!c7!{Nq38H zi9hDmYyC4)*)T}OZ^WZ2)B1O)rXU}8Zuo}_(24lcq+QpLuX_PSN&6RD?)ZD;h6}gO zSWb*mTdSy0+b_|Y5C5>`;pyIIARdI1jvd>_o9@X8H}1rGHz1tP<2QzISq9?Bd{}0f z;A@&sRXIdQw>Qh6rzBcP&cwnjLZzoudU5GumbrbD;9g|9@8w^ju%UQEpWSSwlKI)r ziDTpqgvE3xrHn9)Rv5Z2O{D$cRSDA5Z#Deh+8UVCei&=1%+CERG#RhLu%C0LGaH)< zK8uuDCM%Vu3DTyqQXXu(+2U%-UXKafVog@eDsIU<4i3a$rXxly##)j^PG`+x zE3c{p=bd<`$e0G57c(uSa&3ZCoOa!pj>b4`ay6&O+~M@V+Jk_X%lH>Pa#3jwb8l*1 ziStClFPvY|G0GFHBtgGzuGJhKlGy`z!*bp+&q87OR_V8I&*)`%&~nT0{*DANKe$eA zZZqBSG$&7PxI=p{y(5}RwW>xL8qrbf!AG~qylke%EiHr2Ul^n(BAsTXtagoP&^f*J z?J;2-^Kdos`(D9Kb#p5#(3Etd_%dISZWoUHH@2{m3S8@={kHJA>lfd+Z};_v?q#g-#Uq&AjYgOvf z)<**#Ep9Aq)_(A^o!5%W&OWkuh+SN%&81gmg!B0a#n9*9zU{QIv{bKX%X6F6m&w#I zoG9itE_gLZL-Wn{#iMDTO#LvI7Oq!Q;m%&i}46yYwOT@pOno2)FgIT_5k* zWe;l|`c@j?!Z4+2aQqqk9ymI?xJ_3^A3_EC|7+^I1F3G`|4$(qSs|-qMMh>q_BbMY zug416duMMENs<+XDA^%1$w*RU99we8%-)XiyY%V#eV_A3=MSCt`ySVQt^2xOuQP~J zeSKhvJWDit3A$y~IP~EXQO??06i8#-4%=v(Q?x4@Hkst)<$uo2srK!%^YfGOxf;g+ zm>KLhMaqyvn@VF`tQND75H4e2m8lY5VVP^&w^{1qkSY6X=K9eY8UAUX0?S2>sqma@ zNS?bKd5i(Z9OBkkOJe2ilDf1&l1K_oxW?K2E^;I@{Z~zJAT71aTawmIQFh@ygG>L$jU~T;pllsB$ zQpn!4x#og@&JptpC1u^Xxdhvz229Ti8`Uqf67yZ5zCP_2L-cFM&!wp~h@{673jP^> zj}7%3ZEX(S6(NOd)PFzq(j>YJ3XcEa&vpkB3kYxlabIqgHM6n`b?$=AbpZDW)kGzw zW?rZzlx;h};=2_YMZ|CE0(Yl;5t{ir>jk)Md|l#9Mo2gABuvj$hPJT3$N3fj0;aHC z$jzo&uR0GCK>`zJM+DO~AzhkE!)r8`t3eQH*4HcMz1UovQ!tnW9Fou0f=;7*63}_< ze()8~WbZi6ZzS@iHmCaYI{wliHLGd0@p^Q4RTZVRO+g+AVp_7&713Z!@lZIzSL|ep z^=e18rdZ(Cm5oi$q+E453mJr}4U`PFgbB3cxEPm^ki_7SPj%m`=vH5@m7_vPtrqbO zji**Od7O-Y<0+BLi5qJUMNXPG#`Qgp`rP#mcFE(H1NtSA9)GN)=XIKMl7xCc9q#4z zZ!>Xnp1E@;r)86?MQ`Ajdb0bH2OBWvip~kd{*kJ#PCM7ttx*@%v0sPTIm{oC)2*$n zP{o7t@rhQfiDp&QxL3S6(;Rp8OHxV-iJGIhPhcfINldF%`x+2=DH^|_+ulxSL81o+ z@(K!mSn>4c*?giZQniJP^VaAKJvohylpPw+$dAd=Ka0D%%6e51R##t;b4n9OI^+hs zXct!6X6${#Expt^5x^B0()G*3>7F-^vNAO${guIlcST$`nwwWjN?n3YN!3lCRH|6H zsbj;V+yU(|yzJAsd#pHp%yfnc)q;n2F89si4x`Z@OzZ#sBP2O6D14rPkeT`8=d6^3 z_Pgz$l{DIC)t1(#I-Y-=a+ArAJBuhbde7jf&vz*(Wej6!^#Z*}c6r$Z+S?-<8yVIG zWu4-cC4@L(@0B!EWTA9JS1SqHZ_Xf;OyJJTuVmX+zv?lQ0o*VBGLz_ByiI;l z(a7v@FX1%x1H4xn<}$Zop0{qDpGHK!k*xc0 zo%wF@;-c8Fvkyv9ky%m_PsH_|-&cIx&q>dp6Cr>wYCA1}j53ZNdh#3}DYFe%FCpmI z{c=hR3u7j1PI19(ep%-<-3eU%1Y^0<){)zklZ40fA2}lJU0XZPYgQizCeLhag92Ep zlCrbIL4EFFZzfjNS51^pFdKbbbl9F+T~$qFr1_qxLPhKNImLnBNLhhK7%bbG8{2Om zaesd-=s1fC!%tb?5Y3Q4yHjD9l$x4QJ4^%mJ96hk!am`TD4lj^l@^M6zqkKf!qg?73+rx1G$jaZF<9|Vq(v^8TmZ>))Jcw zU|ZpkXwMzu+DiCf_f`{cul&^@Yra_>YF^9nEoSl3H4XinM=`24J?wc+Q|I1R3Tig_ zkrPMDZf$R$(kiwqbXR__KNz$1`YSE!Pj$K4A1pnW^*1K`sq9UQM27X+$pr=$``t7) z9$iBZP3G9iGE-1s$dRQeI4zKab^E1EMS_%)Dy7M9MpG}&etYWfe1AMTI=bShvP{d& zEW9n!?+TmPNx(He{N?4WJ^#6EajBtL8$s$KRp!c(aOwBE0>MW`C*dG`HLLJr85FLyh1fr|o#1KdFN5~W`x?_5&3Iv%lA={t!6wrVF6ZJ$#+ENhSqs*TvbhQt08%;bVW()>Kz|h3?A1CMV(MgcYF@UwWJRi<$UC)ctg9B+DEV#b* za&N!Wq9!5HxZVIbefN$&G{&54ZPq|jokM+^#fZ|TD^ z8=VO{7Hmn{^{b3N4VSSyj1+@7&HJ0F&L?#C z_MAXG(CQkzISD-J52mKbzosWAf*i)vB>1f!B{nt{PH3ofshpbUTC?Jlxs$ypKZ0x2 zM91qVhx7;_N4^aEFJGeGHhDN}APQmH;n7{7VhuCS!Y$Md2LqqGFgx=m=|3dppGEYS zINzwyzUzg;tM1>9bLO0=(P(e7iUmu->3s?UbR^9-sJo^J&A}Emc4L6 zdbnBFirwTXllrfV&Vg)D7y+U9*j#;Q=d3b+Ws&Vbm*eP(~o)h-BqnD3^w=|@H}^YWgPmv5b4a1Xv;Z{2$q zAS_?JTM?T%K8CL0NSx;FCAGa{3{@hj&g2F2U39ABN|&+ugu|dk`clSo(R=z53C|#d zJE6Pj-NSBmRBsE;_`@!PQf3G`3UvvW<~hJ5i1Ctt9tzkGzOAB%g8;vjoKO$Jq>v?K zlcEFuIpN0U3$zbW$-SxxF}sGWlH8{}Jn~LXReN`6fLCU4S$u7@h`t;X%T_+(RO_+5 zgFnwkLGbjN87@%pY+mARKwb}jkjm9NI2bEpHW``5>7aK@=<>JMmMPR~^nKcB0O~n> z;OC$X(7WyOI=MMh=Z=R?j;|I6d9cm)Jb%#KjJU%7<2cXS&kr|X_j1eeQH&&VZfF0J z_#MH_3V*a9^CCehOZ-Fwce(AVY~uF0R;FOA?}rZ1?+WVb1#1{FF^5)2k(LMagt_y$ z?5v36K0wETUO6>>Am@qa`9YhW1_oA}1>R}WA-uC+JMj@;36FJ}-w4LFxCXNd+M5zyimQgjmV#mz zZ&SvVyLVCwrc;8z9v=svN=k3FFt6}AuqdHR{G&WzmmkEqorGqXrA zxLtNhWDDC|AEM7J_nl;xsPcPqp+$RVdrjOA-xt?vu| zL0o}#UWF7!=?i|A`<7L9#sY$txCn3rB(T5fl&(;iGEq2kDJN(ifb`mxzdV_}$WgwZEwUIA84|B6gY>`Y^T6!1{ zp6UAo3Mfrn|JE%jMU_sjW^nzD;jakNcYx>nDoXTCfPkn_QsdF2 z(xU+7>jn$+sOt!fP4BRur%BJ-3I-Bl^m$H!*Dd@64YO=!^C)_U$P} zXpU!@i6WDJwD4j#Q3fRq4Ou7E(+rFRg@(WX!6P!pm>Wf@MC}qT5LC`D_8p85eohVA z{*{4!>mvvXB@*U+AA}h8eSVcu#=-(I`!$#tVqY+gO?GY!)B=xIiH{;zzb z{Z05QXeyx+=a%<3(*y3k<>GcM_fWVg>}qnAGJIgrv?ISOr50T*3v`@=#l{ccM2aaP zUfRBFu@(eCXBu~R$ew*U_j|J1;fI-dWMr6~Hes|08Ao<+pCd@6A9Z$bb&_X{tc(a9L8@LPmhBWT^WO;A?pPrZ;O;^WO4NVr$(rO<56Fjbq!51P{oKl(IW(PIVxC*J+HI?8 z+hZCz0e3$8p3JFTXAnTxBkDJwHY9vadPb(592_SLvneOaOOhnDeaB^bXw1(XD`Yz% z{0apC^0W06hwpFt914L`eg&ERh!4Bibz}GLvh~)^j@8n;vQs0PmNM;xokmLg9}d*| z+|=nzmCTH1?NFcUM0Z7%@z~UiRe%QjzR0z+zHOFWtdh!oM>tcU%uN`!k10tha;_0; z_T{TmdoE@l5!zkq61b19(Ns{t)Y(4wI*0o?i{M(oE@ODFwcJXvlXac3ol!}iUHwRW ztD?H&{<6m>6L_n-nwAIUD4ghSZzGEbE) zBqRhP+ZH>aoPUN`vv;__ps`od;^6qN4?NlH6fa{2dv>ygmHud1A;Xmdx6jlN0{hj$%f3O&RA)8m zJ_QX;Xvf?)Sr6^Apg-2uubTTwP$$=>zREzc$OZ;pJG6e=px#Yjz(qzwdA>w{u7Bi! zl;Hd$d8$7t;Jmy%jD0TW`imc99U11jgoxLoZp}AX!cc;(kM;h`%r@WKHz^%@96V_p zOq0O=e6+)`ByWCxO;TaT#i&FdLZh};-+}yPYSIYt_Ky$7*Tk zvRv*bLp701a$2ge$URZiEd^DFkpDl;yYCDO8g*JG{!FlMg95ar)5N=0$Mr67qt?1k z4s=jOx)@Fiiro!ePf-Rb$ryx%j4Ptx^-srZ5bEwcjPd2Uj}#IP8 zDX_jrm78HMDJjO#u%#Ain>rw)+~5e*kuUukj{_ zv1pG~w@Xc)%2-0>9B*#LdO-&Rxul<9In%YQWRubA%DZ1qztD&2fZlqSpWX~ z)Z)5ow|`HQiwa}^cR@0kRoSn@MzyuV{}RH%!^i(Y=~gpZv>UI3GhyN(un(=OZE_Fq|;_3}zTNzl6j! zWbo_1?@(wfWJyjw@9jbHE@)>vp4$*cFIS=-d8_~7n?++pXhHRbQ)lDU2|iv8V2ooF zEKx-tp9vKMej>p?%Y@oef(R&FIll!O_!&rI{4!ul1veqT8O1^@mZdJStyy6RjHdVP z;wUL+PUGN7fdyU2F-pKg@d!6OZB23_u)EUU2haEmhUj1PR>_z6P`j(z>Qsa%=bwe7 z+ZW{rTKdMg`GTrS>7d+BKNyGG3o*|GFe*li&k=rw9_de`jqPBoKS2Ejx{ z`e#38IH;5nXK5)cp)l33Q(YZjI{eN}(5*iC}F`Q0Z& zOZeb~M8FgHGKI(6x%AN0r;jBpn@$viTs_=z4RqfAvyZRzRxS8~PMdIJdUr$1@gh3z=9uXvQ!DqA(&TQ{G-NX#&K?s%0kufk3`RUL1 z+~uzvUC`4T%6;>O1o1-uY7U6y-Te09osqrpM==V8x<3oA8vIYFR;nL;nmGHq*o&EP z!?mWhmwxN}626w6sYuC1tCf_3>TgDVPoB+hADr$Se7;@LFTxWuCDrAk^7r>QEI-}m z3wXG=GWpuFua?5l4&)jd^#4xvSxLyV_6y(z=X~q-(gcC=_IUh=Cbzdr!w{7>ByJU! zqKx-Mxjl_`&WdQm6J8pl^QtE?Jz$F?MLD#c>whyBim2VzGkw89ekx}sG@2|XSz&K!I2*j=1C|TWppN_KYI`%@&GWJQ2_~rk;Iyr&IaA9%r77z=}c!X^2lHN~+ w=EhzeAhbPGXY#PL)P-5=ZawuIMDq#0Y;{A;_a<#Tcp~Dqf;y^H&LaH(0nVw*{r~^~ literal 0 HcmV?d00001 diff --git a/docs/learnings/linux-topbar-shim.md b/docs/learnings/linux-topbar-shim.md new file mode 100644 index 0000000..e513c99 --- /dev/null +++ b/docs/learnings/linux-topbar-shim.md @@ -0,0 +1,367 @@ +# Linux desktop topbar — design and history + +How claude.ai's in-app topbar (hamburger / sidebar / search / nav / +Cowork ghost) is wired up on Linux, why the upstream frameless-WCO +config doesn't work on X11, and how the **hybrid mode** (system +frame + in-app topbar shim) lands functional buttons at the cost +of a stacked-bar layout. + +## Status + +**Resolved 2026-04-29 via hybrid mode.** Default +`CLAUDE_TITLEBAR_STYLE` is `hybrid`: native OS frame plus the +wco-shim that convinces claude.ai's bundle to render its in-app +topbar. Topbar buttons are clickable. The trade-off vs Windows is +a stacked layout (DE-drawn titlebar on top, in-app topbar below) +instead of Windows's combined single bar. + +![Hybrid mode on KDE Plasma — DE-drawn "Claude" titlebar on top, claude.ai's in-app topbar (hamburger / search / back-forward) directly below it](images/linux-topbar-hybrid.png) + +Modes: + +| mode | frame | shim | layout | notes | +|---|---|---|---|---| +| `hybrid` (default) | system | active | stacked: OS bar + in-app bar | clickable ✓ | +| `native` | system | inactive | OS bar only | no in-app topbar | +| `hidden` | frameless | active | Windows-style single bar | **clicks broken on X11** — kept for Wayland / future investigation | + +## How the topbar gets to render + +The topbar is **not bundled in `app.asar`**. claude.ai's web app +inside the BrowserView renders it. Rendering is gated by an +independent stack — each gate must pass. + +### Gate 1: server-delivered markup + +Every request to claude.ai/claude.com from the desktop shell +carries unconditional headers set in `index.js:504876-504907`: + +- `anthropic-desktop-topbar: 1` +- `anthropic-client-platform: desktop_app` +- `anthropic-client-os-platform: ` (literal `linux`) + +The topbar markup *is* delivered to Linux clients — this gate +isn't load-bearing for our scenario. + +### Gate 2: Electron-shell boot features + +`index.js` builds a feature-flag object via `J0()` (line 301965) +and passes it to the BrowserView via +`webPreferences.additionalArguments=['--desktop-features=']`. +`mainView.js` parses the arg and exposes the parsed object via +`contextBridge` as `window.desktopBootFeatures`. The relevant key +`desktopTopBar.status` is `"supported"` on Linux, so this gate +also isn't load-bearing. + +### Gate 3: the `isWindows()` user-agent check + +**Load-bearing.** The React bundle +(`https://assets-proxy.anthropic.com/.../index-*.js`) contains: + +```js +const HV = /(win32|win64|windows|wince)/i; +function WV() { + if (typeof window === "undefined") return false; + // ... HV.test(window.navigator.userAgent) +} +``` + +This function and a sibling gate the topbar JSX. Linux's UA +contains `X11; Linux x86_64`, fails the regex, and React skips +rendering the entire `
` +topbar tree (note the `topbar-windows-menu` test ID — upstream +treats this as Windows-specific). + +The shim's `navigator.userAgent` override appends `" Windows"` +page-side so the regex passes. HTTP request UA is unchanged so +analytics, anti-bot fingerprints, and the +`anthropic-client-os-platform` header stay honest. + +### Gate 4: `-webkit-app-region: drag` on the topbar parent + +On Linux X11 with frameless windows, this is what kills clicks in +hidden mode. The topbar's `
` would normally trigger the CSS rule +`.draggable { -webkit-app-region: drag }`. On Windows, Chromium +hit-tests per pixel and child `app-region: no-drag` regions are +clickable; on Linux X11, Chromium pushes a drag-region map to the +WM as a region for `_NET_WM_MOVERESIZE` and the WM intercepts +mouse events before the page sees them. Critically: that map is +**sticky** — not refreshable from CSS, DOM mutations, setSize +jiggles, or hide/show cycles after first paint. + +In hybrid mode (frame:true) this isn't an issue. The OS handles +window dragging via the native titlebar; Chromium doesn't push a +drag-region map for framed windows. The shim's className intercept +strips `'draggable'` from any DOM class assignment as +belt-and-suspenders against the `.draggable` rule producing +surprise click-eaten regions inside the page. + +## The shim: what each part does + +Inlined into mainView.js by `patch_wco_shim`. Skipped in `native` +mode; active in `hybrid` (default) and `hidden`. + +| component | role | load-bearing? | +|---|---|---| +| Native-state probes | Capture Chromium's WCO state for launcher.log diagnostics. Phase 1 syncs non-DOM values; Phase 2 reads `env(titlebar-area-*)` via custom-property indirection on DOMContentLoaded. Bypassed by `CLAUDE_WCO_NATIVE=1`. | No (diagnostic) | +| `navigator.windowControlsOverlay` shim | Returns `visible: true` and synthesized rect. | No (defensive — bundle grep shows no current use) | +| `matchMedia` shim | Returns `matches: true` for `(display-mode: window-controls-overlay)` queries. | No (defensive — same) | +| **`navigator.userAgent` shim** | Appends `" Windows"` so Gate 3 passes. | **Yes** | +| className intercept | Strips `'draggable'` from any class assignment via `Element.prototype.className`, `setAttribute`, `DOMTokenList.prototype.add` overrides. Three vectors covered. | Defensive (belt-and-suspenders) | +| Event nudge | Dispatches `geometrychange` + `resize` to wake any framework that rendered before the shim arrived. | No (defensive) | + +## Investigation chain — why hybrid + +Two phases. Phase 1: render the topbar at all. Phase 2: figure +out why the buttons don't fire mouse events. Phase 2 went through +several false hypotheses before landing on hybrid. + +### Phase 1: render-the-topbar + +Original assumption was WCO `@media` gating. Several wasted +attempts at activating WCO at the page level +(`titleBarStyle:hidden` + `titleBarOverlay`; explicit object form; +`--enable-features=WindowControlsOverlay`; native Wayland) all +failed at the time, leading to the empirical conclusion that +"Linux Electron doesn't activate WCO." Bundle probing eventually +surfaced **Gate 3** (the UA regex). UA spoof made the topbar +render. The other shims stayed in as defensive forward-compat. + +### Phase 2: clicks-don't-fire + +Six escape attempts at defeating the X11 drag-region map all +failed: + +1. CSS override of `.draggable` to `no-drag !important` — computed + style flipped, clicks still broken +2. `MutationObserver` stripping the class on attach — DOM correct, + clicks broken +3. IPC-triggered `setSize` jiggle — no effect +4. `setSize` + hide/show cycle — no effect +5. JS-side `programmaticClickFired: true` confirmed — handlers + wire correctly, problem is purely OS/WM-level +6. Preemptive global `.draggable { no-drag !important }` from + preload — no effect + +All six targeted the `.draggable` class as the source. The 7th +attempt — a JS-DOM API intercept stripping `'draggable'` from any +class assignment via `Element.prototype` overrides — also failed, +even though probes confirmed *zero* elements ended up with the +class. The drag region wasn't coming from `.draggable` at all. + +### Narrowing the source + +With no element having computed `app-region: drag` yet clicks +still broken, the source had to be at the Electron/Chromium +config layer. Three diagnostic experiments narrowed it: + +| experiment | result | +|---|---| +| `CLAUDE_TBO_HEIGHT=off` (omit `titleBarOverlay`) | clicks still broken | +| `CLAUDE_TBS_DISABLE=1` (also omit `titleBarStyle:'hidden'`) | clicks still broken | +| `frame: true` (hybrid mode) | **clicks work** | + +So the source is **`frame: false` itself**, not anything we can +configure at the Electron API level. Chromium-Linux-X11 has a +hardcoded behavior that creates an implicit drag region for the +top of `frame: false` windows. The fix is to not be frameless. +Hybrid trades a stacked layout for clickability. + +## Outstanding upstream bugs + +Two unrelated Linux-X11 / Electron 41 / Chromium 146 issues +surfaced during the investigation. Worth filing if someone has +time. Bug A is the most actionable. + +### Bug A: WCO `@media` query doesn't match where WCO is otherwise active + +In the **main window** webContents of a `frame:false + +titleBarStyle:'hidden' + titleBarOverlay:{...}` BrowserWindow, +runtime probe 2026-04-29: + +| signal | value | +|---|---| +| `navigator.windowControlsOverlay.visible` | true | +| `windowControlsOverlay.getTitlebarAreaRect()` | 1131×40 (matches config) | +| `env(titlebar-area-width)` (via custom-property indirection) | 1131px (matches) | +| `matchMedia('(display-mode: window-controls-overlay)').matches` | **false** ✗ | + +Three of four WCO entry points agree; only the documented `@media` +detection point is broken. + +Minimal repro after `did-finish-load`: + +```js +const wco = navigator.windowControlsOverlay; +const r = wco.getTitlebarAreaRect(); +const s = document.createElement('style'); +s.textContent = ':root { --w: env(titlebar-area-width) }'; +document.head.appendChild(s); +({ + visible: wco.visible, // true + rect: { width: r.width, height: r.height }, // populated + cssEnvWidth: getComputedStyle(document.documentElement) + .getPropertyValue('--w'), // populated + mediaQueryMatches: + matchMedia('(display-mode: window-controls-overlay)').matches, // false +}); +``` + +### Bug B: WCO state doesn't propagate to BrowserView webContents + +Same parent BrowserWindow, probing the BrowserView instead: + +| signal | value | +|---|---| +| `navigator.windowControlsOverlay.visible` | false | +| `getTitlebarAreaRect()` | 0×0 | +| `env(titlebar-area-width)` | empty | +| `matchMedia('(display-mode: window-controls-overlay)').matches` | false | + +The BrowserView sees nothing. May be intentional isolation (each +webContents independent) — could be working-as-designed and not +worth filing. Means any WCO-aware page hosted in a BrowserView +never sees WCO regardless of parent config. + +### Bug C: implicit drag region for `frame:false` Linux windows + +The root cause of the hidden-mode click problem. Investigation +ruled out `.draggable`, `titleBarOverlay`, and `titleBarStyle` as +the source — what remains is some hardcoded behavior in +Chromium's ozone backend that creates a non-overridable drag +region for the top of frameless windows. **Confirmed present on +both X11 and Wayland (2026-04-29):** running +`CLAUDE_USE_WAYLAND=1 CLAUDE_TITLEBAR_STYLE=hidden` produces the +same unclickable topbar as X11, ruling out a Wayland-only +shipping path. Characterizing this as a filable bug would +require source-level inspection of `ui/ozone/platform/{x11,wayland}/`. +The combined impact of A + B + C is that WCO is effectively +unusable on Linux today. + +## Future directions + +- **Wayland-only shipping (ruled out 2026-04-29).** Wayland WCO + landed in Electron 38.2 / 41 with apparently fuller support + ([Electron Wayland tech talk](https://www.electronjs.org/blog/tech-talk-wayland)), + raising the possibility that hidden mode might work on native + Wayland even though X11 is broken. Tested with + `CLAUDE_USE_WAYLAND=1 CLAUDE_TITLEBAR_STYLE=hidden`: topbar + clicks are still unresponsive. The implicit drag region (Bug C) + exists on both backends. Hybrid is the answer everywhere. +- **Bundle rewriting via `session.protocol.handle()`** — was the + proposed last-resort path before hybrid worked. Would intercept + claude.ai's React bundle and regex-replace `class="draggable + absolute top-0` to remove the `draggable` token before Chromium + parses it. Now obsolete given hybrid; documented for posterity. + +## Files + +- `scripts/wco-shim.js` — shim source +- `scripts/patches/wco-shim.sh` — inlines shim into mainView.js +- `scripts/frame-fix-wrapper.js` — main-process BrowserWindow + patching, mode resolution, diagnostic probes +- `scripts/launcher-common.sh` — Chromium feature flags per mode +- `scripts/doctor.sh` — `--doctor` reports the resolved titlebar + style (`PASS` for `hybrid`/`native`, `WARN` for `hidden` with a + pointer to the working modes, `WARN` + valid-value hint for + unrecognized values) +- `tests/launcher-common.bats` — covers `_resolve_titlebar_style` + (default + each mode + case-insensitivity + invalid fallback), + `build_electron_args` flag selection per mode, and + `setup_electron_env` `ELECTRON_USE_SYSTEM_TITLE_BAR` wiring per + mode. Shim runtime behavior (className intercept, UA spoof) is + not unit-tested — verified empirically via the click test in + this doc +- `docs/CONFIGURATION.md` — user-facing env-var docs + +## Diagnostic recipes + +### Bundle probe — re-discover gates if claude.ai changes the bundle + +```js +(async () => { + const reactBundle = [...document.scripts] + .map(s => s.src).filter(Boolean) + .find(s => /index-[A-Za-z0-9]+\.js/.test(s)); + const text = await (await fetch(reactBundle)).text(); + const ctx = (term, len = 200) => { + const i = text.indexOf(term); + return i < 0 ? null : text.slice(Math.max(0, i - len), i + term.length + len); + }; + return { + bundleSize: text.length, + ctx_topbar_windows: ctx('topbar-windows'), + ctx_isWindows_regex: ctx('win32|win64'), + ctx_desktopTopBar: ctx('desktopTopBar'), + ctx_windowControlsOverlay: ctx('windowControlsOverlay'), + }; +})(); +``` + +Inspect the regex pattern, gate variable names, and any new +condition strings. The shim probably needs an update if any of +those move. + +### Drag-region search + +Should return `[]` in hybrid mode (className intercept strips the +class). If it returns elements, the intercept missed a vector +(e.g. `dangerouslySetInnerHTML`, parser-set classes) — investigate +where the class came from. + +```js +[...document.querySelectorAll('*')].filter(el => + getComputedStyle(el).webkitAppRegion === 'drag' +).map(el => ({ + tag: el.tagName, + cls: (el.className || '').toString().slice(0, 100), + rect: el.getBoundingClientRect().toJSON(), +})); +``` + +### Click-state diagnostic + +Confirms a click problem is OS-level rather than CSS or JS: + +```js +const hamburger = document.querySelector('[data-testid="topbar-windows-menu"]'); +const topbar = document.querySelector('div.absolute.top-0.inset-x-0'); +const ts = getComputedStyle(topbar); +const hs = getComputedStyle(hamburger); +let clickFired = false; +hamburger.addEventListener('click', () => { clickFired = true; }, { once: true }); +hamburger.click(); +const r = hamburger.getBoundingClientRect(); +const elemAtCenter = document.elementFromPoint(r.x + r.width/2, r.y + r.height/2); +({ + topbarAppRegion: ts.webkitAppRegion, + hamburgerAppRegion: hs.webkitAppRegion, + topbarPointerEvents: ts.pointerEvents, + hamburgerPointerEvents: hs.pointerEvents, + programmaticClickFired: clickFired, + hitIsHamburgerOrDescendant: hamburger.contains(elemAtCenter), +}); +``` + +When this looks correct (`no-drag`, `auto`, `true`, `true`) but +real mouse clicks don't fire, the click is being intercepted at +the WM level — same failure mode as the hidden-mode investigation. + +### Pitfalls (don't repeat) + +- DOM probes that search `[class*="topbar" i]` or + `header[role="banner"]` won't find the topbar. It identifies + via `data-testid="topbar-windows-menu"` and uses + `class="draggable absolute top-0 ..."`. Search by + `data-testid` first. +- A relative `require('./wco-shim.js')` from the sandboxed + preload **aborts the entire preload** because sandboxed + preloads can only require an allowlist (`electron`, + `ipcRenderer`, `contextBridge`, `webFrame`, ...). The shim + must be inlined into mainView.js, not pulled in via require. +- `webFrame.executeJavaScript` may fire before + `document.documentElement` exists. Probe code that calls + `getComputedStyle(document.documentElement)` immediately + throws "parameter 1 is not of type 'Element'". Defer to + `DOMContentLoaded` if needed. diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 61e45f3..b1aa777 100644 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -406,6 +406,29 @@ run_doctor() { _info 'Menu bar mode: auto (default, Alt toggles visibility)' fi + # -- Titlebar style -- + local titlebar_style="${CLAUDE_TITLEBAR_STYLE:-}" + if [[ -n $titlebar_style ]]; then + local resolved_style="${titlebar_style,,}" + case "$resolved_style" in + hybrid|native) + _pass "Titlebar style: $resolved_style" \ + "(CLAUDE_TITLEBAR_STYLE=$titlebar_style)" + ;; + hidden) + _warn "Titlebar style: hidden — topbar clicks unresponsive on Linux (both X11 and Wayland)" + _info 'Use hybrid (default) or native for clickable buttons' + ;; + *) + _warn "Unknown CLAUDE_TITLEBAR_STYLE: '$titlebar_style'" + _info 'Will fall back to hybrid' + _info 'Valid values: hybrid, native, hidden' + ;; + esac + else + _info 'Titlebar style: hybrid (default, native frame + in-app topbar)' + fi + # -- Electron binary -- # Version is read from the file next to the binary rather than # launching Electron, which can hang (see #371). diff --git a/scripts/frame-fix-wrapper.js b/scripts/frame-fix-wrapper.js index 4cd7107..d8d9f50 100644 --- a/scripts/frame-fix-wrapper.js +++ b/scripts/frame-fix-wrapper.js @@ -38,6 +38,37 @@ if (resolvedMode !== rawMenuBarMode) { } console.log(`[Frame Fix] Menu bar mode: ${MENU_BAR_MODE}`); +// Titlebar mode, controlled by CLAUDE_TITLEBAR_STYLE env var: +// 'hybrid' (default) - native OS frame (frame:true) + wco-shim active. +// Stacked layout: OS titlebar on top draws +// min/max/close, claude.ai's in-app topbar +// renders below it via the shim's UA + +// matchMedia overrides. Topbar buttons clickable. +// Recommended Linux experience. +// 'native' - system-decorated window (frame:true), no shim. +// DE draws min/max/close; claude.ai's in-app +// topbar is hidden by its UA gate. Use if the +// in-app topbar conflicts with your DE. +// 'hidden' - frameless window with Window Controls Overlay +// configured (matches Windows / macOS upstream). +// BROKEN ON LINUX X11: topbar buttons not +// clickable because Chromium creates an implicit +// WM-level drag region for frameless windows +// that intercepts mouse events. Kept for +// Wayland comparison and future investigation; +// see docs/learnings/linux-topbar-shim.md. +// Applies to the main window only. Popups (Quick Entry, About) are +// always frameless regardless of this setting. +const VALID_TITLEBAR_STYLES = ['hybrid', 'native', 'hidden']; +const rawTitlebarStyle = (process.env.CLAUDE_TITLEBAR_STYLE || 'hybrid').toLowerCase(); +const TITLEBAR_STYLE = VALID_TITLEBAR_STYLES.includes(rawTitlebarStyle) + ? rawTitlebarStyle + : 'hybrid'; +if (rawTitlebarStyle !== TITLEBAR_STYLE) { + console.warn(`[Frame Fix] Unknown CLAUDE_TITLEBAR_STYLE value '${process.env.CLAUDE_TITLEBAR_STYLE}', falling back to 'hybrid'. Valid: ${VALID_TITLEBAR_STYLES.join(', ')}`); +} +console.log(`[Frame Fix] Titlebar style: ${TITLEBAR_STYLE}`); + // Keep the app alive when the main window is closed (hide to tray), // so in-app schedulers / MCP servers / the tray icon survive a // stray click on X. Explicit quit paths (Ctrl+Q via the focused @@ -118,17 +149,67 @@ Module.prototype.require = function(id) { delete options.titleBarStyle; delete options.titleBarOverlay; console.log('[Frame Fix] Popup detected, keeping frameless'); - } else { - // Main window: force native frame + } else if (TITLEBAR_STYLE === 'native') { + // Main window, native mode: force system frame. options.frame = true; // Menu bar behavior depends on CLAUDE_MENU_BAR mode: // 'auto' (default): hidden, Alt toggles // 'visible'/'hidden': no Alt toggle options.autoHideMenuBar = (MENU_BAR_MODE === 'auto'); - // Remove custom titlebar options delete options.titleBarStyle; delete options.titleBarOverlay; console.log(`[Frame Fix] Modified frame from ${originalFrame} to true`); + } else if (TITLEBAR_STYLE === 'hybrid') { + // Main window, hybrid mode: native OS frame + + // claude.ai's in-app topbar via wco-shim. + // + // Why this shape: Linux X11 + frameless windows + // hits a Chromium-level implicit drag region at + // the top of the window that intercepts mouse + // events at the WM level. We've ruled out + // titleBarOverlay and titleBarStyle as the source + // (disabling either still produced unclickable + // topbar buttons). The drag region appears to be + // a Linux-X11 default for frame:false windows. With + // frame:true the OS handles dragging via the native + // titlebar and Chromium pushes no drag-region map, + // so the in-app topbar's buttons are clickable. + // + // Visual trade-off vs Windows: stacked layout — OS + // titlebar on top, in-app topbar below it. The + // buttons we care about (hamburger / sidebar / + // search / nav / Cowork ghost) all live in the + // in-app topbar via the shim's UA + matchMedia + // overrides. The shim's className intercept stays + // as belt-and-suspenders against the .draggable + // CSS rule still applying within the framed + // window's content area. + options.frame = true; + options.autoHideMenuBar = (MENU_BAR_MODE === 'auto'); + delete options.titleBarStyle; + delete options.titleBarOverlay; + console.log('[Frame Fix] Hybrid mode: native frame + in-app topbar shim'); + } else { + // Main window, hidden mode: frameless + Window Controls + // Overlay configured (matches Windows / macOS upstream). + // BROKEN ON LINUX X11 — topbar buttons not clickable + // because Chromium creates an implicit drag region for + // frame:false windows that intercepts mouse events at + // the WM level. Investigation chain in + // docs/learnings/linux-topbar-shim.md ruled out + // titleBarOverlay height and titleBarStyle:'hidden' as + // the source. The default is now 'hybrid'; this branch + // is kept for Wayland comparison and future probes. + options.frame = false; + options.titleBarStyle = 'hidden'; + options.titleBarOverlay = { + color: '#1a1a1a', + symbolColor: '#ffffff', + height: 40, + }; + console.log('[Frame Fix] Hidden mode (frame=false, ' + + 'titleBarStyle=hidden, titleBarOverlay=object) — ' + + 'topbar clicks broken on X11'); } } super(options); @@ -144,6 +225,56 @@ Module.prototype.require = function(id) { this.webContents.insertCSS(LINUX_CSS).catch(() => {}); }); + // WCO diagnostic: probe Chromium's native Window Controls + // Overlay state on the main window webContents. Upstream + // electron/electron#41769 (June 2024) implements WCO on + // Linux X11; runtime probes (2026-04-29) show the API + // surface returns visible:true here while display-mode + // and env() vars don't match — partial implementation. + // env() extraction goes through a custom-property + // indirection because getPropertyValue('env(...)') is + // invalid; env() is only meaningful inside CSS values. + // Logs to stdout so the result lands in launcher.log. + // Only meaningful for non-popup main windows in hidden + // mode (the only path that requests WCO). + if (!popup && TITLEBAR_STYLE !== 'native') { + this.webContents.on('did-finish-load', () => { + this.webContents.executeJavaScript(` + (() => { + const wco = navigator.windowControlsOverlay; + let rect = null; + try { + const r = wco && wco.getTitlebarAreaRect && wco.getTitlebarAreaRect(); + if (r) rect = { x: r.x, y: r.y, width: r.width, height: r.height }; + } catch (e) { /* ignore */ } + const s = document.createElement('style'); + s.textContent = ':root{--probe-tbx:env(titlebar-area-x);--probe-tby:env(titlebar-area-y);--probe-tbw:env(titlebar-area-width);--probe-tbh:env(titlebar-area-height);}'; + document.head.appendChild(s); + const cs = getComputedStyle(document.documentElement); + const result = { + visible: !!(wco && wco.visible), + rect, + media_wco: matchMedia('(display-mode: window-controls-overlay)').matches, + media_standalone: matchMedia('(display-mode: standalone)').matches, + media_browser: matchMedia('(display-mode: browser)').matches, + env_x: cs.getPropertyValue('--probe-tbx').trim(), + env_y: cs.getPropertyValue('--probe-tby').trim(), + env_w: cs.getPropertyValue('--probe-tbw').trim(), + env_h: cs.getPropertyValue('--probe-tbh').trim(), + userAgent: navigator.userAgent, + location: location.href, + }; + s.remove(); + return JSON.stringify(result); + })() + `).then((json) => { + console.log('[WCO Diagnostic] main window webContents:', json); + }).catch((err) => { + console.warn('[WCO Diagnostic] main window probe failed:', err.message); + }); + }); + } + // Quit on Ctrl+Q, but only when Claude has keyboard focus. // Replaces a prior globalShortcut registration that grabbed // the key system-wide and, on non-QWERTY layouts (e.g. @@ -373,6 +504,47 @@ Module.prototype.require = function(id) { }); } + // WCO diagnostic console mirror + global Ctrl+Q. + // + // The console mirror forwards [WCO Diagnostic] / [WCO Shim] / + // [Drag Shim] messages from any webContents (including the + // BrowserView that hosts claude.ai) back to stdout so probes + // run from preload land in launcher.log alongside the main + // window probe. Filtered prefixes avoid mirroring claude.ai's + // noisy console. + // + // The Ctrl+Q handler is replicated here from the per-window + // setup above because before-input-event only fires on the + // webContents that has keyboard focus. The BrowserView has + // its own webContents that takes focus over the main window, + // so a handler on the main window alone never sees keypresses + // when the BrowserView is focused (the typical case). Adding + // it to every webContents covers main + BrowserView + popups. + // Linux-only because the per-window handler above is + // Linux-only (and macOS has Cmd+Q natively). + if (process.platform === 'linux') { + result.app.on('web-contents-created', (_evt, wc) => { + if (TITLEBAR_STYLE !== 'native') { + wc.on('console-message', (event) => { + const msg = (event && event.message) || ''; + if (msg.startsWith('[WCO Diagnostic]') + || msg.startsWith('[WCO Shim]') + || msg.startsWith('[Drag Shim]')) { + console.log('[BrowserView]', msg); + } + }); + } + wc.on('before-input-event', (event, input) => { + if (input.type !== 'keyDown') return; + if (!input.control) return; + if (input.alt || input.shift || input.meta) return; + if (input.key !== 'q' && input.key !== 'Q') return; + event.preventDefault(); + result.app.quit(); + }); + }); + } + // Route app.{get,set}LoginItemSettings through XDG Autostart on Linux. // Electron's openAtLogin is a no-op on Linux (electron/electron#15198), // which both prevents the app's "Run on startup" toggle from diff --git a/scripts/launcher-common.sh b/scripts/launcher-common.sh index bfb4efe..05bb183 100644 --- a/scripts/launcher-common.sh +++ b/scripts/launcher-common.sh @@ -51,6 +51,22 @@ check_display() { [[ -n $DISPLAY || -n $WAYLAND_DISPLAY ]] } +# Resolve CLAUDE_TITLEBAR_STYLE to one of {hybrid,native,hidden}, +# defaulting to 'hybrid' when unset or invalid. Echoed (not exported) +# so callers can branch on it without polluting the environment. +# 'hybrid' is the recommended Linux experience: native OS frame + +# in-app topbar via the wco-shim. 'hidden' is upstream's frameless +# WCO config; broken on Linux X11 (clicks unresponsive) but kept for +# Wayland/diagnostic comparison. +_resolve_titlebar_style() { + local raw="${CLAUDE_TITLEBAR_STYLE:-hybrid}" + raw="${raw,,}" + case "$raw" in + hybrid|hidden|native) echo "$raw" ;; + *) echo 'hybrid' ;; + esac +} + # Build Electron arguments array based on display backend # Requires: is_wayland, use_x11_on_wayland to be set # (call detect_display_backend first) @@ -64,8 +80,21 @@ build_electron_args() { # AppImage always needs --no-sandbox due to FUSE constraints [[ $package_type == 'appimage' ]] && electron_args+=('--no-sandbox') - # Disable CustomTitlebar for better Linux integration - electron_args+=('--disable-features=CustomTitlebar') + # CLAUDE_TITLEBAR_STYLE selects between: + # hybrid (default) / native: --disable-features=CustomTitlebar + # so Chromium's drawn CSD titlebar doesn't compete with + # the DE-drawn one. Both modes use frame:true. + # hidden: --enable-features=WindowControlsOverlay because WCO + # is off by default on Linux Chromium (Win/macOS have + # it on by default). Without this flag, titleBarOverlay + # is silently ignored at the page level. + local _tb + _tb=$(_resolve_titlebar_style) + if [[ $_tb == 'hidden' ]]; then + electron_args+=('--enable-features=WindowControlsOverlay') + else + electron_args+=('--disable-features=CustomTitlebar') + fi # Remote XRDP sessions lack GPU acceleration and render a blank # window when GPU compositing is enabled. Detect via XRDP_SESSION @@ -247,7 +276,12 @@ setup_electron_env() { # copied and app resources co-located in resources/, so resourcesPath # naturally points to the right place on all package types. export ELECTRON_FORCE_IS_PACKAGED=true - export ELECTRON_USE_SYSTEM_TITLE_BAR=1 + # ELECTRON_USE_SYSTEM_TITLE_BAR=1 forces a system titlebar at the + # Electron level. Set in 'native' and 'hybrid' modes (both use + # frame:true); skipped in 'hidden' mode (frame:false + WCO config). + if [[ $(_resolve_titlebar_style) != 'hidden' ]]; then + export ELECTRON_USE_SYSTEM_TITLE_BAR=1 + fi } #=============================================================================== diff --git a/scripts/patches/app-asar.sh b/scripts/patches/app-asar.sh index 8f5b15f..2982738 100644 --- a/scripts/patches/app-asar.sh +++ b/scripts/patches/app-asar.sh @@ -62,9 +62,6 @@ console.log('Updated package.json: main entry and node-pty dependency'); cp "$claude_extract_dir/lib/net45/resources/Tray"* app.asar.contents/resources/ 2>/dev/null || \ echo 'Warning: No tray icon files found for asar inclusion' - # Patch title bar detection - patch_titlebar_detection - # Extract electron module variable name for tray patches extract_electron_variable @@ -93,6 +90,13 @@ console.log('Updated package.json: main entry and node-pty dependency'); # Patch Cowork mode for Linux (TypeScript VM client + Unix socket) patch_cowork_linux + # Inject WCO shim into the BrowserView preload so claude.ai's + # desktop topbar renders on Linux. The shim spoofs the bundle's + # isWindows() UA check (load-bearing) plus matchMedia and + # windowControlsOverlay (defensive). See + # docs/learnings/linux-topbar-shim.md. + patch_wco_shim + # Copy cowork VM service daemon for Linux Cowork mode echo 'Installing cowork VM service daemon...' cp "$source_dir/scripts/cowork-vm-service.js" \ diff --git a/scripts/patches/titlebar.sh b/scripts/patches/titlebar.sh deleted file mode 100644 index 7fe9f8d..0000000 --- a/scripts/patches/titlebar.sh +++ /dev/null @@ -1,44 +0,0 @@ -#=============================================================================== -# Title bar detection patch: strip the negation so Linux renders the frame. -# -# Sourced by: build.sh -# Sourced globals: (none) -# Modifies globals: (none) -#=============================================================================== - -patch_titlebar_detection() { - echo '##############################################################' - echo "Removing '!' from 'if (\"!\"isWindows && isMainWindow) return null;'" - echo 'detection flag to enable title bar' - - local search_base='app.asar.contents/.vite/renderer/main_window/assets' - local target_pattern='MainWindowPage-*.js' - - echo "Searching for '$target_pattern' within '$search_base'..." - local target_files - mapfile -t target_files < <(find "$search_base" -type f -name "$target_pattern") - local num_files=${#target_files[@]} - - case $num_files in - 0) - echo "Error: No file matching '$target_pattern' found within '$search_base'." >&2 - exit 1 - ;; - 1) - local target_file="${target_files[0]}" - echo "Found target file: $target_file" - sed -i -E 's/if\(!([a-zA-Z]+)[[:space:]]*&&[[:space:]]*([a-zA-Z]+)\)/if(\1 \&\& \2)/g' "$target_file" - - if grep -q -E 'if\(![a-zA-Z]+[[:space:]]*&&[[:space:]]*[a-zA-Z]+\)' "$target_file"; then - echo "Error: Failed to replace patterns in $target_file." >&2 - exit 1 - fi - echo "Successfully replaced patterns in $target_file" - ;; - *) - echo "Error: Expected exactly one file matching '$target_pattern' within '$search_base', but found $num_files." >&2 - exit 1 - ;; - esac - echo '##############################################################' -} diff --git a/scripts/patches/wco-shim.sh b/scripts/patches/wco-shim.sh new file mode 100644 index 0000000..af41e49 --- /dev/null +++ b/scripts/patches/wco-shim.sh @@ -0,0 +1,40 @@ +#=============================================================================== +# Inject Window Controls Overlay shim into the BrowserView preload. +# +# Sourced by: build.sh +# Sourced globals: source_dir +# Modifies globals: (none) +#=============================================================================== + +patch_wco_shim() { + echo '##############################################################' + echo 'Inlining WCO shim into mainView.js (Linux topbar workaround)' + + local main_view='app.asar.contents/.vite/build/mainView.js' + + if [[ ! -f $main_view ]]; then + echo "Error: mainView.js not found at $main_view." >&2 + exit 1 + fi + + if grep -q '__claude_wco_shim' "$main_view"; then + echo 'mainView.js already has WCO shim, skipping inject' + echo '##############################################################' + return 0 + fi + + # Sandboxed preloads can only require a fixed allowlist of modules + # (electron, ipcRenderer, contextBridge, webFrame…). A relative + # require to a sibling file fails with "module not found" and + # aborts the entire preload — taking desktopBootFeatures and the + # rest of mainView's exposeInMainWorld surface down with it. + # So we inline the shim source directly at the top of mainView.js + # instead of pulling it in via require. + local shim_content + shim_content=$(cat "$source_dir/scripts/wco-shim.js") + local original + original=$(cat "$main_view") + printf '%s\n%s' "$shim_content" "$original" > "$main_view" + echo 'Inlined WCO shim at top of mainView.js' + echo '##############################################################' +} diff --git a/scripts/wco-shim.js b/scripts/wco-shim.js new file mode 100644 index 0000000..a4984a2 --- /dev/null +++ b/scripts/wco-shim.js @@ -0,0 +1,267 @@ +// __claude_wco_shim — marker for patch_wco_shim idempotency check +// +// Window Controls Overlay shim for Linux. Convinces claude.ai's +// React bundle that it's running in a Windows desktop window, so +// the in-app topbar (hamburger / sidebar / search / nav / Cowork +// ghost) renders. claude.ai's bundle gates topbar rendering on a +// `/(win32|win64|windows|wince)/i` test against navigator.userAgent; +// our overrides flip that to true page-side without touching the +// HTTP request UA, plus shim navigator.windowControlsOverlay and +// matchMedia('(display-mode: window-controls-overlay)') as +// defensive forward-compat in case the bundle ever tightens its +// check beyond the UA regex. +// +// Also installs a className intercept that strips 'draggable' from +// any DOM class assignment. This is belt-and-suspenders against +// claude.ai's CSS rule .draggable { app-region: drag } applying +// to in-content elements; in hybrid mode (frame:true) the OS +// handles window dragging via the native titlebar, so any +// remaining app-region:drag inside the BrowserView would only +// produce unexpected click-eaten regions. +// +// Investigation history: docs/learnings/linux-topbar-shim.md. +// CLAUDE_WCO_NATIVE=1 skips all overrides for diagnostic A/B +// testing against unmodified Chromium behavior. +// +// Active only when CLAUDE_TITLEBAR_STYLE != 'native'. + +(function() { + if (process.platform !== 'linux') return; + var style = (process.env.CLAUDE_TITLEBAR_STYLE || 'hybrid').toLowerCase(); + if (style === 'native') return; + + // Diagnostic mode: skip all overrides so the BrowserView sees + // Chromium's native behavior. Native-state logging still runs + // so the user can inspect what Chromium actually reports. + var nativeMode = process.env.CLAUDE_WCO_NATIVE === '1'; + + try { + var webFrame = require('electron').webFrame; + if (!webFrame) return; + + // Inline the shim as a string so it runs in the page's main + // world. CONTROLS_WIDTH leaves room on the right for window + // controls in the shimmed wco_rect; TITLEBAR_HEIGHT matches + // the upstream Windows topbar height. nativeMode flag is + // interpolated so the page script can honor the diagnostic + // switch. + var script = [ + '(function(){', + 'if(window.__claudeWcoShimInstalled)return;', + 'window.__claudeWcoShimInstalled=true;', + 'var CONTROLS_WIDTH=140;', + 'var TITLEBAR_HEIGHT=40;', + 'var __nativeMode=' + (nativeMode ? 'true' : 'false') + ';', + + // Diagnostic: capture and log Chromium's NATIVE WCO + // state. Phase 1 captures non-DOM values synchronously + // (before any overrides apply). Phase 2 injects a + // stylesheet to read env(titlebar-area-*) once the DOM + // is ready, deferred via DOMContentLoaded if necessary + // — webFrame.executeJavaScript can fire before the html + // element exists, so an early getComputedStyle call + // throws "parameter 1 is not of type 'Element'". + // env() values are CSS-engine state that the shim's + // overrides don't touch, so reading them late still + // reflects native behavior. Surfaces in the BrowserView's + // DevTools console and in the launcher log via the + // console-message mirror in frame-fix-wrapper.js. + 'var __nativeProbe={};', + 'try{', + 'var __wco=navigator.windowControlsOverlay;', + '__nativeProbe.visible=!!(__wco&&__wco.visible);', + 'try{', + 'var __r=__wco&&__wco.getTitlebarAreaRect&&__wco.getTitlebarAreaRect();', + '__nativeProbe.rect=__r?{x:__r.x,y:__r.y,width:__r.width,height:__r.height}:null;', + '}catch(e){__nativeProbe.rect=null;}', + '__nativeProbe.media_wco=matchMedia("(display-mode: window-controls-overlay)").matches;', + '__nativeProbe.media_standalone=matchMedia("(display-mode: standalone)").matches;', + '__nativeProbe.media_browser=matchMedia("(display-mode: browser)").matches;', + '__nativeProbe.userAgent=navigator.userAgent;', + '__nativeProbe.nativeMode=__nativeMode;', + '}catch(e){__nativeProbe.captureError=e.message;}', + + // Phase 2: inject a stylesheet using CSS env() to extract + // titlebar-area values, then read them via custom + // properties. getPropertyValue('env(...)') is invalid; + // env() is only meaningful inside CSS values, so we + // indirect through --probe-* custom properties. + 'var __finishProbe=function(){', + 'try{', + 'var __s=document.createElement("style");', + '__s.textContent=":root{--probe-tbx:env(titlebar-area-x);--probe-tby:env(titlebar-area-y);--probe-tbw:env(titlebar-area-width);--probe-tbh:env(titlebar-area-height);}";', + 'document.head.appendChild(__s);', + 'var __cs=getComputedStyle(document.documentElement);', + '__nativeProbe.env_x=__cs.getPropertyValue("--probe-tbx").trim();', + '__nativeProbe.env_y=__cs.getPropertyValue("--probe-tby").trim();', + '__nativeProbe.env_w=__cs.getPropertyValue("--probe-tbw").trim();', + '__nativeProbe.env_h=__cs.getPropertyValue("--probe-tbh").trim();', + '__s.remove();', + '}catch(e){__nativeProbe.envProbeError=e.message;}', + 'window.__claudeWcoNativeState=__nativeProbe;', + 'console.log("[WCO Diagnostic] BrowserView native state:",JSON.stringify(__nativeProbe));', + '};', + 'if(document.documentElement&&document.head){', + '__finishProbe();', + '}else{', + 'document.addEventListener("DOMContentLoaded",__finishProbe,{once:true});', + '}', + + // In native diagnostic mode, skip all overrides so + // the user can see how the page behaves with pure + // Chromium (and to test whether claude.ai's UA gate + // passes naturally — it won't, but it lets us + // confirm that as a baseline). Phase 2 was registered + // above the early return so it still fires. + 'if(__nativeMode){', + 'console.log("[WCO Shim] CLAUDE_WCO_NATIVE=1, skipping all overrides");', + 'return;', + '}', + + // 1. Shim navigator.windowControlsOverlay with proper + // event-target semantics so React listeners fire. + 'var listeners={};', + 'var overlay={', + 'get visible(){return true},', + 'getTitlebarAreaRect:function(){', + 'return new DOMRect(0,0,Math.max(0,window.innerWidth-CONTROLS_WIDTH),TITLEBAR_HEIGHT);', + '},', + 'addEventListener:function(t,fn){', + '(listeners[t]=listeners[t]||[]).push(fn);', + '},', + 'removeEventListener:function(t,fn){', + 'var arr=listeners[t]||[];', + 'var i=arr.indexOf(fn);', + 'if(i>=0)arr.splice(i,1);', + '},', + 'dispatchEvent:function(e){', + '(listeners[e.type]||[]).slice().forEach(function(fn){', + 'try{fn.call(overlay,e)}catch(err){console.warn("[WCO Shim]",err)}', + '});', + 'if(typeof overlay["on"+e.type]==="function"){', + 'try{overlay["on"+e.type](e)}catch(err){}', + '}', + 'return true;', + '},', + 'ongeometrychange:null', + '};', + 'try{', + 'Object.defineProperty(navigator,"windowControlsOverlay",{', + 'value:overlay,configurable:true', + '});', + '}catch(e){console.warn("[WCO Shim] navigator override failed:",e.message)}', + + // 2. Shim matchMedia for the WCO display-mode query. + // The CSS @media engine itself can't be fooled, but + // JS code that branches on matchMedia().matches can. + 'var origMM=window.matchMedia.bind(window);', + 'window.matchMedia=function(q){', + 'if(typeof q==="string"&&q.indexOf("window-controls-overlay")!==-1){', + 'return{', + 'matches:true,', + 'media:q,', + 'onchange:null,', + 'addEventListener:function(){},', + 'removeEventListener:function(){},', + 'addListener:function(){},', + 'removeListener:function(){},', + 'dispatchEvent:function(){return true}', + '};', + '}', + 'return origMM(q);', + '};', + + // 3. Shim navigator.userAgent so claude.ais isWindows() + // check passes. The bundle uses + // /(win32|win64|windows|wince)/i.test(navigator.userAgent) + // to decide whether to render the desktop topbar + // component (data-testid="topbar-windows-menu"). On + // Linux the UA contains "X11; Linux x86_64" and the + // regex fails, so the topbar is never rendered. + // Done page-side only: HTTP request UA is unchanged, + // so analytics and anti-bot fingerprints stay honest. + 'try{', + 'var origUA=navigator.userAgent;', + 'if(!/(win32|win64|windows|wince)/i.test(origUA)){', + 'Object.defineProperty(navigator,"userAgent",{', + 'get:function(){return origUA+" Windows"},', + 'configurable:true', + '});', + '}', + '}catch(e){console.warn("[WCO Shim] userAgent override failed:",e.message)}', + + // 4. Strip 'draggable' class from any DOM class + // assignment. claude.ai's React renders the topbar + // parent with class="draggable absolute top-0 + // inset-x-0 ..." which triggers a CSS rule + // .draggable { -webkit-app-region: drag }. In hybrid + // mode (frame:true) the OS handles window dragging, + // so any in-content app-region:drag region would + // just create surprise click-eaten zones inside the + // page. Stripping the class at the JS-DOM API level + // means the rule never matches, regardless of how + // Chromium decides to consume it. + // Three assignment vectors covered: + // el.className = '...' + // el.setAttribute('class', '...') + // el.classList.add('draggable', ...) + // Round-trip identity is broken for class strings + // containing 'draggable' — el.className=val then + // reading el.className will not return val. No + // code path in claude.ai's bundle appears to + // depend on this; if a regression appears, scope + // the strip to the specific class combination + // (e.g. /draggable\s+absolute\s+top-0/) instead + // of the bare word. + 'try{', + 'var __strip=function(v){', + 'if(typeof v!=="string")return v;', + 'return v.replace(/\\bdraggable\\b/g,"").replace(/\\s+/g," ").trim();', + '};', + 'var __cnDesc=Object.getOwnPropertyDescriptor(Element.prototype,"className");', + 'if(__cnDesc&&__cnDesc.set){', + 'Object.defineProperty(Element.prototype,"className",{', + 'configurable:true,', + 'enumerable:__cnDesc.enumerable,', + 'get:function(){return __cnDesc.get.call(this)},', + 'set:function(v){__cnDesc.set.call(this,__strip(v))}', + '});', + '}', + 'var __origSetAttr=Element.prototype.setAttribute;', + 'Element.prototype.setAttribute=function(n,v){', + 'if((n==="class"||n==="className")&&typeof v==="string"){', + 'v=__strip(v);', + '}', + 'return __origSetAttr.call(this,n,v);', + '};', + 'var __origClAdd=DOMTokenList.prototype.add;', + 'DOMTokenList.prototype.add=function(){', + 'var args=[];', + 'for(var i=0;i