srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/state/menu.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-07-30 22:10:00 +0200
committersrdusr <[email protected]>2024-07-30 22:10:00 +0200
commit38683f069a039f9da6d7ddc64167850560fd07ed (patch)
treec9c240dfb91639c59e27779cd654c96202b25688 /crates/wayland/src/state/menu.rs
parent5fe599437ab9d1d9cfa749e861ce2f3acc02aa3c (diff)
downloadsrdwm-38683f069a039f9da6d7ddc64167850560fd07ed.tar.gz
srdwm-38683f069a039f9da6d7ddc64167850560fd07ed.zip
Split crates/wayland/src/state.rs (1276 lines) into state/
Pure reorganization, no behavior change - verified by diffing the function-name and struct-name sets before/after (both identical) plus a full cargo test pass. mod.rs keeps ClientState/OutputEntry/CompState/ WindowAnim/RepeatState's definitions, the key-repeat impl, and the output-lookup impl (all small and tightly coupled to the type definitions), plus mod declarations. The one large impl CompState block (previously ~600 lines) splits by concern: - lifecycle.rs: new_managed_window, set_decorated_from_mode, redraw_decoration_buffer, remove_window. - layers.rs: ensure_layer_initial_configure. - focus.rs: set_keyboard_focus, set_window_activated. - menu.rs: open/close/run_context_menu_action, is_double_click. - geometry.rs: raise_pinned, sync_geometry. - tick.rs: tick_dirty_broadcasts, tick_animations, resync_stacking_order. - toplevel.rs: the with_toplevel_title/app_id/sync_toplevel_metadata free functions. - tests.rs: unsplit, same reasoning as every other split this pass. CompState's fields were already pub(crate) (this crate's existing convention, unlike core's/config's plain-private), so no field- visibility changes were needed - only resync_stacking_order (called from geometry.rs, defined in tick.rs) needed bumping from private to pub(crate), matching that same convention.
Diffstat (limited to 'crates/wayland/src/state/menu.rs')
-rw-r--r--crates/wayland/src/state/menu.rs72
1 files changed, 72 insertions, 0 deletions
diff --git a/crates/wayland/src/state/menu.rs b/crates/wayland/src/state/menu.rs
new file mode 100644
index 0000000..ccd784e
--- /dev/null
+++ b/crates/wayland/src/state/menu.rs
@@ -0,0 +1,72 @@
+use super::*;
+
+impl CompState {
+
+ /// Opens the right-click titlebar window menu for `window`, top-left
+ /// corner at `pos` (global space, wherever the click landed). Rebuilds
+ /// and caches the rasterised buffer once here rather than per frame --
+ /// same reasoning as `redraw_decoration_buffer`.
+ pub(crate) fn open_context_menu(&mut self, window: WindowId, pos: (i32, i32)) {
+ let Some(menu) = ({
+ let wm = self.wm.borrow();
+ crate::context_menu::ContextMenu::open(&wm, window, pos)
+ }) else {
+ return;
+ };
+ let theme = self.wm.borrow().theme;
+ let items: Vec<(&str, bool)> = menu.items.iter().map(|&(label, _)| (label, false)).collect();
+ let data = decoration::render_context_menu(menu.width, menu.row_height, &items, theme.titlebar_bg, theme.titlebar_fg_focused, theme.titlebar_fg_unfocused, theme.default_border_color);
+ let buffer = MemoryRenderBuffer::from_slice(&data, Fourcc::Argb8888, (menu.width as i32, menu.height()), 1, Transform::Normal, None);
+ self.context_menu_buffer = Some(buffer);
+ self.context_menu = Some(menu);
+ }
+
+ pub(crate) fn close_context_menu(&mut self) {
+ self.context_menu = None;
+ self.context_menu_buffer = None;
+ }
+
+ /// Runs whichever action a click on `row` of the currently-open context
+ /// menu selected. Takes the menu's `window`/action rather than reading
+ /// `self.context_menu` itself so the caller can close the menu first
+ /// (clearing the borrow) before this runs - several of these actions
+ /// (`sync_geometry`, `redraw_decoration_buffer`) need `&mut self` in
+ /// ways that would otherwise conflict with an active `self.context_menu`
+ /// borrow.
+ pub(crate) fn run_context_menu_action(&mut self, window: WindowId, action: crate::context_menu::MenuAction) {
+ use crate::context_menu::MenuAction;
+ match action {
+ MenuAction::Minimize => {
+ self.wm.borrow_mut().minimize_window(window);
+ foreign_toplevel::send_state(self, window);
+ }
+ MenuAction::ToggleMaximize => {
+ self.wm.borrow_mut().toggle_maximize(window);
+ self.sync_geometry(window);
+ foreign_toplevel::send_state(self, window);
+ }
+ MenuAction::ToggleAlwaysOnTop => {
+ self.wm.borrow_mut().toggle_always_on_top(window);
+ }
+ MenuAction::Close => {
+ if let Some(w) = self.id_to_window.get(&window) {
+ crate::input::close_dwindow(w);
+ }
+ }
+ }
+ }
+
+ /// True when this titlebar press is the second of a double-click on the
+ /// same window. Threshold is the usual 400ms.
+ pub(crate) fn is_double_click(&mut self, id: WindowId, time: u32) -> bool {
+ const DOUBLE_CLICK_MS: u32 = 400;
+ let doubled = match self.last_titlebar_click {
+ Some((last_id, last_time)) => last_id == id && time.saturating_sub(last_time) <= DOUBLE_CLICK_MS,
+ None => false,
+ };
+ // Reset after a double, so a third click starts a fresh pair rather
+ // than counting as another double.
+ self.last_titlebar_click = if doubled { None } else { Some((id, time)) };
+ doubled
+ }
+}