Skip to content

Commit 55c9c64

Browse files
committed
adding an example of how to configure and use multiple scratchpads
1 parent b7040c7 commit 55c9c64

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

examples/scratchpads/main.rs

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//! penrose :: adding named scratchpads to your config
2+
//!
3+
//! This file adds named scratchpad support to the `minimal` example.
4+
use penrose::{
5+
builtin::{
6+
actions::{exit, modify_with, send_layout_message, spawn},
7+
layout::messages::{ExpandMain, IncMain, ShrinkMain},
8+
},
9+
core::{
10+
bindings::{parse_keybindings_with_xmodmap, KeyEventHandler},
11+
Config, WindowManager,
12+
},
13+
extensions::hooks::{
14+
add_named_scratchpads, manage::FloatingCentered, NamedScratchPad, ToggleNamedScratchPad,
15+
},
16+
map,
17+
x::query::ClassName,
18+
x11rb::RustConn,
19+
Result,
20+
};
21+
use std::collections::HashMap;
22+
use tracing_subscriber::{self, prelude::*};
23+
24+
fn raw_key_bindings(
25+
toggle_1: ToggleNamedScratchPad,
26+
toggle_2: ToggleNamedScratchPad,
27+
) -> HashMap<String, Box<dyn KeyEventHandler<RustConn>>> {
28+
let mut raw_bindings = map! {
29+
map_keys: |k: &str| k.to_string();
30+
31+
"M-j" => modify_with(|cs| cs.focus_down()),
32+
"M-k" => modify_with(|cs| cs.focus_up()),
33+
"M-S-j" => modify_with(|cs| cs.swap_down()),
34+
"M-S-k" => modify_with(|cs| cs.swap_up()),
35+
"M-S-q" => modify_with(|cs| cs.kill_focused()),
36+
"M-Tab" => modify_with(|cs| cs.toggle_tag()),
37+
"M-bracketright" => modify_with(|cs| cs.next_screen()),
38+
"M-bracketleft" => modify_with(|cs| cs.previous_screen()),
39+
"M-grave" => modify_with(|cs| cs.next_layout()),
40+
"M-S-grave" => modify_with(|cs| cs.previous_layout()),
41+
"M-S-Up" => send_layout_message(|| IncMain(1)),
42+
"M-S-Down" => send_layout_message(|| IncMain(-1)),
43+
"M-S-Right" => send_layout_message(|| ExpandMain),
44+
"M-S-Left" => send_layout_message(|| ShrinkMain),
45+
"M-semicolon" => spawn("dmenu_run"),
46+
"M-Return" => spawn("st"),
47+
"M-A-Escape" => exit(),
48+
49+
// Adding the bindings for the named scratchpad handlers in addition
50+
// to the bindings from `minimal/main.rs`
51+
"M-slash" => Box::new(toggle_1),
52+
"M-p" => Box::new(toggle_2),
53+
};
54+
55+
for tag in &["1", "2", "3", "4", "5", "6", "7", "8", "9"] {
56+
raw_bindings.extend([
57+
(
58+
format!("M-{tag}"),
59+
modify_with(move |client_set| client_set.focus_tag(tag)),
60+
),
61+
(
62+
format!("M-S-{tag}"),
63+
modify_with(move |client_set| client_set.move_focused_to_tag(tag)),
64+
),
65+
]);
66+
}
67+
68+
raw_bindings
69+
}
70+
71+
fn main() -> Result<()> {
72+
tracing_subscriber::fmt()
73+
.with_env_filter("info")
74+
.finish()
75+
.init();
76+
77+
// Constructing NamedScratchPads gives you back the scratchpad itself (which
78+
// needs to be added to the window manager state below) and a handle which is
79+
// usable as a key binding.
80+
// The `Query` used to identify your scratchpads needs to be something that
81+
// can be used to determine which NamedScratchPad you are talking about. In
82+
// this case there are two different programs being used with distinct class
83+
// names but you are free to use any `Query` you wish.
84+
let (nsp_1, toggle_1) = NamedScratchPad::new(
85+
"terminal",
86+
"st -c StScratchpad",
87+
ClassName("StScratchpad"),
88+
FloatingCentered::new(0.8, 0.8),
89+
true,
90+
);
91+
let (nsp_2, toggle_2) = NamedScratchPad::new(
92+
"qt-console",
93+
"jupyter-qtconsole",
94+
ClassName("jupyter-qtconsole"),
95+
FloatingCentered::new(0.8, 0.8),
96+
true,
97+
);
98+
99+
let conn = RustConn::new()?;
100+
let key_bindings = parse_keybindings_with_xmodmap(raw_key_bindings(toggle_1, toggle_2))?;
101+
102+
// `add_named_scratchpads` is used to store the required state extensions in your WindowManager
103+
// so that the toggle hooks bound to keys above are able to track and manage your scratchpad
104+
// windows.
105+
// The order in which the NamedScratchPads are specified in the Vec passed here determines the
106+
// order in which each scratchpad's `Query` will be run to determine owndership of newly
107+
// spawned client windows.
108+
let wm = add_named_scratchpads(
109+
WindowManager::new(Config::default(), key_bindings, HashMap::new(), conn)?,
110+
vec![nsp_1, nsp_2],
111+
);
112+
113+
wm.run()
114+
}
115+
116+
#[cfg(test)]
117+
mod tests {
118+
use super::*;
119+
120+
#[test]
121+
fn bindings_parse_correctly_with_xmodmap() {
122+
let res = parse_keybindings_with_xmodmap(raw_key_bindings());
123+
124+
if let Err(e) = res {
125+
panic!("{e}");
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)