Skip to content

Commit

Permalink
feat(launcher): add option to minimize window if focused
Browse files Browse the repository at this point in the history
  • Loading branch information
pachliopta committed Nov 19, 2024
1 parent 944006f commit f2c2cdc
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 14 deletions.
16 changes: 9 additions & 7 deletions docs/modules/Launcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ Optionally displays a launchable set of favourites.

> Type: `launcher`
| | Type | Default | Description |
|--------------|------------|---------|-----------------------------------------------------------------------------------------------------|
| `favorites` | `string[]` | `[]` | List of app IDs (or classes) to always show at the start of the launcher |
| `show_names` | `boolean` | `false` | Whether to show app names on the button label. Names will still show on tooltips when set to false. |
| `show_icons` | `boolean` | `true` | Whether to show app icons on the button. |
| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). |
| `reversed` | `boolean` | `false` | Whether to reverse the order of favorites/items |
| | Type | Default | Description |
|----------------------|------------|---------|-----------------------------------------------------------------------------------------------------|
| `favorites` | `string[]` | `[]` | List of app IDs (or classes) to always show at the start of the launcher |
| `show_names` | `boolean` | `false` | Whether to show app names on the button label. Names will still show on tooltips when set to false. |
| `show_icons` | `boolean` | `true` | Whether to show app icons on the button. |
| `icon_size` | `integer` | `32` | Size to render icon at (image icons only). |
| `reversed` | `boolean` | `false` | Whether to reverse the order of favorites/items |
| `minimize_focused` | `boolean` | `true` | Whether to minimize a focused window when its icon is clicked. Only minimizes single windows. |

<details>
<summary>JSON</summary>

Expand Down
15 changes: 15 additions & 0 deletions src/clients/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub enum Request {
ToplevelInfoAll,
#[cfg(feature = "launcher")]
ToplevelFocus(usize),
#[cfg(feature = "launcher")]
ToplevelMinimize(usize),

#[cfg(feature = "clipboard")]
CopyToClipboard(ClipboardItem),
Expand Down Expand Up @@ -350,6 +352,19 @@ impl Environment {

send!(env.response_tx, Response::Ok);
}
#[cfg(feature = "launcher")]
Msg(Request::ToplevelMinimize(id)) => {
let handle = env
.handles
.iter()
.find(|handle| handle.info().map_or(false, |info| info.id == id));

if let Some(handle) = handle {
handle.minimize();
}

send!(env.response_tx, Response::Ok);
}
#[cfg(feature = "clipboard")]
Msg(Request::CopyToClipboard(item)) => {
env.copy_to_clipboard(item);
Expand Down
5 changes: 5 additions & 0 deletions src/clients/wayland/wlr_foreign_toplevel/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ impl ToplevelHandle {
trace!("Activating handle");
self.handle.activate(seat);
}

pub fn minimize(&self) {
trace!("Minimizing handle");
self.handle.set_minimized();
}
}

#[derive(Debug, Default)]
Expand Down
9 changes: 9 additions & 0 deletions src/clients/wayland/wlr_foreign_toplevel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ impl Client {
}
}

/// Minimizes the toplevel with the provided ID.
#[cfg(feature = "launcher")]
pub fn toplevel_minimize(&self, handle_id: usize) {
match self.send_request(Request::ToplevelMinimize(handle_id)) {
Response::Ok => (),
_ => unreachable!(),
}
}

/// Subscribes to events from toplevels.
pub fn subscribe_toplevels(&self) -> broadcast::Receiver<ToplevelEvent> {
self.toplevel_channel.0.subscribe()
Expand Down
17 changes: 12 additions & 5 deletions src/modules/launcher/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,24 +195,31 @@ impl ItemButton {
style_context.add_class("focused");
}

let menu_state = Rc::new(RwLock::new(MenuState {
num_windows: item.windows.len(),
}));

{
let app_id = item.app_id.clone();
let tx = controller_tx.clone();
let menu_state = menu_state.clone();
button.connect_clicked(move |button| {
// lazy check :| TODO: Improve this
let style_context = button.style_context();
if style_context.has_class("open") {
try_send!(tx, ItemEvent::FocusItem(app_id.clone()));
let menu_state = read_lock!(menu_state);

if style_context.has_class("focused") && menu_state.num_windows == 1 {
try_send!(tx, ItemEvent::MinimizeItem(app_id.clone()));
} else {
try_send!(tx, ItemEvent::FocusItem(app_id.clone()));
}
} else {
try_send!(tx, ItemEvent::OpenItem(app_id.clone()));
}
});
}

let menu_state = Rc::new(RwLock::new(MenuState {
num_windows: item.windows.len(),
}));

{
let app_id = item.app_id.clone();
let tx = tx.clone();
Expand Down
18 changes: 16 additions & 2 deletions src/modules/launcher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ pub struct LauncherModule {
#[serde(default = "crate::config::default_false")]
reversed: bool,

/// Whether to minimize a window if it is focused when clicked.
///
/// **Default**: `true`
#[serde(default = "crate::config::default_true")]
minimize_focused: bool,

/// See [common options](module-level-options#common-options).
#[serde(flatten)]
pub common: Option<CommonConfig>,
Expand Down Expand Up @@ -86,6 +92,7 @@ pub enum ItemEvent {
FocusItem(String),
FocusWindow(usize),
OpenItem(String),
MinimizeItem(String),
}

enum ItemOrWindow {
Expand Down Expand Up @@ -265,6 +272,7 @@ impl Module<gtk::Box> for LauncherModule {
});

// listen to ui events
let minimize_focused = self.minimize_focused;
let wl = context.client::<wayland::Client>();
spawn(async move {
while let Some(event) = rx.recv().await {
Expand Down Expand Up @@ -293,8 +301,10 @@ impl Module<gtk::Box> for LauncherModule {
} else {
send_async!(tx, ModuleUpdateEvent::ClosePopup);

let minimize_window = matches!(event, ItemEvent::MinimizeItem(_));

let id = match event {
ItemEvent::FocusItem(app_id) => {
ItemEvent::FocusItem(app_id) | ItemEvent::MinimizeItem(app_id) => {
lock!(items).get(&app_id).and_then(|item| {
item.windows
.iter()
Expand All @@ -313,7 +323,11 @@ impl Module<gtk::Box> for LauncherModule {
.find_map(|(_, item)| item.windows.get(&id))
{
debug!("Focusing window {id}: {}", window.name);
wl.toplevel_focus(window.id);
if minimize_window && minimize_focused {
wl.toplevel_minimize(window.id);
} else {
wl.toplevel_focus(window.id);
}
}
}
}
Expand Down

0 comments on commit f2c2cdc

Please sign in to comment.