pinnacle/api/rust/examples/default_config/main.rs

254 lines
8.4 KiB
Rust
Raw Normal View History

2024-03-16 02:51:12 +01:00
use pinnacle_api::layout::{
CornerLayout, CornerLocation, CyclingLayoutManager, DwindleLayout, FairLayout, MasterSide,
MasterStackLayout, SpiralLayout,
2024-03-16 02:51:12 +01:00
};
use pinnacle_api::output::OutputSetup;
use pinnacle_api::signal::WindowSignal;
use pinnacle_api::util::{Axis, Batch};
2024-01-22 05:54:32 +01:00
use pinnacle_api::xkbcommon::xkb::Keysym;
2024-01-20 02:37:00 +01:00
use pinnacle_api::{
input::{Mod, MouseButton, MouseEdge},
ApiModules,
};
// Pinnacle needs to perform some setup before and after your config.
// The `#[pinnacle_api::config(modules)]` attribute does so and
// will bind all the config structs to the provided identifier.
2024-01-20 02:37:00 +01:00
#[pinnacle_api::config(modules)]
async fn main() {
// Deconstruct to get all the APIs.
#[allow(unused_variables)]
2024-01-20 02:37:00 +01:00
let ApiModules {
pinnacle,
process,
window,
input,
output,
tag,
2024-03-16 02:51:12 +01:00
layout,
render,
..
2024-01-20 02:37:00 +01:00
} = modules;
let mod_key = Mod::Ctrl;
2024-01-23 03:27:22 +01:00
let terminal = "alacritty";
//------------------------
// Mousebinds |
//------------------------
2024-01-23 03:27:22 +01:00
// `mod_key + left click` starts moving a window
2024-01-20 02:37:00 +01:00
input.mousebind([mod_key], MouseButton::Left, MouseEdge::Press, || {
window.begin_move(MouseButton::Left);
});
2024-01-23 03:27:22 +01:00
// `mod_key + right click` starts resizing a window
2024-01-20 02:37:00 +01:00
input.mousebind([mod_key], MouseButton::Right, MouseEdge::Press, || {
window.begin_resize(MouseButton::Right);
});
//------------------------
// Keybinds |
//------------------------
2024-01-20 02:37:00 +01:00
2024-01-23 03:27:22 +01:00
// `mod_key + alt + q` quits Pinnacle
2024-01-20 02:37:00 +01:00
input.keybind([mod_key, Mod::Alt], 'q', || {
pinnacle.quit();
});
2024-01-23 03:27:22 +01:00
// `mod_key + alt + c` closes the focused window
2024-01-20 02:37:00 +01:00
input.keybind([mod_key, Mod::Alt], 'c', || {
if let Some(window) = window.get_focused() {
window.close();
}
});
2024-01-23 03:27:22 +01:00
// `mod_key + Return` spawns a terminal
input.keybind([mod_key], Keysym::Return, move || {
process.spawn([terminal]);
2024-01-20 02:37:00 +01:00
});
2024-01-23 03:27:22 +01:00
// `mod_key + alt + space` toggles floating
2024-01-21 04:27:22 +01:00
input.keybind([mod_key, Mod::Alt], Keysym::space, || {
2024-01-20 02:37:00 +01:00
if let Some(window) = window.get_focused() {
window.toggle_floating();
2024-03-22 00:39:27 +01:00
window.raise();
2024-01-20 02:37:00 +01:00
}
});
2024-01-23 03:27:22 +01:00
// `mod_key + f` toggles fullscreen
2024-01-20 02:37:00 +01:00
input.keybind([mod_key], 'f', || {
if let Some(window) = window.get_focused() {
window.toggle_fullscreen();
2024-03-22 00:39:27 +01:00
window.raise();
2024-01-20 02:37:00 +01:00
}
});
2024-01-23 03:27:22 +01:00
// `mod_key + m` toggles maximized
2024-01-20 02:37:00 +01:00
input.keybind([mod_key], 'm', || {
if let Some(window) = window.get_focused() {
window.toggle_maximized();
2024-03-22 00:39:27 +01:00
window.raise();
2024-01-20 02:37:00 +01:00
}
});
//------------------------
// Window rules |
//------------------------
2024-01-23 03:27:22 +01:00
// You can define window rules to get windows to open with desired properties.
// See `pinnacle_api::window::rules` in the docs for more information.
//------------------------
// Layouts |
//------------------------
2024-03-16 02:51:12 +01:00
// Pinnacle does not manage layouts compositor-side.
// Instead, it delegates computation of layouts to your config,
// which provides an interface to calculate the size and location of
// windows that the compositor will use to position windows.
//
// If you're familiar with River's layout generators, you'll understand the system here
// a bit better.
//
// The Rust API provides two layout system abstractions:
// 1. Layout managers, and
// 2. Layout generators.
//
// ### Layout Managers ###
// A layout manager is a struct that implements the `LayoutManager` trait.
// A manager is meant to keep track of and choose various layout generators
// across your usage of the compositor.
//
// ### Layout generators ###
// A layout generator is a struct that implements the `LayoutGenerator` trait.
// It takes in layout arguments and computes a vector of geometries that will
// determine the size and position of windows being laid out.
//
// There is one built-in layout manager and five built-in layout generators,
// as shown below.
//
// Additionally, this system is designed to be user-extensible;
// you are free to create your own layout managers and generators for
// maximum customizability! Docs for doing so are in the works, so sit tight.
2024-03-16 02:51:12 +01:00
// Create a `CyclingLayoutManager` that can cycle between layouts on different tags.
//
// It takes in some layout generators that need to be boxed and dyn-coerced.
let layout_requester = layout.set_manager(CyclingLayoutManager::new([
Box::<MasterStackLayout>::default() as _,
Box::new(MasterStackLayout {
master_side: MasterSide::Right,
..Default::default()
}) as _,
Box::new(MasterStackLayout {
master_side: MasterSide::Top,
..Default::default()
}) as _,
Box::new(MasterStackLayout {
master_side: MasterSide::Bottom,
..Default::default()
}) as _,
Box::<DwindleLayout>::default() as _,
Box::<SpiralLayout>::default() as _,
Box::<CornerLayout>::default() as _,
Box::new(CornerLayout {
corner_loc: CornerLocation::TopRight,
..Default::default()
}) as _,
Box::new(CornerLayout {
corner_loc: CornerLocation::BottomLeft,
..Default::default()
}) as _,
Box::new(CornerLayout {
corner_loc: CornerLocation::BottomRight,
..Default::default()
}) as _,
Box::<FairLayout>::default() as _,
Box::new(FairLayout {
axis: Axis::Horizontal,
..Default::default()
}) as _,
2024-03-16 02:51:12 +01:00
]));
let mut layout_requester_clone = layout_requester.clone();
// `mod_key + space` cycles to the next layout
input.keybind([mod_key], Keysym::space, move || {
let Some(focused_op) = output.get_focused() else { return };
let Some(first_active_tag) = focused_op.tags().batch_find(
|tg| Box::pin(tg.active_async()),
|active| active == &Some(true),
) else {
2024-03-16 02:51:12 +01:00
return;
};
layout_requester.cycle_layout_forward(&first_active_tag);
layout_requester.request_layout_on_output(&focused_op);
});
// `mod_key + shift + space` cycles to the previous layout
input.keybind([mod_key, Mod::Shift], Keysym::space, move || {
let Some(focused_op) = output.get_focused() else { return };
let Some(first_active_tag) = focused_op.tags().batch_find(
|tg| Box::pin(tg.active_async()),
|active| active == &Some(true),
) else {
2024-03-16 02:51:12 +01:00
return;
};
layout_requester_clone.cycle_layout_backward(&first_active_tag);
layout_requester_clone.request_layout_on_output(&focused_op);
});
//------------------------
// Tags |
//------------------------
2024-01-20 02:37:00 +01:00
let tag_names = ["1", "2", "3", "4", "5"];
2024-01-23 03:27:22 +01:00
// Setup all monitors with tags "1" through "5"
output.setup([OutputSetup::new_with_matcher(|_| true).with_tags(tag_names)]);
2024-01-20 02:37:00 +01:00
for tag_name in tag_names {
2024-01-23 03:27:22 +01:00
// `mod_key + 1-5` switches to tag "1" to "5"
2024-01-20 02:37:00 +01:00
input.keybind([mod_key], tag_name, move || {
if let Some(tg) = tag.get(tag_name) {
2024-01-20 02:37:00 +01:00
tg.switch_to();
}
});
2024-01-23 03:27:22 +01:00
// `mod_key + shift + 1-5` toggles tag "1" to "5"
2024-01-20 02:37:00 +01:00
input.keybind([mod_key, Mod::Shift], tag_name, move || {
if let Some(tg) = tag.get(tag_name) {
2024-01-20 02:37:00 +01:00
tg.toggle_active();
}
});
2024-01-23 03:27:22 +01:00
// `mod_key + alt + 1-5` moves the focused window to tag "1" to "5"
2024-01-20 02:37:00 +01:00
input.keybind([mod_key, Mod::Alt], tag_name, move || {
if let Some(tg) = tag.get(tag_name) {
2024-01-20 02:37:00 +01:00
if let Some(win) = window.get_focused() {
win.move_to_tag(&tg);
}
}
});
2024-01-23 03:27:22 +01:00
// `mod_key + shift + alt + 1-5` toggles tag "1" to "5" on the focused window
2024-01-20 02:37:00 +01:00
input.keybind([mod_key, Mod::Shift, Mod::Alt], tag_name, move || {
if let Some(tg) = tag.get(tag_name) {
2024-01-20 02:37:00 +01:00
if let Some(win) = window.get_focused() {
win.toggle_tag(&tg);
}
}
});
}
// Enable sloppy focus
window.connect_signal(WindowSignal::PointerEnter(Box::new(|win| {
win.set_focused(true);
})));
process.spawn_once([terminal]);
2024-01-20 02:37:00 +01:00
}