diff options
Diffstat (limited to 'crates/x11/src/platform/events.rs')
| -rw-r--r-- | crates/x11/src/platform/events.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/crates/x11/src/platform/events.rs b/crates/x11/src/platform/events.rs new file mode 100644 index 0000000..ef970f1 --- /dev/null +++ b/crates/x11/src/platform/events.rs @@ -0,0 +1,122 @@ +use super::*; + +impl X11Platform { + + pub(super) fn handle_event(&mut self, event: XEvent) -> PlatformResult<Option<Event>> { + match event { + XEvent::MapRequest(ev) => self.manage_new_window(ev.window), + XEvent::ConfigureRequest(ev) => { + if self.xid_to_core.contains_key(&ev.window) { + // We own layout for managed clients; just ack with a + // synthetic ConfigureNotify carrying real geometry. + let geom = self.conn.get_geometry(ev.window).map_err(err)?.reply().map_err(err)?; + let notify = x11rb::protocol::xproto::ConfigureNotifyEvent { + response_type: x11rb::protocol::xproto::CONFIGURE_NOTIFY_EVENT, + sequence: 0, + event: ev.window, + window: ev.window, + above_sibling: x11rb::NONE, + x: geom.x, + y: geom.y, + width: geom.width, + height: geom.height, + border_width: 0, + override_redirect: false, + }; + self.conn.send_event(false, ev.window, EventMask::STRUCTURE_NOTIFY, notify).map_err(err)?; + } else { + let aux = ConfigureWindowAux::from_configure_request(&ev); + self.conn.configure_window(ev.window, &aux).map_err(err)?; + } + self.conn.flush().map_err(err)?; + Ok(None) + } + XEvent::UnmapNotify(ev) => Ok(self.unmanage(ev.window)), + XEvent::DestroyNotify(ev) => Ok(self.unmanage(ev.window)), + XEvent::ButtonPress(ev) => { + let (x, y) = (ev.root_x as i32, ev.root_y as i32); + let hit = self.wm.borrow().hit_test(x, y); + if let Some((id, hit)) = hit { + self.raise_and_focus(id)?; + match hit { + TitlebarHit::Drag => self.wm.borrow_mut().start_drag(id, x, y), + TitlebarHit::Close => self.request_close(id)?, + TitlebarHit::Maximize => { + self.wm.borrow_mut().toggle_maximize(id); + self.sync_geometry(id)?; + } + TitlebarHit::Minimize => { + self.wm.borrow_mut().minimize_window(id); + if let Some(frame) = self.frame_for(id) { + self.conn.unmap_window(frame).map_err(err)?; + } + } + TitlebarHit::Resize(edge) => self.wm.borrow_mut().start_resize(id, edge, x, y), + } + self.conn.flush().map_err(err)?; + } + // Let the click through to the client (we grabbed it SYNC). + self.conn.allow_events(x11rb::protocol::xproto::Allow::REPLAY_POINTER, ev.time).map_err(err)?; + self.conn.flush().map_err(err)?; + Ok(Some(Event::MouseButtonPress { button: MouseButton::Left, x, y })) + } + XEvent::ButtonRelease(ev) => { + let mut wm = self.wm.borrow_mut(); + let was_dragging = wm.is_dragging(); + let was_resizing = wm.is_resizing(); + let dragged_id = wm.focused_id(); + if was_dragging { + wm.end_drag(); + } else if was_resizing { + wm.end_resize(); + } + drop(wm); + if was_dragging || was_resizing { + if let Some(id) = dragged_id { + self.sync_geometry(id)?; + } + } + Ok(Some(Event::MouseButtonRelease { button: MouseButton::Left, x: ev.root_x as i32, y: ev.root_y as i32 })) + } + XEvent::MotionNotify(ev) => { + let (x, y) = (ev.root_x as i32, ev.root_y as i32); + let mut wm = self.wm.borrow_mut(); + let id = wm.focused_id(); + if wm.is_dragging() { + wm.update_drag(x, y); + } else if wm.is_resizing() { + wm.update_resize(x, y); + } else { + return Ok(Some(Event::MouseMotion { x, y })); + } + drop(wm); + if let Some(id) = id { + self.sync_geometry(id)?; + } + Ok(Some(Event::MouseMotion { x, y })) + } + XEvent::KeyPress(ev) => { + let keysym = self.keycode_to_keysym(ev.detail); + let Some(key_name) = keysyms::keysym_to_name(keysym) else { return Ok(None) }; + Ok(Some(Event::KeyPress { key_name, modifiers: Self::modifiers_from_state(ev.state.into()) })) + } + XEvent::KeyRelease(ev) => { + let keysym = self.keycode_to_keysym(ev.detail); + let Some(key_name) = keysyms::keysym_to_name(keysym) else { return Ok(None) }; + Ok(Some(Event::KeyRelease { key_name, modifiers: Self::modifiers_from_state(ev.state.into()) })) + } + XEvent::Expose(ev) => { + let target = self.frames.iter().find(|(_, f)| f.frame == ev.window).map(|(&id, _)| id); + if let Some(id) = target { + let w = self.wm.borrow().window(id).cloned_for_render(); + if let Some(w) = w { + let focused = self.wm.borrow().focused_id() == Some(id); + let _ = self.redraw_decoration(id, &w, focused); + } + } + Ok(None) + } + _ => Ok(None), + } + } +} |