moved code around, turned resize, move window handlers into closures

This commit is contained in:
noonebtw 2021-01-12 12:24:18 +01:00
parent 7f7872ce63
commit 90f5d9b9b8

View file

@ -49,6 +49,27 @@ struct XlibState {
// (i32, i32) : initial window position
resize_window: Option<(u64, (i32, i32))>,
atoms: WMAtoms,
event_handlers: Vec<Arc<dyn Fn(&mut Self, &XEvent)>>,
}
impl Default for XlibState {
fn default() -> Self {
let display = unsafe { xlib::XOpenDisplay(null()) };
assert_ne!(display, null_mut());
let display = Display {
0: Arc::new(AtomicPtr::new(display)),
};
Self {
display,
keys: vec![],
move_window: None,
resize_window: None,
atoms: WMAtoms::default(),
event_handlers: vec![],
}
}
}
impl XlibState {
@ -60,7 +81,7 @@ impl XlibState {
0: Arc::new(AtomicPtr::new(display)),
};
let state = Self {
Ok(Self {
display: display.clone(),
keys: vec![],
move_window: None,
@ -81,9 +102,205 @@ impl XlibState {
.filter(|&atom| atom != 0)
},
},
};
event_handlers: vec![],
}
// handle_move_window
.grab_button(
1,
Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
)
.add_event_handler(|state, event| {
let clean_mask = state.clean_mask();
Ok(state)
if unsafe {
state.move_window.is_none()
&& event.get_type() == xlib::ButtonPress
&& event.button.button == 1
&& event.button.state & clean_mask == Mod1Mask & clean_mask
&& event.button.subwindow != 0
} {
let win_pos = unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(state.dpy(), event.button.subwindow, &mut attr);
(attr.x, attr.y)
};
state.move_window = unsafe {
Some((
event.button.subwindow,
(event.button.x, event.button.y),
win_pos,
))
};
} else if unsafe {
state.move_window.is_some()
&& event.get_type() == xlib::ButtonRelease
&& event.button.button == 1
} {
state.move_window = None;
} else if state.move_window.is_some() && event.get_type() == xlib::MotionNotify {
let move_window = state.move_window.unwrap();
let attr = unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(state.dpy(), move_window.0, &mut attr);
attr
};
let (x, y) = unsafe {
(
event.motion.x - move_window.1 .0 + move_window.2 .0,
event.motion.y - move_window.1 .1 + move_window.2 .1,
)
};
let mut wc = xlib::XWindowChanges {
x,
y,
width: attr.width,
height: attr.height,
border_width: 0,
sibling: 0,
stack_mode: 0,
};
unsafe {
xlib::XConfigureWindow(
state.dpy(),
state.move_window.unwrap().0,
(xlib::CWX | xlib::CWY) as u32,
&mut wc,
);
xlib::XSync(state.dpy(), 0);
}
}
})
// resize window handler
.grab_button(
3,
Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
)
.add_event_handler(|state, event| {
let clean_mask = state.clean_mask();
if unsafe {
state.resize_window.is_none()
&& event.get_type() == xlib::ButtonPress
&& event.button.button == 3
&& event.button.state & clean_mask == Mod1Mask & clean_mask
&& event.button.subwindow != 0
} {
unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(state.dpy(), event.button.subwindow, &mut attr);
state.resize_window = Some((event.button.subwindow, (attr.x, attr.y)));
xlib::XWarpPointer(
state.dpy(),
0,
event.button.subwindow,
0,
0,
0,
0,
attr.width + attr.border_width - 1,
attr.height + attr.border_width - 1,
);
};
} else if unsafe {
state.resize_window.is_some()
&& event.get_type() == xlib::ButtonRelease
&& event.button.button == 3
} {
state.resize_window = None;
} else if state.resize_window.is_some() && event.get_type() == xlib::MotionNotify {
let resize_window = state.resize_window.unwrap();
let attr = unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(state.dpy(), resize_window.0, &mut attr);
attr
};
unsafe {
let (width, height) = {
(
std::cmp::max(
1,
event.motion.x - resize_window.1 .0 + 2 * attr.border_width + 1,
),
std::cmp::max(
1,
event.motion.y - resize_window.1 .1 + 2 * attr.border_width + 1,
),
)
};
let mut wc = xlib::XWindowChanges {
x: attr.x,
y: attr.y,
width,
height,
border_width: attr.border_width,
sibling: 0,
stack_mode: 0,
};
xlib::XConfigureWindow(
state.dpy(),
resize_window.0,
(xlib::CWWidth | xlib::CWHeight) as u32,
&mut wc,
);
xlib::XSync(state.dpy(), 0);
}
}
})
.add_key_with_handler(
"T",
Mod1Mask,
|state, _| {
let _ = state.spawn("xterm", &[]);
},
)
.add_key_with_handler(
"Q",
Mod1Mask,
|state, event| unsafe {
if event.key.subwindow != 0 {
if state.atoms.delete.is_none()
|| !state.send_event(event.key.subwindow, state.atoms.delete.unwrap())
{
println!("delete atmom: {:?}", state.atoms.delete);
xlib::XKillClient(state.dpy(), event.key.subwindow);
}
}
},
)
.add_key_with_handler(
"Q",
Mod1Mask | ShiftMask,
|state, _event| {
unsafe {
xlib::XCloseDisplay(state.dpy());
}
std::process::exit(0);
},
))
}
fn dpy(&self) -> *mut xlib::Display {
@ -94,177 +311,6 @@ impl XlibState {
unsafe { xlib::XDefaultRootWindow(self.dpy()) }
}
// mod1mask + mousebutton1 moves window
fn handle_move_window(&mut self, event: &xlib::XEvent) {
let clean_mask = self.clean_mask();
if unsafe {
self.move_window.is_none()
&& event.get_type() == xlib::ButtonPress
&& event.button.button == 1
&& event.button.state & clean_mask == Mod1Mask & clean_mask
&& event.button.subwindow != 0
} {
let win_pos = unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(self.dpy(), event.button.subwindow, &mut attr);
(attr.x, attr.y)
};
self.move_window = unsafe {
Some((
event.button.subwindow,
(event.button.x, event.button.y),
win_pos,
))
};
} else if unsafe {
self.move_window.is_some()
&& event.get_type() == xlib::ButtonRelease
&& event.button.button == 1
} {
self.move_window = None;
} else if self.move_window.is_some() && event.get_type() == xlib::MotionNotify {
let move_window = self.move_window.unwrap();
let attr = unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(self.dpy(), move_window.0, &mut attr);
attr
};
let (x, y) = unsafe {
(
event.motion.x - move_window.1 .0 + move_window.2 .0,
event.motion.y - move_window.1 .1 + move_window.2 .1,
)
};
let mut wc = xlib::XWindowChanges {
x,
y,
width: attr.width,
height: attr.height,
border_width: 0,
sibling: 0,
stack_mode: 0,
};
unsafe {
xlib::XConfigureWindow(
self.dpy(),
self.move_window.unwrap().0,
(xlib::CWX | xlib::CWY) as u32,
&mut wc,
);
xlib::XSync(self.dpy(), 0);
}
}
}
// mod1mask + mousebutton3 resizes window
fn handle_resize_window(&mut self, event: &xlib::XEvent) {
let clean_mask = self.clean_mask();
if unsafe {
self.resize_window.is_none()
&& event.get_type() == xlib::ButtonPress
&& event.button.button == 3
&& event.button.state & clean_mask == Mod1Mask & clean_mask
&& event.button.subwindow != 0
} {
unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(self.dpy(), event.button.subwindow, &mut attr);
self.resize_window = Some((event.button.subwindow, (attr.x, attr.y)));
xlib::XWarpPointer(
self.dpy(),
0,
event.button.subwindow,
0,
0,
0,
0,
attr.width + attr.border_width - 1,
attr.height + attr.border_width - 1,
);
};
} else if unsafe {
self.resize_window.is_some()
&& event.get_type() == xlib::ButtonRelease
&& event.button.button == 3
} {
self.resize_window = None;
} else if self.resize_window.is_some() && event.get_type() == xlib::MotionNotify {
let resize_window = self.resize_window.unwrap();
let attr = unsafe {
let mut attr: xlib::XWindowAttributes =
std::mem::MaybeUninit::uninit().assume_init();
xlib::XGetWindowAttributes(self.dpy(), resize_window.0, &mut attr);
attr
};
unsafe {
let (width, height) = {
(
std::cmp::max(
1,
event.motion.x - resize_window.1 .0 + 2 * attr.border_width + 1,
),
std::cmp::max(
1,
event.motion.y - resize_window.1 .1 + 2 * attr.border_width + 1,
),
)
};
/*
xlib::XWarpPointer(
self.dpy(),
0,
resize_window.0,
0,
0,
0,
0,
width - 1,
height - 1,
);
*/
let mut wc = xlib::XWindowChanges {
x: attr.x,
y: attr.y,
width,
height,
border_width: attr.border_width,
sibling: 0,
stack_mode: 0,
};
xlib::XConfigureWindow(
self.dpy(),
resize_window.0,
(xlib::CWWidth | xlib::CWHeight) as u32,
&mut wc,
);
xlib::XSync(self.dpy(), 0);
}
}
}
fn main_loop(mut self) -> Result<Self> {
loop {
let event = unsafe {
@ -279,7 +325,7 @@ impl XlibState {
// cache clean mask, that way numlock_mask doesnt get called for every cmp
let clean_mask = self.clean_mask();
for (key, mask, handler) in self.keys.iter() {
for (key, mask, handler) in self.keys.iter().clone() {
// check if key and mask with any numlock state fit
if unsafe {
event.key.keycode == *key as u32
@ -290,27 +336,35 @@ impl XlibState {
}
}
// handle window resizes
self.handle_move_window(&event);
self.handle_resize_window(&event);
self.event_handlers
.clone()
.iter()
.for_each(|handler| handler(&mut self, &event));
}
}
fn add_key_with_handler<S: Into<String>>(
mut self,
key: S,
mask: u32,
handler: Box<dyn Fn(&Self, &XEvent)>,
) -> Self {
let keycode = self.keycode(key);
self.keys.push((keycode, mask, Box::new(handler)));
self.grab_key(keycode, mask);
fn add_event_handler<F>(mut self, handler: F) -> Self
where
F: Fn(&mut Self, &XEvent) + 'static,
{
self.event_handlers.push(Arc::new(handler));
self
}
fn grab_key(&self, keycode: i32, mask: u32) -> &Self {
fn add_key_with_handler<S, F>(
mut self,
key: S,
mask: u32,
handler: F,
) -> Self where S: Into<String>, F: Fn(&Self, &XEvent) + 'static {
let keycode = self.keycode(key);
self.keys.push((keycode, mask, Box::new(handler)));
self.grab_key(keycode, mask)
}
fn grab_key(self, keycode: i32, mask: u32) -> Self {
let numlock_mask = self.numlock_mask();
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
for &modifier in modifiers.iter() {
@ -330,11 +384,11 @@ impl XlibState {
self
}
fn grab_button(&self, button: u32, mod_mask: u32, button_mask: i64) -> &Self {
fn grab_button(self, button: u32, mod_mask: u32, button_mask: i64) -> Self {
let numlock_mask = self.numlock_mask();
let modifiers = vec![0, LockMask, numlock_mask, LockMask | numlock_mask];
for &modifier in modifiers.iter() {
modifiers.iter().for_each(|&modifier| {
unsafe {
xlib::XGrabButton(
self.dpy(),
@ -349,7 +403,7 @@ impl XlibState {
0,
);
}
}
});
self
}
@ -390,7 +444,7 @@ impl XlibState {
}
}
fn keycode<S: Into<String>>(&self, string: S) -> i32 {
fn keycode<S>(&self, string: S) -> i32 where S: Into<String> {
let c_string = CString::new(string.into()).unwrap();
unsafe {
let keysym = xlib::XStringToKeysym(c_string.as_ptr());
@ -474,57 +528,6 @@ fn main() -> Result<()> {
let state = XlibState::new()?;
let state = state
.add_key_with_handler(
"T",
Mod1Mask,
Box::new(|state, _| {
let _ = state.spawn("xterm", &[]);
}),
)
.add_key_with_handler(
"F1",
Mod1Mask,
Box::new(|state, event| unsafe {
if event.key.subwindow != 0 {
xlib::XRaiseWindow(state.dpy(), event.key.subwindow);
}
}),
)
.add_key_with_handler(
"Q",
Mod1Mask,
Box::new(|state, event| unsafe {
if event.key.subwindow != 0 {
if state.atoms.delete.is_none()
|| !state.send_event(event.key.subwindow, state.atoms.delete.unwrap())
{
println!("delete atmom: {:?}", state.atoms.delete);
xlib::XKillClient(state.dpy(), event.key.subwindow);
}
}
}),
).add_key_with_handler("Q", Mod1Mask|ShiftMask, Box::new(|state, _event| {
unsafe {
xlib::XCloseDisplay(state.dpy());
}
std::process::exit(0);
}));
state
.grab_key(state.keycode("F1"), Mod1Mask)
.grab_button(
1,
Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
)
.grab_button(
3,
Mod1Mask,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
);
state.main_loop()?;
Ok(())