diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index ed4befc..fc4fe10 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ src-tauri/gen/schemas # Excalidraw fonts (copied from node_modules at install time) static/excalidraw-assets/fonts/ + +.direnv/ diff --git a/CLAUDE.md b/CLAUDE.md index fe7228d..dbe3fc6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -75,8 +75,9 @@ A `flake.nix` is provided. Enter the dev shell before running any build commands nix develop # sets up cargo, pnpm, webkitgtk, GStreamer, pkg-config, etc. ``` -The shell hook also exports `GDK_BACKEND=x11` and `WEBKIT_DISABLE_DMABUF_RENDERER=1` -so the dev server renders correctly under Wayland. +The shell hook exports `XDG_DATA_DIRS` so GTK can find gsettings schemas and +report the correct display scale under Wayland (without this, the WebView +allocates at the wrong size). To install the binary into your Nix profile (wraps it with the required env vars): diff --git a/flake.nix b/flake.nix index 88e74b7..cf6756d 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,14 @@ "${pkgs.gst_all_1.gst-plugins-bad}/lib/gstreamer-1.0" ] ); + + # Path suitable for XDG_DATA_DIRS so GTK can find gsettings schemas + # (needed for Wayland display-scale reporting). Mirrors what + # nixpkgs' gsettingsSchemaSetupHook sets up automatically as + # GSETTINGS_SCHEMAS_PATH from buildInputs in the dev shell. + gsettingsSchemasPath = pkgs.lib.optionalString isLinux ( + "${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}" + ); in { # Formatter (nixfmt) @@ -49,11 +57,14 @@ makeWrapper ${./src-tauri/target/release/annot} $out/bin/annot '' else + # XDG_DATA_DIRS prefixed (not set) so any existing + # desktop-environment entries are preserved. With this in + # place, the installed binary runs on Wayland correctly; + # no GDK_BACKEND override needed. '' mkdir -p $out/bin makeWrapper ${./src-tauri/target/release/annot} $out/bin/annot \ - --set GDK_BACKEND x11 \ - --set WEBKIT_DISABLE_DMABUF_RENDERER 1 \ + --prefix XDG_DATA_DIRS : "${gsettingsSchemasPath}" \ --set GST_PLUGIN_SYSTEM_PATH "${gstPluginPath}" \ --set GIO_MODULE_DIR "${pkgs.glib-networking}/lib/gio/modules" '' @@ -113,9 +124,11 @@ # GStreamer plugin discovery export GST_PLUGIN_SYSTEM_PATH="${gstPluginPath}" - # Force X11 (WebKit2GTK Wayland/DMABuf is broken on NixOS) - export GDK_BACKEND=x11 - export WEBKIT_DISABLE_DMABUF_RENDERER=1 + # Wayland needs gsettings schemas discoverable via XDG_DATA_DIRS + # so GTK can report the correct display scale; otherwise the + # WebView surface allocates at the wrong size. + # (wiki.nixos.org/wiki/Tauri) + export XDG_DATA_DIRS="$GSETTINGS_SCHEMAS_PATH''${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}" # GIO modules for TLS support export GIO_MODULE_DIR="${pkgs.glib-networking}/lib/gio/modules" diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 3de007d..3c25a4a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -79,6 +79,7 @@ dependencies = [ "unidiff", "urlencoding", "uuid", + "webkit2gtk", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8187534..45d6689 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -51,6 +51,12 @@ ignore = "0.4" sublime_fuzzy = "0.7" similar = { version = "3", features = ["inline"] } +[target.'cfg(target_os = "linux")'.dependencies] +# Used only to flip the underlying WebKitGTK Settings (e.g. disable +# enable-smooth-scrolling) via window.with_webview. Match wry's version +# to avoid pulling in a second copy. +webkit2gtk = "2.0" + [dev-dependencies] insta = "1.45" tempfile = "3.23.0" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 203f60a..7dcbff9 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -96,6 +96,22 @@ macro_rules! all_commands { use review::{ActiveReview, Review}; use state::AppState; +/// Apply Linux-specific WebKitGTK settings to a window's webview after +/// creation. Currently: disable `enable-smooth-scrolling` so wheel events +/// scroll instantly instead of with momentum. No-op on non-Linux. +#[cfg(target_os = "linux")] +pub fn configure_linux_webview(window: &tauri::WebviewWindow) { + use webkit2gtk::{SettingsExt, WebViewExt}; + let _ = window.with_webview(|wv| { + if let Some(settings) = wv.inner().settings() { + settings.set_enable_smooth_scrolling(false); + } + }); +} + +#[cfg(not(target_os = "linux"))] +pub fn configure_linux_webview(_window: &tauri::WebviewWindow) {} + /// Shared flag to prevent app exit in MCP mode. pub type ShouldExit = Arc; @@ -154,6 +170,7 @@ pub fn run(state: AppState, context: tauri::Context, json_output: bool) { }; let window = builder.build()?; + configure_linux_webview(&window); // Restore saved window position/size (or keep defaults) window_state::restore_window_state(&window, window_state::WindowType::Main); diff --git a/src-tauri/src/mcp/mod.rs b/src-tauri/src/mcp/mod.rs index 5860b05..d475082 100644 --- a/src-tauri/src/mcp/mod.rs +++ b/src-tauri/src/mcp/mod.rs @@ -448,6 +448,7 @@ fn run_session_with_state( let window = app_handle .get_webview_window(&built_label) .ok_or_else(|| format!("Window {} not found after build", built_label))?; + crate::configure_linux_webview(&window); // Restore the review window onto the monitor it was last used on. The MCP // window shares the "main" slot — it is the main review window, just diff --git a/src/styles/components/code-viewer.css b/src/styles/components/code-viewer.css index cfda00a..bb36f36 100644 --- a/src/styles/components/code-viewer.css +++ b/src/styles/components/code-viewer.css @@ -23,9 +23,7 @@ header.header { padding: 2.4px 12px 0 90px; flex-shrink: 0; border-bottom: 1px solid rgba(0, 0, 0, 0.06); - background: color-mix(in srgb, var(--bg-panel) 85%, transparent); - backdrop-filter: blur(20px) saturate(180%); - -webkit-backdrop-filter: blur(20px) saturate(180%); + background: var(--bg-panel); -webkit-app-region: drag; /* Soft shadow for depth */ box-shadow: @@ -68,9 +66,7 @@ header.header { /* Session slot for global comment editor */ .session-slot { padding: 0 12px 12px 12px; - background: color-mix(in srgb, var(--bg-panel) 85%, transparent); - backdrop-filter: blur(20px) saturate(180%); - -webkit-backdrop-filter: blur(20px) saturate(180%); + background: var(--bg-panel); } /* Override annotation-editor styles when in session slot */ diff --git a/src/styles/components/command-palette.css b/src/styles/components/command-palette.css index 7f275ba..6a04d69 100644 --- a/src/styles/components/command-palette.css +++ b/src/styles/components/command-palette.css @@ -8,8 +8,6 @@ position: fixed; inset: 0; background: var(--backdrop-light); - backdrop-filter: blur(2px); - -webkit-backdrop-filter: blur(2px); z-index: 1000; } diff --git a/src/styles/components/status-bar.css b/src/styles/components/status-bar.css index c349661..7115ed8 100644 --- a/src/styles/components/status-bar.css +++ b/src/styles/components/status-bar.css @@ -10,8 +10,6 @@ gap: 24px; padding: 6px 16px; background: color-mix(in srgb, var(--mode-color, var(--bg-main)) 15%, var(--bg-main)); - backdrop-filter: blur(16px) saturate(150%); - -webkit-backdrop-filter: blur(16px) saturate(150%); border-top: 1px solid color-mix(in srgb, var(--mode-color, transparent) 20%, rgba(0, 0, 0, 0.06)); font-size: 12px; z-index: 10;