Implement Ctrl+w and Alt+F4 to close the current activity

Mouse not required

This is done by sending StopCommand to shepherdd, not by natively
closing the window. Sway initiates this to avoid any issues with
shepherd-launcher not having focus (as it won't when an activity is
running).
This commit is contained in:
Albert Armea 2026-02-08 13:54:17 -05:00
parent 64ee1d7bc6
commit b840a7d694
3 changed files with 55 additions and 4 deletions

View file

@ -9,8 +9,10 @@ mod grid;
mod state; mod state;
mod tile; mod tile;
use crate::client::CommandClient;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use shepherd_api::{ErrorCode, ResponsePayload, ResponseResult};
use shepherd_util::default_socket_path; use shepherd_util::default_socket_path;
use std::path::PathBuf; use std::path::PathBuf;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
@ -27,6 +29,10 @@ struct Args {
/// Log level /// Log level
#[arg(short, long, default_value = "info")] #[arg(short, long, default_value = "info")]
log_level: String, log_level: String,
/// Send StopCurrent to shepherdd and exit (for compositor keybindings)
#[arg(long)]
stop_current: bool,
} }
fn main() -> Result<()> { fn main() -> Result<()> {
@ -35,8 +41,7 @@ fn main() -> Result<()> {
// Initialize logging // Initialize logging
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter( .with_env_filter(
EnvFilter::try_from_default_env() EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(&args.log_level)),
.unwrap_or_else(|_| EnvFilter::new(&args.log_level)),
) )
.init(); .init();
@ -45,6 +50,33 @@ fn main() -> Result<()> {
// Determine socket path with fallback to default // Determine socket path with fallback to default
let socket_path = args.socket.unwrap_or_else(default_socket_path); let socket_path = args.socket.unwrap_or_else(default_socket_path);
if args.stop_current {
let runtime = tokio::runtime::Runtime::new()?;
runtime.block_on(async move {
let client = CommandClient::new(&socket_path);
match client.stop_current().await {
Ok(response) => match response.result {
ResponseResult::Ok(ResponsePayload::Stopped) => {
tracing::info!("StopCurrent succeeded");
Ok(())
}
ResponseResult::Err(err) if err.code == ErrorCode::NoActiveSession => {
tracing::debug!("No active session to stop");
Ok(())
}
ResponseResult::Err(err) => {
anyhow::bail!("StopCurrent failed: {}", err.message)
}
ResponseResult::Ok(payload) => {
anyhow::bail!("Unexpected StopCurrent response: {:?}", payload)
}
},
Err(e) => anyhow::bail!("Failed to send StopCurrent: {}", e),
}
})?;
return Ok(());
}
// Run GTK application // Run GTK application
let application = app::LauncherApp::new(socket_path); let application = app::LauncherApp::new(socket_path);
let exit_code = application.run(); let exit_code = application.run();

View file

@ -0,0 +1,15 @@
# Sway StopCurrent Keybinds
Prompt summary:
- Move keyboard exit handling out of launcher UI code and into `sway.conf`.
- Keep controller home behavior as-is.
- Ensure "exit" uses the API (`StopCurrent`) rather than closing windows directly.
Implemented summary:
- Added a `--stop-current` mode to `shepherd-launcher` that sends `StopCurrent` to shepherdd over IPC and exits.
- Added Sway keybindings for `Alt+F4`, `Ctrl+W`, and `Home` that execute `shepherd-launcher --stop-current`.
- Kept controller home behavior in launcher UI unchanged.
Key files:
- `sway.conf`
- `crates/shepherd-launcher-ui/src/main.rs`

View file

@ -11,6 +11,7 @@ exec_always dbus-update-activation-environment --systemd \
### Variables ### Variables
set $launcher ./target/debug/shepherd-launcher set $launcher ./target/debug/shepherd-launcher
set $hud ./target/debug/shepherd-hud set $hud ./target/debug/shepherd-hud
set $stop_current $launcher --stop-current
### Output configuration ### Output configuration
# Set up displays (adjust as needed for your hardware) # Set up displays (adjust as needed for your hardware)
@ -129,8 +130,11 @@ focus_follows_mouse no
# Hide any title/tab text by using minimal font size # Hide any title/tab text by using minimal font size
font pango:monospace 1 font pango:monospace 1
# Prevent window closing via keybindings (no Alt+F4) # Session stop keybindings via shepherdd API (does not close windows directly)
# Windows can only be closed by the application itself # Handled in sway so they work regardless of which client currently has focus.
bindsym --locked Alt+F4 exec $stop_current
bindsym --locked Ctrl+w exec $stop_current
bindsym --locked Home exec $stop_current
# Hide mouse cursor after inactivity # Hide mouse cursor after inactivity
seat * hide_cursor 5000 seat * hide_cursor 5000