mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-25 09:59:21 +01:00
Add documentation
This commit is contained in:
parent
f5b626e14d
commit
f0e2282445
8 changed files with 189 additions and 0 deletions
|
@ -52,6 +52,10 @@ impl Input {
|
|||
send_msg(msg).unwrap();
|
||||
}
|
||||
|
||||
/// Set a mousebind. If called with an already existing mousebind, it gets replaced.
|
||||
///
|
||||
/// The mousebind can happen either on button press or release, so you must
|
||||
/// specify which edge you desire.
|
||||
pub fn mousebind<F>(
|
||||
&self,
|
||||
modifiers: &[Modifier],
|
||||
|
|
|
@ -1,56 +1,111 @@
|
|||
use crate::{msg::Msg, send_msg};
|
||||
|
||||
/// Libinput settings.
|
||||
///
|
||||
/// Here you can set things like pointer acceleration.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Libinput;
|
||||
|
||||
impl Libinput {
|
||||
/// Set a libinput setting.
|
||||
///
|
||||
/// This takes a [`LibinputSetting`] containing what you want set.
|
||||
pub fn set(&self, setting: LibinputSetting) {
|
||||
let msg = Msg::SetLibinputSetting(setting);
|
||||
send_msg(msg).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// The acceleration profile.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, serde::Serialize)]
|
||||
pub enum AccelProfile {
|
||||
/// Flat pointer acceleration.
|
||||
Flat,
|
||||
/// Adaptive pointer acceleration.
|
||||
///
|
||||
/// This is the default for most devices.
|
||||
Adaptive,
|
||||
}
|
||||
|
||||
/// The click method for a touchpad.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, serde::Serialize)]
|
||||
pub enum ClickMethod {
|
||||
/// Use software-button areas to generate button events.
|
||||
ButtonAreas,
|
||||
/// The number of fingers decides which button press to generate.
|
||||
Clickfinger,
|
||||
}
|
||||
|
||||
/// The scroll method for a touchpad.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, serde::Serialize)]
|
||||
pub enum ScrollMethod {
|
||||
/// Never send scroll events.
|
||||
NoScroll,
|
||||
/// Send scroll events when two fingers are logically down on the device.
|
||||
TwoFinger,
|
||||
/// Send scroll events when a finger moves along the bottom or right edge of a device.
|
||||
Edge,
|
||||
/// Send scroll events when a button is down and the device moves along a scroll-capable axis.
|
||||
OnButtonDown,
|
||||
}
|
||||
|
||||
/// The mapping between finger count and button event for a touchpad.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, serde::Serialize)]
|
||||
pub enum TapButtonMap {
|
||||
/// 1/2/3 finger tap is mapped to left/right/middle click.
|
||||
LeftRightMiddle,
|
||||
/// 1/2/3 finger tap is mapped to left/middle/right click.
|
||||
LeftMiddleRight,
|
||||
}
|
||||
|
||||
/// Libinput settings.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, serde::Serialize)]
|
||||
pub enum LibinputSetting {
|
||||
/// Set the acceleration profile.
|
||||
AccelProfile(AccelProfile),
|
||||
/// Set the acceleration speed.
|
||||
///
|
||||
/// This should be a float from -1.0 to 1.0.
|
||||
AccelSpeed(f64),
|
||||
/// Set the calibration matrix.
|
||||
CalibrationMatrix([f32; 6]),
|
||||
/// Set the click method.
|
||||
///
|
||||
/// The click method defines when to generate software-emulated buttons, usually on a device
|
||||
/// that does not have a specific physical button available.
|
||||
ClickMethod(ClickMethod),
|
||||
/// Set whether or not the device will be disabled while typing.
|
||||
DisableWhileTypingEnabled(bool),
|
||||
/// Set device left-handedness.
|
||||
LeftHanded(bool),
|
||||
/// Set whether or not the middle click can be emulated.
|
||||
MiddleEmulationEnabled(bool),
|
||||
/// Set the rotation angle of a device.
|
||||
RotationAngle(u32),
|
||||
/// Set the scroll method.
|
||||
ScrollMethod(ScrollMethod),
|
||||
/// Set whether or not natural scroll is enabled.
|
||||
///
|
||||
/// This reverses the direction of scrolling and is mainly used with touchpads.
|
||||
NaturalScrollEnabled(bool),
|
||||
/// Set the scroll button.
|
||||
ScrollButton(u32),
|
||||
/// Set the tap button map,
|
||||
///
|
||||
/// This determines whether taps with 2 and 3 fingers register as right and middle clicks or
|
||||
/// the reverse.
|
||||
TapButtonMap(TapButtonMap),
|
||||
/// Set whether or not tap-and-drag is enabled.
|
||||
///
|
||||
/// When enabled, a single-finger tap immediately followed by a finger down results in
|
||||
/// a button down event, and subsequent finger motion thus triggers a drag.
|
||||
/// The button is released on finger up.
|
||||
TapDragEnabled(bool),
|
||||
/// Set whether or not tap drag lock is enabled.
|
||||
///
|
||||
/// When enabled, a finger may be lifted and put back on the touchpad within a timeout and the drag process
|
||||
/// continues. When disabled, lifting the finger during a tap-and-drag will immediately stop the drag.
|
||||
TapDragLockEnabled(bool),
|
||||
/// Set whether or not tap-to-click is enabled.
|
||||
TapEnabled(bool),
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ pub use xkbcommon;
|
|||
/// To that end, you can do `use pinnacle_api::prelude::*` to
|
||||
/// prevent your config file from being cluttered with imports.
|
||||
pub mod prelude {
|
||||
pub use crate::input::libinput::*;
|
||||
pub use crate::input::Modifier;
|
||||
pub use crate::input::MouseButton;
|
||||
pub use crate::input::MouseEdge;
|
||||
|
@ -226,6 +227,7 @@ pub struct Pinnacle {
|
|||
}
|
||||
|
||||
impl Pinnacle {
|
||||
/// Quit Pinnacle.
|
||||
pub fn quit(&self) {
|
||||
send_msg(Msg::Quit).unwrap();
|
||||
}
|
||||
|
|
|
@ -56,6 +56,19 @@ impl Output {
|
|||
.find(|op| op.properties().focused == Some(true))
|
||||
}
|
||||
|
||||
/// Connect a function to be run on all current and future outputs.
|
||||
///
|
||||
/// When called, `connect_for_all` will run `func` with all currently connected outputs.
|
||||
/// If a new output is connected, `func` will also be called with it.
|
||||
///
|
||||
/// This will *not* be called if it has already been called for a given connector.
|
||||
/// This means turning your monitor off and on or unplugging and replugging it *to the same port*
|
||||
/// won't trigger `func`. Plugging it in to a new port *will* trigger `func`.
|
||||
/// This is intended to prevent duplicate setup.
|
||||
///
|
||||
/// Please note: this function will be run *after* Pinnacle processes your entire config.
|
||||
/// For example, if you define tags in `func` but toggle them directly after `connect_for_all`,
|
||||
/// nothing will happen as the tags haven't been added yet.
|
||||
pub fn connect_for_all<F>(&self, mut func: F)
|
||||
where
|
||||
F: FnMut(OutputHandle) + Send + 'static,
|
||||
|
@ -247,16 +260,24 @@ enum LeftOrRight {
|
|||
Right,
|
||||
}
|
||||
|
||||
/// Horizontal alignment.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum AlignmentHorizontal {
|
||||
/// Align the outputs such that the left edges are in line.
|
||||
Left,
|
||||
/// Center the outputs horizontally.
|
||||
Center,
|
||||
/// Align the outputs such that the right edges are in line.
|
||||
Right,
|
||||
}
|
||||
|
||||
/// Vertical alignment.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum AlignmentVertical {
|
||||
/// Align the outputs such that the top edges are in line.
|
||||
Top,
|
||||
/// Center the outputs vertically.
|
||||
Center,
|
||||
/// Align the outputs such that the bottom edges are in line.
|
||||
Bottom,
|
||||
}
|
||||
|
|
|
@ -3,10 +3,16 @@ use crate::{
|
|||
send_msg, CALLBACK_VEC,
|
||||
};
|
||||
|
||||
/// Process management.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Process;
|
||||
|
||||
impl Process {
|
||||
/// Spawn a process.
|
||||
///
|
||||
/// This will use Rust's (more specifically `async_process`'s) `Command` to spawn the provided
|
||||
/// arguments. If you are using any shell syntax like `~`, you may need to spawn a shell
|
||||
/// instead. If so, you may *also* need to correctly escape the input.
|
||||
pub fn spawn(&self, command: Vec<&str>) -> anyhow::Result<()> {
|
||||
let msg = Msg::Spawn {
|
||||
command: command.into_iter().map(|s| s.to_string()).collect(),
|
||||
|
@ -16,6 +22,13 @@ impl Process {
|
|||
send_msg(msg)
|
||||
}
|
||||
|
||||
/// Spawn a process with an optional callback for its stdout, stderr, and exit information.
|
||||
///
|
||||
/// `callback` has the following parameters:
|
||||
/// - `0`: The process's stdout printed this line.
|
||||
/// - `1`: The process's stderr printed this line.
|
||||
/// - `2`: The process exited with this code.
|
||||
/// - `3`: The process exited with this message.
|
||||
pub fn spawn_with_callback<F>(&self, command: Vec<&str>, mut callback: F) -> anyhow::Result<()>
|
||||
where
|
||||
F: FnMut(Option<String>, Option<String>, Option<i32>, Option<String>) + Send + 'static,
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
request, send_msg,
|
||||
};
|
||||
|
||||
/// Tag management.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Tag;
|
||||
|
||||
|
@ -48,6 +49,15 @@ impl Tag {
|
|||
send_msg(msg).unwrap();
|
||||
}
|
||||
|
||||
/// Create a `LayoutCycler` to cycle layouts on tags.
|
||||
///
|
||||
/// Given a slice of layouts, this will create a `LayoutCycler` with two methods;
|
||||
/// one will cycle forward the layout for the active tag, and one will cycle backward.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// todo!()
|
||||
/// ```
|
||||
pub fn layout_cycler(&self, layouts: &[Layout]) -> LayoutCycler {
|
||||
let mut indices = HashMap::<TagId, usize>::new();
|
||||
let layouts = layouts.to_vec();
|
||||
|
@ -174,13 +184,21 @@ impl TagHandle {
|
|||
}
|
||||
}
|
||||
|
||||
/// Layouts for tags.
|
||||
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Layout {
|
||||
/// One master window on the left with all other windows stacked to the right.
|
||||
MasterStack,
|
||||
/// Windows split in half towards the bottom right corner.
|
||||
Dwindle,
|
||||
/// Windows split in half in a spiral
|
||||
Spiral,
|
||||
/// One main corner window in the top left with a column of windows on the right and a row on the bottom.
|
||||
CornerTopLeft,
|
||||
/// One main corner window in the top right with a column of windows on the left and a row on the bottom.
|
||||
CornerTopRight,
|
||||
/// One main corner window in the bottom left with a column of windows on the right and a row on the top.
|
||||
CornerBottomLeft,
|
||||
/// One main corner window in the bottom right with a column of windows on the left and a row on the top.
|
||||
CornerBottomRight,
|
||||
}
|
||||
|
|
|
@ -19,22 +19,27 @@ pub enum WindowId {
|
|||
Some(u32),
|
||||
}
|
||||
|
||||
/// Window management.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Window {
|
||||
/// Window rules.
|
||||
pub rules: WindowRules,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
/// Get all windows with the class `class`.
|
||||
pub fn get_by_class<'a>(&self, class: &'a str) -> impl Iterator<Item = WindowHandle> + 'a {
|
||||
self.get_all()
|
||||
.filter(|win| win.properties().class.as_deref() == Some(class))
|
||||
}
|
||||
|
||||
/// Get the currently focused window, or `None` if there isn't one.
|
||||
pub fn get_focused(&self) -> Option<WindowHandle> {
|
||||
self.get_all()
|
||||
.find(|win| win.properties().focused.is_some_and(|focused| focused))
|
||||
}
|
||||
|
||||
/// Get all windows.
|
||||
pub fn get_all(&self) -> impl Iterator<Item = WindowHandle> {
|
||||
let RequestResponse::Windows { window_ids } = request(Request::GetWindows) else {
|
||||
unreachable!()
|
||||
|
@ -43,6 +48,10 @@ impl Window {
|
|||
window_ids.into_iter().map(WindowHandle)
|
||||
}
|
||||
|
||||
/// Begin a window move.
|
||||
///
|
||||
/// This will start a window move grab with the provided button on the window the pointer
|
||||
/// is currently hovering over. Once `button` is let go, the move will end.
|
||||
pub fn begin_move(&self, button: MouseButton) {
|
||||
let msg = Msg::WindowMoveGrab {
|
||||
button: button as u32,
|
||||
|
@ -51,6 +60,10 @@ impl Window {
|
|||
send_msg(msg).unwrap();
|
||||
}
|
||||
|
||||
/// Begin a window resize.
|
||||
///
|
||||
/// This will start a window resize grab with the provided button on the window the
|
||||
/// pointer is currently hovering over. Once `button` is let go, the resize will end.
|
||||
pub fn begin_resize(&self, button: MouseButton) {
|
||||
let msg = Msg::WindowResizeGrab {
|
||||
button: button as u32,
|
||||
|
@ -143,15 +156,34 @@ impl WindowHandle {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether or not a window is floating or tiled.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize)]
|
||||
pub enum FloatingOrTiled {
|
||||
/// The window is floating.
|
||||
///
|
||||
/// It can be freely moved around and resized and will not respond to layouts.
|
||||
Floating,
|
||||
/// The window is tiled.
|
||||
///
|
||||
/// It cannot be resized and can only move by swapping places with other tiled windows.
|
||||
Tiled,
|
||||
}
|
||||
|
||||
/// Whether the window is fullscreen, maximized, or neither.
|
||||
///
|
||||
/// These three states are mutually exclusive. Setting a window to maximized while it is fullscreen
|
||||
/// will make it stop being fullscreen and vice versa.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub enum FullscreenOrMaximized {
|
||||
/// The window is not fullscreen or maximized.
|
||||
Neither,
|
||||
/// The window is fullscreen.
|
||||
///
|
||||
/// It will be the only rendered window on screen and will fill the output it resides on.
|
||||
/// Layer surfaces will also not be rendered while a window is fullscreen.
|
||||
Fullscreen,
|
||||
/// The window is maximized.
|
||||
///
|
||||
/// It will fill up as much space on its output as it can, respecting any layer surfaces.
|
||||
Maximized,
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ use crate::{msg::Msg, output::OutputHandle, send_msg, tag::TagHandle};
|
|||
|
||||
use super::{FloatingOrTiled, FullscreenOrMaximized};
|
||||
|
||||
/// Window rules.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct WindowRules;
|
||||
|
||||
impl WindowRules {
|
||||
/// Add a window rule.
|
||||
pub fn add(&self, cond: WindowRuleCondition, rule: WindowRule) {
|
||||
let msg = Msg::AddWindowRule {
|
||||
cond: cond.0,
|
||||
|
@ -18,29 +20,40 @@ impl WindowRules {
|
|||
}
|
||||
}
|
||||
|
||||
/// A window rule.
|
||||
///
|
||||
/// This is what will be applied to a window if it meets a [`WindowRuleCondition`].
|
||||
///
|
||||
/// `WindowRule`s are built using the builder pattern.
|
||||
/// // TODO: show example
|
||||
#[derive(Default)]
|
||||
pub struct WindowRule(crate::msg::WindowRule);
|
||||
|
||||
impl WindowRule {
|
||||
/// Create a new, empty window rule.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// This rule will force windows to open on the provided `output`.
|
||||
pub fn output(mut self, output: &OutputHandle) -> Self {
|
||||
self.0.output = Some(output.0.clone());
|
||||
self
|
||||
}
|
||||
|
||||
/// This rule will force windows to open with the provided `tags`.
|
||||
pub fn tags(mut self, tags: &[TagHandle]) -> Self {
|
||||
self.0.tags = Some(tags.iter().map(|tag| tag.0).collect());
|
||||
self
|
||||
}
|
||||
|
||||
/// This rule will force windows to open either floating or tiled.
|
||||
pub fn floating_or_tiled(mut self, floating_or_tiled: FloatingOrTiled) -> Self {
|
||||
self.0.floating_or_tiled = Some(floating_or_tiled);
|
||||
self
|
||||
}
|
||||
|
||||
/// This rule will force windows to open either fullscreen, maximized, or neither.
|
||||
pub fn fullscreen_or_maximized(
|
||||
mut self,
|
||||
fullscreen_or_maximized: FullscreenOrMaximized,
|
||||
|
@ -49,45 +62,76 @@ impl WindowRule {
|
|||
self
|
||||
}
|
||||
|
||||
/// This rule will force windows to open with a specific size.
|
||||
///
|
||||
/// This will only actually be visible if the window is also floating.
|
||||
pub fn size(mut self, width: NonZeroU32, height: NonZeroU32) -> Self {
|
||||
self.0.size = Some((width, height));
|
||||
self
|
||||
}
|
||||
|
||||
/// This rule will force windows to open at a specific location.
|
||||
///
|
||||
/// This will only actually be visible if the window is also floating.
|
||||
pub fn location(mut self, x: i32, y: i32) -> Self {
|
||||
self.0.location = Some((x, y));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A condition for a [`WindowRule`] to apply to a window.
|
||||
#[derive(Default, Debug)]
|
||||
pub struct WindowRuleCondition(crate::msg::WindowRuleCondition);
|
||||
|
||||
impl WindowRuleCondition {
|
||||
/// Create a new, empty `WindowRuleCondition`.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// This condition requires that at least one provided condition is true.
|
||||
pub fn any(mut self, conds: &[WindowRuleCondition]) -> Self {
|
||||
self.0.cond_any = Some(conds.iter().map(|cond| cond.0.clone()).collect());
|
||||
self
|
||||
}
|
||||
|
||||
/// This condition requires that all provided conditions are true.
|
||||
pub fn all(mut self, conds: &[WindowRuleCondition]) -> Self {
|
||||
self.0.cond_all = Some(conds.iter().map(|cond| cond.0.clone()).collect());
|
||||
self
|
||||
}
|
||||
|
||||
/// This condition requires that the window's class matches.
|
||||
///
|
||||
/// When used in a top level condition or inside of [`WindowRuleCondition::all`],
|
||||
/// *all* classes must match (this is impossible).
|
||||
///
|
||||
/// When used in [`WindowRuleCondition::any`], at least one of the
|
||||
/// provided classes must match.
|
||||
pub fn class(mut self, classes: &[&str]) -> Self {
|
||||
self.0.class = Some(classes.iter().map(|s| s.to_string()).collect());
|
||||
self
|
||||
}
|
||||
|
||||
/// This condition requires that the window's title matches.
|
||||
///
|
||||
/// When used in a top level condition or inside of [`WindowRuleCondition::all`],
|
||||
/// *all* titles must match (this is impossible).
|
||||
///
|
||||
/// When used in [`WindowRuleCondition::any`], at least one of the
|
||||
/// provided titles must match.
|
||||
pub fn title(mut self, titles: &[&str]) -> Self {
|
||||
self.0.title = Some(titles.iter().map(|s| s.to_string()).collect());
|
||||
self
|
||||
}
|
||||
|
||||
/// This condition requires that the window's is opened on the given tags.
|
||||
///
|
||||
/// When used in a top level condition or inside of [`WindowRuleCondition::all`],
|
||||
/// the window must opne on *all* given tags.
|
||||
///
|
||||
/// When used in [`WindowRuleCondition::any`], the window must open on at least
|
||||
/// one of the given tags.
|
||||
pub fn tag(mut self, tags: &[TagHandle]) -> Self {
|
||||
self.0.tag = Some(tags.iter().map(|tag| tag.0).collect());
|
||||
self
|
||||
|
|
Loading…
Reference in a new issue