Skip to content

Commit 0fce819

Browse files
committed
Window now closes instead of hiding
1 parent 5050f82 commit 0fce819

8 files changed

Lines changed: 149 additions & 97 deletions

File tree

src/cli.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ xflags! {
1414
}
1515

1616
/// Open the Waystart window.
17-
cmd show {}
17+
cmd open {}
1818

19-
/// Hide the Waystart window.
20-
cmd hide {}
19+
/// Close the Waystart window.
20+
cmd close {}
21+
22+
/// Open/close the Waystart window.
23+
cmd toggle {}
2124
}
2225
}
2326

@@ -33,8 +36,9 @@ pub struct Waystart {
3336
pub enum WaystartCmd {
3437
Standalone(Standalone),
3538
Daemon(Daemon),
36-
Show(Show),
37-
Hide(Hide),
39+
Open(Open),
40+
Close(Close),
41+
Toggle(Toggle),
3842
}
3943

4044
#[derive(Debug)]
@@ -46,10 +50,13 @@ pub struct Daemon {
4650
}
4751

4852
#[derive(Debug)]
49-
pub struct Show;
53+
pub struct Open;
54+
55+
#[derive(Debug)]
56+
pub struct Close;
5057

5158
#[derive(Debug)]
52-
pub struct Hide;
59+
pub struct Toggle;
5360

5461
impl Waystart {
5562
#[allow(dead_code)]

src/ipc/client.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::cell::RefCell;
22
use std::io::Write;
33
use std::os::unix::net::UnixStream;
44

5-
use crate::ipc::{MESSAGE_HIDE, MESSAGE_QUIT, MESSAGE_SHOW, SOCKET_PATH};
5+
use crate::ipc::{MESSAGE_CLOSE, MESSAGE_OPEN, MESSAGE_QUIT, MESSAGE_TOGGLE, SOCKET_PATH};
66

77
pub struct SocketClient {
88
stream: RefCell<UnixStream>,
@@ -22,8 +22,9 @@ impl SocketClient {
2222
pub fn send_message_socket(&self, message: SocketMessage) {
2323
let mut stream = self.stream.borrow_mut();
2424
if let Err(e) = match message {
25-
SocketMessage::Show => stream.write_all(MESSAGE_SHOW),
26-
SocketMessage::Hide => stream.write_all(MESSAGE_HIDE),
25+
SocketMessage::Open => stream.write_all(MESSAGE_OPEN),
26+
SocketMessage::Close => stream.write_all(MESSAGE_CLOSE),
27+
SocketMessage::Toggle => stream.write_all(MESSAGE_TOGGLE),
2728
SocketMessage::Quit => stream.write_all(MESSAGE_QUIT),
2829
} {
2930
eprintln!("Failed to send IPC message: {}", e);
@@ -32,7 +33,8 @@ impl SocketClient {
3233
}
3334

3435
pub enum SocketMessage {
35-
Show,
36-
Hide,
36+
Open,
37+
Close,
38+
Toggle,
3739
Quit,
3840
}

src/ipc/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod server;
33

44
const SOCKET_PATH: &str = "/tmp/waystart.sock";
55

6-
const MESSAGE_SHOW: &[u8] = b"show";
7-
const MESSAGE_HIDE: &[u8] = b"hide";
6+
const MESSAGE_OPEN: &[u8] = b"open";
7+
const MESSAGE_CLOSE: &[u8] = b"close";
8+
const MESSAGE_TOGGLE: &[u8] = b"toggle";
89
const MESSAGE_QUIT: &[u8] = b"quit";

src/ipc/server.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
1+
use std::cell::RefCell;
2+
use std::rc::Rc;
3+
14
use smol::io::{AsyncBufReadExt, BufReader};
25
use smol::net::unix::{UnixListener, UnixStream};
36
use smol::stream::StreamExt;
47

5-
use gpui::{AsyncApp, BorrowAppContext, WindowHandle};
8+
use gpui::{AsyncApp, Entity, WindowHandle};
69

7-
use crate::entries::SearchEntries;
8-
use crate::ipc::{MESSAGE_HIDE, MESSAGE_QUIT, MESSAGE_SHOW, SOCKET_PATH};
10+
use crate::ipc::*;
11+
use crate::open_window;
912
use crate::ui::Waystart;
1013

1114
#[derive(Clone)]
1215
pub struct SocketServer {
1316
app: AsyncApp,
14-
window: WindowHandle<Waystart>,
17+
waystart: Entity<Waystart>,
18+
window: Rc<RefCell<Option<WindowHandle<Waystart>>>>,
1519
}
1620

1721
impl SocketServer {
18-
pub fn new(app: AsyncApp, window: WindowHandle<Waystart>) -> Self {
19-
Self { app, window }
22+
pub fn new(app: AsyncApp, waystart: Entity<Waystart>) -> Self {
23+
Self {
24+
app,
25+
waystart,
26+
window: Rc::new(RefCell::new(None)),
27+
}
2028
}
2129

2230
pub fn listen(&self) {
@@ -32,8 +40,10 @@ impl SocketServer {
3240
loop {
3341
match listener.accept().await {
3442
Ok((stream, _)) => {
43+
let window = this.window.clone();
44+
let waystart = this.waystart.clone();
3545
cx.spawn(async move |cx| {
36-
Self::handle_ipc_stream(stream, this.window, cx).await
46+
Self::handle_ipc_stream(stream, window, waystart, cx).await
3747
})
3848
.detach();
3949
}
@@ -48,20 +58,43 @@ impl SocketServer {
4858

4959
async fn handle_ipc_stream(
5060
stream: UnixStream,
51-
window: WindowHandle<Waystart>,
61+
window: Rc<RefCell<Option<WindowHandle<Waystart>>>>,
62+
waystart: Entity<Waystart>,
5263
cx: &mut AsyncApp,
5364
) {
5465
let reader = BufReader::new(stream);
5566
let mut lines = reader.lines();
5667

5768
while let Some(Ok(message)) = lines.next().await {
5869
if let Err(e) = match message.as_bytes() {
59-
MESSAGE_SHOW => window.update(cx, |waystart, window, cx| {
60-
cx.update_global(|entries: &mut SearchEntries, _| entries.sort_by_frequency());
61-
waystart.reset_search(cx);
62-
window.activate_window();
70+
MESSAGE_OPEN => cx.update(|cx| {
71+
let mut window = window.borrow_mut();
72+
if window.map(|w| w.is_active(cx).is_none()).unwrap_or(true) {
73+
*window = Some(open_window(cx, waystart.clone()));
74+
}
75+
}),
76+
MESSAGE_CLOSE => cx.update(|cx| {
77+
let mut window = window.borrow_mut();
78+
if let Some(window) = window.take()
79+
&& window.is_active(cx).is_some()
80+
{
81+
window
82+
.update(cx, |_, window, _| window.remove_window())
83+
.unwrap();
84+
}
85+
}),
86+
MESSAGE_TOGGLE => cx.update(|cx| {
87+
let mut window = window.borrow_mut();
88+
if let Some(window) = window.take()
89+
&& window.is_active(cx).is_some()
90+
{
91+
window
92+
.update(cx, |_, window, _| window.remove_window())
93+
.unwrap();
94+
} else {
95+
*window = Some(open_window(cx, waystart.clone()));
96+
}
6397
}),
64-
MESSAGE_HIDE => cx.update(|cx| cx.hide()),
6598
MESSAGE_QUIT => cx.update(|cx| cx.quit()),
6699
_ => {
67100
eprintln!("Received unknown IPC message: {}", message);

src/main.rs

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use gpui::{
2-
AppContext, Application, Bounds, Focusable, TitlebarOptions, WindowBounds, WindowDecorations,
3-
WindowKind, WindowOptions, point, px, size,
2+
App, AppContext, Application, BorrowAppContext, Bounds, Entity, Focusable, TitlebarOptions,
3+
WindowBounds, WindowDecorations, WindowHandle, WindowKind, WindowOptions, point, px, size,
44
};
55

66
use crate::config::Config;
77
use crate::entries::SearchEntries;
88
use crate::ipc::client::{SocketClient, SocketMessage};
99
use crate::ipc::server::SocketServer;
10-
use crate::ui::{CloseWaystart, Waystart};
10+
use crate::ui::Waystart;
1111

1212
mod cli;
1313
mod config;
@@ -16,79 +16,85 @@ mod ipc;
1616
mod ui;
1717

1818
fn main() {
19-
match cli::Waystart::from_env_or_exit().subcommand {
20-
cli::WaystartCmd::Standalone(_) => match SocketClient::try_connect().ok() {
21-
Some(client) => client.send_message_socket(SocketMessage::Show),
22-
None => {
23-
start_app(false);
19+
let daemon = match cli::Waystart::from_env_or_exit().subcommand {
20+
cli::WaystartCmd::Standalone(_) => {
21+
if let Ok(client) = SocketClient::try_connect() {
22+
client.send_message_socket(SocketMessage::Open);
23+
return;
2424
}
25-
},
26-
25+
// Start without daemon
26+
false
27+
}
2728
cli::WaystartCmd::Daemon(daemon) => {
2829
if daemon.exit {
2930
let client = SocketClient::connect();
3031
client.send_message_socket(SocketMessage::Quit);
31-
} else {
32-
start_app(true);
32+
return;
3333
}
34+
// Start with daemon
35+
true
3436
}
35-
36-
cli::WaystartCmd::Show(_) => {
37+
cli::WaystartCmd::Open(_) => {
3738
let client = SocketClient::connect();
38-
client.send_message_socket(SocketMessage::Show);
39+
client.send_message_socket(SocketMessage::Open);
40+
return;
3941
}
40-
41-
cli::WaystartCmd::Hide(_) => {
42+
cli::WaystartCmd::Close(_) => {
4243
let client = SocketClient::connect();
43-
client.send_message_socket(SocketMessage::Hide);
44+
client.send_message_socket(SocketMessage::Close);
45+
return;
4446
}
45-
}
46-
}
47+
cli::WaystartCmd::Toggle(_) => {
48+
let client = SocketClient::connect();
49+
client.send_message_socket(SocketMessage::Toggle);
50+
return;
51+
}
52+
};
4753

48-
fn start_app(daemonize: bool) {
4954
Application::new()
5055
.with_assets(ui::Assets)
51-
.keep_running(daemonize)
56+
.keep_running(daemon)
5257
.run(move |cx| {
5358
ui::init(cx);
5459
cx.set_global(SearchEntries::load());
5560
cx.set_global(Config::load());
56-
cx.on_action(move |_: &CloseWaystart, cx| {
57-
if daemonize {
58-
cx.hide();
59-
} else {
60-
cx.quit();
61-
}
62-
});
6361

64-
let bounds = Bounds::centered(None, size(px(800.), px(500.)), cx);
65-
let window = cx
66-
.open_window(
67-
WindowOptions {
68-
kind: WindowKind::PopUp,
69-
is_movable: true,
70-
show: !daemonize,
71-
focus: !daemonize,
72-
window_bounds: Some(WindowBounds::Windowed(bounds)),
73-
window_decorations: Some(WindowDecorations::Client),
74-
titlebar: Some(TitlebarOptions {
75-
title: Some("Waystart".into()),
76-
appears_transparent: true,
77-
traffic_light_position: Some(point(px(-100.0), px(0.0))),
78-
}),
79-
..Default::default()
80-
},
81-
|window, cx| {
82-
let root = cx.new(Waystart::new);
83-
window.focus(&root.focus_handle(cx));
84-
root
85-
},
86-
)
87-
.unwrap();
62+
let waystart = cx.new(Waystart::new);
8863

89-
if daemonize {
90-
let server = SocketServer::new(cx.to_async(), window);
64+
if daemon {
65+
let server = SocketServer::new(cx.to_async(), waystart);
9166
server.listen();
67+
} else {
68+
open_window(cx, waystart);
9269
}
9370
});
9471
}
72+
73+
pub fn open_window(cx: &mut App, waystart: Entity<Waystart>) -> WindowHandle<Waystart> {
74+
cx.update_global(|entries: &mut SearchEntries, _| entries.sort_by_frequency());
75+
cx.update_entity(&waystart, |waystart: &mut Waystart, cx| {
76+
waystart.reset_search(cx)
77+
});
78+
79+
let bounds = Bounds::centered(None, size(px(800.), px(500.)), cx);
80+
cx.open_window(
81+
WindowOptions {
82+
kind: WindowKind::PopUp,
83+
is_resizable: false,
84+
is_minimizable: false,
85+
window_bounds: Some(WindowBounds::Windowed(bounds)),
86+
window_decorations: Some(WindowDecorations::Client),
87+
titlebar: Some(TitlebarOptions {
88+
title: Some("Waystart".into()),
89+
appears_transparent: true,
90+
traffic_light_position: Some(point(px(-100.0), px(0.0))),
91+
}),
92+
..Default::default()
93+
},
94+
|window, cx| {
95+
window.focus(&waystart.focus_handle(cx));
96+
waystart
97+
},
98+
)
99+
.unwrap()
100+
}

src/ui/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod power_options;
88
mod waystart;
99

1010
pub use power_options::PowerOptions;
11-
pub use waystart::{Close as CloseWaystart, Waystart};
11+
pub use waystart::Waystart;
1212

1313
pub fn init(cx: &mut App) {
1414
waystart::init(cx);

0 commit comments

Comments
 (0)