Skip to content

Commit 436a8be

Browse files
committed
updating docs
1 parent d8a0264 commit 436a8be

File tree

6 files changed

+115
-17
lines changed

6 files changed

+115
-17
lines changed

docs/src/SUMMARY.md

+3-9
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,11 @@
2222
- [Overview of Concepts](./overview/index.md)
2323
- [Pure Code vs X Code](./overview/pure-vs-x.md)
2424
- [Data Structures](./overview/data-structures.md)
25-
- [Layouts](./overview/layouts.md)
26-
- [Actions]()
27-
- [Hooks]()
28-
29-
- [Built in UI elements]()
30-
- [Draw and Context]()
31-
- [Status Bar]()
3225

33-
- [Building on top of penrose]()
26+
- [Building on top of penrose](./building/index.md)
27+
- [Actions](./building/actions.md)
28+
- [Layouts](./building/layouts.md)
3429
- [Hooks]()
35-
- [Actions]()
3630
- [State Extensions]()
3731
- [Example: Named Scratchpads]()
3832

docs/src/building/actions.md

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<image width="50px" src="https://raw.githubusercontent.com/sminez/penrose/develop/icon.svg" align="left"></image>
2+
# Actions
3+
4+
To start with we're going to assume that when we talk about running an `Action` we're talking about
5+
executing some custom code in response to a key binding bein pressed. With that in mind, lets take
6+
a look at the [KeyEventHandler][0] trait found in `penrose::core::bindings`:
7+
8+
```rust
9+
pub trait KeyEventHandler<X: XConn> {
10+
fn call(&mut self, state: &mut State<X>, x: &X) -> Result<()>;
11+
}
12+
```
13+
14+
There's not much to it: you are given mutable access to the window manager `State` and a reference to
15+
the X connection. From there you can do pretty much whatever you like other than return data (we'll
16+
take a look at how you can persist and manage your own state in a bit!)
17+
18+
To make things easier to work with (and to avoid having to implement this trait for every piece of
19+
custom logic you want to run) there are several helper functions provided for wrapping free functions
20+
of the right signature.
21+
22+
> **NOTE**: In any case where you do not need to manage any additional state, it is _strongly_
23+
> recommended that you make use of these helpers to write your actions as simple functions rather
24+
> than structs that implement the `KeyEventHandler` trait.
25+
26+
27+
## Built-in helpers
28+
29+
In the [penrose::builtin::actions][1] module you will find a number of helper functions for writing
30+
actions. The most general of these being `key_handler` which simply handles plumbing through the
31+
required type information for Rust to generate the `KeyEventHandler` trait implementation for you.
32+
33+
### An example
34+
As a real example of how this can be used, here is the power menu helper I have in my own set up
35+
which makes use of the dmenu based helpers in [penrose::extensions::util::dmenu][2] to prompt the
36+
user for a selection before executing the selected action:
37+
```rust
38+
use penrose::{
39+
builtin::actions::key_handler,
40+
core::bindings::KeyEventHandler,
41+
custom_error,
42+
extensions::util::dmenu::{DMenu, DMenuConfig, MenuMatch},
43+
util::spawn,
44+
};
45+
use std::process::exit;
46+
47+
pub fn power_menu<X: XConn>() -> KeyEventHandler<X> {
48+
key_handler(|state, _| {
49+
let options = vec!["lock", "logout", "restart-wm", "shutdown", "reboot"];
50+
let menu = DMenu::new(">>> ", options, DMenuConfig::default());
51+
let screen_index = state.client_set.current_screen().index();
52+
53+
if let Ok(MenuMatch::Line(_, choice)) = menu.run(screen_index) {
54+
match choice.as_ref() {
55+
"lock" => spawn("xflock4"),
56+
"logout" => spawn("pkill -fi penrose"),
57+
"shutdown" => spawn("sudo shutdown -h now"),
58+
"reboot" => spawn("sudo reboot"),
59+
"restart-wm" => exit(0), // Wrapper script then handles restarting us
60+
_ => unimplemented!(),
61+
}
62+
} else {
63+
Ok(())
64+
}
65+
})
66+
}
67+
```
68+
69+
The window manager state is used to determine the current screen (where we want to open dmenu)
70+
but other than that we're running completely arbitrary code in response to a keypress. The main
71+
thing to keep in mind is that penrose is _single threaded_ so anything you do in an action must
72+
complete in order for the event loop to continue running.
73+
74+
### StackSet manipulation
75+
76+
The most common set of actions you'll want to perform are modifications to the `StackSet` in
77+
to reposition and select windows on the screen. There are [a large number of methods][3] available
78+
for modifying the current state of your windows and the [modify_with][4] helper gives you an
79+
easy way to call them directly. If you think back to the minimal example window manager we covered
80+
in the "getting started" section, we saw this in use for most of the key bindings. Paraphrasing
81+
a little, it looks like this:
82+
```rust
83+
use penrose::builtin::actions::modify_with;
84+
85+
// Select the next available layout algorithm
86+
modify_with(|cs| cs.next_layout());
87+
88+
// Close the currently focused window
89+
modify_with(|cs| cs.kill_focused());
90+
```
91+
92+
[0]: https://sminez.github.io/penrose/rustdoc/penrose/core/bindings/trait.KeyEventHandler.html
93+
[1]: https://sminez.github.io/penrose/rustdoc/penrose/builtin/actions/index.html
94+
[2]: https://sminez.github.io/penrose/rustdoc/penrose/extensions/util/dmenu/index.html
95+
[3]: https://sminez.github.io/penrose/rustdoc/penrose/pure/struct.StackSet.html
96+
[4]: https://sminez.github.io/penrose/rustdoc/penrose/builtin/actions/fn.modify_with.html

docs/src/building/index.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<image width="50px" src="https://raw.githubusercontent.com/sminez/penrose/develop/icon.svg" align="left"></image>
2+
# Building on top of penrose
3+
4+
Out of the box, the examples provided in the penrose GitHub repository show you how to put
5+
together a fairly minimal window manager. By design, penrose does not attempt to implement
6+
every piece of functionality you might like from your favourite window manager, instead it
7+
provides a set of rich, composable APIs for extending the behaviour and adding your own
8+
custom logic.
9+
10+
The simplest place to start is with running custom code in response to key bindings, whether
11+
that's to modify how your windows are arranged on the screen, to launch a new program or
12+
run completely custom logic. From there you can dig into things like custom layout algorithms
13+
and extending the core window manager behaviour with hooks.
14+
15+
> If you've ever experimented with Xmonad or Qtile before then the set up should feel
16+
> somewhat familiar to you.
File renamed without changes.

docs/src/overview/actions.md

-4
This file was deleted.

docs/src/overview/hooks.md

-4
This file was deleted.

0 commit comments

Comments
 (0)