use crate::{
builtin::actions::{key_handler, modify_with},
core::{
bindings::{
KeyEventHandler, MotionNotifyEvent, MouseEvent, MouseEventHandler, MouseEventKind,
},
State,
},
custom_error,
pure::geometry::{Point, Rect},
x::{XConn, XConnExt},
Result, Xid,
};
use tracing::error;
pub fn resize<X: XConn>(dw: i32, dh: i32) -> Box<dyn KeyEventHandler<X>> {
modify_with(move |cs| {
let id = match cs.current_client() {
Some(&id) => id,
None => return,
};
cs.floating.entry(id).and_modify(|r| {
*r = r.apply_as_rect(&cs.screens.focus.r, |mut r| {
r.resize(dw, dh);
r
});
});
})
}
pub fn reposition<X: XConn>(dx: i32, dy: i32) -> Box<dyn KeyEventHandler<X>> {
modify_with(move |cs| {
let id = match cs.current_client() {
Some(&id) => id,
None => return,
};
cs.floating.entry(id).and_modify(|r| {
*r = r.apply_as_rect(&cs.screens.focus.r, |mut r| {
r.reposition(dx, dy);
r
});
});
})
}
pub fn float_focused<X: XConn>() -> Box<dyn KeyEventHandler<X>> {
key_handler(|state, x: &X| {
let id = match state.client_set.current_client() {
Some(&id) => id,
None => return Ok(()),
};
let r = x.client_geometry(id)?;
x.modify_and_refresh(state, |cs| {
if let Err(err) = cs.float(id, r) {
error!(%err, %id, "unable to float requested client window");
}
})
})
}
pub fn sink_focused<X: XConn>() -> Box<dyn KeyEventHandler<X>> {
modify_with(|cs| {
let id = match cs.current_client() {
Some(&id) => id,
None => return,
};
cs.sink(&id);
})
}
pub fn toggle_floating_focused<X: XConn>() -> Box<dyn KeyEventHandler<X>> {
key_handler(|state, x: &X| {
let id = match state.client_set.current_client() {
Some(&id) => id,
None => return Ok(()),
};
let r = x.client_geometry(id)?;
x.modify_and_refresh(state, |cs| {
if let Err(err) = cs.toggle_floating_state(id, r) {
error!(%err, %id, "unable to float requested client window");
}
})
})
}
pub fn float_all<X: XConn>() -> Box<dyn KeyEventHandler<X>> {
key_handler(|state, x: &X| {
let positions = state.visible_client_positions(x);
x.modify_and_refresh(state, |cs| {
for &(id, r) in positions.iter() {
if let Err(err) = cs.float(id, r) {
error!(%err, %id, "unable to float requested client window");
}
}
})
})
}
pub fn sink_all<X: XConn>() -> Box<dyn KeyEventHandler<X>> {
modify_with(|cs| cs.floating.clear())
}
#[derive(Debug, Default, Clone, Copy)]
struct ClickData {
x_initial: i32,
y_initial: i32,
r_initial: Rect,
}
impl ClickData {
fn on_motion<X: XConn>(
&self,
f: impl Fn(&mut Rect, i32, i32),
id: Xid,
rpt: Point,
state: &mut State<X>,
x: &X,
) -> Result<()> {
let (dx, dy) = (rpt.x - self.x_initial, rpt.y - self.y_initial);
let mut r = self.r_initial;
(f)(&mut r, dx, dy);
state.client_set.float(id, r)?;
let border = state.config.border_width;
x.position_client(id, r.shrink_in(border))?;
Ok(())
}
}
trait ClickWrapper {
fn data(&mut self) -> &mut Option<ClickData>;
fn motion_fn(&self) -> impl Fn(&mut Rect, i32, i32);
fn on_mouse_event<X: XConn>(
&mut self,
evt: &MouseEvent,
state: &mut State<X>,
x: &X,
) -> Result<()> {
let id = evt.data.id;
match evt.kind {
MouseEventKind::Press => {
let r_client = x.client_geometry(id)?;
state.client_set.float(id, r_client)?;
*self.data() = Some(ClickData {
x_initial: evt.data.rpt.x,
y_initial: evt.data.rpt.y,
r_initial: r_client,
});
}
MouseEventKind::Release => *self.data() = None,
}
Ok(())
}
fn on_motion<X: XConn>(
&mut self,
evt: &MotionNotifyEvent,
state: &mut State<X>,
x: &X,
) -> Result<()> {
match *self.data() {
Some(data) => data.on_motion(self.motion_fn(), evt.data.id, evt.data.rpt, state, x),
None => Err(custom_error!("mouse motion without held state")),
}
}
}
#[derive(Debug, Default, Clone)]
pub struct MouseDragHandler {
data: Option<ClickData>,
}
impl MouseDragHandler {
pub fn boxed_default<X: XConn>() -> Box<dyn MouseEventHandler<X>> {
Box::<MouseDragHandler>::default()
}
}
impl ClickWrapper for MouseDragHandler {
fn data(&mut self) -> &mut Option<ClickData> {
&mut self.data
}
fn motion_fn(&self) -> impl Fn(&mut Rect, i32, i32) {
|r, dx, dy| r.reposition(dx, dy)
}
}
impl<X: XConn> MouseEventHandler<X> for MouseDragHandler {
fn on_mouse_event(&mut self, evt: &MouseEvent, state: &mut State<X>, x: &X) -> Result<()> {
ClickWrapper::on_mouse_event(self, evt, state, x)
}
fn on_motion(&mut self, evt: &MotionNotifyEvent, state: &mut State<X>, x: &X) -> Result<()> {
ClickWrapper::on_motion(self, evt, state, x)
}
}
#[derive(Debug, Default, Clone)]
pub struct MouseResizeHandler {
data: Option<ClickData>,
}
impl MouseResizeHandler {
pub fn boxed_default<X: XConn>() -> Box<dyn MouseEventHandler<X>> {
Box::<MouseResizeHandler>::default()
}
}
impl ClickWrapper for MouseResizeHandler {
fn data(&mut self) -> &mut Option<ClickData> {
&mut self.data
}
fn motion_fn(&self) -> impl Fn(&mut Rect, i32, i32) {
|r, dw, dh| r.resize(dw, dh)
}
}
impl<X: XConn> MouseEventHandler<X> for MouseResizeHandler {
fn on_mouse_event(&mut self, evt: &MouseEvent, state: &mut State<X>, x: &X) -> Result<()> {
ClickWrapper::on_mouse_event(self, evt, state, x)
}
fn on_motion(&mut self, evt: &MotionNotifyEvent, state: &mut State<X>, x: &X) -> Result<()> {
ClickWrapper::on_motion(self, evt, state, x)
}
}