diff --git a/README.md b/README.md index fd45eb9cd..0b7b9932b 100644 --- a/README.md +++ b/README.md @@ -205,10 +205,10 @@ drag-and-drop, set **Preferences › Performance › Linux Display Server** to * the app with `WAYLAND_DISPLAY= vectorcraft`: the window then opens through XWayland, where drops work (see [`docs/development.md`](docs/development.md#linux-wayland-and-x11)). -On Linux with Wayland, under KDE Plasma 6.3 or later and under GNOME, VectorCraft doesn't respond to a drawing tablet's -pen yet (#491, #2028). Open the window through XWayland instead, where the pen works as a mouse and the app reads its -pressure: set the same preference to **X11 (XWayland)**, or to **X11 (XWayland) When a Pen Is Attached** to use -XWayland only when a pen is attached as VectorCraft starts, and restart; or start the app with +On Linux with Wayland, under KDE Plasma 6.3 or later and under GNOME, VectorCraft can't get a drawing tablet's pen +input on native Wayland yet (#491, #2028). When a pen is attached as VectorCraft starts, the window opens through +XWayland, where the pen works as a mouse and the app reads its pressure (#4967; `VECTORCRAFT_NATIVE_WAYLAND=1` keeps +Wayland). For a pen attached later, set the same preference to **X11 (XWayland)** and restart, or start the app with `WAYLAND_DISPLAY= vectorcraft` (see [`docs/development.md`](docs/development.md#linux-wayland-and-x11)). ### Use it from Claude Code and other agents diff --git a/apps/vectorcraft/src/main.rs b/apps/vectorcraft/src/main.rs index 8bb9600af..980d3826b 100644 --- a/apps/vectorcraft/src/main.rs +++ b/apps/vectorcraft/src/main.rs @@ -290,15 +290,15 @@ fn main() -> std::process::ExitCode { let options = native_options(custom_titlebar); // winit picks Wayland whenever `WAYLAND_DISPLAY` is set; Preferences › Performance › Linux // Display Server › X11 opens the window through XWayland instead, where file drops work (#1151), - // and X11 (XWayland) When a Pen Is Attached does so when a pen is attached, where the pen draws (#2028). + // and the other choices do so when a pen is attached, where the pen draws (#2028, #4967). #[cfg(target_os = "linux")] let options = { let mut options = options; let pref = saved.as_ref().and_then(|ui| ui.engine_prefs.get("linuxDisplayServer")).and_then(serde_json::Value::as_str); if xwayland::wanted(pref, |name| std::env::var_os(name), xwayland::pen_attached) { if xwayland::x11_libraries_found() { - if pref == Some("x11WithPen") { - log::info!("pen found: opening the window through XWayland (Preferences › Performance › Linux Display Server)"); + if pref != Some("x11") { + log::info!("pen found: opening the window through XWayland, where the pen works (VECTORCRAFT_NATIVE_WAYLAND=1 keeps Wayland)"); } else { log::info!("opening the window through XWayland (Preferences › Performance › Linux Display Server)"); } diff --git a/apps/vectorcraft/src/xwayland.rs b/apps/vectorcraft/src/xwayland.rs index 509a70056..38b210c05 100644 --- a/apps/vectorcraft/src/xwayland.rs +++ b/apps/vectorcraft/src/xwayland.rs @@ -1,8 +1,10 @@ //! Linux: Preferences › Performance › Linux Display Server › X11 opens the window through XWayland //! on a Wayland session, where dropped files arrive (winit 0.30 has no Wayland drag and drop, -//! #1151). X11 (XWayland) When a Pen Is Attached does so only when a pen is attached as the app -//! starts: winit 0.30 doesn't bind the Wayland tablet protocol, and XWayland hands the pen to X11 -//! windows as a pointer (#2028). Only when XWayland can run the window: an X display is set and +//! #1151). Automatic and X11 (XWayland) When a Pen Is Attached do so only when a pen is attached +//! as the app starts, as PhotoCraft does: winit 0.30 doesn't bind the Wayland tablet protocol, so +//! on native Wayland the pen moves only the compositor's cursor, and XWayland hands the pen to X11 +//! windows as a pointer (#2028, #4967). `VECTORCRAFT_NATIVE_WAYLAND=1` keeps a pen's window on +//! Wayland. Only when XWayland can run the window: an X display is set and //! the X11 libraries winit loads at runtime are installed. Otherwise the window opens on Wayland, //! so a missing library never keeps the app from starting. //! @@ -21,16 +23,17 @@ const X11_LIBS: &[&str] = &["libX11.so.6", "libX11-xcb.so.1", "libxcb.so.1", "libXcursor.so.1", "libXi.so.6", "libxkbcommon.so.0", "libxkbcommon-x11.so.0"]; /// Whether the saved `linuxDisplayServer` and the environment ask for XWayland: `x11` chosen, or -/// `x11WithPen` chosen and `pen` finding a pen; a Wayland session (winit picks Wayland whenever -/// `WAYLAND_DISPLAY` or `WAYLAND_SOCKET` is set); and an X display to open. `pen` runs only for -/// `x11WithPen`, after the session checks. +/// any other choice (`automatic`, `x11WithPen`, none saved) with `pen` finding a pen and +/// `VECTORCRAFT_NATIVE_WAYLAND` unset (or `0`); a Wayland session (winit picks Wayland whenever +/// `WAYLAND_DISPLAY` or `WAYLAND_SOCKET` is set); and an X display to open. `pen` runs only after +/// the other checks. pub fn wanted(pref: Option<&str>, var: impl Fn(&str) -> Option, pen: impl FnOnce() -> bool) -> bool { let set = |name: &str| var(name).is_some_and(|v| !v.is_empty()); let session = (set("WAYLAND_DISPLAY") || set("WAYLAND_SOCKET")) && set("DISPLAY"); + let native_wayland = var("VECTORCRAFT_NATIVE_WAYLAND").is_some_and(|v| !v.is_empty() && v != "0"); match pref { Some("x11") => session, - Some("x11WithPen") => session && pen(), - _ => false, + _ => session && !native_wayland && pen(), } } @@ -149,27 +152,35 @@ mod tests { let wayland = env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", ":0")]); assert!(wanted(Some("x11"), &wayland, no_probe)); assert!(wanted(Some("x11"), env(&[("WAYLAND_SOCKET", "3"), ("DISPLAY", ":0")]), no_probe)); - assert!(!wanted(Some("automatic"), &wayland, no_probe)); - assert!(!wanted(None, &wayland, no_probe)); - assert!(!wanted(Some("wayland"), &wayland, no_probe)); + assert!(!wanted(Some("automatic"), &wayland, || false)); + assert!(!wanted(None, &wayland, || false)); // An X11 session already opens on X11; without an X display there is no XWayland to use. assert!(!wanted(Some("x11"), env(&[("DISPLAY", ":0")]), no_probe)); assert!(!wanted(Some("x11"), env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", "")]), no_probe)); assert!(!wanted(Some("x11"), env(&[("WAYLAND_DISPLAY", "wayland-0")]), no_probe)); } - /// X11 (XWayland) When a Pen Is Attached (#2028): XWayland on a Wayland session with an X - /// display when a pen is found, the session's own display server otherwise. The pen check - /// runs only on such a session. + /// Automatic and X11 (XWayland) When a Pen Is Attached (#2028, #4967): XWayland on a Wayland + /// session with an X display when a pen is found, where the pen reaches the window, the + /// session's own display server otherwise. The pen check runs only on such a session, and + /// `VECTORCRAFT_NATIVE_WAYLAND` keeps Wayland. #[test] - fn the_pen_choice_opens_xwayland_only_with_a_pen() { + fn a_pen_opens_xwayland_unless_native_wayland_is_asked_for() { let wayland = env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", ":0")]); - assert!(wanted(Some("x11WithPen"), &wayland, || true)); - assert!(wanted(Some("x11WithPen"), env(&[("WAYLAND_SOCKET", "3"), ("DISPLAY", ":0")]), || true)); - assert!(!wanted(Some("x11WithPen"), &wayland, || false)); - assert!(!wanted(Some("x11WithPen"), env(&[("DISPLAY", ":0")]), no_probe)); - assert!(!wanted(Some("x11WithPen"), env(&[("WAYLAND_DISPLAY", "wayland-0")]), no_probe)); - assert!(!wanted(Some("x11WithPen"), env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", "")]), no_probe)); + let native = env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", ":0"), ("VECTORCRAFT_NATIVE_WAYLAND", "1")]); + let not_native = env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", ":0"), ("VECTORCRAFT_NATIVE_WAYLAND", "0")]); + for pref in [Some("automatic"), None, Some("x11WithPen")] { + assert!(wanted(pref, &wayland, || true), "{pref:?}"); + assert!(wanted(pref, env(&[("WAYLAND_SOCKET", "3"), ("DISPLAY", ":0")]), || true), "{pref:?}"); + assert!(!wanted(pref, &wayland, || false), "{pref:?}"); + assert!(!wanted(pref, env(&[("DISPLAY", ":0")]), no_probe), "{pref:?}"); + assert!(!wanted(pref, env(&[("WAYLAND_DISPLAY", "wayland-0")]), no_probe), "{pref:?}"); + assert!(!wanted(pref, env(&[("WAYLAND_DISPLAY", "wayland-0"), ("DISPLAY", "")]), no_probe), "{pref:?}"); + assert!(!wanted(pref, &native, no_probe), "{pref:?}"); + assert!(wanted(pref, ¬_native, || true), "{pref:?}"); + } + // The X11 choice opens XWayland with or without a pen; the opt-out is for the pen only. + assert!(wanted(Some("x11"), &native, no_probe)); } /// `/proc/bus/input/devices` of a laptop with a Wacom Intuos Pro attached (64-bit longs: the diff --git a/crates/engine/src/cmd/prefscmds.rs b/crates/engine/src/cmd/prefscmds.rs index d3bf73b95..257b6f0f1 100644 --- a/crates/engine/src/cmd/prefscmds.rs +++ b/crates/engine/src/cmd/prefscmds.rs @@ -89,8 +89,9 @@ pub const GPU_PREFERENCES: &[(&str, &str)] = &[("automatic", "Automatic"), ("lowPower", "Power Saving (integrated)"), ("highPerformance", "High Performance (discrete)")]; /// Performance › Linux Display Server (`linuxDisplayServer`), read by the desktop app at startup: /// `x11` opens the window through XWayland on a Wayland session, where dropped files arrive -/// (winit 0.30 has no Wayland drag and drop, #1151); `x11WithPen` does the same only when a pen is -/// attached as the app starts: under XWayland a drawing tablet's pen draws as a mouse (#2028). +/// (winit 0.30 has no Wayland drag and drop, #1151); `automatic` and `x11WithPen` do the same only +/// when a pen is attached as the app starts: under XWayland a drawing tablet's pen draws as a mouse +/// (#2028, #4967). const LINUX_DISPLAY_SERVERS: &[(&str, &str)] = &[("automatic", "Automatic"), ("x11", "X11 (XWayland)"), ("x11WithPen", "X11 (XWayland) When a Pen Is Attached")]; const BLACK: &[(&str, &str)] = &[("accurate", "Display All Blacks Accurately"), ("rich", "Display All Blacks as Rich Black")]; diff --git a/crates/engine/src/prefs.rs b/crates/engine/src/prefs.rs index 05f7880ba..db3ee7e75 100644 --- a/crates/engine/src/prefs.rs +++ b/crates/engine/src/prefs.rs @@ -162,9 +162,10 @@ pub struct Prefs { pub real_time_drawing: bool, /// Rasterizer worker threads; -1 = automatic. pub render_threads: i32, - /// Linux: `automatic` opens the window on the session's display server; `x11` opens it through - /// XWayland on a Wayland session, where dropped files arrive (#1151); `x11WithPen` opens it - /// through XWayland only when a pen is attached (#2028). Read when the app starts. + /// Linux: `automatic` opens the window on the session's display server, or through XWayland on + /// a Wayland session when a pen is attached (#4967); `x11` opens it through XWayland on a + /// Wayland session, where dropped files arrive (#1151); `x11WithPen` opens it through XWayland + /// only when a pen is attached (#2028). Read when the app starts. pub linux_display_server: String, // File Handling pub background_save: bool, diff --git a/docs/development.md b/docs/development.md index 2dfa4fea6..db22dcf72 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,5 +1,6 @@ # Development +> **Last updated:** 2026-11-01 · **Change:** Linux: Automatic Linux Display Server opens the window through XWayland when a pen is attached on a Wayland session, so the pen draws (#4967); `VECTORCRAFT_NATIVE_WAYLAND=1` keeps Wayland. > **Last updated:** 2026-10-31 · **Change:** files opened while the app runs open in its window on Windows and Linux (#4892); `--new-instance`. > **Last updated:** 2026-10-29 · **Change:** Linux clipboard: the Flatpak on GNOME copies and pastes text through the core Wayland protocol. > **Last updated:** 2026-10-29 · **Change:** Linux clipboard: a clipboard that can't be opened is retried with a growing wait and logged once. @@ -124,7 +125,7 @@ The window runs natively on Wayland (eframe's `wayland` feature) and on X11. On - **Clipboard owners that never answer (#510):** reading the clipboard waits on the app that owns it: arboard gives up on an X11 owner after 4 s, and a Wayland read waits for the owner to send its data. So on Linux the check that enables the Paste menu items runs on a background thread with a second clipboard handle (`crates/ui-egui/src/clipboard_probe.rs`, installed as `Services::clipboard_probe`), only while nothing is copied in the app and a document is open, and the window keeps drawing. A paste itself still reads on the UI thread, so pasting from such an owner waits for it once. Windows and macOS keep the check on the UI thread: Windows only asks which formats the clipboard holds, macOS asks the pasteboard server. - **Copied files:** files copied in a file manager (`text/uri-list`; `CF_HDROP` on Windows, file URLs on macOS) paste as the first one that is art (SVG, PDF, EPS, EMF/WMF or a bitmap; a `.ai` or `.ait` file from the editing data it holds, else as the PDF or PostScript it holds), before the clipboard's other formats (which include the files' paths as text). - **Dropping files on the window does not work under Wayland:** winit 0.30, which eframe 0.37 runs on, has no Wayland drag and drop ([winit#1881](https://github.com/rust-windowing/winit/issues/1881), added in winit 0.31; [egui#1563](https://github.com/emilk/egui/issues/1563)), so no `dropped_files` arrive. Until eframe moves to winit 0.31: copy the files in the file manager and paste them, use File › Place or Open, or open the window through XWayland, where drops work: set **Preferences › Performance › Linux Display Server** to **X11 (XWayland)** and restart (#1151), or start the app with `WAYLAND_DISPLAY= vectorcraft`. The preference (`linuxDisplayServer`, read at startup in `apps/vectorcraft/src/main.rs`, shown on Linux only) has winit open the window on X11 (`EventLoopBuilderExtX11::with_x11`) when the session is Wayland, `DISPLAY` is set and the X11 libraries winit loads are installed (`apps/vectorcraft/src/xwayland.rs` reads `ldconfig -p` and the usual library directories); otherwise the window opens on Wayland and the log says why. Unlike clearing `WAYLAND_DISPLAY`, it leaves the clipboard on the compositor's own. -- **Pens and pen displays under Wayland (#491, #2028):** winit 0.30 doesn't bind the Wayland tablet protocol (`zwp_tablet_v2`; tablet input arrives in winit 0.31, [winit#4318](https://github.com/rust-windowing/winit/pull/4318), [egui#7731](https://github.com/emilk/egui/pull/7731)). Since Plasma 6.3, KWin no longer turns tablet input into pointer input for such apps ([kwin!6336](https://invent.kde.org/plasma/kwin/-/merge_requests/6336), commit [25c65abd](https://invent.kde.org/plasma/kwin/-/commit/25c65abddd95eb87fb892a8594faccbf509ff62f)), and GNOME's Mutter does not turn it into pointer input either (that commit's message): on KWin the pen moves the compositor's cursor over the window, but the app gets no motion or presses and shows none of its own cursors. Until eframe moves to winit 0.31, either run the app under XWayland, which supports the tablet protocol and hands the pen to X11 apps as a pointer (Preferences › Performance › Linux Display Server › X11 (XWayland); X11 (XWayland) When a Pen Is Attached (`x11WithPen`), which opens the window through XWayland only when `/proc/bus/input/devices` lists a pen as the app starts, a device with the `BTN_TOOL_PEN` key and the `ABS_X` and `ABS_Y` axes, and logs `pen found: opening the window through XWayland`; `WAYLAND_DISPLAY= vectorcraft`, or `env -u WAYLAND_DISPLAY vectorcraft`; for a desktop launcher, put `env WAYLAND_DISPLAY=` before the command in its `Exec=` line), or turn KWin's deprecated emulation back on for the whole session by setting `KWIN_WAYLAND_EMULATE_TABLET=1` in KWin's environment (for example in a file under `~/.config/environment.d/` or in `/etc/environment`) and logging in again. The pen then works as a mouse. Under XWayland the app also reads the pen's pressure (next item); with KWin's emulation on native Wayland the pen has no pressure. Other compositors that don't emulate a pointer for tablets behave the same way. +- **Pens and pen displays under Wayland (#491, #2028):** winit 0.30 doesn't bind the Wayland tablet protocol (`zwp_tablet_v2`; tablet input arrives in winit 0.31, [winit#4318](https://github.com/rust-windowing/winit/pull/4318), [egui#7731](https://github.com/emilk/egui/pull/7731)). Since Plasma 6.3, KWin no longer turns tablet input into pointer input for such apps ([kwin!6336](https://invent.kde.org/plasma/kwin/-/merge_requests/6336), commit [25c65abd](https://invent.kde.org/plasma/kwin/-/commit/25c65abddd95eb87fb892a8594faccbf509ff62f)), and GNOME's Mutter does not turn it into pointer input either (that commit's message): on KWin the pen moves the compositor's cursor over the window, but the app gets no motion or presses and shows none of its own cursors. Until eframe moves to winit 0.31, the app runs under XWayland, which supports the tablet protocol and hands the pen to X11 apps as a pointer: Preferences › Performance › Linux Display Server's Automatic (the default) and X11 (XWayland) When a Pen Is Attached (`x11WithPen`) open the window through XWayland when `/proc/bus/input/devices` lists a pen as the app starts, a device with the `BTN_TOOL_PEN` key and the `ABS_X` and `ABS_Y` axes, and log `pen found: opening the window through XWayland`, as PhotoCraft does (#4967; `VECTORCRAFT_NATIVE_WAYLAND=1` keeps the window on Wayland). For a pen attached after the app started, either run the app under XWayland (Preferences › Performance › Linux Display Server › X11 (XWayland); `WAYLAND_DISPLAY= vectorcraft`, or `env -u WAYLAND_DISPLAY vectorcraft`; for a desktop launcher, put `env WAYLAND_DISPLAY=` before the command in its `Exec=` line), or turn KWin's deprecated emulation back on for the whole session by setting `KWIN_WAYLAND_EMULATE_TABLET=1` in KWin's environment (for example in a file under `~/.config/environment.d/` or in `/etc/environment`) and logging in again. The pen then works as a mouse. Under XWayland the app also reads the pen's pressure (next item); with KWin's emulation on native Wayland the pen has no pressure. Other compositors that don't emulate a pointer for tablets behave the same way. - **Pen pressure under X11 and XWayland (#764):** winit 0.30 hands a pen to an X11 window as a mouse, without its pressure. When the window is on X11, XWayland included, the desktop app opens a second X connection (x11rb's `RustConnection`) and reads XInput2 raw events for every device (`apps/vectorcraft/src/tablet.rs`, from PhotoCraft's `crates/tablet`). A device with an `Abs Pressure` valuator is a pen, unless its XInput type is `TOUCHPAD` or `TOUCHSCREEN`. While a pen is the pointer that moved last, its pressure, scaled from the valuator's range to 0..1, reaches the tools that use pressure: the Paintbrush's pressure-sensitive brushes and the Liquify tools' Use Pressure Pen. A pen device whose name or XInput type contains `eraser` (in any case) is the pen's eraser end: while the pointer is over the window, the canvas selects the Eraser tool when the eraser end moves, and it selects the tool used before when the tip moves again (`crates/ui-egui/src/stylus.rs`). The X server needs XInput 2.1 or later; otherwise the log has a `tablet pressure:` warning with the reason, and the pen draws at full pressure. ## Fonts: craft-fonts (optional build input) diff --git a/docs/hardware-parity.md b/docs/hardware-parity.md index 336fe696b..3baf8d30d 100644 --- a/docs/hardware-parity.md +++ b/docs/hardware-parity.md @@ -1,6 +1,6 @@ # Hardware parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** patch (a second finger cancels the tool press the first finger began, and a finger landing while another is down presses nothing; the pinch only navigates, #4198) · **Target:** Adobe Illustrator 2026 (30.x) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** patch (Linux: on a Wayland session with a pen attached, Automatic opens the window through XWayland, where the pen draws, #4967) · **Target:** Adobe Illustrator 2026 (30.x) What hardware Illustrator uses, per platform, against VectorCraft. Illustrator's side is from its public documentation (GPU Performance, touch workspace, pen pressure pages); ours from the code @@ -21,7 +21,7 @@ reads the pen's eraser end on Windows, on macOS and on Linux under X11 and XWayl | Multithreaded rendering off the UI thread | partial | yes | yes | yes | single-threaded | beyond Illustrator | | Hybrid-graphics GPU choice | automatic | power-saving GPU by default, Preferences › Graphics Processor | same; DX12 then OpenGL; no Vulkan unless asked (#545, #806) | the desktop's GPU | browser | done | | Restart on another GPU when the first fails to present | — | yes (#502, #964) | yes | yes | restart on lost device (#369) | done | -| Pen pressure | yes (Wacom, Windows Ink, macOS tablet events) | yes, read from AppKit's tablet events before the window gets them (winit reports none), each move of a stroke with its own pressure, mouse event coalescing off (#852; not yet tried on a Mac) | yes (pointer force via `WM_POINTER`) | under X11 and XWayland (Preferences › Performance › Linux Display Server, #1151, #2028), read from XInput2 raw events (#764); **no** on native Wayland, where winit reports none and the pen may not reach the window (#491) | browser pointer events, with coalesced events; Apple Pencil on iPad (hover, palm rejection: fingers navigate after a pen contact until reload) | partial: 2–4 h for Wayland (winit 0.31), plus a check on a Mac | +| Pen pressure | yes (Wacom, Windows Ink, macOS tablet events) | yes, read from AppKit's tablet events before the window gets them (winit reports none), each move of a stroke with its own pressure, mouse event coalescing off (#852; not yet tried on a Mac) | yes (pointer force via `WM_POINTER`) | under X11 and XWayland (Preferences › Performance › Linux Display Server, #1151, #2028; Automatic uses XWayland when a pen is attached on a Wayland session, #4967), read from XInput2 raw events (#764); **no** on native Wayland, where winit reports none and the pen may not reach the window (#491) | browser pointer events, with coalesced events; Apple Pencil on iPad (hover, palm rejection: fingers navigate after a pen contact until reload) | partial: 2–4 h for Wayland (winit 0.31), plus a check on a Mac | | Pen tilt, bearing, barrel rotation (6D Art Pen) | yes, drives brushes | no | no | no | no | missing: 4–8 h after the input layer (#372) | | Pen eraser end | yes | the eraser end (AppKit's tablet proximity events) selects the Eraser tool and the tip brings back the tool used before, as on Linux (#852; not yet tried on a Mac) | no | under X11 and XWayland, the eraser end selects the Eraser tool and the tip brings back the tool used before (#764); **no** on native Wayland | a press of the eraser end (Pointer Events eraser button, `button` 5) selects the Eraser tool, and that press erases; a press of the tip brings back the tool used before; Pointer Events report no end while the pen hovers | partial | | Pen eraser end | yes | the eraser end (AppKit's tablet proximity events) selects the Eraser tool and the tip brings back the tool used before, as on Linux (#852; not yet tried on a Mac) | with Windows Ink, an inverted pen or its eraser button (`PEN_FLAG_INVERTED`, `PEN_FLAG_ERASER` in the pen's pointer messages) selects the Eraser tool and the tip brings back the tool used before, as on Linux (not yet tried with a pen) | under X11 and XWayland, the eraser end selects the Eraser tool and the tip brings back the tool used before (#764); **no** on native Wayland | no | partial | @@ -36,6 +36,7 @@ reads the pen's eraser end on Windows, on macOS and on Linux under X11 and XWayl | Date | Change | Summary | |---|---|---| +| 2026-11-01 | patch | Linux (#4967): on a Wayland session, Linux Display Server › Automatic opens the window through XWayland when a pen is attached as the app starts, as X11 (XWayland) When a Pen Is Attached does and as PhotoCraft does; on native Wayland winit 0.30 gets no tablet input and KWin 6.3+ and Mutter emulate no pointer, so the pen moved only the compositor's cursor. `VECTORCRAFT_NATIVE_WAYLAND=1` keeps Wayland. Unit-tested (`xwayland::tests`); not tried with a tablet; score unchanged (estimated) | | 2026-10-30 | patch | Touch (#4198): a second finger landing cancels the tool press the first finger began, also in the same frame (the Pencil's stroke and a Selection move are rolled back, nothing enters the undo history), and a finger landing while another is down presses nothing, so a pinch or two-finger pan only navigates. Headless canvas test `a_second_finger_cancels_the_tool_gesture_the_first_began`; not tried on a touch screen; score unchanged (estimated) | | 2026-10-24 | minor | macOS: an AppKit local event monitor reads each mouse and tablet event's pen pressure and the pen's end before the window gets it and writes them into the canvas's pen feed (#852): each pointer move of a stroke keeps its own pressure, mouse event coalescing is off, and the eraser end selects the Eraser tool. The mapping is unit-tested on every platform and the macOS code type-checks for `aarch64-apple-darwin`; not yet tried on a Mac with a tablet, so the score is unchanged (estimated) | | 2026-10-15 | patch | Web review: preserve pen buttons and modifiers; leave fingers to eframe before the first pen contact; remove persistent pen policy. Canvas regression tests cover intermediate moves and long-touch cancellation on native and web input. Physical-device QA pending. |