Skip to content

Commit

Permalink
adding click_handler helper function for using existing key handlers …
Browse files Browse the repository at this point in the history
…as mouse handlers
  • Loading branch information
sminez committed Jun 25, 2024
1 parent cf6424e commit aa3efe5
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 47 deletions.
7 changes: 4 additions & 3 deletions examples/minimal/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use penrose::{
builtin::{
actions::{
exit,
floating::{sink_clicked, MouseDragHandler, MouseResizeHandler},
floating::{sink_focused, MouseDragHandler, MouseResizeHandler},
modify_with, send_layout_message, spawn,
},
layout::messages::{ExpandMain, IncMain, ShrinkMain},
},
core::{
bindings::{
parse_keybindings_with_xmodmap, KeyEventHandler, MouseEventHandler, MouseState,
click_handler, parse_keybindings_with_xmodmap, KeyEventHandler, MouseEventHandler,
MouseState,
},
Config, WindowManager,
},
Expand Down Expand Up @@ -74,7 +75,7 @@ fn mouse_bindings() -> HashMap<MouseState, Box<dyn MouseEventHandler<RustConn>>>

(Left, vec![Shift, Meta]) => MouseDragHandler::boxed_default(),
(Right, vec![Shift, Meta]) => MouseResizeHandler::boxed_default(),
(Middle, vec![Shift, Meta]) => sink_clicked(),
(Middle, vec![Shift, Meta]) => click_handler(sink_focused()),
}
}

Expand Down
14 changes: 1 addition & 13 deletions src/builtin/actions/floating.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Actions for manipulating floating windows.
use crate::{
builtin::actions::{key_handler, modify_with, mouse_modify_with},
builtin::actions::{key_handler, modify_with},
core::{
bindings::{
KeyEventHandler, MotionNotifyEvent, MouseEvent, MouseEventHandler, MouseEventKind,
Expand Down Expand Up @@ -238,15 +238,3 @@ impl<X: XConn> MouseEventHandler<X> for MouseResizeHandler {
ClickWrapper::on_motion(self, evt, state, x)
}
}

/// Sink the current window back into tiling mode if it was floating
pub fn sink_clicked<X: XConn>() -> Box<dyn MouseEventHandler<X>> {
mouse_modify_with(|cs| {
let id = match cs.current_client() {
Some(&id) => id,
None => return,
};

cs.sink(&id);
})
}
30 changes: 1 addition & 29 deletions src/builtin/actions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
//! Helpers and pre-defined actions for use in user defined key bindings
use crate::{
core::{
bindings::{KeyEventHandler, MouseEventHandler},
layout::IntoMessage,
ClientSet, State,
},
core::{bindings::KeyEventHandler, layout::IntoMessage, ClientSet, State},
util,
x::{XConn, XConnExt},
Result,
Expand Down Expand Up @@ -106,27 +102,3 @@ pub fn remove_and_unmap_focused_client<X: XConn>() -> Box<dyn KeyEventHandler<X>
}
})
}

// NOTE: this is here to force the correct lifetime requirements on closures being
// used as handlers. The generic impl in crate::bindings for functions of the
// right signature isn't sufficient on its own.

/// Construct a [MouseEventHandler] from a closure or free function.
///
/// The resulting handler will run on button press events.
pub fn mouse_handler<F, X>(f: F) -> Box<dyn MouseEventHandler<X>>
where
F: FnMut(&mut State<X>, &X) -> Result<()> + 'static,
X: XConn,
{
Box::new(f)
}

/// Mutate the [ClientSet] and refresh the on screen state
pub fn mouse_modify_with<F, X>(f: F) -> Box<dyn MouseEventHandler<X>>
where
F: FnMut(&mut ClientSet) + Clone + 'static,
X: XConn,
{
Box::new(move |s: &mut State<X>, x: &X| x.modify_and_refresh(s, f.clone()))
}
45 changes: 43 additions & 2 deletions src/core/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,49 @@ where
F: FnMut(&mut State<X>, &X) -> Result<()>,
X: XConn,
{
fn on_mouse_event(&mut self, _: &MouseEvent, state: &mut State<X>, x: &X) -> Result<()> {
(self)(state, x)
fn on_mouse_event(&mut self, evt: &MouseEvent, state: &mut State<X>, x: &X) -> Result<()> {
if evt.kind == MouseEventKind::Press {
(self)(state, x)
} else {
Ok(())
}
}

fn on_motion(&mut self, _: &MotionNotifyEvent, _: &mut State<X>, _: &X) -> Result<()> {
Ok(())
}
}

/// Convert a [KeyEventHandler] to a [MouseEventHandler] that runs on button `Press` events.
///
/// This allows for running pre-existing simple key handlers that do not care about press/release
/// or motion behaviour as a simplified mouse event handler.
///
/// ## Example
/// ```rust
/// use penrose::builtin::actions::floating::sink_all;
/// use penrose::core::bindings::{click_handler, MouseEventHandler};
/// use penrose::x11rb::RustConn;
///
/// let handler: Box<dyn MouseEventHandler<RustConn>> = click_handler(sink_all());
/// ```
pub fn click_handler<X: XConn + 'static>(
kh: Box<dyn KeyEventHandler<X>>,
) -> Box<dyn MouseEventHandler<X>> {
Box::new(MouseWrapper { inner: kh })
}

struct MouseWrapper<X: XConn> {
inner: Box<dyn KeyEventHandler<X>>,
}

impl<X: XConn> MouseEventHandler<X> for MouseWrapper<X> {
fn on_mouse_event(&mut self, evt: &MouseEvent, state: &mut State<X>, x: &X) -> Result<()> {
if evt.kind == MouseEventKind::Press {
self.inner.call(state, x)
} else {
Ok(())
}
}

fn on_motion(&mut self, _: &MotionNotifyEvent, _: &mut State<X>, _: &X) -> Result<()> {
Expand Down

0 comments on commit aa3efe5

Please sign in to comment.