config: add documentation
This commit is contained in:
parent
6916f03e94
commit
fe80440f38
36 changed files with 620 additions and 199 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
use {
|
use {
|
||||||
chrono::{format::StrftimeItems, Local, Timelike},
|
chrono::{format::StrftimeItems, Local},
|
||||||
jay_config::{
|
jay_config::{
|
||||||
config,
|
config,
|
||||||
drm::on_graphics_initialized,
|
exec::Command,
|
||||||
get_timer, get_workspace,
|
get_workspace,
|
||||||
input::{get_seat, input_devices, on_new_input_device, InputDevice, Seat},
|
input::{get_seat, input_devices, on_new_input_device, InputDevice, Seat},
|
||||||
keyboard::{
|
keyboard::{
|
||||||
mods::{Modifiers, ALT, CTRL, SHIFT},
|
mods::{Modifiers, ALT, CTRL, SHIFT},
|
||||||
|
|
@ -16,8 +16,9 @@ use {
|
||||||
quit, reload,
|
quit, reload,
|
||||||
status::set_status,
|
status::set_status,
|
||||||
switch_to_vt,
|
switch_to_vt,
|
||||||
|
timer::{duration_until_wall_clock_is_multiple_of, get_timer},
|
||||||
|
video::on_graphics_initialized,
|
||||||
Axis::{Horizontal, Vertical},
|
Axis::{Horizontal, Vertical},
|
||||||
Command,
|
|
||||||
Direction::{Down, Left, Right, Up},
|
Direction::{Down, Left, Right, Up},
|
||||||
},
|
},
|
||||||
std::time::Duration,
|
std::time::Duration,
|
||||||
|
|
@ -77,16 +78,9 @@ fn setup_status() {
|
||||||
set_status(&status);
|
set_status(&status);
|
||||||
};
|
};
|
||||||
update_status();
|
update_status();
|
||||||
// Sleep until the time becomes a multiple of 5 seconds
|
let period = Duration::from_secs(5);
|
||||||
let initial = {
|
|
||||||
let now = Local::now();
|
|
||||||
5000 - (now.second() * 1000 + now.timestamp_subsec_millis()) % 5000
|
|
||||||
};
|
|
||||||
let timer = get_timer("status_timer");
|
let timer = get_timer("status_timer");
|
||||||
timer.program(
|
timer.repeated(duration_until_wall_clock_is_multiple_of(period), period);
|
||||||
Duration::from_millis(initial as u64),
|
|
||||||
Some(Duration::from_secs(5)),
|
|
||||||
);
|
|
||||||
timer.on_tick(update_status);
|
timer.on_tick(update_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,17 @@ use {
|
||||||
ipc::{ClientMessage, InitMessage, Response, ServerMessage},
|
ipc::{ClientMessage, InitMessage, Response, ServerMessage},
|
||||||
logging, Config, ConfigEntry, ConfigEntryGen, VERSION,
|
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_type::{ConnectorType, CON_UNKNOWN},
|
||||||
Connector, DrmDevice, Mode,
|
Connector, DrmDevice, Mode,
|
||||||
},
|
},
|
||||||
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
|
Axis, Direction, ModifiedKeySym, PciId, Workspace,
|
||||||
keyboard::keymap::Keymap,
|
|
||||||
theme::{colors::Colorable, sized::Resizable, Color},
|
|
||||||
Axis, Command, Direction, LogLevel, ModifiedKeySym, PciId, Timer, Workspace,
|
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
drm::{connector_type::ConnectorType, Connector, DrmDevice},
|
|
||||||
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
|
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},
|
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},
|
bincode::{BorrowDecode, Decode, Encode},
|
||||||
std::time::Duration,
|
std::time::Duration,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::LogLevel,
|
crate::logging::LogLevel,
|
||||||
log::{Level, LevelFilter, Log, Metadata, Record},
|
log::{Level, LevelFilter, Log, Metadata, Record},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
|
//! Tools to configure the compositor in embedded environments.
|
||||||
|
|
||||||
use crate::input::InputDevice;
|
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) {
|
pub fn grab_input_device(kb: InputDevice, grab: bool) {
|
||||||
get!().grab(kb, grab);
|
get!().grab(kb, grab);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
jay-config/src/exec.rs
Normal file
50
jay-config/src/exec.rs
Normal file
|
|
@ -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<String>,
|
||||||
|
pub(crate) env: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,48 +1,90 @@
|
||||||
|
//! Tools for configuring input devices.
|
||||||
|
|
||||||
pub mod acceleration;
|
pub mod acceleration;
|
||||||
pub mod capability;
|
pub mod capability;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
input::{acceleration::AccelProfile, capability::Capability},
|
input::{acceleration::AccelProfile, capability::Capability},
|
||||||
Axis, Direction, Keymap, ModifiedKeySym, Workspace,
|
keyboard::Keymap,
|
||||||
|
Axis, Direction, ModifiedKeySym, Workspace,
|
||||||
},
|
},
|
||||||
bincode::{Decode, Encode},
|
bincode::{Decode, Encode},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An input device.
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct InputDevice(pub u64);
|
pub struct InputDevice(pub u64);
|
||||||
|
|
||||||
impl InputDevice {
|
impl InputDevice {
|
||||||
|
/// Assigns the input device to a seat.
|
||||||
pub fn set_seat(self, seat: Seat) {
|
pub fn set_seat(self, seat: Seat) {
|
||||||
get!().set_seat(self, seat)
|
get!().set_seat(self, seat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the device has the specified capability.
|
||||||
pub fn has_capability(self, cap: Capability) -> bool {
|
pub fn has_capability(self, cap: Capability) -> bool {
|
||||||
get!(false).has_capability(self, cap)
|
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) {
|
pub fn set_left_handed(self, left_handed: bool) {
|
||||||
get!().set_left_handed(self, left_handed);
|
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) {
|
pub fn set_accel_profile(self, profile: AccelProfile) {
|
||||||
get!().set_accel_profile(self, profile);
|
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) {
|
pub fn set_accel_speed(self, speed: f64) {
|
||||||
get!().set_accel_speed(self, speed);
|
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]) {
|
pub fn set_transform_matrix(self, matrix: [[f64; 2]; 2]) {
|
||||||
get!().set_transform_matrix(self, matrix);
|
get!().set_transform_matrix(self, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the device.
|
||||||
pub fn name(self) -> String {
|
pub fn name(self) -> String {
|
||||||
get!(String::new()).device_name(self)
|
get!(String::new()).device_name(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A seat.
|
||||||
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub struct Seat(pub u64);
|
||||||
|
|
||||||
impl Seat {
|
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)]
|
#[doc(hidden)]
|
||||||
pub fn raw(self) -> u64 {
|
pub fn raw(self) -> u64 {
|
||||||
self.0
|
self.0
|
||||||
|
|
@ -53,143 +95,164 @@ impl Seat {
|
||||||
Self(raw)
|
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<T: Into<ModifiedKeySym>, F: Fn() + 'static>(self, mod_sym: T, f: F) {
|
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(self, mod_sym: T, f: F) {
|
||||||
get!().bind(self, mod_sym, f)
|
get!().bind(self, mod_sym, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unbinds a hotkey.
|
||||||
pub fn unbind<T: Into<ModifiedKeySym>>(self, mod_sym: T) {
|
pub fn unbind<T: Into<ModifiedKeySym>>(self, mod_sym: T) {
|
||||||
get!().unbind(self, mod_sym)
|
get!().unbind(self, mod_sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Moves the keyboard focus of the seat in the specified direction.
|
||||||
pub fn focus(self, direction: Direction) {
|
pub fn focus(self, direction: Direction) {
|
||||||
get!().focus(self, direction)
|
get!().focus(self, direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Moves the focused window in the specified direction.
|
||||||
pub fn move_(self, direction: Direction) {
|
pub fn move_(self, direction: Direction) {
|
||||||
get!().move_(self, direction)
|
get!().move_(self, direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the keymap of the seat.
|
||||||
pub fn set_keymap(self, keymap: Keymap) {
|
pub fn set_keymap(self, keymap: Keymap) {
|
||||||
get!().seat_set_keymap(self, 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) {
|
pub fn repeat_rate(self) -> (i32, i32) {
|
||||||
let mut res = (25, 250);
|
get!((25, 250)).seat_get_repeat_rate(self)
|
||||||
(|| res = get!().seat_get_repeat_rate(self))();
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the repeat rate of the seat.
|
||||||
pub fn set_repeat_rate(self, rate: i32, delay: i32) {
|
pub fn set_repeat_rate(self, rate: i32, delay: i32) {
|
||||||
get!().seat_set_repeat_rate(self, rate, delay)
|
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 {
|
pub fn mono(self) -> bool {
|
||||||
get!(false).mono(self)
|
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) {
|
pub fn set_mono(self, mono: bool) {
|
||||||
get!().set_mono(self, mono)
|
get!().set_mono(self, mono)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggles whether the parent-container of the currently focused window is in mono-mode.
|
||||||
pub fn toggle_mono(self) {
|
pub fn toggle_mono(self) {
|
||||||
self.set_mono(!self.mono());
|
self.set_mono(!self.mono());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the split axis of the parent-container of the currently focused window.
|
||||||
pub fn split(self) -> Axis {
|
pub fn split(self) -> Axis {
|
||||||
get!(Axis::Horizontal).split(self)
|
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) {
|
pub fn set_split(self, axis: Axis) {
|
||||||
get!().set_split(self, axis)
|
get!().set_split(self, axis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggles the split axis of the parent-container of the currently focused window.
|
||||||
pub fn toggle_split(self) {
|
pub fn toggle_split(self) {
|
||||||
self.set_split(self.split().other());
|
self.set_split(self.split().other());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the input devices assigned to this seat.
|
||||||
pub fn input_devices(self) -> Vec<InputDevice> {
|
pub fn input_devices(self) -> Vec<InputDevice> {
|
||||||
get!().get_input_devices(Some(self))
|
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) {
|
pub fn create_split(self, axis: Axis) {
|
||||||
get!().create_split(self, axis);
|
get!().create_split(self, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Focuses the parent node of the currently focused window.
|
||||||
pub fn focus_parent(self) {
|
pub fn focus_parent(self) {
|
||||||
get!().focus_parent(self);
|
get!().focus_parent(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Requests the currently focused window to be closed.
|
||||||
pub fn close(self) {
|
pub fn close(self) {
|
||||||
get!().close(self);
|
get!().close(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the currently focused window is floating.
|
||||||
pub fn get_floating(self) -> bool {
|
pub fn get_floating(self) -> bool {
|
||||||
get!().get_floating(self)
|
get!().get_floating(self)
|
||||||
}
|
}
|
||||||
|
/// Sets whether the currently focused window is floating.
|
||||||
pub fn set_floating(self, floating: bool) {
|
pub fn set_floating(self, floating: bool) {
|
||||||
get!().set_floating(self, floating);
|
get!().set_floating(self, floating);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggles whether the currently focused window is floating.
|
||||||
pub fn toggle_floating(self) {
|
pub fn toggle_floating(self) {
|
||||||
get!().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) {
|
pub fn show_workspace(self, workspace: Workspace) {
|
||||||
get!().show_workspace(self, workspace)
|
get!().show_workspace(self, workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Moves the currently focused window to the workspace.
|
||||||
pub fn set_workspace(self, workspace: Workspace) {
|
pub fn set_workspace(self, workspace: Workspace) {
|
||||||
get!().set_workspace(self, workspace)
|
get!().set_workspace(self, workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggles whether the currently focused window is fullscreen.
|
||||||
pub fn toggle_fullscreen(self) {
|
pub fn toggle_fullscreen(self) {
|
||||||
let c = get!();
|
let c = get!();
|
||||||
c.set_fullscreen(self, !c.get_fullscreen(self));
|
c.set_fullscreen(self, !c.get_fullscreen(self));
|
||||||
}
|
}
|
||||||
|
/// Returns whether the currently focused window is fullscreen.
|
||||||
pub fn fullscreen(self) -> bool {
|
pub fn fullscreen(self) -> bool {
|
||||||
get!(false).get_fullscreen(self)
|
get!(false).get_fullscreen(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets whether the currently focused window is fullscreen.
|
||||||
pub fn set_fullscreen(self, fullscreen: bool) {
|
pub fn set_fullscreen(self, fullscreen: bool) {
|
||||||
get!().set_fullscreen(self, fullscreen)
|
get!().set_fullscreen(self, fullscreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all seats.
|
||||||
pub fn get_seats() -> Vec<Seat> {
|
pub fn get_seats() -> Vec<Seat> {
|
||||||
let mut res = vec![];
|
get!().seats()
|
||||||
(|| res = get!().seats())();
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all input devices.
|
||||||
pub fn input_devices() -> Vec<InputDevice> {
|
pub fn input_devices() -> Vec<InputDevice> {
|
||||||
get!().get_input_devices(None)
|
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 {
|
pub fn get_seat(name: &str) -> Seat {
|
||||||
let mut res = Seat(0);
|
get!(Seat(0)).get_seat(name)
|
||||||
(|| res = get!().get_seat(name))();
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a closure to run when a new seat has been created.
|
||||||
pub fn on_new_seat<F: Fn(Seat) + 'static>(f: F) {
|
pub fn on_new_seat<F: Fn(Seat) + 'static>(f: F) {
|
||||||
get!().on_new_seat(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: Fn(InputDevice) + 'static>(f: F) {
|
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(f: F) {
|
||||||
get!().on_new_input_device(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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
|
//! Constants determining the acceleration profile of a device.
|
||||||
|
//!
|
||||||
|
//! See the libinput documentation for details.
|
||||||
|
|
||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
/// The acceleration profile of a device.
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct AccelProfile(pub u32);
|
pub struct AccelProfile(pub u32);
|
||||||
|
|
||||||
|
/// A flat acceleration profile.
|
||||||
pub const ACCEL_PROFILE_FLAT: AccelProfile = AccelProfile(1 << 0);
|
pub const ACCEL_PROFILE_FLAT: AccelProfile = AccelProfile(1 << 0);
|
||||||
|
/// An adaptive acceleration profile.
|
||||||
pub const ACCEL_PROFILE_ADAPTIVE: AccelProfile = AccelProfile(1 << 1);
|
pub const ACCEL_PROFILE_ADAPTIVE: AccelProfile = AccelProfile(1 << 1);
|
||||||
|
|
|
||||||
|
|
@ -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};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
/// A capability of an input device.
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct Capability(pub u32);
|
pub struct Capability(pub u32);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
|
//! Tools affecting the keyboard behavior.
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::keyboard::{mods::Modifiers, syms::KeySym},
|
crate::keyboard::{mods::Modifiers, syms::KeySym},
|
||||||
bincode::{Decode, Encode},
|
bincode::{Decode, Encode},
|
||||||
std::ops::{BitOr, BitOrAssign},
|
std::ops::{BitOr, BitOrAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod keymap;
|
|
||||||
pub mod mods;
|
pub mod mods;
|
||||||
pub mod syms;
|
pub mod syms;
|
||||||
|
|
||||||
|
/// A keysym with zero or more modifiers
|
||||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub struct ModifiedKeySym {
|
pub struct ModifiedKeySym {
|
||||||
pub mods: Modifiers,
|
pub mods: Modifiers,
|
||||||
|
|
@ -39,3 +41,62 @@ impl BitOrAssign<Modifiers> for ModifiedKeySym {
|
||||||
self.mods |= rhs;
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,39 @@
|
||||||
|
//! Keyboard modifiers
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{keyboard::syms::KeySym, ModifiedKeySym},
|
crate::{keyboard::syms::KeySym, ModifiedKeySym},
|
||||||
bincode::{Decode, Encode},
|
bincode::{Decode, Encode},
|
||||||
std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign},
|
std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Zero or more keyboard modifiers
|
||||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default, Hash, Debug)]
|
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default, Hash, Debug)]
|
||||||
pub struct Modifiers(pub u32);
|
pub struct Modifiers(pub u32);
|
||||||
|
|
||||||
|
/// The Shift modifier
|
||||||
pub const SHIFT: Modifiers = Modifiers(1 << 0);
|
pub const SHIFT: Modifiers = Modifiers(1 << 0);
|
||||||
|
/// The CapsLock modifier.
|
||||||
pub const LOCK: Modifiers = Modifiers(1 << 1);
|
pub const LOCK: Modifiers = Modifiers(1 << 1);
|
||||||
|
/// The Ctrl modifier.
|
||||||
pub const CTRL: Modifiers = Modifiers(1 << 2);
|
pub const CTRL: Modifiers = Modifiers(1 << 2);
|
||||||
|
/// The Mod1 modifier, i.e., Alt.
|
||||||
pub const MOD1: Modifiers = Modifiers(1 << 3);
|
pub const MOD1: Modifiers = Modifiers(1 << 3);
|
||||||
|
/// The Mod2 modifier, i.e., NumLock.
|
||||||
pub const MOD2: Modifiers = Modifiers(1 << 4);
|
pub const MOD2: Modifiers = Modifiers(1 << 4);
|
||||||
|
/// The Mod3 modifier.
|
||||||
pub const MOD3: Modifiers = Modifiers(1 << 5);
|
pub const MOD3: Modifiers = Modifiers(1 << 5);
|
||||||
|
/// The Mod4 modifier, i.e., Logo.
|
||||||
pub const MOD4: Modifiers = Modifiers(1 << 6);
|
pub const MOD4: Modifiers = Modifiers(1 << 6);
|
||||||
|
/// The Mod5 modifier.
|
||||||
pub const MOD5: Modifiers = Modifiers(1 << 7);
|
pub const MOD5: Modifiers = Modifiers(1 << 7);
|
||||||
|
|
||||||
|
/// Alias for `LOCK`.
|
||||||
pub const CAPS: Modifiers = LOCK;
|
pub const CAPS: Modifiers = LOCK;
|
||||||
|
/// Alias for `MOD1`.
|
||||||
pub const ALT: Modifiers = MOD1;
|
pub const ALT: Modifiers = MOD1;
|
||||||
|
/// Alias for `MOD2`.
|
||||||
pub const NUM: Modifiers = MOD2;
|
pub const NUM: Modifiers = MOD2;
|
||||||
|
/// Alias for `MOD4`.
|
||||||
pub const LOGO: Modifiers = MOD4;
|
pub const LOGO: Modifiers = MOD4;
|
||||||
|
|
||||||
impl BitOr for Modifiers {
|
impl BitOr for Modifiers {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
//! Keysyms
|
||||||
|
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
/// A keysym.
|
||||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub struct KeySym(pub u32);
|
pub struct KeySym(pub u32);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
use {
|
||||||
crate::keyboard::{keymap::Keymap, ModifiedKeySym},
|
crate::keyboard::ModifiedKeySym,
|
||||||
bincode::{Decode, Encode},
|
bincode::{Decode, Encode},
|
||||||
std::{
|
std::fmt::{Debug, Display, Formatter},
|
||||||
collections::HashMap,
|
|
||||||
fmt::{Debug, Display, Formatter},
|
|
||||||
time::Duration,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod _private;
|
pub mod _private;
|
||||||
pub mod drm;
|
|
||||||
pub mod embedded;
|
pub mod embedded;
|
||||||
|
pub mod exec;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
pub mod logging;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod video;
|
||||||
|
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug)]
|
/// A planar direction.
|
||||||
pub enum LogLevel {
|
|
||||||
Error,
|
|
||||||
Warn,
|
|
||||||
Info,
|
|
||||||
Debug,
|
|
||||||
Trace,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Unspecified,
|
|
||||||
Left,
|
Left,
|
||||||
Down,
|
Down,
|
||||||
Up,
|
Up,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A planar axis.
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub enum Axis {
|
pub enum Axis {
|
||||||
Horizontal,
|
Horizontal,
|
||||||
|
|
@ -44,6 +71,7 @@ pub enum Axis {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Axis {
|
impl Axis {
|
||||||
|
/// Returns the axis orthogonal to `self`.
|
||||||
pub fn other(self) -> Self {
|
pub fn other(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Horizontal => Self::Vertical,
|
Self::Horizontal => Self::Vertical,
|
||||||
|
|
@ -52,88 +80,47 @@ impl Axis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Exits the compositor.
|
||||||
pub fn quit() {
|
pub fn quit() {
|
||||||
get!().quit()
|
get!().quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Switches to a different VT.
|
||||||
pub fn switch_to_vt(n: u32) {
|
pub fn switch_to_vt(n: u32) {
|
||||||
get!().switch_to_vt(n)
|
get!().switch_to_vt(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_env(key: &str, val: &str) {
|
/// Reloads the configuration.
|
||||||
get!().set_env(key, val);
|
///
|
||||||
}
|
/// If the configuration cannot be reloaded, this function has no effect.
|
||||||
|
|
||||||
pub struct Command {
|
|
||||||
prog: String,
|
|
||||||
args: Vec<String>,
|
|
||||||
env: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Duration>) {
|
|
||||||
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<F: Fn() + 'static>(self, f: F) {
|
|
||||||
get!().on_timer_tick(self, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reload() {
|
pub fn reload() {
|
||||||
get!().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 {
|
pub fn is_reload() -> bool {
|
||||||
get!(false).is_reload()
|
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)]
|
#[derive(Encode, Decode, Debug, Copy, Clone, Hash, Eq, PartialEq, Default)]
|
||||||
pub struct PciId {
|
pub struct PciId {
|
||||||
pub vendor: u32,
|
pub vendor: u32,
|
||||||
|
|
|
||||||
16
jay-config/src/logging.rs
Normal file
16
jay-config/src/logging.rs
Normal file
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/// Declares the entry point of the configuration.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! config {
|
macro_rules! config {
|
||||||
($f:path) => {
|
($f:path) => {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
pub fn set_status(status: &str) {
|
||||||
get!().set_status(status);
|
get!().set_status(status);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//! Knobs for changing the look of the compositor.
|
//! Tools for configuring the look of the compositor.
|
||||||
|
|
||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
|
@ -156,7 +156,7 @@ pub fn reset_font() {
|
||||||
get!().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 {
|
pub mod colors {
|
||||||
use {
|
use {
|
||||||
crate::theme::Color,
|
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 {
|
pub mod sized {
|
||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
|
|
||||||
92
jay-config/src/timer.rs
Normal file
92
jay-config/src/timer.rs
Normal file
|
|
@ -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<F: Fn() + 'static>(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 _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
//! Tools for configuring graphics cards and monitors.
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
drm::connector_type::{
|
video::connector_type::{
|
||||||
ConnectorType, CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI,
|
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_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,
|
CON_HDMIB, CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA,
|
||||||
|
|
@ -12,7 +14,14 @@ use {
|
||||||
std::str::FromStr,
|
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 struct Mode {
|
||||||
pub(crate) width: i32,
|
pub(crate) width: i32,
|
||||||
pub(crate) height: i32,
|
pub(crate) height: i32,
|
||||||
|
|
@ -20,14 +29,19 @@ pub struct Mode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mode {
|
impl Mode {
|
||||||
|
/// Returns the width of the mode.
|
||||||
pub fn width(&self) -> i32 {
|
pub fn width(&self) -> i32 {
|
||||||
self.width
|
self.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the height of the mode.
|
||||||
pub fn height(&self) -> i32 {
|
pub fn height(&self) -> i32 {
|
||||||
self.height
|
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 {
|
pub fn refresh_rate(&self) -> u32 {
|
||||||
self.refresh_millihz
|
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)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct Connector(pub u64);
|
pub struct Connector(pub u64);
|
||||||
|
|
||||||
impl Connector {
|
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 {
|
pub fn exists(self) -> bool {
|
||||||
self.0 != 0
|
self.0 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the connector is connected to an output device.
|
||||||
pub fn connected(self) -> bool {
|
pub fn connected(self) -> bool {
|
||||||
if !self.exists() {
|
if !self.exists() {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -56,6 +79,7 @@ impl Connector {
|
||||||
get!(false).connector_connected(self)
|
get!(false).connector_connected(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the connector type.
|
||||||
pub fn ty(self) -> ConnectorType {
|
pub fn ty(self) -> ConnectorType {
|
||||||
if !self.exists() {
|
if !self.exists() {
|
||||||
return CON_UNKNOWN;
|
return CON_UNKNOWN;
|
||||||
|
|
@ -63,6 +87,7 @@ impl Connector {
|
||||||
get!(CON_UNKNOWN).connector_type(self)
|
get!(CON_UNKNOWN).connector_type(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the current mode of the connector.
|
||||||
pub fn mode(self) -> Mode {
|
pub fn mode(self) -> Mode {
|
||||||
if !self.exists() {
|
if !self.exists() {
|
||||||
return Mode::zeroed();
|
return Mode::zeroed();
|
||||||
|
|
@ -70,18 +95,34 @@ impl Connector {
|
||||||
get!(Mode::zeroed()).connector_mode(self)
|
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 {
|
pub fn width(self) -> i32 {
|
||||||
self.mode().width
|
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 {
|
pub fn height(self) -> i32 {
|
||||||
self.mode().height
|
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 {
|
pub fn refresh_rate(self) -> u32 {
|
||||||
self.mode().refresh_millihz
|
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) {
|
pub fn set_position(self, x: i32, y: i32) {
|
||||||
if !self.exists() {
|
if !self.exists() {
|
||||||
log::warn!("set_position called on a connector that does not exist");
|
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<DrmDevice> {
|
pub fn drm_devices() -> Vec<DrmDevice> {
|
||||||
get!().drm_devices()
|
get!().drm_devices()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the callback to be called when a new DRM device appears.
|
||||||
pub fn on_new_drm_device<F: Fn(DrmDevice) + 'static>(f: F) {
|
pub fn on_new_drm_device<F: Fn(DrmDevice) + 'static>(f: F) {
|
||||||
get!().on_new_drm_device(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: Fn(DrmDevice) + 'static>(f: F) {
|
pub fn on_drm_device_removed<F: Fn(DrmDevice) + 'static>(f: F) {
|
||||||
get!().on_del_drm_device(f)
|
get!().on_del_drm_device(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the callback to be called when a new connector appears.
|
||||||
pub fn on_new_connector<F: Fn(Connector) + 'static>(f: F) {
|
pub fn on_new_connector<F: Fn(Connector) + 'static>(f: F) {
|
||||||
get!().on_new_connector(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: Fn(Connector) + 'static>(f: F) {
|
pub fn on_connector_connected<F: Fn(Connector) + 'static>(f: F) {
|
||||||
get!().on_connector_connected(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: FnOnce() + 'static>(f: F) {
|
pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
|
||||||
get!().on_graphics_initialized(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 {
|
pub fn get_connector(id: impl ToConnectorId) -> Connector {
|
||||||
let (ty, idx) = match id.to_connector_id() {
|
let (ty, idx) = match id.to_connector_id() {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
|
|
@ -126,6 +209,7 @@ pub fn get_connector(id: impl ToConnectorId) -> Connector {
|
||||||
get!(Connector(0)).get_connector(ty, idx)
|
get!(Connector(0)).get_connector(ty, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type that can be converted to a `(ConnectorType, idx)` tuple.
|
||||||
pub trait ToConnectorId {
|
pub trait ToConnectorId {
|
||||||
fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
|
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 {
|
pub mod connector_type {
|
||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
|
||||||
|
/// The type of a connector.
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct ConnectorType(pub u32);
|
pub struct ConnectorType(pub u32);
|
||||||
|
|
||||||
|
|
@ -202,26 +288,44 @@ pub mod connector_type {
|
||||||
pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
|
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)]
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
pub struct DrmDevice(pub u64);
|
pub struct DrmDevice(pub u64);
|
||||||
|
|
||||||
impl DrmDevice {
|
impl DrmDevice {
|
||||||
|
/// Returns the connectors of this device.
|
||||||
pub fn connectors(self) -> Vec<Connector> {
|
pub fn connectors(self) -> Vec<Connector> {
|
||||||
get!().device_connectors(self)
|
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 {
|
pub fn syspath(self) -> String {
|
||||||
get!().drm_device_syspath(self)
|
get!().drm_device_syspath(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the vendor of this device.
|
||||||
|
///
|
||||||
|
/// E.g. `Advanced Micro Devices, Inc. [AMD/ATI]`.
|
||||||
pub fn vendor(self) -> String {
|
pub fn vendor(self) -> String {
|
||||||
get!().drm_device_vendor(self)
|
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 {
|
pub fn model(self) -> String {
|
||||||
get!().drm_device_model(self)
|
get!().drm_device_model(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the PIC ID of this device.
|
||||||
|
///
|
||||||
|
/// E.g. `1002:67DF`.
|
||||||
pub fn pci_id(self) -> PciId {
|
pub fn pci_id(self) -> PciId {
|
||||||
get!().drm_device_pci_id(self)
|
get!().drm_device_pci_id(self)
|
||||||
}
|
}
|
||||||
|
|
@ -19,9 +19,9 @@ use {
|
||||||
ipc::{InitMessage, ServerMessage, V1InitMessage},
|
ipc::{InitMessage, ServerMessage, V1InitMessage},
|
||||||
ConfigEntry, VERSION,
|
ConfigEntry, VERSION,
|
||||||
},
|
},
|
||||||
drm::{Connector, DrmDevice},
|
|
||||||
input::{InputDevice, Seat},
|
input::{InputDevice, Seat},
|
||||||
keyboard::ModifiedKeySym,
|
keyboard::ModifiedKeySym,
|
||||||
|
video::{Connector, DrmDevice},
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
std::{cell::Cell, mem, ptr, rc::Rc},
|
std::{cell::Cell, mem, ptr, rc::Rc},
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ use {
|
||||||
bincode_ops,
|
bincode_ops,
|
||||||
ipc::{ClientMessage, Response, ServerMessage},
|
ipc::{ClientMessage, Response, ServerMessage},
|
||||||
},
|
},
|
||||||
drm::{Connector, DrmDevice},
|
|
||||||
input::{
|
input::{
|
||||||
acceleration::{AccelProfile, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT},
|
acceleration::{AccelProfile, ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT},
|
||||||
capability::{
|
capability::{
|
||||||
|
|
@ -36,9 +35,12 @@ use {
|
||||||
},
|
},
|
||||||
InputDevice, Seat,
|
InputDevice, Seat,
|
||||||
},
|
},
|
||||||
keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym},
|
keyboard::{mods::Modifiers, syms::KeySym, Keymap},
|
||||||
|
logging::LogLevel,
|
||||||
theme::{colors::Colorable, sized::Resizable},
|
theme::{colors::Colorable, sized::Resizable},
|
||||||
Axis, Direction, LogLevel, Workspace,
|
timer::Timer as JayTimer,
|
||||||
|
video::{Connector, DrmDevice},
|
||||||
|
Axis, Direction, Workspace,
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
log::Level,
|
log::Level,
|
||||||
|
|
@ -254,14 +256,14 @@ impl ConfigProxyHandler {
|
||||||
self.state.set_status(status);
|
self.state.set_status(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_timer(&self, timer: jay_config::Timer) -> Result<Rc<TimerData>, CphError> {
|
fn get_timer(&self, timer: JayTimer) -> Result<Rc<TimerData>, CphError> {
|
||||||
match self.timers_by_id.get(&timer.0) {
|
match self.timers_by_id.get(&timer.0) {
|
||||||
Some(t) => Ok(t),
|
Some(t) => Ok(t),
|
||||||
_ => Err(CphError::TimerDoesNotExist(timer)),
|
_ => 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)?;
|
let timer = self.get_timer(timer)?;
|
||||||
self.timers_by_id.remove(&timer.id);
|
self.timers_by_id.remove(&timer.id);
|
||||||
self.timers_by_name.remove(&timer.name);
|
self.timers_by_name.remove(&timer.name);
|
||||||
|
|
@ -276,7 +278,7 @@ impl ConfigProxyHandler {
|
||||||
|
|
||||||
fn handle_program_timer(
|
fn handle_program_timer(
|
||||||
&self,
|
&self,
|
||||||
timer: jay_config::Timer,
|
timer: JayTimer,
|
||||||
initial: Option<Duration>,
|
initial: Option<Duration>,
|
||||||
periodic: Option<Duration>,
|
periodic: Option<Duration>,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
|
|
@ -289,7 +291,7 @@ impl ConfigProxyHandler {
|
||||||
let name = Rc::new(name.to_owned());
|
let name = Rc::new(name.to_owned());
|
||||||
if let Some(t) = self.timers_by_name.get(&name) {
|
if let Some(t) = self.timers_by_name.get(&name) {
|
||||||
self.respond(Response::GetTimer {
|
self.respond(Response::GetTimer {
|
||||||
timer: jay_config::Timer(t.id),
|
timer: JayTimer(t.id),
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +304,7 @@ impl ConfigProxyHandler {
|
||||||
loop {
|
loop {
|
||||||
match timer.expired(&slf.state.ring).await {
|
match timer.expired(&slf.state.ring).await {
|
||||||
Ok(_) => slf.send(&ServerMessage::TimerExpired {
|
Ok(_) => slf.send(&ServerMessage::TimerExpired {
|
||||||
timer: jay_config::Timer(id),
|
timer: JayTimer(id),
|
||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Could not wait for timer expiration: {}", ErrorFmt(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_name.set(name.clone(), td.clone());
|
||||||
self.timers_by_id.set(id, td.clone());
|
self.timers_by_id.set(id, td.clone());
|
||||||
self.respond(Response::GetTimer {
|
self.respond(Response::GetTimer {
|
||||||
timer: jay_config::Timer(id),
|
timer: JayTimer(id),
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -337,13 +339,13 @@ impl ConfigProxyHandler {
|
||||||
|
|
||||||
fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), CphError> {
|
fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), CphError> {
|
||||||
let seat = self.get_seat(seat)?;
|
let seat = self.get_seat(seat)?;
|
||||||
seat.move_focus(direction);
|
seat.move_focus(direction.into());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_move(&self, seat: Seat, direction: Direction) -> Result<(), CphError> {
|
fn handle_move(&self, seat: Seat, direction: Direction) -> Result<(), CphError> {
|
||||||
let seat = self.get_seat(seat)?;
|
let seat = self.get_seat(seat)?;
|
||||||
seat.move_focused(direction);
|
seat.move_focused(direction.into());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -592,7 +594,7 @@ impl ConfigProxyHandler {
|
||||||
|
|
||||||
fn handle_get_connector(
|
fn handle_get_connector(
|
||||||
&self,
|
&self,
|
||||||
ty: jay_config::drm::connector_type::ConnectorType,
|
ty: jay_config::video::connector_type::ConnectorType,
|
||||||
idx: u32,
|
idx: u32,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let connectors = self.state.connectors.lock();
|
let connectors = self.state.connectors.lock();
|
||||||
|
|
@ -1101,7 +1103,7 @@ enum CphError {
|
||||||
#[error("Connector {0:?} does not exist")]
|
#[error("Connector {0:?} does not exist")]
|
||||||
ConnectorDoesNotExist(Connector),
|
ConnectorDoesNotExist(Connector),
|
||||||
#[error("Timer {0:?} does not exist")]
|
#[error("Timer {0:?} does not exist")]
|
||||||
TimerDoesNotExist(jay_config::Timer),
|
TimerDoesNotExist(JayTimer),
|
||||||
#[error("Connector {0:?} does not exist or is not connected")]
|
#[error("Connector {0:?} does not exist or is not connected")]
|
||||||
OutputDoesNotExist(Connector),
|
OutputDoesNotExist(Connector),
|
||||||
#[error("{0}x{1} is not a valid connector position")]
|
#[error("{0}x{1} is not a valid connector position")]
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ use {
|
||||||
object::Object,
|
object::Object,
|
||||||
state::State,
|
state::State,
|
||||||
tree::{
|
tree::{
|
||||||
generic_node_visitor, ContainerNode, ContainerSplit, FloatNode, FoundNode, Node,
|
generic_node_visitor, ContainerNode, ContainerSplit, Direction, FloatNode, FoundNode,
|
||||||
OutputNode, WorkspaceNode,
|
Node, OutputNode, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent,
|
asyncevent::AsyncEvent,
|
||||||
|
|
@ -60,7 +60,7 @@ use {
|
||||||
xkbcommon::{XkbKeymap, XkbState},
|
xkbcommon::{XkbKeymap, XkbState},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
jay_config::{keyboard::mods::Modifiers, Direction},
|
jay_config::keyboard::mods::Modifiers,
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,12 @@ use {
|
||||||
},
|
},
|
||||||
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
||||||
},
|
},
|
||||||
tree::{FloatNode, Node, ToplevelNode},
|
tree::{Direction, FloatNode, Node, ToplevelNode},
|
||||||
utils::{bitflags::BitflagsExt, clonecell::CloneCell, smallmap::SmallMap},
|
utils::{bitflags::BitflagsExt, clonecell::CloneCell, smallmap::SmallMap},
|
||||||
wire::WlDataOfferId,
|
wire::WlDataOfferId,
|
||||||
xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP},
|
xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||||
},
|
},
|
||||||
jay_config::{
|
jay_config::keyboard::{mods::Modifiers, syms::KeySym, ModifiedKeySym},
|
||||||
keyboard::{mods::Modifiers, syms::KeySym, ModifiedKeySym},
|
|
||||||
Direction,
|
|
||||||
},
|
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ use {
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
state::State,
|
state::State,
|
||||||
tree::{
|
tree::{
|
||||||
FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, ToplevelNode,
|
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData,
|
||||||
ToplevelNodeId, WorkspaceNode,
|
ToplevelNode, ToplevelNodeId, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
buffd::{MsgParser, MsgParserError},
|
buffd::{MsgParser, MsgParserError},
|
||||||
|
|
@ -25,7 +25,6 @@ use {
|
||||||
wire::{xdg_toplevel::*, XdgToplevelId},
|
wire::{xdg_toplevel::*, XdgToplevelId},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
jay_config::Direction,
|
|
||||||
num_derive::FromPrimitive,
|
num_derive::FromPrimitive,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ use {
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
state::State,
|
state::State,
|
||||||
tree::{
|
tree::{
|
||||||
FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode, ToplevelData,
|
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, StackedNode,
|
||||||
ToplevelNode,
|
ToplevelData, ToplevelNode,
|
||||||
},
|
},
|
||||||
utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode},
|
utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode},
|
||||||
wire::WlSurfaceId,
|
wire::WlSurfaceId,
|
||||||
|
|
@ -20,7 +20,6 @@ use {
|
||||||
xwayland::XWaylandEvent,
|
xwayland::XWaylandEvent,
|
||||||
},
|
},
|
||||||
bstr::BString,
|
bstr::BString,
|
||||||
jay_config::Direction,
|
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
ops::{Deref, Not},
|
ops::{Deref, Not},
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use {
|
||||||
ConfigEntry, VERSION,
|
ConfigEntry, VERSION,
|
||||||
},
|
},
|
||||||
input::{InputDevice, Seat},
|
input::{InputDevice, Seat},
|
||||||
keyboard::{keymap::Keymap, ModifiedKeySym},
|
keyboard::{Keymap, ModifiedKeySym},
|
||||||
Axis, Direction,
|
Axis, Direction,
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
xkb_keymap {
|
xkb_keymap {
|
||||||
|
|
||||||
|
# See the file keycodes.xkb for a full list of keycodes.
|
||||||
xkb_keycodes {
|
xkb_keycodes {
|
||||||
|
|
||||||
<1> = 9; # ESC
|
<1> = 9; # ESC
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ use {
|
||||||
render::RenderContext,
|
render::RenderContext,
|
||||||
theme::Theme,
|
theme::Theme,
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, DisplayNode, FloatNode, Node, NodeIds, NodeVisitorBase,
|
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds,
|
||||||
OutputNode, PlaceholderNode, ToplevelNode, WorkspaceNode,
|
NodeVisitorBase, OutputNode, PlaceholderNode, ToplevelNode, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
|
|
@ -43,7 +43,7 @@ use {
|
||||||
xwayland::{self, XWaylandEvent},
|
xwayland::{self, XWaylandEvent},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
jay_config::{Direction, PciId},
|
jay_config::PciId,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
|
|
||||||
22
src/tree.rs
22
src/tree.rs
|
|
@ -12,7 +12,7 @@ use {
|
||||||
utils::numcell::NumCell,
|
utils::numcell::NumCell,
|
||||||
xkbcommon::ModifierState,
|
xkbcommon::ModifierState,
|
||||||
},
|
},
|
||||||
jay_config::Direction,
|
jay_config::Direction as JayDirection,
|
||||||
std::{
|
std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
|
@ -34,6 +34,26 @@ mod toplevel;
|
||||||
mod walker;
|
mod walker;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Direction {
|
||||||
|
Unspecified,
|
||||||
|
Left,
|
||||||
|
Down,
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<JayDirection> 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 {
|
pub struct NodeIds {
|
||||||
next: NumCell<u32>,
|
next: NumCell<u32>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ use {
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
tree::{
|
tree::{
|
||||||
walker::NodeVisitor, ContainingNode, FindTreeResult, FoundNode, Node, NodeId,
|
walker::NodeVisitor, ContainingNode, Direction, FindTreeResult, FoundNode, Node,
|
||||||
ToplevelData, ToplevelNode, WorkspaceNode,
|
NodeId, ToplevelData, ToplevelNode, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
|
|
@ -25,7 +25,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
jay_config::{Axis, Direction},
|
jay_config::Axis,
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ use {
|
||||||
render::{Renderer, Texture},
|
render::{Renderer, Texture},
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
tree::{walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode},
|
tree::{
|
||||||
|
walker::NodeVisitor, Direction, FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode,
|
||||||
|
},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList, scroller::Scroller,
|
clonecell::CloneCell, errorfmt::ErrorFmt, linkedlist::LinkedList, scroller::Scroller,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
jay_config::Direction,
|
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@ use {
|
||||||
render::{Renderer, Texture},
|
render::{Renderer, Texture},
|
||||||
state::State,
|
state::State,
|
||||||
text,
|
text,
|
||||||
tree::{FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData, ToplevelNode},
|
tree::{
|
||||||
|
Direction, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, ToplevelData,
|
||||||
|
ToplevelNode,
|
||||||
|
},
|
||||||
utils::{clonecell::CloneCell, errorfmt::ErrorFmt},
|
utils::{clonecell::CloneCell, errorfmt::ErrorFmt},
|
||||||
},
|
},
|
||||||
jay_config::Direction,
|
|
||||||
std::{cell::Cell, ops::Deref, rc::Rc},
|
std::{cell::Cell, ops::Deref, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@ use {
|
||||||
ifs::wl_seat::{collect_kb_foci, collect_kb_foci2, NodeSeatState, SeatId},
|
ifs::wl_seat::{collect_kb_foci, collect_kb_foci2, NodeSeatState, SeatId},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
state::State,
|
state::State,
|
||||||
tree::{ContainingNode, Node, OutputNode, PlaceholderNode, WorkspaceNode},
|
tree::{ContainingNode, Direction, Node, OutputNode, PlaceholderNode, WorkspaceNode},
|
||||||
utils::{clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap},
|
utils::{clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap},
|
||||||
},
|
},
|
||||||
jay_config::Direction,
|
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,14 @@ use {
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
tree::{
|
tree::{
|
||||||
container::ContainerNode, walker::NodeVisitor, ContainingNode, FindTreeResult,
|
container::ContainerNode, walker::NodeVisitor, ContainingNode, Direction,
|
||||||
FoundNode, Node, NodeId, OutputNode, StackedNode, ToplevelNode,
|
FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode, ToplevelNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
linkedlist::{LinkedList, LinkedNode},
|
linkedlist::{LinkedList, LinkedNode},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
jay_config::Direction,
|
|
||||||
std::{cell::Cell, fmt::Debug, rc::Rc},
|
std::{cell::Cell, fmt::Debug, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -803,8 +803,8 @@ impl ConnectorType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_config(self) -> jay_config::drm::connector_type::ConnectorType {
|
pub fn to_config(self) -> jay_config::video::connector_type::ConnectorType {
|
||||||
use jay_config::drm::connector_type::*;
|
use jay_config::video::connector_type::*;
|
||||||
match self {
|
match self {
|
||||||
Self::Unknown(_) => CON_UNKNOWN,
|
Self::Unknown(_) => CON_UNKNOWN,
|
||||||
Self::VGA => CON_VGA,
|
Self::VGA => CON_VGA,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue