Browse / github.com/storytold/vectorcraft / patch
Linux: VectorCraft draws its own title bar on every desktop unless System Title Bar is on
Linux: VectorCraft draws its own title bar on every desktop unless System Title Bar is on ## What and why On KDE Plasma, Sway, Hyprland, COSMIC and X11 window managers, VectorCraft keeps the desktop's frame and draws its app bar, brand mark included, below it. Where the desktop draws a title bar, as KDE Plasma does, the window shows two. When the desktop's bar is hidden through the window manager, the app bar left behind does not move the window and has no caption buttons. The desktop frame on these desktops came with #3366, whose commit message says "The only behavioral change: KDE/Wayland now keeps KWin's native decorations (Frame::Desktop) instead of always drawing a custom tit
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- dotCooCoo (imported from pull request #4281, open)
- Base
e2a8280134a7c3c9b4e117ee668b9b3e7eb3e315- Size
- +178 −79 in 31 files
- Review
- pending
- Shared
- 2026-10-28
- Id
8fe0ad9c39a627dcd60d9dda
How it went
No other operator has reported using it yet.
Diff
raw · apps/vectorcraft/src/main.rs crates/ui-egui/src/chrome.rs crates/ui-egui/src/i18n/bg.tsv crates/ui-egui/src/i18n/cs.tsv crates/ui-egui/src/i18n/da.tsv crates/ui-egui/src/i18n/de.tsv crates/ui-egui/src/i18n/el.tsv crates/ui-egui/src/i18n/es.tsv crates/ui-egui/src/i18n/fi.tsv crates/ui-egui/src/i18n/fr.tsv crates/ui-egui/src/i18n/hu.tsv crates/ui-egui/src/i18n/id.tsv crates/ui-egui/src/i18n/it.tsv crates/ui-egui/src/i18n/ja.tsv crates/ui-egui/src/i18n/ka.tsv crates/ui-egui/src/i18n/ko.tsv crates/ui-egui/src/i18n/nl.tsv crates/ui-egui/src/i18n/pl.tsv crates/ui-egui/src/i18n/pt-br.tsv crates/ui-egui/src/i18n/ru.tsv crates/ui-egui/src/i18n/sv.tsv crates/ui-egui/src/i18n/tr.tsv crates/ui-egui/src/i18n/uk.tsv crates/ui-egui/src/i18n/vi.tsv crates/ui-egui/src/i18n/zh-hans.tsv crates/ui-egui/src/i18n/zh-hant.tsv crates/ui-egui/src/lib.rs crates/ui-egui/src/prefs_dialog.rs docs/control-protocol.md docs/development.md docs/target-app-parity.md
@@ -705,11 +705,11 @@ fn adapter_summary(info: &eframe::wgpu::AdapterInfo) -> String { format!("{} ({:?}, {:?})", info.name.trim(), info.backend, info.device_type) } -/// Windows and Linux: no OS title bar; the app bar is the title bar (`vectorcraft_ui_egui::titlebar`).+/// Windows: no OS title bar; the app bar is the title bar (`vectorcraft_ui_egui::titlebar`). /// macOS keeps its traffic lights over the integrated title strip. ///-/// Used on macOS and Windows (where VectorCraft keeps today's frame regardless of the-/// `craft-window` probe) and by the tests; Linux and the BSDs take the decision from the probe.+/// Used on macOS and Windows; Linux and the BSDs decide in [`custom_titlebar_from`], where+/// VectorCraft also draws its own title bar by default. #[cfg_attr(not(any(target_os = "macos", target_os = "windows")), allow(dead_code))] const CUSTOM_TITLEBAR: bool = !cfg!(target_os = "macos"); @@ -720,60 +720,42 @@ fn opted_into_system_title_bar(saved: Option<&vectorcraft_ui_egui::UiState>) -> saved.map(|ui| ui.engine_prefs.get("systemTitleBar").and_then(serde_json::Value::as_bool).unwrap_or(false)).unwrap_or(false) } -/// Whether this start draws its own title bar, given the frame the shared `craft-window` crate-/// decided and the user's System Title Bar preference.+/// Whether this start draws its own title bar, given `VECTORCRAFT_TITLEBAR` (`overridden`, as+/// [`craft_window::Choice::overridden`] reads it) and the user's System Title Bar preference. ///-/// The suite-wide rule (`craft_window::Choice`) is: the desktop draws the frame-/// ([`craft_window::Frame::Desktop`]) on macOS, Windows, X11 and any Wayland compositor with-/// server-side decorations (KDE, Sway, Hyprland, COSMIC); the app draws it-/// ([`craft_window::Frame::App`]) only where the compositor leaves it to the app (GNOME's Mutter),-/// or when `VECTORCRAFT_TITLEBAR` overrides the probe. VectorCraft draws its own title bar exactly-/// when `craft-window` says the app owns the frame **and** the user has not opted into the system-/// title bar; the preference always forces the native frame back on.-///-/// macOS and Windows keep today's behavior and are decided by [`CUSTOM_TITLEBAR`] rather than the-/// probe: `craft-window` returns `Frame::Desktop` for both (the OS always draws a frame), but-/// VectorCraft insets its content under the macOS traffic lights and draws its own caption buttons-/// on Windows — an overdraw on an OS-decorated window that is VectorCraft's choice, not-/// `craft-window`'s. Only Linux and the BSDs take the decision from the probe.+/// Linux and the BSDs: VectorCraft draws its own title bar on every desktop (GNOME, KDE, Sway,+/// Hyprland, COSMIC, X11 window managers) unless System Title Bar is on, as PhotoCraft does. The+/// variable decides for one run when it is set: `app` draws VectorCraft's bar and `system` or+/// `desktop` keeps the desktop's frame, whatever the preference says. The desktop the+/// `craft-window` probe finds does not change the result. #[cfg(not(any(target_os = "macos", target_os = "windows")))]-fn custom_titlebar_from(frame: &craft_window::Frame, opted_into_system: bool) -> bool {- matches!(frame, craft_window::Frame::App(_)) && !opted_into_system+fn custom_titlebar_from(overridden: Option<bool>, opted_into_system: bool) -> bool {+ overridden.unwrap_or(!opted_into_system) } -/// macOS and Windows: today's behavior, independent of the `craft-window` probe (see-/// [`custom_titlebar_from`]). macOS never draws its own frame (`CUSTOM_TITLEBAR` is `false`);-/// Windows draws its own caption unless the user opted into the system title bar.+/// macOS and Windows: decided by [`CUSTOM_TITLEBAR`] and the preference; `VECTORCRAFT_TITLEBAR`+/// is not read. macOS never draws its own frame (`CUSTOM_TITLEBAR` is `false`); Windows draws its+/// own caption unless the user opted into the system title bar. #[cfg(any(target_os = "macos", target_os = "windows"))]-fn custom_titlebar_from(_frame: &craft_window::Frame, opted_into_system: bool) -> bool {+fn custom_titlebar_from(_overridden: Option<bool>, opted_into_system: bool) -> bool { CUSTOM_TITLEBAR && !opted_into_system } -/// Whether this start draws its own title bar. Probes the shared `craft-window` crate once (its-/// override variable is `VECTORCRAFT_TITLEBAR`) and combines its decision with the saved System-/// Title Bar preference. Call once at startup, before [`native_options`].-///-/// On Linux, Preferences › Performance › Linux Display Server › X11 opens the window through-/// XWayland (below). A GNOME/Wayland probe would say `Frame::App` there, but the window really runs-/// on X11, whose window manager draws the frame — so when XWayland is being forced, keep the native-/// frame, the same as a real X11 session. An explicit `VECTORCRAFT_TITLEBAR` override still wins.-fn custom_titlebar(saved: Option<&vectorcraft_ui_egui::UiState>) -> bool {- let choice = craft_window::Choice::probe(craft_window::Prefix::new("VECTORCRAFT"));- let opted_into_system = opted_into_system_title_bar(saved);- #[cfg(target_os = "linux")]- {- let pref = saved.and_then(|ui| ui.engine_prefs.get("linuxDisplayServer")).and_then(serde_json::Value::as_str);- // `overridden() == None` means the probe decided (no VECTORCRAFT_TITLEBAR). When the window- // will actually open on X11 (XWayland) — the user asked for it *and* the X11 libraries are- // present, the same two conditions the launch path checks below — that run is effectively- // X11, so keep the native frame. If the libraries are missing, startup stays on Wayland, so- // the probe's own decision (app-drawn on GNOME) must stand.- let forced_to_x11 = xwayland::wanted(pref, |name| std::env::var_os(name), xwayland::pen_attached) && xwayland::x11_libraries_found();- if choice.overridden().is_none() && forced_to_x11 {- return custom_titlebar_from(&craft_window::Frame::Desktop, opted_into_system);- }+/// What `VECTORCRAFT_TITLEBAR` asks for on Linux and the BSDs: `Some(true)` VectorCraft's own title+/// bar, `Some(false)` the desktop's frame, `None` when it is unset or holds another value. Always+/// `None` on macOS and Windows. The `craft-window` probe runs once per process.+fn titlebar_override() -> Option<bool> {+ static OVERRIDE: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();+ if cfg!(any(target_os = "macos", target_os = "windows")) {+ return None; }- custom_titlebar_from(choice.frame(), opted_into_system)+ *OVERRIDE.get_or_init(|| craft_window::Choice::probe(craft_window::Prefix::new("VECTORCRAFT")).overridden())+}++/// Whether this start draws its own title bar: [`custom_titlebar_from`] with `VECTORCRAFT_TITLEBAR`+/// and the saved System Title Bar preference. Call once at startup, before [`native_options`].+fn custom_titlebar(saved: Option<&vectorcraft_ui_egui::UiState>) -> bool {+ custom_titlebar_from(titlebar_override(), opted_into_system_title_bar(saved)) } fn native_options(custom_titlebar: bool) -> eframe::NativeOptions {@@ -1128,6 +1110,7 @@ fn main() -> std::process::ExitCode { app.graphics_adapter = Some("OpenGL (Windows 7 compatibility)".into()); } app.custom_titlebar = custom_titlebar;+ app.titlebar_from_env = titlebar_override().is_some(); if let Some(port) = control_port { let rx = control_server::start(port, cc.egui_ctx.clone()); app = app.with_control(rx).with_automation_roots(roots.clone());@@ -1314,8 +1297,6 @@ mod tests { #[test] fn the_system_title_bar_preference_keeps_the_window_decorations() {- use craft_window::{Frame, Layout};- // The System Title Bar preference (Preferences › User Interface) is read the same way on // every platform; a missing or unreadable value is `false`. assert!(!super::opted_into_system_title_bar(None), "no preferences: the default");@@ -1324,33 +1305,40 @@ mod tests { let on = ui_state_with_prefs(serde_json::json!({"systemTitleBar": true})); assert!(super::opted_into_system_title_bar(Some(&on))); - // The suite-wide mapping (Frame + preference -> whether VectorCraft draws its own title- // bar). The desktop frame (macOS, Windows, X11, KDE/Wayland, …) always keeps native- // decorations; the app frame (GNOME/Wayland, or a `VECTORCRAFT_TITLEBAR` override) draws- // our own title bar — unless the user opted into the system title bar, which forces the- // native frame back on.- let app = Frame::App(Layout::default());- let desktop = Frame::Desktop;- #[cfg(not(any(target_os = "macos", target_os = "windows")))]- {- assert!(super::custom_titlebar_from(&app, false), "GNOME/Wayland: VectorCraft draws its own");- assert!(!super::custom_titlebar_from(&app, true), "System Title Bar preference forces native");- assert!(!super::custom_titlebar_from(&desktop, false), "KDE/X11/…: keep the compositor's frame");- assert!(!super::custom_titlebar_from(&desktop, true));- }- // macOS and Windows keep today's behavior, independent of the probed frame: the pref still- // forces the native frame back on where a custom one would otherwise be drawn.+ // macOS and Windows: `VECTORCRAFT_TITLEBAR` is not read, and the preference turns the+ // native frame back on where VectorCraft would draw its own. #[cfg(any(target_os = "macos", target_os = "windows"))] {- assert_eq!(super::custom_titlebar_from(&desktop, false), super::CUSTOM_TITLEBAR);- assert_eq!(super::custom_titlebar_from(&app, false), super::CUSTOM_TITLEBAR, "the probe does not change macOS/Windows");- assert!(!super::custom_titlebar_from(&desktop, true));+ assert_eq!(super::titlebar_override(), None);+ for overridden in [None, Some(true), Some(false)] {+ assert_eq!(super::custom_titlebar_from(overridden, false), super::CUSTOM_TITLEBAR, "{overridden:?}");+ assert!(!super::custom_titlebar_from(overridden, true), "{overridden:?}");+ } } assert_eq!(super::native_options(false).viewport.decorations, Some(true)); assert_eq!(super::native_options(true).viewport.decorations, Some(false)); } + /// Linux and the BSDs: VectorCraft's own title bar on every desktop unless System Title Bar is+ /// on, and `VECTORCRAFT_TITLEBAR` decides over the preference for the run it is set in.+ #[cfg(not(any(target_os = "macos", target_os = "windows")))]+ #[test]+ fn every_linux_desktop_gets_the_app_title_bar_unless_system_title_bar_is_on() {+ // What the `craft-window` probe reports: the desktop's frame on KDE Plasma, Sway, Hyprland,+ // COSMIC and X11, the app's on GNOME's Wayland session; none of them sets the override.+ for desktop in ["GNOME Wayland", "KDE Plasma", "Sway", "Hyprland", "COSMIC", "X11 window manager", "GNOME on X11"] {+ assert!(super::custom_titlebar_from(None, false), "{desktop}: VectorCraft's own title bar");+ assert!(!super::custom_titlebar_from(None, true), "{desktop}: System Title Bar keeps the desktop's frame");+ }+ // VECTORCRAFT_TITLEBAR=app draws VectorCraft's bar and =system (or =desktop) keeps the+ // desktop's frame, whatever the preference says.+ for opted_into_system in [false, true] {+ assert!(super::custom_titlebar_from(Some(true), opted_into_system), "app, preference {opted_into_system}");+ assert!(!super::custom_titlebar_from(Some(false), opted_into_system), "system, preference {opted_into_system}");+ }+ }+ /// The file extensions the macOS bundle declares: its document types and its own exported type. fn plist_extensions(plist: &str) -> Vec<&str> { ["<key>CFBundleTypeExtensions</key>", "<key>public.filename-extension</key>"]@@ -111,12 +111,13 @@ pub fn app_bar(app: &mut VectorcraftApp, ui: &mut Ui) { } /// Whether the window shows the system's title bar instead of the app drawing its own: Windows-/// and Linux with Preferences › User Interface › System Title Bar. macOS always has system-/// decorations, but keeps the in-app brand mark, so it never counts as system mode here; nor-/// does the web build (the browser tab has no document title), nor an embedder that never-/// turned the preference on.+/// and Linux with Preferences › User Interface › System Title Bar, and Linux when+/// `VECTORCRAFT_TITLEBAR` kept the desktop's frame ([`VectorcraftApp::titlebar_from_env`]). macOS+/// always has system decorations, but keeps the in-app brand mark, so it never counts as system+/// mode here; nor does the web build (the browser tab has no document title), nor an embedder+/// that never turned the preference on. pub fn system_title_bar(app: &VectorcraftApp) -> bool {- !app.custom_titlebar && app.session.prefs.system_title_bar && !cfg!(any(target_os = "macos", target_arch = "wasm32"))+ !app.custom_titlebar && (app.session.prefs.system_title_bar || app.titlebar_from_env) && !cfg!(any(target_os = "macos", target_arch = "wasm32")) } /// The OS window title: the active document's name suffixed with the app name (a `*` prefix@@ -2216,6 +2217,19 @@ mod tests { } } + #[test]+ fn a_desktop_frame_from_the_environment_variable_is_system_mode() {+ // VECTORCRAFT_TITLEBAR=system with System Title Bar off: the desktop draws the title bar.+ let mut app = crate::VectorcraftApp::new(Session::new(), Default::default());+ app.titlebar_from_env = true;+ assert!(!app.session.prefs.system_title_bar);+ assert_eq!(super::system_title_bar(&app), !cfg!(target_os = "macos"));+ // VECTORCRAFT_TITLEBAR=app: VectorCraft draws it, whatever the preference says.+ app.custom_titlebar = true;+ app.run("prefs.set", json!({"key": "systemTitleBar", "value": true})).unwrap();+ assert!(!super::system_title_bar(&app));+ }+ #[test] fn sync_window_title_sends_only_on_change() { let mut app = title_test_app(true);@@ -190,6 +190,7 @@ font-technology Variable Променливи Appearance panel Панел „Външен вид“ Applies when the linked file is relinked or updated. Прилага се, когато свързаният файл бъде пресвързан или актуализиран. Applies the next time VectorCraft starts. Прилага се при следващото стартиране на VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Докато е зададена, променливата на средата VECTORCRAFT_TITLEBAR избира заглавната лента. Apply Прилагане Apply Brush Прилагане на четка Apply Character Style Прилагане на стил на знаци@@ -3890,6 +3890,7 @@ font-technology Variable Variabilní Panel menu Nabídka panelu Unembed… Zrušit vložení… Applies the next time VectorCraft starts. Projeví se při příštím spuštění VectorCraftu.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Dokud je proměnná prostředí VECTORCRAFT_TITLEBAR nastavena, záhlaví okna volí ona. Enable Contextual Task Bar Povolit kontextový panel úloh Next Další OK OK@@ -3633,6 +3633,7 @@ font-technology Variable Variable Panel menu Panelmenu Unembed… Ophæv integrering… Applies the next time VectorCraft starts. Anvendes næste gang VectorCraft starter.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Miljøvariablen VECTORCRAFT_TITLEBAR vælger titellinjen, så længe den er angivet. Enable Contextual Task Bar Aktivér kontekstuel opgavelinje Next Næste OK OK@@ -179,6 +179,7 @@ font-technology Variable Variabel Appearance panel Bedienfeld „Aussehen“ Applies when the linked file is relinked or updated. Gilt, wenn die verknüpfte Datei neu verknüpft oder aktualisiert wird. Applies the next time VectorCraft starts. Gilt ab dem nächsten Start von VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Solange die Umgebungsvariable VECTORCRAFT_TITLEBAR gesetzt ist, bestimmt sie die Titelleiste. Apply Anwenden Apply Brush Pinsel anwenden Apply Character Style Zeichenformat anwenden@@ -183,6 +183,7 @@ font-technology Variable Μεταβλητές Appearance Panel Πίνακας εμφάνισης Appearance panel Πίνακας εμφάνισης Applies the next time VectorCraft starts. Εφαρμόζεται στην επόμενη εκκίνηση του VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Όσο είναι ορισμένη, η μεταβλητή περιβάλλοντος VECTORCRAFT_TITLEBAR επιλέγει τη γραμμή τίτλου. Apply Εφαρμογή Apply Brush Εφαρμογή πινέλου Apply Character Style Εφαρμογή στυλ χαρακτήρων@@ -204,6 +204,7 @@ font-technology Variable Variables Appearance panel Panel Apariencia Applies when the linked file is relinked or updated. Se aplica al volver a vincular o actualizar el archivo vinculado. Applies the next time VectorCraft starts. Se aplica la próxima vez que se inicie VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Mientras está definida, la variable de entorno VECTORCRAFT_TITLEBAR elige la barra de título. Apply Aplicar Apply Brush Aplicar pincel Apply Character Style Aplicar estilo de carácter@@ -3814,6 +3814,7 @@ font-technology Variable Muuttuvat Panel menu Paneelivalikko Unembed… Poista upotus… Applies the next time VectorCraft starts. Tulee voimaan, kun VectorCraft käynnistetään seuraavan kerran.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Ympäristömuuttuja VECTORCRAFT_TITLEBAR valitsee otsikkorivin niin kauan kuin se on asetettu. Enable Contextual Task Bar Ota kontekstuaalinen tehtäväpalkki käyttöön Next Seuraava OK OK@@ -205,6 +205,7 @@ font-technology Variable Variables Appearance panel Panneau Aspect Applies when the linked file is relinked or updated. S’applique lorsque le fichier lié est de nouveau lié ou mis à jour. Applies the next time VectorCraft starts. S’applique au prochain démarrage de VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Tant qu’elle est définie, la variable d’environnement VECTORCRAFT_TITLEBAR choisit la barre de titre. Apply Appliquer Apply Brush Appliquer la forme Apply Character Style Appliquer le style de caractère@@ -286,6 +286,7 @@ font-technology Variable Változó Appearance panel Megjelenés panel Appearance Panel Megjelenés panel Applies the next time VectorCraft starts. A VectorCraft következő indításakor lép életbe.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Amíg a VECTORCRAFT_TITLEBAR környezeti változó be van állítva, az választja ki a címsort. Applies when the linked file is relinked or updated. A csatolt fájl újracsatolásakor vagy frissítésekor érvényes. Apply Alkalmaz Apply Brush Ecset alkalmazása@@ -3633,6 +3633,7 @@ font-technology Variable Variabel Panel menu Menu panel Unembed… Lepaskan sematan… Applies the next time VectorCraft starts. Berlaku saat VectorCraft dimulai berikutnya.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Selama ditetapkan, variabel lingkungan VECTORCRAFT_TITLEBAR memilih bilah judul. Enable Contextual Task Bar Aktifkan bilah tugas kontekstual Next Berikutnya OK OK@@ -204,6 +204,7 @@ font-technology Variable Variabili Appearance panel Pannello Aspetto Applies when the linked file is relinked or updated. Si applica quando il file collegato viene ricollegato o aggiornato. Applies the next time VectorCraft starts. Si applica al prossimo avvio di VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Finché è impostata, la variabile d'ambiente VECTORCRAFT_TITLEBAR sceglie la barra del titolo. Apply Applica Apply Brush Applica pennello Apply Character Style Applica stile carattere@@ -920,6 +920,7 @@ font-technology Variable バリアブル Appearance of Black ブラックのアピアランス Appearance panel アピアランスパネル Applies the next time VectorCraft starts. VectorCraft の次回起動時に適用されます。+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. 環境変数 VECTORCRAFT_TITLEBAR が設定されている間は、この変数でタイトルバーが決まります。 Applies when the linked file is relinked or updated. リンクファイルを再リンクまたは更新したときに適用されます。 Apply Brush ブラシを適用 Apply Character Style 文字スタイルを適用@@ -3412,6 +3412,7 @@ font-technology Variable ცვლადი Panel menu პანელის მენიუ Unembed… ჩაშენების მოხსნა… Applies the next time VectorCraft starts. ძალაში შევა VectorCraft-ის მომდევნო გაშვებისას.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. სანამ გარემოს ცვლადი VECTORCRAFT_TITLEBAR დაყენებულია, სათაურის ზოლს ის ირჩევს. Enable Contextual Task Bar კონტექსტური ამოცანების ზოლის ჩართვა Next შემდეგი OK OK@@ -915,6 +915,7 @@ font-technology Variable 가변 Appearance of Black 검정 표시 방식 Appearance panel 모양새 패널 Applies the next time VectorCraft starts. 다음에 VectorCraft를 시작할 때 적용됩니다.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. 환경 변수 VECTORCRAFT_TITLEBAR가 설정되어 있는 동안에는 이 변수가 제목 표시줄을 정합니다. Applies when the linked file is relinked or updated. 링크된 파일을 다시 연결하거나 업데이트할 때 적용됩니다. Apply Brush 브러시 적용 Apply Character Style 문자 스타일 적용@@ -3647,6 +3647,7 @@ font-technology Variable Variabel Panel menu Paneelmenu Unembed… Insluiten ongedaan maken… Applies the next time VectorCraft starts. Wordt toegepast de volgende keer dat VectorCraft start.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Zolang de omgevingsvariabele VECTORCRAFT_TITLEBAR is ingesteld, kiest die de titelbalk. Enable Contextual Task Bar Contextuele taakbalk inschakelen Next Volgende OK OK@@ -3729,6 +3729,7 @@ font-technology Variable Zmienne Panel menu Menu panelu Unembed… Wyodrębnij… Applies the next time VectorCraft starts. Zostanie zastosowane przy następnym uruchomieniu VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Dopóki zmienna środowiskowa VECTORCRAFT_TITLEBAR jest ustawiona, to ona wybiera pasek tytułu. Enable Contextual Task Bar Włącz kontekstowy pasek zadań Next Dalej OK OK@@ -199,6 +199,7 @@ Appearance of Black Aparência do Preto Appearance panel Painel de Aparência Applies the next time VectorCraft starts. Aplica na próxima inicialização do VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Enquanto estiver definida, a variável de ambiente VECTORCRAFT_TITLEBAR escolhe a barra de título. Applies when the linked file is relinked or updated. Aplica quando o arquivo vinculado é revinculado ou atualizado. Apply Brush Aplicar Pincel Apply Character Style Aplicar Estilo de Caractere@@ -202,6 +202,7 @@ font-technology Variable Вариативные Appearance panel Панель «Оформление» Applies when the linked file is relinked or updated. Применяется при повторной привязке или обновлении связанного файла. Applies the next time VectorCraft starts. Применяется при следующем запуске VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Пока переменная среды VECTORCRAFT_TITLEBAR задана, строку заголовка выбирает она. Apply Применить Apply Brush Применить кисть Apply Character Style Применить стиль символа@@ -192,6 +192,7 @@ font-technology Variable Variabla Appearance panel Utseendepanelen Applies when the linked file is relinked or updated. Gäller när den länkade filen länkas om eller uppdateras. Applies the next time VectorCraft starts. Gäller nästa gång VectorCraft startas.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Miljövariabeln VECTORCRAFT_TITLEBAR väljer namnlisten så länge den är angiven. Apply Använd Apply Brush Använd pensel Apply Character Style Använd teckenstil@@ -189,6 +189,7 @@ font-technology Variable Değişken Appearance panel Görünüm paneli Applies when the linked file is relinked or updated. Bağlantılı dosya yeniden bağlandığında veya güncellendiğinde geçerlidir. Applies the next time VectorCraft starts. VectorCraft'ın bir sonraki başlatılışında uygulanır.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. VECTORCRAFT_TITLEBAR ortam değişkeni ayarlı olduğu sürece başlık çubuğunu o seçer. Apply Uygula Apply Brush Fırça Uygula Apply Character Style Karakter Stilini Uygula@@ -198,6 +198,7 @@ font-technology Variable Варіативні Appearance panel Панель «Оформлення» Applies when the linked file is relinked or updated. Використовується при повторній прив’язці або оновленні пов’язаного файлу. Applies the next time VectorCraft starts. Застосовується при наступному запуску VectorCraft.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Поки змінну середовища VECTORCRAFT_TITLEBAR задано, рядок заголовка вибирає вона. Apply Застосувати Apply Brush Застосувати пензель Apply Character Style Застосувати стиль символу@@ -221,6 +221,7 @@ font-technology Variable Biến thiên Appearance Panel Bảng Diện mạo Appearance panel Bảng diện mạo Applies the next time VectorCraft starts. Áp dụng vào lần tiếp theo VectorCraft khởi động.+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. Khi biến môi trường VECTORCRAFT_TITLEBAR được đặt, biến này chọn thanh tiêu đề. Applies when the linked file is relinked or updated. Áp dụng khi tệp liên kết được liên kết lại hoặc cập nhật. Apply Áp dụng Apply Brush Áp dụng cọ@@ -4663,6 +4663,7 @@ imageTrace Outline 轮廓 Font Technology 字体技术 font-technology Variable 可变 Applies the next time VectorCraft starts. 下次启动 VectorCraft 时生效。+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. 设置了环境变量 VECTORCRAFT_TITLEBAR 时,由它选择标题栏。 Collapse to Icons 折叠为图标 Decorative 装饰 Dim Images to: 图像变暗至:@@ -162,6 +162,7 @@ font-technology Variable 可變 Appearance panel 外觀面板 Applies when the linked file is relinked or updated. 重新連結或更新連結檔案時套用。 Applies the next time VectorCraft starts. 下次啟動 VectorCraft 時生效。+ The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set. 設定了環境變數 VECTORCRAFT_TITLEBAR 時,由它選擇標題列。 Apply 套用 Apply Brush 套用筆刷 Apply Character Style 套用字元樣式@@ -521,6 +521,9 @@ pub struct VectorcraftApp { /// Windows and Linux: the window has no OS decorations, so the app bar is the title bar (drag, /// double-click to maximize, caption buttons) and invisible edge zones resize the window. pub custom_titlebar: bool,+ /// `VECTORCRAFT_TITLEBAR` chose this window's frame (Linux and the BSDs), so Preferences › User+ /// Interface › System Title Bar does not apply while it is set. `false` unless the host sets it.+ pub titlebar_from_env: bool, /// Last window title sent to the OS (`ViewportCommand::Title`, see `chrome::sync_window_title`): /// sent again only when it changes, so idle frames don't spam the backend. pub(crate) last_window_title: String,@@ -813,6 +816,7 @@ impl VectorcraftApp { canvas_rect: None, hover_doc: None, custom_titlebar: false,+ titlebar_from_env: false, last_window_title: String::new(), graphics_adapter: None, place: Default::default(),@@ -32,6 +32,8 @@ pub fn open(app: &mut VectorcraftApp, category: Option<&str>) { fields.insert("__smartGuides".into(), json!(app.ui.view.smart_guides)); fields.insert("__snapToGrid".into(), json!(app.ui.view.snap_to_grid)); fields.insert("__taskBar".into(), json!(app.ui.task_bar));+ // Read-only: whether VECTORCRAFT_TITLEBAR chose this window's frame (System Title Bar's note).+ fields.insert("__titlebarFromEnv".into(), json!(app.titlebar_from_env)); app.ui.dialog = Some(Dialog { kind: "preferences".into(), fields }); } @@ -278,9 +280,16 @@ fn category_fields(ui: &mut egui::Ui, d: &mut Dialog, cat: &str) { // Windows and Linux only: macOS always has the system's title bar, the web has none. PrefKind::Bool if sp.key == "systemTitleBar" => { if cfg!(all(not(target_arch = "wasm32"), not(target_os = "macos"))) {- bool_row(ui, d, sp.key, sp.label);- // The window's decorations are chosen once, when the app starts.- ui.label(egui::RichText::new(tl!("Applies the next time VectorCraft starts.")).color(t.text_dim).size(11.0));+ // The window's decorations are chosen once, when the app starts; while+ // VECTORCRAFT_TITLEBAR is set it chooses them, and the checkbox is dimmed.+ let from_env = d.bool("__titlebarFromEnv");+ ui.add_enabled_ui(!from_env, |ui| bool_row(ui, d, sp.key, sp.label));+ let note = if from_env {+ tl!("The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set.")+ } else {+ tl!("Applies the next time VectorCraft starts.")+ };+ ui.label(egui::RichText::new(note).color(t.text_dim).size(11.0)); } } PrefKind::Bool => bool_row(ui, d, sp.key, sp.label),@@ -646,6 +655,61 @@ mod tests { assert_eq!(saved["engine_prefs"]["systemTitleBar"], json!(true)); } + /// While VECTORCRAFT_TITLEBAR chooses the frame, System Title Bar says so in place of the+ /// next-launch note, and its checkbox does not take clicks.+ #[test]+ fn system_title_bar_names_the_environment_variable_that_overrides_it() {+ fn texts(s: &egui::Shape, out: &mut Vec<String>) {+ match s {+ egui::Shape::Text(t) => out.push(t.galley.text().to_string()),+ egui::Shape::Vec(v) => v.iter().for_each(|s| texts(s, out)),+ _ => {}+ }+ }+ let note = "The VECTORCRAFT_TITLEBAR environment variable chooses the title bar while it is set.";+ let supported = cfg!(all(not(target_arch = "wasm32"), not(target_os = "macos")));+ for from_env in [false, true] {+ let mut a = app();+ a.titlebar_from_env = from_env;+ open(&mut a, Some("User Interface"));+ let ctx = egui::Context::default();+ crate::theme::install_fonts(&ctx);+ let mut out = ctx.run_ui(egui::RawInput::default(), |ui| show(&mut a, ui.ctx()));+ out.textures_delta.clear();+ let mut out = ctx.run_ui(egui::RawInput::default(), |ui| show(&mut a, ui.ctx()));+ out.textures_delta.clear();+ let mut shown = vec![];+ out.shapes.iter().for_each(|c| texts(&c.shape, &mut shown));+ assert_eq!(shown.iter().any(|t| t == note), supported && from_env, "{shown:?}");+ assert_eq!(shown.iter().any(|t| t == "Applies the next time VectorCraft starts."), supported && !from_env, "{shown:?}");+ // A click on the checkbox's label: it turns the preference on only without the variable.+ let label = out.shapes.iter().find_map(|c| match &c.shape {+ egui::Shape::Text(t) if t.galley.text() == "System Title Bar" => Some(t.visual_bounding_rect()),+ _ => None,+ });+ if let Some(r) = label {+ for pressed in [true, false] {+ let input = egui::RawInput {+ events: vec![+ egui::Event::PointerMoved(r.center()),+ egui::Event::PointerButton {+ pos: r.center(),+ button: egui::PointerButton::Primary,+ pressed,+ modifiers: Default::default(),+ },+ ],+ ..Default::default()+ };+ let mut out = ctx.run_ui(input, |ui| show(&mut a, ui.ctx()));+ out.textures_delta.clear();+ }+ assert_eq!(a.ui.dialog.as_ref().unwrap().bool("systemTitleBar"), !from_env, "clicked with the variable {from_env}");+ }+ assert_eq!(label.is_some(), supported);+ }+ }+ /// Performance › Linux Display Server (#2028): on Linux it shows the drawing-tablet note, and /// X11 (XWayland) When a Pen Is Attached is applied by OK and saved under the key the desktop /// app reads before the window opens.@@ -310,7 +310,11 @@ not commands, so drive them with `ui.click` if needed. Close runs `app.quit` (th modified documents), and empty bar space and the 5 pt window edges move and resize the window. Preferences › User Interface › System Title Bar (`systemTitleBar`, read when the app starts) gives the window its OS decorations back instead: the OS title then shows the active document (`*name — VectorCraft` with unsaved changes) and the app bar-drops its brand mark. On macOS the window buttons are centred on the app bar; the web build is unchanged.+drops its brand mark. On Linux and the BSDs the environment variable `VECTORCRAFT_TITLEBAR` chooses the frame for one+run, whatever the preference says: `app` keeps the app bar as the title bar, and `system` or `desktop` gives the+window the desktop's decorations. While it is set, the Preferences dialog dims System Title Bar and its+`__titlebarFromEnv` field is `true`. On macOS the window buttons are centred on the app bar; the web build is+unchanged. Fill/Stroke chips and panel shortcuts: the Control bar's and Properties' Fill and Stroke chips bring their proxy forward (`paint.toggleActive {fill}`) and open a popover with the Swatches panel (Shift-click: the Color panel's mixer);@@ -109,7 +109,7 @@ On macOS the menus live in the system menu bar, not in the window's app bar (whi ## Linux: Wayland and X11 -On GNOME/Wayland, enable **Preferences › User Interface › System Title Bar** and restart to use winit's font-free Adwaita window controls (`wayland-csd-adwaita-notitle`); the existing custom title bar remains the Linux default.+On every Linux desktop the app bar is the window's title bar by default. Enable **Preferences › User Interface › System Title Bar** and restart to give the window the desktop's frame instead: KDE Plasma, Sway, Hyprland, COSMIC and X11 window managers draw it, and on GNOME/Wayland winit draws its font-free Adwaita window controls (`wayland-csd-adwaita-notitle`). `VECTORCRAFT_TITLEBAR=app`, `=system` or `=desktop` chooses the frame for one run, whatever the preference says. The window runs natively on Wayland (eframe's `wayland` feature) and on X11. On machines with two GPUs it renders on the one the desktop runs on unless Preferences say otherwise; see [Desktop graphics processor](#desktop-graphics-processor) (#502). The system clipboard (`apps/vectorcraft/src/clipboard.rs`) is arboard with its `wayland-data-control` feature: @@ -610,6 +610,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - Cmd/Ctrl+Shift+X (`type.resetHorizontalScale`) sets the horizontal scale of the selected type, or of the text the Type tool has selected, to 100% as the Character panel shows it (the object's own stretch included), in one undo step; at a caret it leaves the text as it is. - Cmd/Ctrl+Alt+N (`file.newWithoutDialog`) makes a document without opening the New Document dialog, on the key the reference app's [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page lists for making a new document with no New Document dialog box. The page does not say which settings the document gets. VectorCraft gives it the settings the dialog opens on (the first Recent entry, or the Print category's Letter while Recent is empty) and the next untitled name. - Shortcut sets other apps save as text (`.kys`) open in Import Shortcut Set from File › Open, from Edit › Keyboard Shortcuts › Import… in the desktop app, or from a drop on the window. It matches each entry to a tool, command or panel by name and decodes the file's key and modifier codes where VectorCraft's default shortcuts agree on them; the user answers the rest, and Apply fills the Keyboard Shortcuts dialog's working set. The answers are kept with the preferences for the next import (`shortcutSet.read`, `importMatches.*`).+ - On Linux the app bar is the title bar on every desktop, KDE Plasma, Sway, Hyprland, COSMIC and X11 window managers included, unless Preferences › User Interface › System Title Bar gives the window the desktop's frame; `VECTORCRAFT_TITLEBAR=app` or `=system` chooses the frame for one run. - On Windows and Linux the app bar is the window's title bar (its own minimize, maximize and close buttons, drag to move, edges to resize), with the dragon app icon as the brand mark; dialogs and menus size to their content. As on a native menu bar, once one menu is open, moving the pointer onto another title opens that one. - **Tools:** - **Shaper:** uneven squares and rectangles become live rectangles even when drawing begins mid-edge. Recognition uses uniformly spaced samples and closed-loop corners, fits rectangle edges/angles rather than requiring a nearly perfect bounding-box fill, and includes the pointer-release position. Rectangles/squares and ellipses snap to 45° steps, hexagons to 90°, and triangles point up or down; lines keep their free angle even with Shift. Shaper Groups retain the live originals, merge regions with the gesture-origin fill, punch fills independently from strokes, remove boundaries on exiting scribbles and trim protruding stroke pieces. Source moves/resizes re-evaluate the result in the same undo step; double-click enters construction editing, and with the Shaper or Selection tool a click on the arrow widget beside a Shaper Group's original shapes switches the group between Face Selection and Construction mode. Native save/reopen, face recoloring, Release and Expand are covered. Finer gesture heuristics remain.