Skip to content
93 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

The desktop app draws its own title bar, as Slack and Discord do, and the site can call the app again.1//! The window's frame. g1t draws its own title bar, as Slack and Discord
2//! do, so the window is all g1t and looks the same on every system: on
3//! Windows and Linux the system's frame goes and the bar has the menu
4//! button, back and forward, search, and minimize, maximize and close; on
5//! macOS the bar sits under the window's own traffic lights. The bar
6//! itself is bridge.js's, drawn on every page the window shows, the
7//! site's, the launcher's, and GitHub's while signing in; the site makes
8//! room for it (`--frame-top`, apps/web/app/app.css). Settings can give
9//! the window back its system frame, and the menu bar with it, from the
10//! next start: the bar is a script each window gets as it opens.
11
12use tauri::{AppHandle, LogicalPosition, Manager, Runtime, WebviewWindow, WebviewWindowBuilder};
13
14use crate::{WINDOW, config, tray};
15
16/// The bar's height, in CSS pixels; bridge.js draws it this tall.
17pub const HEIGHT: f64 = 36.0;
18
19/// Whether g1t draws its own title bar, as the settings say now.
20pub fn custom(app: &AppHandle) -> bool {
21 !config::settings(app).system_title_bar
22}
23
24/// The title bar g1t started with, which its windows keep until it restarts.
25static STARTED_CUSTOM: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
26
27/// Whether this run draws g1t's own title bar: decided once, at the start.
28pub fn started(app: &AppHandle) -> bool {
29 *STARTED_CUSTOM.get_or_init(|| custom(app))
30}
31
32/// A window with g1t's title bar, or the system's.
33pub fn style<'a, R: Runtime, M: Manager<R>>(builder: WebviewWindowBuilder<'a, R, M>, custom: bool) -> WebviewWindowBuilder<'a, R, M> {
34 if !custom {
35 return builder;
36 }
37 #[cfg(target_os = "macos")]
38 {
39 // The traffic lights stay, over the bar and centred in it.
40 builder
41 .title_bar_style(tauri::TitleBarStyle::Overlay)
42 .hidden_title(true)
43 .traffic_light_position(LogicalPosition::new(14.0, (HEIGHT - 14.0) / 2.0))
44 }
45 #[cfg(not(target_os = "macos"))]
46 {
47 builder.decorations(false)
48 }
49}
50
51/// The main window's menu bar: shown under the system's frame, and kept
52/// hidden under g1t's, whose menu button opens the same menu (`menu`) and
53/// whose shortcuts still work.
54pub fn menu_bar(window: &WebviewWindow, custom: bool) {
55 let _ = if custom { window.hide_menu() } else { window.show_menu() };
56 // GTK shows everything in a window each time the window is shown, the
57 // hidden menu bar too, unless the menu bar is told to sit that out.
58 #[cfg(target_os = "linux")]
59 if let Ok(vbox) = window.default_vbox() {
60 use gtk::prelude::*;
61 for child in vbox.children().into_iter().filter(|child| child.is::<gtk::MenuBar>()) {
62 child.set_no_show_all(custom);
63 }
64 }
65}
66
67/// What a button on the bar asks of the window it is in.
68pub fn control(app: &AppHandle, window: &WebviewWindow, action: &str) -> Result<bool, String> {
69 let main = window.label() == WINDOW;
70 match action {
71 "minimize" => window.minimize().map_err(|error| error.to_string())?,
72 "maximize" => {
73 let maximized = window.is_maximized().unwrap_or(false);
74 let _ = if maximized { window.unmaximize() } else { window.maximize() };
75 }
76 "close" if main => tray::close(app),
77 "close" => window.close().map_err(|error| error.to_string())?,
78 "drag" => window.start_dragging().map_err(|error| error.to_string())?,
79 "maximized" => {}
80 other => return Err(format!("the window cannot {other}")),
81 }
82 Ok(window.is_maximized().unwrap_or(false))
83}
84
85/// The menu button: the window's menu, under the button.
86pub fn menu(window: &WebviewWindow, x: f64, y: f64) -> Result<(), String> {
87 #[cfg(target_os = "macos")]
88 let menu = window.app_handle().menu();
89 #[cfg(not(target_os = "macos"))]
90 let menu = window.menu();
91 let menu = menu.ok_or("the window has no menu")?;
92 window.popup_menu_at(&menu, LogicalPosition::new(x, y)).map_err(|error| error.to_string())
93}