macOS 上点关闭按钮改为把 ShellRS 隐藏到后台:连接、传输和端口转发照常运行,点 Dock 图标恢复窗口,⌘Q 才退出
This commit is contained in:
1 parent
bcf2db0413
commit
ef2bd8c3a6
7 files changed
+77
-32
No files matched your search
@@ -4,6 +4,7 @@ mod actions;
|
||||
mod app_icon;
|
||||
mod assets;
|
||||
mod paths;
|
||||
mod window_hiding;
|
||||
|
||||
pub use actions::*;
|
||||
pub use app_icon::show_logo_when_unbundled;
|
||||
@@ -11,6 +12,7 @@ pub use assets::{AppAssets, CatalogIcon};
|
||||
pub use paths::{
|
||||
cli_endpoint, cli_socket_path, data_dir, database_path, keys_dir, settings_path, updates_dir,
|
||||
};
|
||||
pub use window_hiding::{bring_forward, hide_when_closed};
|
||||
|
||||
use gpui_kit::component::{Theme, dock::ToggleZoom};
|
||||
use gpui_kit::*;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
//! On macOS the window's close button hides ShellRS instead of closing it.
|
||||
//!
|
||||
//! ShellRS has one window, and the workspace in it owns everything that
|
||||
//! runs: connections, transfers, port forwards, the external CLI. Closing
|
||||
//! it would stop all of that yet leave the app in the Dock with no window,
|
||||
//! and the Dock icon could not bring one back. So, like Mac terminals,
|
||||
//! closing hides the app: the Dock icon, ⌘Tab or opening ShellRS again
|
||||
//! shows the window as it was, and ⌘Q quits. Windows and Linux quit when
|
||||
//! the window closes, as GPUI does there by default.
|
||||
|
||||
use gpui_kit::{App, Window};
|
||||
|
||||
/// Make the window's close button hide ShellRS. Nothing outside macOS.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn hide_when_closed(window: &Window, cx: &App) {
|
||||
window.on_window_should_close(cx, |_, cx| {
|
||||
cx.hide();
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn hide_when_closed(_: &Window, _: &App) {}
|
||||
|
||||
/// Show the window again, in front of other apps: when the Dock icon is
|
||||
/// clicked, or ShellRS is opened again while it runs.
|
||||
pub fn bring_forward(window: &mut Window, cx: &mut App) {
|
||||
// Activating alone may leave a hidden app's windows hidden.
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Some(main_thread) = objc2::MainThreadMarker::new() {
|
||||
objc2_app_kit::NSApplication::sharedApplication(main_thread).unhide(None);
|
||||
}
|
||||
cx.activate(true);
|
||||
window.activate_window();
|
||||
}
|
||||
+35
-30
@@ -22,38 +22,43 @@ fn main() {
|
||||
if shellrs::cli::activate_running_app(&shellrs::app::cli_socket_path()) {
|
||||
return;
|
||||
}
|
||||
gpui_kit::application()
|
||||
.with_assets(shellrs::app::AppAssets)
|
||||
.run(|cx| {
|
||||
shellrs::init(cx);
|
||||
shellrs::app::show_logo_when_unbundled(cx);
|
||||
cx.activate(true);
|
||||
let app = gpui_kit::application().with_assets(shellrs::app::AppAssets);
|
||||
// macOS: the Dock icon of a ShellRS whose window was closed, which only
|
||||
// hid it (see `hide_when_closed`).
|
||||
app.on_reopen(|cx| {
|
||||
if let Some(window) = cx.windows().first().copied() {
|
||||
window
|
||||
.update(cx, |_, window, cx| shellrs::app::bring_forward(window, cx))
|
||||
.ok();
|
||||
}
|
||||
});
|
||||
app.run(|cx| {
|
||||
shellrs::init(cx);
|
||||
shellrs::app::show_logo_when_unbundled(cx);
|
||||
cx.activate(true);
|
||||
|
||||
let options = shellrs::workspace::window_options(cx);
|
||||
cx.spawn(async move |cx| {
|
||||
cx.open_window(options, |window, cx| {
|
||||
window.activate_window();
|
||||
window.set_window_title("ShellRS");
|
||||
let (store, problem) = open_store();
|
||||
let store = cx.new(|_| store);
|
||||
let (settings, settings_problem) = open_settings();
|
||||
let settings = cx.new(|_| settings);
|
||||
let workspace = cx
|
||||
.new(|cx| shellrs::workspace::Workspace::new(store, settings, window, cx));
|
||||
// Not pushed here: the window has no `Root` to show it yet.
|
||||
for problem in [problem, settings_problem].into_iter().flatten() {
|
||||
shellrs::workspace::notify_once_open(
|
||||
Notification::error(problem),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
cx.new(|cx| Root::new(workspace, window, cx))
|
||||
})
|
||||
.expect("failed to open window");
|
||||
let options = shellrs::workspace::window_options(cx);
|
||||
cx.spawn(async move |cx| {
|
||||
cx.open_window(options, |window, cx| {
|
||||
window.activate_window();
|
||||
window.set_window_title("ShellRS");
|
||||
shellrs::app::hide_when_closed(window, cx);
|
||||
let (store, problem) = open_store();
|
||||
let store = cx.new(|_| store);
|
||||
let (settings, settings_problem) = open_settings();
|
||||
let settings = cx.new(|_| settings);
|
||||
let workspace =
|
||||
cx.new(|cx| shellrs::workspace::Workspace::new(store, settings, window, cx));
|
||||
// Not pushed here: the window has no `Root` to show it yet.
|
||||
for problem in [problem, settings_problem].into_iter().flatten() {
|
||||
shellrs::workspace::notify_once_open(Notification::error(problem), window, cx);
|
||||
}
|
||||
cx.new(|cx| Root::new(workspace, window, cx))
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
.expect("failed to open window");
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
// On Windows the event loop ends and `run` returns: an update that is
|
||||
// to be installed now starts its setup, which waits for this process.
|
||||
shellrs::update::start_handed_over();
|
||||
|
||||
@@ -251,8 +251,7 @@ impl Workspace {
|
||||
.as_ref()
|
||||
.is_some_and(|server| server.take_activation());
|
||||
if asked {
|
||||
cx.activate(true);
|
||||
window.activate_window();
|
||||
crate::app::bring_forward(window, cx);
|
||||
}
|
||||
});
|
||||
if open.is_err() {
|
||||
|
||||
Reference in new issue
Block a user