Merge pull request #5211 from dotCooCoo/fix/brand-mark-under-desktop-frame

Title bar: the app bar shows no brand mark under the desktop's own frame
This commit is contained in:
BFlat
2026-11-09 01:17:32 +08:00
committed by GitHub
6 changed files with 51 additions and 7 deletions
+1
View File
@@ -467,6 +467,7 @@ fn main() -> std::process::ExitCode {
rs.device.set_device_lost_callback(move |reason, msg| loss.report(&ctx, format!("{reason:?}: {msg}")));
}
app.custom_titlebar = custom_titlebar;
app.desktop_frame = !custom_titlebar;
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());
+1
View File
@@ -123,6 +123,7 @@ impl VectorcraftApp {
canvas_rect: None,
hover_doc: None,
custom_titlebar: false,
desktop_frame: false,
last_window_title: String::new(),
fullscreen_for_mode: false,
graphics_adapter: None,
+8 -6
View File
@@ -129,13 +129,15 @@ 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.
/// Whether the window shows the system's title bar instead of the app drawing its own
/// ([`VectorcraftApp::desktop_frame`]): Windows with Preferences › User Interface › System Title
/// Bar, and Linux whenever the desktop draws the frame, with or without the preference. The
/// preference is read when the app starts, so changing it later does not change this. 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
/// without a window of its own.
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.desktop_frame && !app.custom_titlebar && !cfg!(any(target_os = "macos", target_arch = "wasm32"))
}
/// The OS window title: the active document's name suffixed with the app name (a `*` prefix
+35
View File
@@ -1230,16 +1230,51 @@ fn the_zoom_hint_follows_animated_zoom() {
fn title_test_app(custom_titlebar: bool) -> crate::VectorcraftApp {
let mut app = crate::VectorcraftApp::new(Session::new(), Default::default());
app.custom_titlebar = custom_titlebar;
app.desktop_frame = !custom_titlebar;
// The preference that makes the shell launch without its own title bar.
app.run("prefs.set", json!({"key": "systemTitleBar", "value": !custom_titlebar})).unwrap();
app
}
/// How many brand marks one frame of the app bar paints.
fn brand_marks(app: &mut crate::VectorcraftApp) -> usize {
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
let mut out = ctx.run_ui(egui::RawInput::default(), |ui| super::app_bar(app, ui));
out.textures_delta.clear();
out.shapes.iter().filter(|c| matches!(&c.shape, egui::Shape::Mesh(m) if m.texture_id == crate::brand::texture_id(&ctx))).count()
}
#[test]
fn without_the_preference_the_mark_stays() {
// The default (e.g. the web build): no custom bar, no preference.
let app = crate::VectorcraftApp::new(Session::new(), Default::default());
assert!(!super::system_title_bar(&app));
// An embedder without a window of its own keeps the mark with the preference on too.
let mut app = crate::VectorcraftApp::new(Session::new(), Default::default());
app.run("prefs.set", json!({"key": "systemTitleBar", "value": true})).unwrap();
assert!(!super::system_title_bar(&app));
assert_eq!(brand_marks(&mut app), 1);
}
#[test]
fn a_desktop_frame_hides_the_mark_whatever_the_preference_says() {
// Linux on a desktop that draws the frame (KDE, X11): the window has the desktop's title bar
// with System Title Bar off.
let mut app = crate::VectorcraftApp::new(Session::new(), Default::default());
app.desktop_frame = true;
app.run("prefs.set", json!({"key": "systemTitleBar", "value": false})).unwrap();
let hidden = !cfg!(target_os = "macos");
assert_eq!(super::system_title_bar(&app), hidden);
assert_eq!(brand_marks(&mut app), if hidden { 0 } else { 1 });
// The preference applies at the next start: changing it now leaves the window's frame, and the mark, as they are.
let mut app = title_test_app(false);
app.run("prefs.set", json!({"key": "systemTitleBar", "value": false})).unwrap();
assert_eq!(super::system_title_bar(&app), hidden);
let mut app = title_test_app(true);
app.run("prefs.set", json!({"key": "systemTitleBar", "value": true})).unwrap();
assert!(!super::system_title_bar(&app));
assert_eq!(brand_marks(&mut app), 1);
}
#[test]
+4
View File
@@ -198,6 +198,10 @@ 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,
/// The window has the desktop's own title bar: the OS or the window manager draws its frame,
/// icon and title. Set by the desktop app when it opens the window; `false` for embedders
/// without a window of their own.
pub desktop_frame: 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,
+2 -1
View File
@@ -328,7 +328,8 @@ 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 the app bar also drops its brand mark whenever the desktop draws the window's frame, with
System Title Bar on or off. 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);