From 046c23981696bc14f5a040addd0d88fbee4479e3 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 24 Dec 2025 18:04:49 -0800 Subject: [PATCH] Add support for alt-backtick switching --- src/app.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/src/app.rs b/src/app.rs index 1020bb3..bf36480 100644 --- a/src/app.rs +++ b/src/app.rs @@ -76,6 +76,10 @@ pub enum LauncherTasks { Input { input: Option }, #[clap(about = "Close the launcher if open")] Close, + #[clap(about = "Switch to the next window of the current application")] + AltBacktick, + #[clap(about = "Switch to the previous window of the current application")] + ShiftAltBacktick, } impl Display for LauncherTasks { @@ -151,6 +155,7 @@ pub struct CosmicLauncher { focused: usize, last_hide: Instant, alt_tab: bool, + alt_backtick: Option, window_id: window::Id, queue: VecDeque, result_ids: Vec, @@ -180,6 +185,8 @@ pub enum Message { ActivationToken(Option, String, String, GpuPreference, bool), AltTab, ShiftAltTab, + AltBacktick, + ShiftAltBacktick, Opened(Size, window::Id), AltRelease, Overlap(OverlapNotifyEvent), @@ -221,6 +228,7 @@ impl CosmicLauncher { self.input_value.clear(); self.focused = 0; self.alt_tab = false; + self.alt_backtick = None; self.queue.clear(); self.hand_over.clear(); @@ -330,6 +338,7 @@ impl cosmic::Application for CosmicLauncher { focused: 0, last_hide: Instant::now(), alt_tab: false, + alt_backtick: None, window_id: SurfaceId::unique(), queue: VecDeque::new(), result_ids: (0..10) @@ -527,6 +536,35 @@ impl cosmic::Application for CosmicLauncher { let b = i32::from(b.window.is_none()); a.cmp(&b) }); + + // Filter for Alt-Backtick mode: show only windows of the current application + if let Some(ref app_name) = self.alt_backtick { + if app_name.is_empty() { + // First invocation: determine current app from first window + if let Some(first_window) = + list.iter().find(|item| item.window.is_some()) + { + let app_name_to_filter = first_window.name.clone(); + self.alt_backtick = Some(app_name_to_filter.clone()); + list.retain(|item| { + item.window.is_some() && item.name == app_name_to_filter + }); + } else { + return self.hide(); // No windows found + } + } else { + // Already have app name, filter by it + let app_name_clone = app_name.clone(); + list.retain(|item| { + item.window.is_some() && item.name == app_name_clone + }); + } + + if list.is_empty() { + return self.hide(); + } + } + self.launcher_items.splice(.., list); if self.result_ids.len() < self.launcher_items.len() { self.result_ids.extend( @@ -709,8 +747,34 @@ impl cosmic::Application for CosmicLauncher { }, ); } + Message::AltBacktick => { + self.focus_next(); + return operation::snap_to( + SCROLLABLE.clone(), + RelativeOffset { + x: None, + y: Some( + (self.focused as f32 / (self.launcher_items.len() as f32 - 1.).max(1.)) + .max(0.0), + ), + }, + ); + } + Message::ShiftAltBacktick => { + self.focus_previous(); + return operation::snap_to( + SCROLLABLE.clone(), + RelativeOffset { + x: None, + y: Some( + (self.focused as f32 / (self.launcher_items.len() as f32 - 1.).max(1.)) + .max(0.0), + ), + }, + ); + } Message::AltRelease => { - if self.alt_tab { + if self.alt_tab || self.alt_backtick.is_some() { return self.update(Message::Activate(None)); } } @@ -779,6 +843,24 @@ impl cosmic::Application for CosmicLauncher { LauncherTasks::Close => { return self.update(Message::Hide); } + LauncherTasks::AltBacktick => { + if self.alt_backtick.is_some() { + return self.update(Message::AltBacktick); + } + + self.alt_backtick = Some(String::new()); + self.request(launcher::Request::Search(String::new())); + self.queue.push_back(Message::AltBacktick); + } + LauncherTasks::ShiftAltBacktick => { + if self.alt_backtick.is_some() { + return self.update(Message::ShiftAltBacktick); + } + + self.alt_backtick = Some(String::new()); + self.request(launcher::Request::Search(String::new())); + self.queue.push_back(Message::ShiftAltBacktick); + } } } Details::Open { .. } => {} @@ -846,6 +928,7 @@ impl cosmic::Application for CosmicLauncher { let mut button_content = Vec::new(); if !self.alt_tab + && self.alt_backtick.is_none() && let Some(source) = item.category_icon.as_ref() { let icon_handle = match source { @@ -980,7 +1063,7 @@ impl cosmic::Application for CosmicLauncher { }) .collect(); - let mut content = if self.alt_tab { + let mut content = if self.alt_tab || self.alt_backtick.is_some() { Column::new() .max_width(600) .spacing(16)