From d8ee1ac19c84d36e6eb664af54ad3929ffd4de34 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 1 Oct 2024 11:18:25 +0200 Subject: [PATCH] config: make ui dragging configurable --- deploy-notes.md | 4 ++ jay-config/src/_private/client.rs | 8 ++++ jay-config/src/_private/ipc.rs | 6 +++ jay-config/src/lib.rs | 14 +++++++ release-notes.md | 3 ++ src/compositor.rs | 2 + src/config/handler.rs | 14 +++++++ src/ifs/wl_seat.rs | 8 +++- src/state.rs | 11 +++++ src/tree/container.rs | 5 +-- src/tree/output.rs | 8 ++-- toml-config/src/config.rs | 7 ++++ toml-config/src/config/parsers.rs | 1 + toml-config/src/config/parsers/config.rs | 15 ++++++- toml-config/src/config/parsers/ui_drag.rs | 49 +++++++++++++++++++++++ toml-config/src/lib.rs | 8 +++- toml-spec/spec/spec.generated.json | 19 +++++++++ toml-spec/spec/spec.generated.md | 46 +++++++++++++++++++++ toml-spec/spec/spec.yaml | 39 ++++++++++++++++++ 19 files changed, 255 insertions(+), 12 deletions(-) create mode 100644 toml-config/src/config/parsers/ui_drag.rs diff --git a/deploy-notes.md b/deploy-notes.md index cc27f4b7..e38eaf3a 100644 --- a/deploy-notes.md +++ b/deploy-notes.md @@ -1,5 +1,9 @@ # Unreleased +- Needs jay-config release. +- Needs jay-toml-config release. +- Needs jay-compositor release. + # 1.6.0 - Needs jay-algorithms release. diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 4e35aa34..c396ba03 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -748,6 +748,14 @@ impl Client { self.send(&ClientMessage::SetFlipMargin { device, margin }); } + pub fn set_ui_drag_enabled(&self, enabled: bool) { + self.send(&ClientMessage::SetUiDragEnabled { enabled }); + } + + pub fn set_ui_drag_threshold(&self, threshold: i32) { + self.send(&ClientMessage::SetUiDragThreshold { threshold }); + } + pub fn connector_connected(&self, connector: Connector) -> bool { let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector }); get_response!(res, false, ConnectorConnected { connected }); diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index d5a4b173..e43d3a1a 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -517,6 +517,12 @@ pub enum ClientMessage<'a> { device: DrmDevice, margin: Duration, }, + SetUiDragEnabled { + enabled: bool, + }, + SetUiDragThreshold { + threshold: i32, + }, } #[derive(Serialize, Deserialize, Debug)] diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index 118d7fa0..3fd88169 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -234,3 +234,17 @@ pub fn set_idle(timeout: Option) { pub fn set_explicit_sync_enabled(enabled: bool) { get!().set_explicit_sync_enabled(enabled); } + +/// Enables or disables dragging of tiles and workspaces. +/// +/// The default is `true`. +pub fn set_ui_drag_enabled(enabled: bool) { + get!().set_ui_drag_enabled(enabled); +} + +/// Sets the distance at which ui dragging starts. +/// +/// The default is `10`. +pub fn set_ui_drag_threshold(threshold: i32) { + get!().set_ui_drag_threshold(threshold); +} diff --git a/release-notes.md b/release-notes.md index 89b3875c..01f458ea 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,5 +1,8 @@ # Unreleased +- Various bugfixes. +- Tiles and workspaces can now be dragged with the mouse. + # 1.6.0 (2024-09-25) - Various bugfixes. diff --git a/src/compositor.rs b/src/compositor.rs index c8b55322..5cda411b 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -267,6 +267,8 @@ fn start_compositor2( ei_clients: EiClients::new(), slow_ei_clients: Default::default(), cpu_worker, + ui_drag_enabled: Cell::new(true), + ui_drag_threshold_squared: Cell::new(10), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); diff --git a/src/config/handler.rs b/src/config/handler.rs index 681f6d8b..7d0ca3f2 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -759,6 +759,16 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_set_ui_drag_enabled(&self, enabled: bool) { + self.state.ui_drag_enabled.set(enabled); + } + + fn handle_set_ui_drag_threshold(&self, threshold: i32) { + let threshold = threshold.max(1); + let squared = threshold.saturating_mul(threshold); + self.state.ui_drag_threshold_squared.set(squared); + } + fn handle_set_direct_scanout_enabled( &self, device: Option, @@ -1951,6 +1961,10 @@ impl ConfigProxyHandler { ClientMessage::SetFlipMargin { device, margin } => self .handle_set_flip_margin(device, margin) .wrn("set_flip_margin")?, + ClientMessage::SetUiDragEnabled { enabled } => self.handle_set_ui_drag_enabled(enabled), + ClientMessage::SetUiDragThreshold { threshold } => { + self.handle_set_ui_drag_threshold(threshold) + } } Ok(()) } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 4027c6ff..b68c911b 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -776,11 +776,15 @@ impl WlSeatGlobal { } pub fn start_tile_drag(self: &Rc, tl: &Rc) { - self.pointer_owner.start_tile_drag(self, tl); + if self.state.ui_drag_enabled.get() { + self.pointer_owner.start_tile_drag(self, tl); + } } pub fn start_workspace_drag(self: &Rc, ws: &Rc) { - self.pointer_owner.start_workspace_drag(self, ws); + if self.state.ui_drag_enabled.get() { + self.pointer_owner.start_workspace_drag(self, ws); + } } pub fn cancel_dnd(self: &Rc) { diff --git a/src/state.rs b/src/state.rs index 2279898b..f63c23a3 100644 --- a/src/state.rs +++ b/src/state.rs @@ -218,6 +218,8 @@ pub struct State { pub ei_clients: EiClients, pub slow_ei_clients: AsyncQueue>, pub cpu_worker: Rc, + pub ui_drag_enabled: Cell, + pub ui_drag_threshold_squared: Cell, } // impl Drop for State { @@ -1240,6 +1242,15 @@ impl State { } } } + + pub fn ui_drag_threshold_reached(&self, (x1, y1): (i32, i32), (x2, y2): (i32, i32)) -> bool { + if !self.ui_drag_enabled.get() { + return false; + } + let dx = x1 - x2; + let dy = y1 - y2; + dx * dx + dy * dy > self.ui_drag_threshold_squared.get() + } } #[derive(Debug, Error)] diff --git a/src/tree/container.rs b/src/tree/container.rs index 55ffb588..2a562e99 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -586,10 +586,7 @@ impl ContainerNode { match op.kind { SeatOpKind::Move => { if let CursorType::Seat(_) = id { - const DRAG_DIST: i32 = 10; - let dx = x - op.x; - let dy = y - op.y; - if dx * dx + dy * dy > DRAG_DIST * DRAG_DIST { + if self.state.ui_drag_threshold_reached((x, y), (op.x, op.y)) { let node = op.child.node.clone(); drop(seats); seat.start_tile_drag(&node); diff --git a/src/tree/output.rs b/src/tree/output.rs index 1df39b9e..a526e00d 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -1341,10 +1341,10 @@ impl Node for OutputNode { fn node_on_pointer_motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { self.pointer_move(PointerType::Seat(seat.id()), x, y); if let Some((down_x, down_y)) = self.pointer_down.get(&seat.id()) { - const DRAG_DIST: i32 = 10; - let dx = x.round_down() - down_x; - let dy = y.round_down() - down_y; - if dx * dx + dy * dy > DRAG_DIST * DRAG_DIST { + if self + .state + .ui_drag_threshold_reached((x.round_down(), y.round_down()), (down_x, down_y)) + { let rd = self.render_data.borrow_mut(); for title in &rd.titles { if down_x >= title.x1 && down_x < title.x2 { diff --git a/toml-config/src/config.rs b/toml-config/src/config.rs index ffd9af1d..e5ce4e1a 100644 --- a/toml-config/src/config.rs +++ b/toml-config/src/config.rs @@ -154,6 +154,12 @@ pub struct Status { pub separator: Option, } +#[derive(Debug, Clone, Default)] +pub struct UiDrag { + pub enabled: Option, + pub threshold: Option, +} + #[derive(Debug, Clone)] pub enum OutputMatch { Any(Vec), @@ -342,6 +348,7 @@ pub struct Config { pub vrr: Option, pub tearing: Option, pub libei: Libei, + pub ui_drag: UiDrag, } #[derive(Debug, Error)] diff --git a/toml-config/src/config/parsers.rs b/toml-config/src/config/parsers.rs index b60776a2..ba16087c 100644 --- a/toml-config/src/config/parsers.rs +++ b/toml-config/src/config/parsers.rs @@ -32,6 +32,7 @@ pub mod shortcuts; mod status; mod tearing; mod theme; +mod ui_drag; mod vrr; #[derive(Debug, Error)] diff --git a/toml-config/src/config/parsers/config.rs b/toml-config/src/config/parsers/config.rs index be4f0b82..efc9868a 100644 --- a/toml-config/src/config/parsers/config.rs +++ b/toml-config/src/config/parsers/config.rs @@ -25,10 +25,11 @@ use { status::StatusParser, tearing::TearingParser, theme::ThemeParser, + ui_drag::UiDragParser, vrr::VrrParser, }, spanned::SpannedErrorExt, - Action, Config, Libei, Theme, + Action, Config, Libei, Theme, UiDrag, }, toml::{ toml_span::{DespanExt, Span, Spanned}, @@ -112,6 +113,7 @@ impl Parser for ConfigParser<'_> { vrr_val, tearing_val, libei_val, + ui_drag_val, ), ) = ext.extract(( ( @@ -147,6 +149,7 @@ impl Parser for ConfigParser<'_> { opt(val("vrr")), opt(val("tearing")), opt(val("libei")), + opt(val("ui-drag")), ), ))?; let mut keymap = None; @@ -338,6 +341,15 @@ impl Parser for ConfigParser<'_> { } } } + let mut ui_drag = UiDrag::default(); + if let Some(value) = ui_drag_val { + match value.parse(&mut UiDragParser(self.0)) { + Ok(v) => ui_drag = v, + Err(e) => { + log::warn!("Could not parse ui-drag setting: {}", self.0.error(e)); + } + } + } Ok(Config { keymap, repeat_rate, @@ -365,6 +377,7 @@ impl Parser for ConfigParser<'_> { vrr, tearing, libei, + ui_drag, }) } } diff --git a/toml-config/src/config/parsers/ui_drag.rs b/toml-config/src/config/parsers/ui_drag.rs new file mode 100644 index 00000000..e164aa86 --- /dev/null +++ b/toml-config/src/config/parsers/ui_drag.rs @@ -0,0 +1,49 @@ +use { + crate::{ + config::{ + context::Context, + extractor::{bol, int, opt, recover, Extractor, ExtractorError}, + parser::{DataType, ParseResult, Parser, UnexpectedDataType}, + parsers::exec::ExecParserError, + UiDrag, + }, + toml::{ + toml_span::{DespanExt, Span, Spanned}, + toml_value::Value, + }, + }, + indexmap::IndexMap, + thiserror::Error, +}; + +#[derive(Debug, Error)] +pub enum UiDragParserError { + #[error(transparent)] + Expected(#[from] UnexpectedDataType), + #[error(transparent)] + Exec(#[from] ExecParserError), + #[error(transparent)] + Extract(#[from] ExtractorError), +} + +pub struct UiDragParser<'a>(pub &'a Context<'a>); + +impl Parser for UiDragParser<'_> { + type Value = UiDrag; + type Error = UiDragParserError; + const EXPECTED: &'static [DataType] = &[DataType::Table]; + + fn parse_table( + &mut self, + span: Span, + table: &IndexMap, Spanned>, + ) -> ParseResult { + let mut ext = Extractor::new(self.0, span, table); + let (enabled, threshold) = + ext.extract((recover(opt(bol("enabled"))), recover(opt(int("threshold")))))?; + Ok(UiDrag { + enabled: enabled.despan(), + threshold: threshold.despan().map(|v| v as i32), + }) + } +} diff --git a/toml-config/src/lib.rs b/toml-config/src/lib.rs index 8567d86d..ff3f5a9f 100644 --- a/toml-config/src/lib.rs +++ b/toml-config/src/lib.rs @@ -24,7 +24,7 @@ use { keyboard::{Keymap, ModifiedKeySym}, logging::set_log_level, on_devices_enumerated, on_idle, quit, reload, set_default_workspace_capture, - set_explicit_sync_enabled, set_idle, + set_explicit_sync_enabled, set_idle, set_ui_drag_enabled, set_ui_drag_threshold, status::{set_i3bar_separator, set_status, set_status_command, unset_status_command}, switch_to_vt, theme::{reset_colors, reset_font, reset_sizes, set_font}, @@ -1055,6 +1055,12 @@ fn load_config(initial_load: bool, persistent: &Rc) { } } set_libei_socket_enabled(config.libei.enable_socket.unwrap_or(false)); + if let Some(enabled) = config.ui_drag.enabled { + set_ui_drag_enabled(enabled); + } + if let Some(threshold) = config.ui_drag.threshold { + set_ui_drag_threshold(threshold); + } } fn create_command(exec: &Exec) -> Command { diff --git a/toml-spec/spec/spec.generated.json b/toml-spec/spec/spec.generated.json index 9a972fd5..ef77ef77 100644 --- a/toml-spec/spec/spec.generated.json +++ b/toml-spec/spec/spec.generated.json @@ -589,6 +589,10 @@ "libei": { "description": "Configures the libei settings.\n\n- Example:\n\n ```toml\n libei.enable-socket = true\n ```\n", "$ref": "#/$defs/Libei" + }, + "ui-drag": { + "description": "Configures the ui-drag settings.\n\n- Example:\n\n ```toml\n ui-drag = { enabled = false, threshold = 20 }\n ```\n", + "$ref": "#/$defs/UiDrag" } }, "required": [] @@ -1342,6 +1346,21 @@ "flip-rotate-270" ] }, + "UiDrag": { + "description": "Describes ui-drag settings.\n\n- Example:\n\n ```toml\n ui-drag = { enabled = false, threshold = 20 }\n ```\n", + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enables or disables dragging of tiles and workspaces.\n\nThe default is `true`.\n" + }, + "threshold": { + "type": "integer", + "description": "Sets the distance at which ui dragging starts.\n\nThe default is `10`.\n" + } + }, + "required": [] + }, "Vrr": { "description": "Describes VRR settings.\n\n- Example:\n\n ```toml\n vrr = { mode = \"always\", cursor-hz = 90 }\n ```\n", "type": "object", diff --git a/toml-spec/spec/spec.generated.md b/toml-spec/spec/spec.generated.md index 5c51ff1c..14d29ebf 100644 --- a/toml-spec/spec/spec.generated.md +++ b/toml-spec/spec/spec.generated.md @@ -1154,6 +1154,18 @@ The table has the following fields: The value of this field should be a [Libei](#types-Libei). +- `ui-drag` (optional): + + Configures the ui-drag settings. + + - Example: + + ```toml + ui-drag = { enabled = false, threshold = 20 } + ``` + + The value of this field should be a [UiDrag](#types-UiDrag). + ### `Connector` @@ -2981,6 +2993,40 @@ The string should have one of the following values: + +### `UiDrag` + +Describes ui-drag settings. + +- Example: + + ```toml + ui-drag = { enabled = false, threshold = 20 } + ``` + +Values of this type should be tables. + +The table has the following fields: + +- `enabled` (optional): + + Enables or disables dragging of tiles and workspaces. + + The default is `true`. + + The value of this field should be a boolean. + +- `threshold` (optional): + + Sets the distance at which ui dragging starts. + + The default is `10`. + + The value of this field should be a number. + + The numbers should be integers. + + ### `Vrr` diff --git a/toml-spec/spec/spec.yaml b/toml-spec/spec/spec.yaml index b34ca4d1..dd65fafc 100644 --- a/toml-spec/spec/spec.yaml +++ b/toml-spec/spec/spec.yaml @@ -2264,6 +2264,17 @@ Config: ```toml libei.enable-socket = true ``` + ui-drag: + ref: UiDrag + required: false + description: | + Configures the ui-drag settings. + + - Example: + + ```toml + ui-drag = { enabled = false, threshold = 20 } + ``` Idle: @@ -2588,3 +2599,31 @@ Format: description: "" - value: xbgr16161616f description: "" + + +UiDrag: + kind: table + description: | + Describes ui-drag settings. + + - Example: + + ```toml + ui-drag = { enabled = false, threshold = 20 } + ``` + fields: + enabled: + kind: boolean + required: false + description: | + Enables or disables dragging of tiles and workspaces. + + The default is `true`. + threshold: + kind: number + integer_only: true + required: false + description: | + Sets the distance at which ui dragging starts. + + The default is `10`.