From fe80440f38c34d0f2e918720a4921535ae03f6bb Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 16 May 2022 18:21:56 +0200 Subject: [PATCH] config: add documentation --- default-config/src/lib.rs | 20 +-- jay-config/src/_private/client.rs | 13 +- jay-config/src/_private/ipc.rs | 8 +- jay-config/src/_private/logging.rs | 2 +- jay-config/src/embedded.rs | 6 + jay-config/src/exec.rs | 50 ++++++ jay-config/src/input.rs | 113 ++++++++++--- jay-config/src/input/acceleration.rs | 7 + jay-config/src/input/capability.rs | 5 + jay-config/src/keyboard/keymap.rs | 16 -- jay-config/src/keyboard/mod.rs | 63 +++++++- jay-config/src/keyboard/mods.rs | 15 ++ jay-config/src/keyboard/syms.rs | 3 + jay-config/src/lib.rs | 153 ++++++++---------- jay-config/src/logging.rs | 16 ++ jay-config/src/macros.rs | 1 + jay-config/src/status.rs | 9 ++ jay-config/src/theme.rs | 6 +- jay-config/src/timer.rs | 92 +++++++++++ jay-config/src/{drm.rs => video.rs} | 108 ++++++++++++- src/config.rs | 2 +- src/config/handler.rs | 28 ++-- src/ifs/wl_seat.rs | 6 +- src/ifs/wl_seat/event_handling.rs | 7 +- .../wl_surface/xdg_surface/xdg_toplevel.rs | 5 +- src/ifs/wl_surface/xwindow.rs | 5 +- src/it/test_config.rs | 2 +- src/keymap.xkb | 1 + src/state.rs | 6 +- src/tree.rs | 22 ++- src/tree/container.rs | 6 +- src/tree/output.rs | 5 +- src/tree/placeholder.rs | 6 +- src/tree/toplevel.rs | 3 +- src/tree/workspace.rs | 5 +- src/video/drm.rs | 4 +- 36 files changed, 620 insertions(+), 199 deletions(-) create mode 100644 jay-config/src/exec.rs delete mode 100644 jay-config/src/keyboard/keymap.rs create mode 100644 jay-config/src/logging.rs create mode 100644 jay-config/src/timer.rs rename jay-config/src/{drm.rs => video.rs} (59%) diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index ed9b91ca..3a1f7a55 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,9 +1,9 @@ use { - chrono::{format::StrftimeItems, Local, Timelike}, + chrono::{format::StrftimeItems, Local}, jay_config::{ config, - drm::on_graphics_initialized, - get_timer, get_workspace, + exec::Command, + get_workspace, input::{get_seat, input_devices, on_new_input_device, InputDevice, Seat}, keyboard::{ mods::{Modifiers, ALT, CTRL, SHIFT}, @@ -16,8 +16,9 @@ use { quit, reload, status::set_status, switch_to_vt, + timer::{duration_until_wall_clock_is_multiple_of, get_timer}, + video::on_graphics_initialized, Axis::{Horizontal, Vertical}, - Command, Direction::{Down, Left, Right, Up}, }, std::time::Duration, @@ -77,16 +78,9 @@ fn setup_status() { set_status(&status); }; update_status(); - // Sleep until the time becomes a multiple of 5 seconds - let initial = { - let now = Local::now(); - 5000 - (now.second() * 1000 + now.timestamp_subsec_millis()) % 5000 - }; + let period = Duration::from_secs(5); let timer = get_timer("status_timer"); - timer.program( - Duration::from_millis(initial as u64), - Some(Duration::from_secs(5)), - ); + timer.repeated(duration_until_wall_clock_is_multiple_of(period), period); timer.on_tick(update_status); } diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 54f2ed93..b67a712a 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -7,14 +7,17 @@ use { ipc::{ClientMessage, InitMessage, Response, ServerMessage}, logging, Config, ConfigEntry, ConfigEntryGen, VERSION, }, - drm::{ + exec::Command, + input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat}, + keyboard::Keymap, + logging::LogLevel, + theme::{colors::Colorable, sized::Resizable, Color}, + timer::Timer, + video::{ connector_type::{ConnectorType, CON_UNKNOWN}, Connector, DrmDevice, Mode, }, - input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat}, - keyboard::keymap::Keymap, - theme::{colors::Colorable, sized::Resizable, Color}, - Axis, Command, Direction, LogLevel, ModifiedKeySym, PciId, Timer, Workspace, + Axis, Direction, ModifiedKeySym, PciId, Workspace, }, std::{ cell::{Cell, RefCell}, diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 0dba3258..5c86cd6e 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -1,10 +1,12 @@ use { crate::{ - drm::{connector_type::ConnectorType, Connector, DrmDevice}, input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat}, - keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym}, + keyboard::{mods::Modifiers, syms::KeySym, Keymap}, + logging::LogLevel, theme::{colors::Colorable, sized::Resizable, Color}, - Axis, Direction, LogLevel, PciId, Timer, Workspace, + timer::Timer, + video::{connector_type::ConnectorType, Connector, DrmDevice}, + Axis, Direction, PciId, Workspace, }, bincode::{BorrowDecode, Decode, Encode}, std::time::Duration, diff --git a/jay-config/src/_private/logging.rs b/jay-config/src/_private/logging.rs index 5f313bcf..28836038 100644 --- a/jay-config/src/_private/logging.rs +++ b/jay-config/src/_private/logging.rs @@ -1,5 +1,5 @@ use { - crate::LogLevel, + crate::logging::LogLevel, log::{Level, LevelFilter, Log, Metadata, Record}, }; diff --git a/jay-config/src/embedded.rs b/jay-config/src/embedded.rs index 5d5e6dc2..66536e64 100644 --- a/jay-config/src/embedded.rs +++ b/jay-config/src/embedded.rs @@ -1,5 +1,11 @@ +//! Tools to configure the compositor in embedded environments. + use crate::input::InputDevice; +/// Grab the input device. +/// +/// This usually only works if the compositor is running as an application under X. It will +/// probably not work under XWayland. pub fn grab_input_device(kb: InputDevice, grab: bool) { get!().grab(kb, grab); } diff --git a/jay-config/src/exec.rs b/jay-config/src/exec.rs new file mode 100644 index 00000000..6f828b18 --- /dev/null +++ b/jay-config/src/exec.rs @@ -0,0 +1,50 @@ +//! Tools for spawning programs. + +use std::collections::HashMap; + +/// Sets an environment variable. +/// +/// This does not affect the compositor itself but only programs spawned by the compositor. +pub fn set_env(key: &str, val: &str) { + get!().set_env(key, val); +} + +/// A command to be spawned. +pub struct Command { + pub(crate) prog: String, + pub(crate) args: Vec, + pub(crate) env: HashMap, +} + +impl Command { + /// Creates a new command to be spawned. + /// + /// `prog` should be the path to the program being spawned. If `prog` does not contain + /// a `/`, then it will be searched in `PATH` similar to how a shell would do it. + /// + /// The first argument passed to `prog`, `argv[0]`, is `prog` itself. + pub fn new(prog: &str) -> Self { + Self { + prog: prog.to_string(), + args: vec![], + env: Default::default(), + } + } + + /// Adds an argument to be passed to the command. + pub fn arg(&mut self, arg: &str) -> &mut Self { + self.args.push(arg.to_string()); + self + } + + /// Sets an environment variable for this command only. + pub fn env(&mut self, key: &str, val: &str) -> &mut Self { + self.env.insert(key.to_string(), val.to_string()); + self + } + + /// Executes the command. + pub fn spawn(&self) { + get!().spawn(self); + } +} diff --git a/jay-config/src/input.rs b/jay-config/src/input.rs index 25d2f74e..dfbdefdf 100644 --- a/jay-config/src/input.rs +++ b/jay-config/src/input.rs @@ -1,48 +1,90 @@ +//! Tools for configuring input devices. + pub mod acceleration; pub mod capability; use { crate::{ input::{acceleration::AccelProfile, capability::Capability}, - Axis, Direction, Keymap, ModifiedKeySym, Workspace, + keyboard::Keymap, + Axis, Direction, ModifiedKeySym, Workspace, }, bincode::{Decode, Encode}, }; +/// An input device. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct InputDevice(pub u64); impl InputDevice { + /// Assigns the input device to a seat. pub fn set_seat(self, seat: Seat) { get!().set_seat(self, seat) } + /// Returns whether the device has the specified capability. pub fn has_capability(self, cap: Capability) -> bool { get!(false).has_capability(self, cap) } + /// Sets the device to be left handed. + /// + /// This has the effect of swapping the left and right mouse button. See the libinput + /// documentation for more details. pub fn set_left_handed(self, left_handed: bool) { get!().set_left_handed(self, left_handed); } + /// Sets the acceleration profile of the device. + /// + /// This corresponds to the libinput setting of the same name. pub fn set_accel_profile(self, profile: AccelProfile) { get!().set_accel_profile(self, profile); } + /// Sets the acceleration speed of the device. + /// + /// This corresponds to the libinput setting of the same name. pub fn set_accel_speed(self, speed: f64) { get!().set_accel_speed(self, speed); } + /// Sets the transformation matrix of the device. + /// + /// This is not a libinput setting but a setting of the compositor. It currently affects + /// relative mouse motions in that the matrix is applied to the motion. To reduce the mouse + /// speed to 35%, use the following matrix: + /// + /// ```text + /// [ + /// [0.35, 1.0], + /// [1.0, 0.35], + /// ] + /// ``` + /// + /// This might give you better results than using `set_accel_profile` and `set_accel_speed`. pub fn set_transform_matrix(self, matrix: [[f64; 2]; 2]) { get!().set_transform_matrix(self, matrix); } + /// Returns the name of the device. pub fn name(self) -> String { get!(String::new()).device_name(self) } } +/// A seat. +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct Seat(pub u64); + impl Seat { + pub const INVALID: Self = Self(0); + + /// Returns whether the seat is invalid. + pub fn is_invalid(self) -> bool { + self == Self::INVALID + } + #[doc(hidden)] pub fn raw(self) -> u64 { self.0 @@ -53,143 +95,164 @@ impl Seat { Self(raw) } + /// Creates a compositor-wide hotkey. + /// + /// The closure is invoked when the user presses the last key of the modified keysym. + /// Note that the keysym is calculated without modifiers applied. To perform an action + /// when `SHIFT+k` is pressed, use `SHIFT | SYM_k` not `SHIFT | SYM_K`. pub fn bind, F: Fn() + 'static>(self, mod_sym: T, f: F) { get!().bind(self, mod_sym, f) } + /// Unbinds a hotkey. pub fn unbind>(self, mod_sym: T) { get!().unbind(self, mod_sym) } + /// Moves the keyboard focus of the seat in the specified direction. pub fn focus(self, direction: Direction) { get!().focus(self, direction) } + /// Moves the focused window in the specified direction. pub fn move_(self, direction: Direction) { get!().move_(self, direction) } + /// Sets the keymap of the seat. pub fn set_keymap(self, keymap: Keymap) { get!().seat_set_keymap(self, keymap) } + /// Returns the repeat rate of the seat. + /// + /// The returned tuple is `(rate, delay)` where `rate` is the number of times keys repeat per second + /// and `delay` is the time after the button press after which keys start repeating. pub fn repeat_rate(self) -> (i32, i32) { - let mut res = (25, 250); - (|| res = get!().seat_get_repeat_rate(self))(); - res + get!((25, 250)).seat_get_repeat_rate(self) } + /// Sets the repeat rate of the seat. pub fn set_repeat_rate(self, rate: i32, delay: i32) { get!().seat_set_repeat_rate(self, rate, delay) } + /// Returns whether the parent-container of the currently focused window is in mono-mode. pub fn mono(self) -> bool { get!(false).mono(self) } + /// Sets whether the parent-container of the currently focused window is in mono-mode. pub fn set_mono(self, mono: bool) { get!().set_mono(self, mono) } + /// Toggles whether the parent-container of the currently focused window is in mono-mode. pub fn toggle_mono(self) { self.set_mono(!self.mono()); } + /// Returns the split axis of the parent-container of the currently focused window. pub fn split(self) -> Axis { get!(Axis::Horizontal).split(self) } + /// Sets the split axis of the parent-container of the currently focused window. pub fn set_split(self, axis: Axis) { get!().set_split(self, axis) } + /// Toggles the split axis of the parent-container of the currently focused window. pub fn toggle_split(self) { self.set_split(self.split().other()); } + /// Returns the input devices assigned to this seat. pub fn input_devices(self) -> Vec { get!().get_input_devices(Some(self)) } + /// Creates a new container with the specified split in place of the currently focused window. pub fn create_split(self, axis: Axis) { get!().create_split(self, axis); } + /// Focuses the parent node of the currently focused window. pub fn focus_parent(self) { get!().focus_parent(self); } + /// Requests the currently focused window to be closed. pub fn close(self) { get!().close(self); } + /// Returns whether the currently focused window is floating. pub fn get_floating(self) -> bool { get!().get_floating(self) } - + /// Sets whether the currently focused window is floating. pub fn set_floating(self, floating: bool) { get!().set_floating(self, floating); } + /// Toggles whether the currently focused window is floating. pub fn toggle_floating(self) { get!().toggle_floating(self); } + /// Shows the workspace and sets the keyboard focus of the seat to that workspace. + /// + /// If the workspace doesn't currently exist, it is created on the output that contains the + /// seat's cursor. pub fn show_workspace(self, workspace: Workspace) { get!().show_workspace(self, workspace) } + /// Moves the currently focused window to the workspace. pub fn set_workspace(self, workspace: Workspace) { get!().set_workspace(self, workspace) } + /// Toggles whether the currently focused window is fullscreen. pub fn toggle_fullscreen(self) { let c = get!(); c.set_fullscreen(self, !c.get_fullscreen(self)); } - + /// Returns whether the currently focused window is fullscreen. pub fn fullscreen(self) -> bool { get!(false).get_fullscreen(self) } + /// Sets whether the currently focused window is fullscreen. pub fn set_fullscreen(self, fullscreen: bool) { get!().set_fullscreen(self, fullscreen) } } +/// Returns all seats. pub fn get_seats() -> Vec { - let mut res = vec![]; - (|| res = get!().seats())(); - res + get!().seats() } +/// Returns all input devices. pub fn input_devices() -> Vec { get!().get_input_devices(None) } -pub fn remove_all_seats() {} - +/// Returns or creates a seat. +/// +/// Seats are identified by their name. If no seat with the name exists, a new seat will be created. pub fn get_seat(name: &str) -> Seat { - let mut res = Seat(0); - (|| res = get!().get_seat(name))(); - res + get!(Seat(0)).get_seat(name) } +/// Sets a closure to run when a new seat has been created. pub fn on_new_seat(f: F) { get!().on_new_seat(f) } +/// Sets a closure to run when a new input device has been added. pub fn on_new_input_device(f: F) { get!().on_new_input_device(f) } - -#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub struct Seat(pub u64); - -impl Seat { - pub const INVALID: Self = Self(0); - - pub fn is_invalid(self) -> bool { - self == Self::INVALID - } -} diff --git a/jay-config/src/input/acceleration.rs b/jay-config/src/input/acceleration.rs index 345d915f..d2661bcd 100644 --- a/jay-config/src/input/acceleration.rs +++ b/jay-config/src/input/acceleration.rs @@ -1,7 +1,14 @@ +//! Constants determining the acceleration profile of a device. +//! +//! See the libinput documentation for details. + use bincode::{Decode, Encode}; +/// The acceleration profile of a device. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct AccelProfile(pub u32); +/// A flat acceleration profile. pub const ACCEL_PROFILE_FLAT: AccelProfile = AccelProfile(1 << 0); +/// An adaptive acceleration profile. pub const ACCEL_PROFILE_ADAPTIVE: AccelProfile = AccelProfile(1 << 1); diff --git a/jay-config/src/input/capability.rs b/jay-config/src/input/capability.rs index fe5b3929..7482d6c6 100644 --- a/jay-config/src/input/capability.rs +++ b/jay-config/src/input/capability.rs @@ -1,5 +1,10 @@ +//! Constants specifying the capabilities of an input device. +//! +//! See the libinput documentation for the meanings of these constants. + use bincode::{Decode, Encode}; +/// A capability of an input device. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct Capability(pub u32); diff --git a/jay-config/src/keyboard/keymap.rs b/jay-config/src/keyboard/keymap.rs deleted file mode 100644 index 6ec092be..00000000 --- a/jay-config/src/keyboard/keymap.rs +++ /dev/null @@ -1,16 +0,0 @@ -use bincode::{Decode, Encode}; - -#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub struct Keymap(pub u64); - -impl Keymap { - pub const INVALID: Self = Self(0); - - pub fn is_invalid(self) -> bool { - self == Self::INVALID - } -} - -pub fn parse_keymap(keymap: &str) -> Keymap { - get!(Keymap::INVALID).parse_keymap(keymap) -} diff --git a/jay-config/src/keyboard/mod.rs b/jay-config/src/keyboard/mod.rs index 7bbac76e..762acfe0 100644 --- a/jay-config/src/keyboard/mod.rs +++ b/jay-config/src/keyboard/mod.rs @@ -1,13 +1,15 @@ +//! Tools affecting the keyboard behavior. + use { crate::keyboard::{mods::Modifiers, syms::KeySym}, bincode::{Decode, Encode}, std::ops::{BitOr, BitOrAssign}, }; -pub mod keymap; pub mod mods; pub mod syms; +/// A keysym with zero or more modifiers #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct ModifiedKeySym { pub mods: Modifiers, @@ -39,3 +41,62 @@ impl BitOrAssign for ModifiedKeySym { self.mods |= rhs; } } + +/// A keymap. +#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct Keymap(pub u64); + +impl Keymap { + /// The invalid keymap. + pub const INVALID: Self = Self(0); + + /// Returns whether this keymap is valid. + pub fn is_valid(self) -> bool { + self != Self::INVALID + } + + /// Returns whether this keymap is invalid. + pub fn is_invalid(self) -> bool { + self == Self::INVALID + } +} + +/// Parses a keymap. +/// +/// The returned keymap can later be used to set the keymap of a seat. If the keymap cannot +/// be parsed, returns an invalid keymap. Trying to set a seat's keymap to an invalid keymap +/// has no effect. +/// +/// A simple keymap looks as follows: +/// +/// ```text +/// xkb_keymap { +/// xkb_keycodes { include "evdev+aliases(qwerty)" }; +/// xkb_types { include "complete" }; +/// xkb_compat { include "complete" }; +/// xkb_symbols { include "pc+inet(evdev)+us(basic)" }; +/// }; +/// ``` +/// +/// To use a programmer Dvorak, replace the corresponding line by +/// +/// ```text +/// xkb_symbols { include "pc+inet(evdev)+us(dvp)" }; +/// ``` +/// +/// To use a German keymap, replace the corresponding line by +/// +/// ```text +/// xkb_symbols { include "pc+inet(evdev)+de(basic)" }; +/// ``` +/// +/// You can also use a completely custom keymap that doesn't use any includes. See the +/// [default][default] Jay keymap for an example. +/// +/// General information about the keymap format can be found in the [arch wiki][wiki]. +/// +/// [default]: https://github.com/mahkoh/jay/tree/master/src/keymap.xkb +/// [wiki]: https://wiki.archlinux.org/title/X_keyboard_extension +pub fn parse_keymap(keymap: &str) -> Keymap { + get!(Keymap::INVALID).parse_keymap(keymap) +} diff --git a/jay-config/src/keyboard/mods.rs b/jay-config/src/keyboard/mods.rs index cd9f72ed..2f5c1790 100644 --- a/jay-config/src/keyboard/mods.rs +++ b/jay-config/src/keyboard/mods.rs @@ -1,24 +1,39 @@ +//! Keyboard modifiers + use { crate::{keyboard::syms::KeySym, ModifiedKeySym}, bincode::{Decode, Encode}, std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign}, }; +/// Zero or more keyboard modifiers #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default, Hash, Debug)] pub struct Modifiers(pub u32); +/// The Shift modifier pub const SHIFT: Modifiers = Modifiers(1 << 0); +/// The CapsLock modifier. pub const LOCK: Modifiers = Modifiers(1 << 1); +/// The Ctrl modifier. pub const CTRL: Modifiers = Modifiers(1 << 2); +/// The Mod1 modifier, i.e., Alt. pub const MOD1: Modifiers = Modifiers(1 << 3); +/// The Mod2 modifier, i.e., NumLock. pub const MOD2: Modifiers = Modifiers(1 << 4); +/// The Mod3 modifier. pub const MOD3: Modifiers = Modifiers(1 << 5); +/// The Mod4 modifier, i.e., Logo. pub const MOD4: Modifiers = Modifiers(1 << 6); +/// The Mod5 modifier. pub const MOD5: Modifiers = Modifiers(1 << 7); +/// Alias for `LOCK`. pub const CAPS: Modifiers = LOCK; +/// Alias for `MOD1`. pub const ALT: Modifiers = MOD1; +/// Alias for `MOD2`. pub const NUM: Modifiers = MOD2; +/// Alias for `MOD4`. pub const LOGO: Modifiers = MOD4; impl BitOr for Modifiers { diff --git a/jay-config/src/keyboard/syms.rs b/jay-config/src/keyboard/syms.rs index e9cc673e..63baa548 100644 --- a/jay-config/src/keyboard/syms.rs +++ b/jay-config/src/keyboard/syms.rs @@ -1,7 +1,10 @@ +//! Keysyms + #![allow(non_upper_case_globals)] use bincode::{Decode, Encode}; +/// A keysym. #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct KeySym(pub u32); diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index c01e9269..aafb8dc1 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -1,42 +1,69 @@ +//! This crate allows you to configure the Jay compositor. +//! +//! A minimal example configuration looks as follows: +//! +//! ```rust +//! use jay_config::config; +//! +//! fn configure() { +//! +//! } +//! +//! config!(configure); +//! ``` +//! +//! This configuration will not allow you to interact with the compositor at all nor exit it. +//! To add at least that much functionality, add the following code to `configure`: +//! +//! ```rust +//! use jay_config::{config, quit}; +//! use jay_config::input::{get_seat, input_devices, on_new_input_device}; +//! use jay_config::keyboard::mods::ALT; +//! use jay_config::keyboard::syms::SYM_q; +//! +//! fn configure() { +//! // Create a seat. +//! let seat = get_seat("default"); +//! // Create a key binding to exit the compositor. +//! seat.bind(ALT | SYM_q, || quit()); +//! // Assign all current and future input devices to this seat. +//! input_devices().into_iter().for_each(move |d| d.set_seat(seat)); +//! on_new_input_device(move |d| d.set_seat(seat)); +//! } +//! +//! config!(configure); +//! ``` + use { - crate::keyboard::{keymap::Keymap, ModifiedKeySym}, + crate::keyboard::ModifiedKeySym, bincode::{Decode, Encode}, - std::{ - collections::HashMap, - fmt::{Debug, Display, Formatter}, - time::Duration, - }, + std::fmt::{Debug, Display, Formatter}, }; #[macro_use] mod macros; #[doc(hidden)] pub mod _private; -pub mod drm; pub mod embedded; +pub mod exec; pub mod input; pub mod keyboard; +pub mod logging; pub mod status; pub mod theme; +pub mod timer; +pub mod video; -#[derive(Encode, Decode, Copy, Clone, Debug)] -pub enum LogLevel { - Error, - Warn, - Info, - Debug, - Trace, -} - +/// A planar direction. #[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)] pub enum Direction { - Unspecified, Left, Down, Up, Right, } +/// A planar axis. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum Axis { Horizontal, @@ -44,6 +71,7 @@ pub enum Axis { } impl Axis { + /// Returns the axis orthogonal to `self`. pub fn other(self) -> Self { match self { Self::Horizontal => Self::Vertical, @@ -52,88 +80,47 @@ impl Axis { } } +/// Exits the compositor. pub fn quit() { get!().quit() } +/// Switches to a different VT. pub fn switch_to_vt(n: u32) { get!().switch_to_vt(n) } -pub fn set_env(key: &str, val: &str) { - get!().set_env(key, val); -} - -pub struct Command { - prog: String, - args: Vec, - env: HashMap, -} - -impl Command { - pub fn new(prog: &str) -> Self { - Self { - prog: prog.to_string(), - args: vec![], - env: Default::default(), - } - } - - pub fn arg(&mut self, arg: &str) -> &mut Self { - self.args.push(arg.to_string()); - self - } - - pub fn env(&mut self, key: &str, val: &str) -> &mut Self { - self.env.insert(key.to_string(), val.to_string()); - self - } - - pub fn spawn(&self) { - get!().spawn(self); - } -} - -#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub struct Workspace(pub u64); - -pub fn get_workspace(name: &str) -> Workspace { - get!(Workspace(0)).get_workspace(name) -} - -#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub struct Timer(pub u64); - -pub fn get_timer(name: &str) -> Timer { - get!(Timer(0)).get_timer(name) -} - -impl Timer { - pub fn program(self, initial: Duration, periodic: Option) { - get!().program_timer(self, Some(initial), periodic); - } - - pub fn cancel(self) { - get!().program_timer(self, None, None); - } - - pub fn remove(self) { - get!().remove_timer(self); - } - - pub fn on_tick(self, f: F) { - get!().on_timer_tick(self, f); - } -} - +/// Reloads the configuration. +/// +/// If the configuration cannot be reloaded, this function has no effect. pub fn reload() { get!().reload() } +/// Returns whether this execution of the configuration function is due to a reload. +/// +/// This can be used to decide whether the configuration should auto-start programs. pub fn is_reload() -> bool { get!(false).is_reload() } +/// A workspace. +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct Workspace(pub u64); + +/// Returns the workspace with the given name. +/// +/// Workspaces are identified by their name. Calling this function alone does not create the +/// workspace if it doesn't already exist. +pub fn get_workspace(name: &str) -> Workspace { + get!(Workspace(0)).get_workspace(name) +} + +/// A PCI ID. +/// +/// PCI IDs can be used to identify a hardware component. See the Debian [documentation][pci]. +/// +/// [pci]: https://wiki.debian.org/HowToIdentifyADevice/PCI #[derive(Encode, Decode, Debug, Copy, Clone, Hash, Eq, PartialEq, Default)] pub struct PciId { pub vendor: u32, diff --git a/jay-config/src/logging.rs b/jay-config/src/logging.rs new file mode 100644 index 00000000..adde1df6 --- /dev/null +++ b/jay-config/src/logging.rs @@ -0,0 +1,16 @@ +//! Tools for modifying the logging behavior of the compositor. +//! +//! Note that you can use the `log` crate for logging. All invocations of `log::info` etc. +//! automatically log into the compositors log. + +use bincode::{Decode, Encode}; + +/// The log level of the compositor or a log message. +#[derive(Encode, Decode, Copy, Clone, Debug)] +pub enum LogLevel { + Error, + Warn, + Info, + Debug, + Trace, +} diff --git a/jay-config/src/macros.rs b/jay-config/src/macros.rs index 5ec79ea0..597809eb 100644 --- a/jay-config/src/macros.rs +++ b/jay-config/src/macros.rs @@ -1,3 +1,4 @@ +/// Declares the entry point of the configuration. #[macro_export] macro_rules! config { ($f:path) => { diff --git a/jay-config/src/status.rs b/jay-config/src/status.rs index 05d4e254..55a0560c 100644 --- a/jay-config/src/status.rs +++ b/jay-config/src/status.rs @@ -1,3 +1,12 @@ +//! Knobs for changing the status text. + +/// Sets the status text. +/// +/// The status text is displayed at the right end of the bar. +/// +/// The status text should be specified in [pango][pango] markup language. +/// +/// [pango]: https://docs.gtk.org/Pango/pango_markup.html pub fn set_status(status: &str) { get!().set_status(status); } diff --git a/jay-config/src/theme.rs b/jay-config/src/theme.rs index 7fe4509c..bd191bc3 100644 --- a/jay-config/src/theme.rs +++ b/jay-config/src/theme.rs @@ -1,4 +1,4 @@ -//! Knobs for changing the look of the compositor. +//! Tools for configuring the look of the compositor. use bincode::{Decode, Encode}; @@ -156,7 +156,7 @@ pub fn reset_font() { get!().reset_font() } -/// Tools for customizing the colors of the desktop. +/// Elements of the compositor whose color can be changed. pub mod colors { use { crate::theme::Color, @@ -248,7 +248,7 @@ pub mod colors { } } -/// Tools for customizing the sizes of GUI elements. +/// Elements of the compositor whose size can be changed. pub mod sized { use bincode::{Decode, Encode}; diff --git a/jay-config/src/timer.rs b/jay-config/src/timer.rs new file mode 100644 index 00000000..926e183a --- /dev/null +++ b/jay-config/src/timer.rs @@ -0,0 +1,92 @@ +//! Timers for one-time or repeated actions. + +use { + bincode::{Decode, Encode}, + std::time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +/// A timer. +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub struct Timer(pub u64); + +/// Creates a new timer or returns an existing one. +/// +/// Timers are identified by their name and their lifetime is bound by the lifetime of +/// the configuration. Reloading the configuration destroys all existing timers. +/// +/// Within the same configuration, calling this function multiple times with the same name +/// will return the same timer. +/// +/// Timers can be deleted by calling `remove`. At that point all existing references to +/// the timer become invalid and `get_timer` will return a new timer. +pub fn get_timer(name: &str) -> Timer { + get!(Timer(0)).get_timer(name) +} + +impl Timer { + /// Programs the timer to fire once. + pub fn once(self, initial: Duration) { + get!().program_timer(self, Some(initial), None); + } + + /// Programs the timer to fire repeatedly. + /// + /// `initial` is the period after which the timer expires for the first time. + pub fn repeated(self, initial: Duration, period: Duration) { + get!().program_timer(self, Some(initial), Some(period)); + } + + /// Cancels the timer. + /// + /// The timer remains valid but will never expire. It can be reprogrammed by calling + /// `once` or `repeated`. + pub fn cancel(self) { + get!().program_timer(self, None, None); + } + + /// Removes the time. + /// + /// This reference to the timer becomes invalid as do all other existing references. + /// A new timer with the same name can be created by calling `get_timer`. + pub fn remove(self) { + get!().remove_timer(self); + } + + /// Sets the function to be executed when the timer expires. + pub fn on_tick(self, f: F) { + get!().on_timer_tick(self, f); + } +} + +/// Returns the duration until the wall clock is a multiple of `duration`. +/// +/// # Example +/// +/// Execute a timer every time the wall clock becomes a multiple of 5 seconds: +/// +/// ```rust,ignore +/// let period = Duration::from_secs(5); +/// let timer = get_timer("status_timer"); +/// timer.repeated( +/// duration_until_wall_clock_is_multiple_of(period), +/// period, +/// ); +/// timer.on_tick(|| todo!()); +/// ``` +pub fn duration_until_wall_clock_is_multiple_of(duration: Duration) -> Duration { + let now = match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(n) => n, + _ => return Duration::from_secs(0), + }; + let now = now.as_nanos(); + let duration = duration.as_nanos(); + if duration == 0 { + return Duration::from_secs(0); + } + let nanos = duration - now % duration; + if nanos == duration { + Duration::from_secs(0) + } else { + Duration::from_nanos(nanos as _) + } +} diff --git a/jay-config/src/drm.rs b/jay-config/src/video.rs similarity index 59% rename from jay-config/src/drm.rs rename to jay-config/src/video.rs index 00ba9990..f18c309d 100644 --- a/jay-config/src/drm.rs +++ b/jay-config/src/video.rs @@ -1,6 +1,8 @@ +//! Tools for configuring graphics cards and monitors. + use { crate::{ - drm::connector_type::{ + video::connector_type::{ ConnectorType, CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI, CON_DSI, CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA, CON_HDMIB, CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA, @@ -12,7 +14,14 @@ use { std::str::FromStr, }; -#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +/// The mode of a connector. +/// +/// Currently a mode consists of three properties: +/// +/// - width in pixels +/// - height in pixels +/// - refresh rate in mhz. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct Mode { pub(crate) width: i32, pub(crate) height: i32, @@ -20,14 +29,19 @@ pub struct Mode { } impl Mode { + /// Returns the width of the mode. pub fn width(&self) -> i32 { self.width } + /// Returns the height of the mode. pub fn height(&self) -> i32 { self.height } + /// Returns the refresh rate of the mode in mhz. + /// + /// For a 60hz monitor, this function would return 60_000. pub fn refresh_rate(&self) -> u32 { self.refresh_millihz } @@ -41,14 +55,23 @@ impl Mode { } } +/// A connector that is potentially connected to an output device. +/// +/// A connector is the part that sticks out of your graphics card. A graphics card usually +/// has many connectors but one few of them are actually connected to a monitor. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct Connector(pub u64); impl Connector { + /// Returns whether this connector existed at the time `get_connector` was called. + /// + /// This only implies existence at the time `get_connector` was called. Even if this + /// function returns true, the connector might since have disappeared. pub fn exists(self) -> bool { self.0 != 0 } + /// Returns whether the connector is connected to an output device. pub fn connected(self) -> bool { if !self.exists() { return false; @@ -56,6 +79,7 @@ impl Connector { get!(false).connector_connected(self) } + /// Returns the connector type. pub fn ty(self) -> ConnectorType { if !self.exists() { return CON_UNKNOWN; @@ -63,6 +87,7 @@ impl Connector { get!(CON_UNKNOWN).connector_type(self) } + /// Returns the current mode of the connector. pub fn mode(self) -> Mode { if !self.exists() { return Mode::zeroed(); @@ -70,18 +95,34 @@ impl Connector { get!(Mode::zeroed()).connector_mode(self) } + /// Returns the width of the current mode of the connector. + /// + /// This is a shortcut for `mode().width()`. pub fn width(self) -> i32 { self.mode().width } + /// Returns the height of the current mode of the connector. + /// + /// This is a shortcut for `mode().height()`. pub fn height(self) -> i32 { self.mode().height } + /// Returns the refresh rate in mhz of the current mode of the connector. + /// + /// This is a shortcut for `mode().refresh_rate()`. pub fn refresh_rate(self) -> u32 { self.mode().refresh_millihz } + /// Sets the position of the connector in the global compositor space. + /// + /// `x` and `y` must be non-negative and must not exceed a currently unspecified limit. + /// Any reasonable values for `x` and `y` should work. + /// + /// This function allows the connector to overlap with other connectors, however, such + /// configurations are not supported and might result in unexpected behavior. pub fn set_position(self, x: i32, y: i32) { if !self.exists() { log::warn!("set_position called on a connector that does not exist"); @@ -91,30 +132,72 @@ impl Connector { } } +/// Returns all available DRM devices. pub fn drm_devices() -> Vec { get!().drm_devices() } +/// Sets the callback to be called when a new DRM device appears. pub fn on_new_drm_device(f: F) { get!().on_new_drm_device(f) } +/// Sets the callback to be called when a DRM device is removed. pub fn on_drm_device_removed(f: F) { get!().on_del_drm_device(f) } +/// Sets the callback to be called when a new connector appears. pub fn on_new_connector(f: F) { get!().on_new_connector(f) } +/// Sets the callback to be called when a connector becomes connected to an output device. pub fn on_connector_connected(f: F) { get!().on_connector_connected(f) } +/// Sets the callback to be called when the graphics of the compositor have been initialized. +/// +/// This callback is only invoked once during the lifetime of the compositor. This is a good place +/// to auto start graphical applications. pub fn on_graphics_initialized(f: F) { get!().on_graphics_initialized(f) } +/// Returns the connector with the given id. +/// +/// The linux kernel identifies connectors by a (type, idx) tuple, e.g., `DP-0`. +/// If the connector does not exist at the time this function is called, a sentinel value is +/// returned. This can be checked by calling `exists()` on the returned connector. +/// +/// The `id` argument can either be an explicit tuple, e.g. `(CON_DISPLAY_PORT, 0)`, or a string +/// that can be parsed to such a tuple, e.g. `"DP-0"`. +/// +/// The following string prefixes exist: +/// +/// - `DP` +/// - `eDP` +/// - `HDMI-A` +/// - `HDMI-B` +/// - `EmbeddedWindow` - this is an implementation detail of the compositor and used if it +/// runs as an embedded application. +/// - `VGA` +/// - `DVI-I` +/// - `DVI-D` +/// - `DVI-A` +/// - `Composite` +/// - `SVIDEO` +/// - `LVDS` +/// - `Component` +/// - `DIN` +/// - `TV` +/// - `Virtual` +/// - `DSI` +/// - `DPI` +/// - `Writeback` +/// - `SPI` +/// - `USB` pub fn get_connector(id: impl ToConnectorId) -> Connector { let (ty, idx) = match id.to_connector_id() { Ok(id) => id, @@ -126,6 +209,7 @@ pub fn get_connector(id: impl ToConnectorId) -> Connector { get!(Connector(0)).get_connector(ty, idx) } +/// A type that can be converted to a `(ConnectorType, idx)` tuple. pub trait ToConnectorId { fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>; } @@ -172,9 +256,11 @@ impl ToConnectorId for &'_ str { } } +/// Module containing all known connector types. pub mod connector_type { use bincode::{Decode, Encode}; + /// The type of a connector. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct ConnectorType(pub u32); @@ -202,26 +288,44 @@ pub mod connector_type { pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX); } +/// A *Direct Rendering Manager* (DRM) device. +/// +/// It's easiest to think of a DRM device as a graphics card. +/// There are also DRM devices that are emulated in software but you are unlikely to encounter +/// those accidentally. #[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] pub struct DrmDevice(pub u64); impl DrmDevice { + /// Returns the connectors of this device. pub fn connectors(self) -> Vec { get!().device_connectors(self) } + /// Returns the syspath of this device. + /// + /// E.g. `/sys/devices/pci0000:00/0000:00:03.1/0000:07:00.0`. pub fn syspath(self) -> String { get!().drm_device_syspath(self) } + /// Returns the vendor of this device. + /// + /// E.g. `Advanced Micro Devices, Inc. [AMD/ATI]`. pub fn vendor(self) -> String { get!().drm_device_vendor(self) } + /// Returns the model of this device. + /// + /// E.g. `Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570 Armor 8G OC)`. pub fn model(self) -> String { get!().drm_device_model(self) } + /// Returns the PIC ID of this device. + /// + /// E.g. `1002:67DF`. pub fn pci_id(self) -> PciId { get!().drm_device_pci_id(self) } diff --git a/src/config.rs b/src/config.rs index 6926868b..523ce7e8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,9 +19,9 @@ use { ipc::{InitMessage, ServerMessage, V1InitMessage}, ConfigEntry, VERSION, }, - drm::{Connector, DrmDevice}, input::{InputDevice, Seat}, keyboard::ModifiedKeySym, + video::{Connector, DrmDevice}, }, libloading::Library, std::{cell::Cell, mem, ptr, rc::Rc}, diff --git a/src/config/handler.rs b/src/config/handler.rs index 262467f2..cf99ae48 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -27,7 +27,6 @@ use { bincode_ops, ipc::{ClientMessage, Response, ServerMessage}, }, - drm::{Connector, DrmDevice}, input::{ acceleration::{AccelProfile, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT}, capability::{ @@ -36,9 +35,12 @@ use { }, InputDevice, Seat, }, - keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym}, + keyboard::{mods::Modifiers, syms::KeySym, Keymap}, + logging::LogLevel, theme::{colors::Colorable, sized::Resizable}, - Axis, Direction, LogLevel, Workspace, + timer::Timer as JayTimer, + video::{Connector, DrmDevice}, + Axis, Direction, Workspace, }, libloading::Library, log::Level, @@ -254,14 +256,14 @@ impl ConfigProxyHandler { self.state.set_status(status); } - fn get_timer(&self, timer: jay_config::Timer) -> Result, CphError> { + fn get_timer(&self, timer: JayTimer) -> Result, CphError> { match self.timers_by_id.get(&timer.0) { Some(t) => Ok(t), _ => Err(CphError::TimerDoesNotExist(timer)), } } - fn handle_remove_timer(&self, timer: jay_config::Timer) -> Result<(), CphError> { + fn handle_remove_timer(&self, timer: JayTimer) -> Result<(), CphError> { let timer = self.get_timer(timer)?; self.timers_by_id.remove(&timer.id); self.timers_by_name.remove(&timer.name); @@ -276,7 +278,7 @@ impl ConfigProxyHandler { fn handle_program_timer( &self, - timer: jay_config::Timer, + timer: JayTimer, initial: Option, periodic: Option, ) -> Result<(), CphError> { @@ -289,7 +291,7 @@ impl ConfigProxyHandler { let name = Rc::new(name.to_owned()); if let Some(t) = self.timers_by_name.get(&name) { self.respond(Response::GetTimer { - timer: jay_config::Timer(t.id), + timer: JayTimer(t.id), }); return Ok(()); } @@ -302,7 +304,7 @@ impl ConfigProxyHandler { loop { match timer.expired(&slf.state.ring).await { Ok(_) => slf.send(&ServerMessage::TimerExpired { - timer: jay_config::Timer(id), + timer: JayTimer(id), }), Err(e) => { log::error!("Could not wait for timer expiration: {}", ErrorFmt(e)); @@ -324,7 +326,7 @@ impl ConfigProxyHandler { self.timers_by_name.set(name.clone(), td.clone()); self.timers_by_id.set(id, td.clone()); self.respond(Response::GetTimer { - timer: jay_config::Timer(id), + timer: JayTimer(id), }); Ok(()) } @@ -337,13 +339,13 @@ impl ConfigProxyHandler { fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), CphError> { let seat = self.get_seat(seat)?; - seat.move_focus(direction); + seat.move_focus(direction.into()); Ok(()) } fn handle_move(&self, seat: Seat, direction: Direction) -> Result<(), CphError> { let seat = self.get_seat(seat)?; - seat.move_focused(direction); + seat.move_focused(direction.into()); Ok(()) } @@ -592,7 +594,7 @@ impl ConfigProxyHandler { fn handle_get_connector( &self, - ty: jay_config::drm::connector_type::ConnectorType, + ty: jay_config::video::connector_type::ConnectorType, idx: u32, ) -> Result<(), CphError> { let connectors = self.state.connectors.lock(); @@ -1101,7 +1103,7 @@ enum CphError { #[error("Connector {0:?} does not exist")] ConnectorDoesNotExist(Connector), #[error("Timer {0:?} does not exist")] - TimerDoesNotExist(jay_config::Timer), + TimerDoesNotExist(JayTimer), #[error("Connector {0:?} does not exist or is not connected")] OutputDoesNotExist(Connector), #[error("{0}x{1} is not a valid connector position")] diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index b3225867..6a1537cc 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -40,8 +40,8 @@ use { object::Object, state::State, tree::{ - generic_node_visitor, ContainerNode, ContainerSplit, FloatNode, FoundNode, Node, - OutputNode, WorkspaceNode, + generic_node_visitor, ContainerNode, ContainerSplit, Direction, FloatNode, FoundNode, + Node, OutputNode, WorkspaceNode, }, utils::{ asyncevent::AsyncEvent, @@ -60,7 +60,7 @@ use { xkbcommon::{XkbKeymap, XkbState}, }, ahash::{AHashMap, AHashSet}, - jay_config::{keyboard::mods::Modifiers, Direction}, + jay_config::keyboard::mods::Modifiers, smallvec::SmallVec, std::{ cell::{Cell, RefCell}, diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 07d7e67f..85f510e4 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -23,15 +23,12 @@ use { }, wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface}, }, - tree::{FloatNode, Node, ToplevelNode}, + tree::{Direction, FloatNode, Node, ToplevelNode}, utils::{bitflags::BitflagsExt, clonecell::CloneCell, smallmap::SmallMap}, wire::WlDataOfferId, xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP}, }, - jay_config::{ - keyboard::{mods::Modifiers, syms::KeySym, ModifiedKeySym}, - Direction, - }, + jay_config::keyboard::{mods::Modifiers, syms::KeySym, ModifiedKeySym}, smallvec::SmallVec, std::rc::Rc, }; diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index d8aab2bf..adc5aabc 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -15,8 +15,8 @@ use { render::Renderer, state::State, tree::{ - FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, ToplevelNode, - ToplevelNodeId, WorkspaceNode, + Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, + ToplevelNode, ToplevelNodeId, WorkspaceNode, }, utils::{ buffd::{MsgParser, MsgParserError}, @@ -25,7 +25,6 @@ use { wire::{xdg_toplevel::*, XdgToplevelId}, }, ahash::{AHashMap, AHashSet}, - jay_config::Direction, num_derive::FromPrimitive, std::{ cell::{Cell, RefCell}, diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/xwindow.rs index dcbab7a5..76cf18f7 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/xwindow.rs @@ -11,8 +11,8 @@ use { render::Renderer, state::State, tree::{ - FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode, ToplevelData, - ToplevelNode, + Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode, + ToplevelData, ToplevelNode, }, utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode}, wire::WlSurfaceId, @@ -20,7 +20,6 @@ use { xwayland::XWaylandEvent, }, bstr::BString, - jay_config::Direction, std::{ cell::{Cell, RefCell}, ops::{Deref, Not}, diff --git a/src/it/test_config.rs b/src/it/test_config.rs index b0feb417..816108f6 100644 --- a/src/it/test_config.rs +++ b/src/it/test_config.rs @@ -13,7 +13,7 @@ use { ConfigEntry, VERSION, }, input::{InputDevice, Seat}, - keyboard::{keymap::Keymap, ModifiedKeySym}, + keyboard::{Keymap, ModifiedKeySym}, Axis, Direction, }, std::{cell::Cell, ops::Deref, ptr, rc::Rc}, diff --git a/src/keymap.xkb b/src/keymap.xkb index c82f86bc..ea0cef66 100644 --- a/src/keymap.xkb +++ b/src/keymap.xkb @@ -1,5 +1,6 @@ xkb_keymap { + # See the file keycodes.xkb for a full list of keycodes. xkb_keycodes { <1> = 9; # ESC diff --git a/src/state.rs b/src/state.rs index 8f5480e1..fb81b950 100644 --- a/src/state.rs +++ b/src/state.rs @@ -30,8 +30,8 @@ use { render::RenderContext, theme::Theme, tree::{ - ContainerNode, ContainerSplit, DisplayNode, FloatNode, Node, NodeIds, NodeVisitorBase, - OutputNode, PlaceholderNode, ToplevelNode, WorkspaceNode, + ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds, + NodeVisitorBase, OutputNode, PlaceholderNode, ToplevelNode, WorkspaceNode, }, utils::{ asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap, @@ -43,7 +43,7 @@ use { xwayland::{self, XWaylandEvent}, }, ahash::AHashMap, - jay_config::{Direction, PciId}, + jay_config::PciId, std::{ cell::{Cell, RefCell}, fmt::{Debug, Formatter}, diff --git a/src/tree.rs b/src/tree.rs index 709a648d..de492ce7 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -12,7 +12,7 @@ use { utils::numcell::NumCell, xkbcommon::ModifierState, }, - jay_config::Direction, + jay_config::Direction as JayDirection, std::{ fmt::{Debug, Display}, rc::Rc, @@ -34,6 +34,26 @@ mod toplevel; mod walker; mod workspace; +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Direction { + Unspecified, + Left, + Down, + Up, + Right, +} + +impl From for Direction { + fn from(d: JayDirection) -> Self { + match d { + JayDirection::Left => Self::Left, + JayDirection::Down => Self::Down, + JayDirection::Up => Self::Up, + JayDirection::Right => Self::Right, + } + } +} + pub struct NodeIds { next: NumCell, } diff --git a/src/tree/container.rs b/src/tree/container.rs index 6b9ecd8f..17debdec 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -12,8 +12,8 @@ use { state::State, text, tree::{ - walker::NodeVisitor, ContainingNode, FindTreeResult, FoundNode, Node, NodeId, - ToplevelData, ToplevelNode, WorkspaceNode, + walker::NodeVisitor, ContainingNode, Direction, FindTreeResult, FoundNode, Node, + NodeId, ToplevelData, ToplevelNode, WorkspaceNode, }, utils::{ clonecell::CloneCell, @@ -25,7 +25,7 @@ use { }, }, ahash::AHashMap, - jay_config::{Axis, Direction}, + jay_config::Axis, smallvec::SmallVec, std::{ cell::{Cell, RefCell}, diff --git a/src/tree/output.rs b/src/tree/output.rs index ce80e98b..2cc086a7 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -12,12 +12,13 @@ use { render::{Renderer, Texture}, state::State, text, - tree::{walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}, + tree::{ + walker::NodeVisitor, Direction, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode, + }, utils::{ clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList, scroller::Scroller, }, }, - jay_config::Direction, smallvec::SmallVec, std::{ cell::{Cell, RefCell}, diff --git a/src/tree/placeholder.rs b/src/tree/placeholder.rs index 90c05e4f..02f5c3bc 100644 --- a/src/tree/placeholder.rs +++ b/src/tree/placeholder.rs @@ -8,10 +8,12 @@ use { render::{Renderer, Texture}, state::State, text, - tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, ToplevelNode}, + tree::{ + Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, + ToplevelNode, + }, utils::{clonecell::CloneCell, errorfmt::ErrorFmt}, }, - jay_config::Direction, std::{cell::Cell, ops::Deref, rc::Rc}, }; diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 91be19a5..77338322 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -4,10 +4,9 @@ use { ifs::wl_seat::{collect_kb_foci, collect_kb_foci2, NodeSeatState, SeatId}, rect::Rect, state::State, - tree::{ContainingNode, Node, OutputNode, PlaceholderNode, WorkspaceNode}, + tree::{ContainingNode, Direction, Node, OutputNode, PlaceholderNode, WorkspaceNode}, utils::{clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap}, }, - jay_config::Direction, std::{ cell::{Cell, RefCell}, ops::Deref, diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 10dbb7ab..78f25ad4 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -5,15 +5,14 @@ use { rect::Rect, render::Renderer, tree::{ - container::ContainerNode, walker::NodeVisitor, ContainingNode, FindTreeResult, - FoundNode, Node, NodeId, OutputNode, StackedNode, ToplevelNode, + container::ContainerNode, walker::NodeVisitor, ContainingNode, Direction, + FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode, ToplevelNode, }, utils::{ clonecell::CloneCell, linkedlist::{LinkedList, LinkedNode}, }, }, - jay_config::Direction, std::{cell::Cell, fmt::Debug, rc::Rc}, }; diff --git a/src/video/drm.rs b/src/video/drm.rs index 7351644b..417a2fed 100644 --- a/src/video/drm.rs +++ b/src/video/drm.rs @@ -803,8 +803,8 @@ impl ConnectorType { } } - pub fn to_config(self) -> jay_config::drm::connector_type::ConnectorType { - use jay_config::drm::connector_type::*; + pub fn to_config(self) -> jay_config::video::connector_type::ConnectorType { + use jay_config::video::connector_type::*; match self { Self::Unknown(_) => CON_UNKNOWN, Self::VGA => CON_VGA,