commit e88e3c9cebb17b196a5df74cc3c2355ecb316023
parent 33718f2901632bc44bdf650ebfe45349476f7159
Author: deurzen <m.deurzen@tum.de>
Date: Tue, 16 Feb 2021 05:07:57 +0100
mouse binding backend refactoring
Diffstat:
7 files changed, 220 insertions(+), 286 deletions(-)
diff --git a/src/core/binding.rs b/src/core/binding.rs
@@ -2,14 +2,13 @@ use crate::model::Model;
use winsys::common::Window;
use winsys::input::KeyCode;
-use winsys::input::MouseEvent;
use winsys::input::MouseEventKey;
use winsys::input::MouseShortcut;
use std::collections::HashMap;
pub type Action = Box<dyn FnMut(&mut Model)>;
-pub type MouseEvents = Box<dyn FnMut(&mut Model, &MouseEvent, Option<Window>)>;
+pub type MouseEvents = Box<dyn FnMut(&mut Model, Option<Window>)>;
pub type KeyEvents = Box<dyn FnMut(&mut Model)>;
pub type KeyBindings = HashMap<KeyCode, KeyEvents>;
pub type MouseBindings =
diff --git a/src/core/macros.rs b/src/core/macros.rs
@@ -23,6 +23,37 @@ macro_rules! do_internal_block(
);
#[macro_export]
+macro_rules! do_nothing(
+ () => {
+ Box::new(|_: &mut $crate::model::Model, _| {}) as $crate::binding::MouseEvents
+ };
+);
+
+#[macro_export]
+macro_rules! do_internal_mouse(
+ ($func:ident) => {
+ Box::new(|model: &mut $crate::model::Model, _| {
+ model.$func();
+ }) as $crate::binding::MouseEvents
+ };
+
+ ($func:ident, $($arg:expr),+) => {
+ Box::new(|model: &mut $crate::model::Model, _| {
+ model.$func($($arg),+);
+ }) as $crate::binding::MouseEvents
+ };
+);
+
+#[macro_export]
+macro_rules! do_internal_mouse_block(
+ ($model:ident, $window:ident, $body:block) => {
+ Box::new(|$model: &mut $crate::model::Model, $window: Option<winsys::common::Window>| {
+ $body
+ }) as $crate::binding::MouseEvents
+ };
+);
+
+#[macro_export]
macro_rules! spawn_external(
($cmd:expr) => {
{
@@ -76,3 +107,47 @@ macro_rules! build_key_bindings(
}
};
);
+
+#[macro_export]
+macro_rules! build_mouse_bindings(
+ { @start $mouse_bindings:expr,
+ $( ( $kind:ident, $target:ident, $focus:expr ) : $binding:expr ),+ => $action:expr,
+ $($tail:tt)*
+ } => {
+ $(
+ match $crate::util::Util::parse_mouse_binding($binding) {
+ None => panic!("could not parse mouse binding: {}", $binding),
+ Some(shortcut) => $mouse_bindings.insert(
+ (
+ winsys::input::MouseEventKey {
+ kind: winsys::input::MouseEventKind::$kind,
+ target: winsys::input::EventTarget::$target,
+ },
+ shortcut
+ ),
+ (
+ $action,
+ $focus
+ )
+ ),
+ };
+ )+
+ build_mouse_bindings!(@start $mouse_bindings, $($tail)*);
+ };
+
+ { @start $mouse_bindings:expr,
+ $($tail:tt)*
+ } => {
+ $(compile_error!(
+ stringify!(incorrect syntax in build_mouse_bindings: $tail)
+ );)*
+ };
+
+ { $($tokens:tt)+ } => {
+ {
+ let mut mouse_bindings = std::collections::HashMap::new();
+ build_mouse_bindings!(@start mouse_bindings, $($tokens)+);
+ mouse_bindings
+ }
+ };
+);
diff --git a/src/core/main.rs b/src/core/main.rs
@@ -9,16 +9,9 @@ use simplelog::LevelFilter;
#[allow(unused_imports)]
use simplelog::SimpleLogger;
-pub use winsys::Result;
-
use winsys::common::Edge;
-use winsys::input::Button;
-use winsys::input::EventTarget;
-use winsys::input::Modifier;
-use winsys::input::MouseEventKey;
-use winsys::input::MouseEventKind;
-use winsys::input::MouseShortcut;
use winsys::xdata::xconnection::XConnection;
+pub use winsys::Result;
#[macro_use]
mod macros;
@@ -65,285 +58,93 @@ pub fn main() -> Result<()> {
}
fn init_bindings() -> (MouseBindings, KeyBindings) {
- let mut mouse_bindings = MouseBindings::new();
-
- let modkey = if cfg!(debug_assertions) {
- Modifier::Alt
- } else {
- Modifier::Meta
- };
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Left, vec![modkey]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.start_moving(w);
- }
- }),
- true,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Right, vec![modkey]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.start_resizing(w);
- }
- }),
- true,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Middle, vec![modkey]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.center_client(w);
- }
- }),
- true,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Right, vec![modkey, Modifier::Ctrl]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.toggle_float_client(w);
- }
- }),
- true,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Middle, vec![
- modkey,
- Modifier::Ctrl,
- Modifier::Shift,
- ]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.toggle_fullscreen_client(w);
- }
- }),
- true,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::ScrollDown, vec![
- modkey,
- Modifier::Ctrl,
- Modifier::Shift,
- ]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.grow_ratio_client(w, -15);
- }
- }),
- false,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::ScrollUp, vec![
- modkey,
- Modifier::Ctrl,
- Modifier::Shift,
- ]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.grow_ratio_client(w, 15);
- }
- }),
- false,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Forward, vec![modkey]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.move_client_to_next_workspace(w);
- }
- }),
- false,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Client,
- },
- MouseShortcut::new(Button::Backward, vec![modkey]),
- ),
- (
- Box::new(|m, _, w| {
- if let Some(w) = w {
- m.move_client_to_prev_workspace(w);
- }
- }),
- false,
- ),
- );
-
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Global,
- },
- MouseShortcut::new(Button::ScrollDown, vec![modkey]),
- ),
- (
- Box::new(|m, _, _| {
- m.cycle_focus(Direction::Forward);
- }),
- false,
- ),
- );
+ // (kind, target, focus): "[modifiers]-button" => action
+ let mouse_bindings = build_mouse_bindings!(
+ // client state modifiers
+ (Press, Client, true):
+ "1-C-Right" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.toggle_float_client(window);
+ }
+ }),
+ (Press, Client, true):
+ "1-C-S-Middle" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.toggle_fullscreen_client(window);
+ }
+ }),
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Global,
- },
- MouseShortcut::new(Button::ScrollUp, vec![modkey]),
- ),
- (
- Box::new(|m, _, _| {
- m.cycle_focus(Direction::Backward);
- }),
- false,
- ),
- );
+ // free client arrangers
+ (Press, Client, true):
+ "1-Middle" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.center_client(window);
+ }
+ }),
+ (Press, Client, true):
+ "1-Left" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.start_moving(window);
+ }
+ }),
+ (Press, Client, true):
+ "1-Right" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.start_resizing(window);
+ }
+ }),
+ (Press, Client, false):
+ "1-C-S-ScrollDown" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.grow_ratio_client(window, -15);
+ }
+ }),
+ (Press, Client, false):
+ "1-C-S-ScrollUp" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.grow_ratio_client(window, 15);
+ }
+ }),
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Global,
- },
- MouseShortcut::new(Button::ScrollDown, vec![
- modkey,
- Modifier::Shift,
- ]),
- ),
- (
- Box::new(|m, _, _| {
- m.activate_next_workspace();
- }),
- false,
- ),
- );
+ // client order modifiers
+ (Press, Global, false):
+ "1-ScrollDown" => do_internal_mouse!(cycle_focus, Direction::Forward),
+ (Press, Global, false):
+ "1-ScrollUp" => do_internal_mouse!(cycle_focus, Direction::Backward),
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Press,
- target: EventTarget::Global,
- },
- MouseShortcut::new(Button::ScrollUp, vec![modkey, Modifier::Shift]),
- ),
- (
- Box::new(|m, _, _| {
- m.activate_prev_workspace();
- }),
- false,
- ),
- );
+ // workspace activators
+ (Press, Global, false):
+ "1-S-ScrollDown" => do_internal_mouse!(activate_next_workspace),
+ (Press, Global, false):
+ "1-S-ScrollUp" => do_internal_mouse!(activate_prev_workspace),
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Release,
- target: EventTarget::Global,
- },
- MouseShortcut::new(Button::ScrollDown, vec![modkey]),
- ),
- (Box::new(|_, _, _| {}), false),
- );
+ // workspace client movement
+ (Press, Client, false):
+ "1-Forward" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.move_client_to_next_workspace(window);
+ }
+ }),
+ (Press, Client, false):
+ "1-Backward" => do_internal_mouse_block!(model, window, {
+ if let Some(window) = window {
+ model.move_client_to_prev_workspace(window);
+ }
+ }),
- mouse_bindings.insert(
- (
- MouseEventKey {
- kind: MouseEventKind::Release,
- target: EventTarget::Global,
- },
- MouseShortcut::new(Button::ScrollUp, vec![modkey]),
- ),
- (Box::new(|_, _, _| {}), false),
+ // NOPs
+ (Release, Global, false):
+ "1-ScrollDown" => do_nothing!(),
+ (Release, Global, false):
+ "1-ScrollUp" => do_nothing!(),
);
+ // "[modifiers]-key" => action
let key_bindings = build_key_bindings!(
"1-C-S-q" => do_internal!(exit),
- // client manipulators
- "1-c" => do_internal!(kill_focus),
- "1-C-space" => do_internal!(center_focus),
-
// client state modifiers
+ "1-c" => do_internal!(kill_focus),
"1-S-space" => do_internal!(toggle_float_focus),
"1-f" => do_internal!(toggle_fullscreen_focus),
"1-x" => do_internal!(toggle_stick_focus),
@@ -358,6 +159,7 @@ fn init_bindings() -> (MouseBindings, KeyBindings) {
}),
// free client arrangers
+ "1-C-space" => do_internal!(center_focus),
"1-C-h" => do_internal!(nudge_focus, Edge::Left, 15),
"1-C-j" => do_internal!(nudge_focus, Edge::Bottom, 15),
"1-C-k" => do_internal!(nudge_focus, Edge::Top, 15),
diff --git a/src/core/model.rs b/src/core/model.rs
@@ -575,9 +575,11 @@ impl<'a> Model<'a> {
instance: &str,
) -> Rules {
const PREFIX: &str = &concat!(WM_NAME!(), ":");
+ const PREFIX_LEN: usize = PREFIX.len();
+
let mut rules: Rules = Default::default();
- match (instance.get(..4), instance.get(4..)) {
+ match (instance.get(..PREFIX_LEN), instance.get(PREFIX_LEN..)) {
(Some(PREFIX), flags) => {
if let Some(flags) = flags {
let mut invert = false;
@@ -2669,7 +2671,7 @@ impl<'a> Model<'a> {
));
if let Some((action, moves_focus)) = binding {
- action(self, &event, None);
+ action(self, None);
if *moves_focus {
// TODO: config.focus_follows_mouse
@@ -2698,7 +2700,7 @@ impl<'a> Model<'a> {
));
if let Some((action, _)) = binding {
- action(self, &event, None);
+ action(self, None);
}
return;
@@ -2717,7 +2719,7 @@ impl<'a> Model<'a> {
if let Some(window) = self.window(window) {
if let Some((action, moves_focus)) = binding {
- action(self, &event, Some(window));
+ action(self, Some(window));
if *moves_focus {
// TODO: config.focus_follows_mouse
diff --git a/src/core/util.rs b/src/core/util.rs
@@ -1,8 +1,11 @@
use crate::common::Change;
use crate::common::Index;
+use winsys::input::Button;
use winsys::input::CodeMap;
use winsys::input::KeyCode;
+use winsys::input::Modifier;
+use winsys::input::MouseShortcut;
use std::cmp::Ord;
use std::hash::BuildHasherDefault;
@@ -155,7 +158,7 @@ impl Util {
"A" | "Alt" | "Meta" => u16::from(ModMask::M1),
"M" | "Super" => u16::from(ModMask::M4),
"S" | "Shift" => u16::from(ModMask::SHIFT),
- "C" | "Control" => u16::from(ModMask::CONTROL),
+ "C" | "Ctrl" | "Control" => u16::from(ModMask::CONTROL),
"1" | "Mod" => u16::from(if cfg!(debug_assertions) {
ModMask::M1
} else {
@@ -178,4 +181,57 @@ impl Util {
None => None,
}
}
+
+ pub fn parse_mouse_binding(
+ mouse_binding: impl Into<String>
+ ) -> Option<MouseShortcut> {
+ let s = mouse_binding.into();
+ let mut constituents: Vec<&str> = s.split('-').collect();
+
+ let button = match constituents.remove(constituents.len() - 1) {
+ "1" | "Left" => Button::Left,
+ "2" | "Middle" => Button::Middle,
+ "3" | "Right" => Button::Right,
+ "4" | "ScrollUp" => Button::ScrollUp,
+ "5" | "ScrollDown" => Button::ScrollDown,
+ "8" | "Backward" => Button::Backward,
+ "9" | "Forward" => Button::Forward,
+ s => panic!("invalid button: {}", s),
+ };
+
+ let mut modifiers = constituents
+ .iter()
+ .map(|&modifier| match modifier {
+ "A" | "Alt" | "Meta" => Modifier::Alt,
+ "AGr" | "AltGr" => Modifier::AltGr,
+ "M" | "Super" => Modifier::Super,
+ "S" | "Shift" => Modifier::Shift,
+ "C" | "Ctrl" | "Control" => Modifier::Ctrl,
+ "N" | "NumLock" => Modifier::NumLock,
+ "L" | "ScrollLock" => Modifier::ScrollLock,
+ "1" | "Mod" => {
+ if cfg!(debug_assertions) {
+ Modifier::Alt
+ } else {
+ Modifier::Super
+ }
+ },
+ "2" | "Sec" => {
+ if cfg!(debug_assertions) {
+ Modifier::Super
+ } else {
+ Modifier::Alt
+ }
+ },
+ _ => panic!("invalid modifier: {}", s),
+ })
+ .collect::<Vec<Modifier>>();
+
+ modifiers.sort();
+
+ Some(MouseShortcut {
+ button,
+ modifiers,
+ })
+ }
}
diff --git a/src/winsys/input.rs b/src/winsys/input.rs
@@ -35,7 +35,7 @@ pub enum Modifier {
Shift,
Alt,
AltGr,
- Meta,
+ Super,
NumLock,
ScrollLock,
}
diff --git a/src/winsys/xdata/input.rs b/src/winsys/xdata/input.rs
@@ -84,7 +84,7 @@ impl From<Modifier> for u16 {
Modifier::Ctrl => ModMask::CONTROL,
Modifier::Shift => ModMask::SHIFT,
Modifier::Alt => ModMask::M1,
- Modifier::Meta => ModMask::M4,
+ Modifier::Super => ModMask::M4,
Modifier::AltGr => ModMask::M3,
Modifier::NumLock => ModMask::M2,
Modifier::ScrollLock => ModMask::M5,
@@ -100,7 +100,7 @@ impl TryFrom<&str> for Modifier {
"C" => Ok(Self::Ctrl),
"A" => Ok(Self::Alt),
"S" => Ok(Self::Shift),
- "M" => Ok(Self::Meta),
+ "M" => Ok(Self::Super),
"AltGr" => Ok(Self::Alt),
"Num" => Ok(Self::NumLock),
"Scroll" => Ok(Self::ScrollLock),