1
0
Fork 0
forked from wry/wry

config: make ui dragging configurable

This commit is contained in:
Julian Orth 2024-10-01 11:18:25 +02:00
parent 1dd20fb87b
commit d8ee1ac19c
19 changed files with 255 additions and 12 deletions

View file

@ -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.

View file

@ -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 });

View file

@ -517,6 +517,12 @@ pub enum ClientMessage<'a> {
device: DrmDevice,
margin: Duration,
},
SetUiDragEnabled {
enabled: bool,
},
SetUiDragThreshold {
threshold: i32,
},
}
#[derive(Serialize, Deserialize, Debug)]

View file

@ -234,3 +234,17 @@ pub fn set_idle(timeout: Option<Duration>) {
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);
}

View file

@ -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.

View file

@ -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);

View file

@ -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<DrmDevice>,
@ -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(())
}

View file

@ -776,11 +776,15 @@ impl WlSeatGlobal {
}
pub fn start_tile_drag(self: &Rc<Self>, tl: &Rc<dyn ToplevelNode>) {
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<Self>, ws: &Rc<WorkspaceNode>) {
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<Self>) {

View file

@ -218,6 +218,8 @@ pub struct State {
pub ei_clients: EiClients,
pub slow_ei_clients: AsyncQueue<Rc<EiClient>>,
pub cpu_worker: Rc<CpuWorker>,
pub ui_drag_enabled: Cell<bool>,
pub ui_drag_threshold_squared: Cell<i32>,
}
// 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)]

View file

@ -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);

View file

@ -1341,10 +1341,10 @@ impl Node for OutputNode {
fn node_on_pointer_motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, 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 {

View file

@ -154,6 +154,12 @@ pub struct Status {
pub separator: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct UiDrag {
pub enabled: Option<bool>,
pub threshold: Option<i32>,
}
#[derive(Debug, Clone)]
pub enum OutputMatch {
Any(Vec<OutputMatch>),
@ -342,6 +348,7 @@ pub struct Config {
pub vrr: Option<Vrr>,
pub tearing: Option<Tearing>,
pub libei: Libei,
pub ui_drag: UiDrag,
}
#[derive(Debug, Error)]

View file

@ -32,6 +32,7 @@ pub mod shortcuts;
mod status;
mod tearing;
mod theme;
mod ui_drag;
mod vrr;
#[derive(Debug, Error)]

View file

@ -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,
})
}
}

View file

@ -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<String>, Spanned<Value>>,
) -> ParseResult<Self> {
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),
})
}
}

View file

@ -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<PersistentState>) {
}
}
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 {

View file

@ -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",

View file

@ -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).
<a name="types-Connector"></a>
### `Connector`
@ -2981,6 +2993,40 @@ The string should have one of the following values:
<a name="types-UiDrag"></a>
### `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.
<a name="types-Vrr"></a>
### `Vrr`

View file

@ -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`.