From 5eb5af46756f2f2bc5e812cf68fe4c4b79efd924 Mon Sep 17 00:00:00 2001 From: Ashley Wulber <48420062+wash2@users.noreply.github.com> Date: Thu, 8 Feb 2024 14:25:18 -0500 Subject: [PATCH] feat: add tiling variables to cosmic config --- cosmic-comp-config/src/lib.rs | 33 ++++++++++++++- src/backend/render/mod.rs | 8 +++- src/config/mod.rs | 80 ++++++++++++++++++++++++----------- src/input/mod.rs | 43 ++++++++++++++++--- src/shell/mod.rs | 69 ++++++++++++++++++++++++++---- 5 files changed, 189 insertions(+), 44 deletions(-) diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 6d6d4145..32dbd3f4 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -7,13 +7,44 @@ use std::collections::HashMap; pub mod input; pub mod workspace; -#[derive(Clone, Debug, Default, PartialEq, CosmicConfigEntry)] +#[derive(Clone, Debug, PartialEq, CosmicConfigEntry)] +#[version = 1] pub struct CosmicCompConfig { pub workspaces: workspace::WorkspaceConfig, pub input_default: input::InputConfig, pub input_touchpad: input::InputConfig, pub input_devices: HashMap, pub xkb_config: XkbConfig, + /// Autotiling enabled + pub autotile: bool, + /// Determines the behavior of the autotile variable + /// If set to Global, autotile applies to all windows in all workspaces + /// If set to PerWorkspace, autotile only applies to new windows, and new workspaces + pub autotile_behavior: TileBehavior, + /// Active hint enabled + pub active_hint: bool, +} + +impl Default for CosmicCompConfig { + fn default() -> Self { + Self { + workspaces: Default::default(), + input_default: Default::default(), + input_touchpad: Default::default(), + input_devices: Default::default(), + xkb_config: Default::default(), + autotile: Default::default(), + autotile_behavior: Default::default(), + active_hint: true, + } + } +} + +#[derive(Debug, Default, Copy, Clone, PartialEq, Deserialize, Serialize)] +pub enum TileBehavior { + #[default] + Global, + PerWorkspace, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 0cc0aeda..6c53dee8 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -578,7 +578,11 @@ where Vec::new() }; - let active_hint = theme.active_hint as u8; + let active_hint = if state.config.cosmic_conf.active_hint { + theme.active_hint as u8 + } else { + 0 + }; // overlay redirect windows // they need to be over sticky windows, because they could be popups of sticky windows, @@ -664,7 +668,7 @@ where let offset = match previous.as_ref() { Some((previous, previous_idx, start)) => { - let layout = state.config.workspace.workspace_layout; + let layout = state.config.cosmic_conf.workspaces.workspace_layout; let workspace = state .shell diff --git a/src/config/mod.rs b/src/config/mod.rs index 3bfda4bb..3fec7a1f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,7 +5,7 @@ use crate::{ state::{BackendData, State}, wayland::protocols::output_configuration::OutputConfigurationState, }; -use cosmic_config::ConfigGet; +use cosmic_config::{ConfigGet, CosmicConfigEntry}; use serde::{Deserialize, Serialize}; use smithay::input::Seat; pub use smithay::{ @@ -32,25 +32,20 @@ pub use self::types::*; use cosmic_comp_config::{ input::InputConfig, workspace::{WorkspaceConfig, WorkspaceLayout}, - XkbConfig, + CosmicCompConfig, TileBehavior, XkbConfig, }; #[derive(Debug)] pub struct Config { pub static_conf: StaticConfig, pub dynamic_conf: DynamicConfig, - pub config: cosmic_config::Config, - pub xkb: XkbConfig, - pub input_default: InputConfig, - pub input_touchpad: InputConfig, - pub input_devices: HashMap, - pub workspace: WorkspaceConfig, + pub cosmic_helper: cosmic_config::Config, + pub cosmic_conf: CosmicCompConfig, } #[derive(Debug, Deserialize)] pub struct StaticConfig { pub key_bindings: HashMap, - pub tiling_enabled: bool, pub data_control_enabled: bool, } @@ -172,15 +167,18 @@ impl Config { .expect("Failed to add cosmic-config to the event loop"); let xdg = xdg::BaseDirectories::new().ok(); let workspace = get_config::(&config, "workspaces"); + let cosmic_comp_config = + CosmicCompConfig::get_entry(&config).unwrap_or_else(|(errs, c)| { + for err in errs { + error!(?err, ""); + } + c + }); Config { static_conf: Self::load_static(xdg.as_ref(), workspace.workspace_layout), dynamic_conf: Self::load_dynamic(xdg.as_ref()), - xkb: get_config(&config, "xkb_config"), - input_default: get_config(&config, "input_default"), - input_touchpad: get_config(&config, "input_touchpad"), - input_devices: get_config(&config, "input_devices"), - workspace, - config, + cosmic_conf: cosmic_comp_config, + cosmic_helper: config, } } @@ -221,7 +219,6 @@ impl Config { StaticConfig { key_bindings: HashMap::new(), - tiling_enabled: false, data_control_enabled: false, } } @@ -410,7 +407,7 @@ impl Config { } pub fn xkb_config(&self) -> XkbConfig { - self.xkb.clone() + self.cosmic_conf.xkb_config.clone() } pub fn read_device(&self, device: &mut InputDevice) { @@ -438,11 +435,11 @@ impl Config { fn get_device_config(&self, device: &InputDevice) -> (Option<&InputConfig>, &InputConfig) { let default_config = if device.config_tap_finger_count() > 0 { - &self.input_touchpad + &self.cosmic_conf.input_touchpad } else { - &self.input_default + &self.cosmic_conf.input_default }; - let device_config = self.input_devices.get(device.name()); + let device_config = self.cosmic_conf.input_devices.get(device.name()); (device_config, default_config) } } @@ -525,28 +522,61 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut } } } - state.common.config.xkb = value; + state.common.config.cosmic_conf.xkb_config = value; } "input_default" => { let value = get_config::(&config, "input_default"); - state.common.config.input_default = value; + state.common.config.cosmic_conf.input_default = value; update_input(state); } "input_touchpad" => { let value = get_config::(&config, "input_touchpad"); - state.common.config.input_touchpad = value; + state.common.config.cosmic_conf.input_touchpad = value; update_input(state); } "input_devices" => { let value = get_config::>(&config, "input_devices"); - state.common.config.input_devices = value; + state.common.config.cosmic_conf.input_devices = value; update_input(state); } "workspaces" => { - state.common.config.workspace = + state.common.config.cosmic_conf.workspaces = get_config::(&config, "workspaces"); state.common.shell.update_config(&state.common.config); } + "autotile" => { + let new = get_config::(&config, "autotile"); + if new != state.common.config.cosmic_conf.autotile { + state.common.config.cosmic_conf.autotile = new; + let seats: Vec<_> = state.common.seats().cloned().collect(); + let mut guard = state.common.shell.workspace_state.update(); + state + .common + .shell + .workspaces + .update_autotile(new, &mut guard, seats); + } + } + "autotile_behavior" => { + let new = get_config::(&config, "autotile_behavior"); + if new != state.common.config.cosmic_conf.autotile_behavior { + state.common.config.cosmic_conf.autotile_behavior = new; + let seats: Vec<_> = state.common.seats().cloned().collect(); + let mut guard = state.common.shell.workspace_state.update(); + state + .common + .shell + .workspaces + .update_autotile_behavior(new, &mut guard, seats); + } + } + "active_hint" => { + let new = get_config::(&config, "active_hint"); + if new != state.common.config.cosmic_conf.active_hint { + state.common.config.cosmic_conf.active_hint = new; + state.common.shell.update_config(&state.common.config); + } + } _ => {} } } diff --git a/src/input/mod.rs b/src/input/mod.rs index 077d38f2..021760e6 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -20,7 +20,8 @@ use crate::{ }, }; use calloop::{timer::Timer, RegistrationToken}; -use cosmic_comp_config::workspace::WorkspaceLayout; +use cosmic_comp_config::{workspace::WorkspaceLayout, TileBehavior}; +use cosmic_config::ConfigSet; use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::InputType; use smithay::{ backend::input::{ @@ -61,6 +62,7 @@ use std::{ any::Any, cell::RefCell, collections::HashMap, + thread, time::{Duration, Instant}, }; @@ -1651,7 +1653,10 @@ impl State { _ => {} } } else if propagate { - match (direction, self.common.config.workspace.workspace_layout) { + match ( + direction, + self.common.config.cosmic_conf.workspaces.workspace_layout, + ) { (Direction::Left, WorkspaceLayout::Horizontal) | (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action( Action::PreviousWorkspace, @@ -1786,7 +1791,10 @@ impl State { } } } else if propagate { - match (direction, self.common.config.workspace.workspace_layout) { + match ( + direction, + self.common.config.cosmic_conf.workspaces.workspace_layout, + ) { (Direction::Left, WorkspaceLayout::Horizontal) | (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action( Action::MoveToPreviousWorkspace, @@ -2048,10 +2056,31 @@ impl State { } } Action::ToggleTiling => { - let output = seat.active_output(); - let workspace = self.common.shell.workspaces.active_mut(&output); - let mut guard = self.common.shell.workspace_state.update(); - workspace.toggle_tiling(seat, &mut guard); + if matches!( + self.common.config.cosmic_conf.autotile_behavior, + TileBehavior::Global + ) { + let autotile = !self.common.config.cosmic_conf.autotile; + self.common.config.cosmic_conf.autotile = autotile; + let seats: Vec<_> = self.common.seats().cloned().collect(); + let mut guard = self.common.shell.workspace_state.update(); + self.common.shell.workspaces.update_autotile( + self.common.config.cosmic_conf.autotile, + &mut guard, + seats, + ); + let config = self.common.config.cosmic_helper.clone(); + thread::spawn(move || { + if let Err(err) = config.set("autotile", autotile) { + error!(?err, "Failed to update autotile key"); + } + }); + } else { + let output = seat.active_output(); + let workspace = self.common.shell.workspaces.active_mut(&output); + let mut guard = self.common.shell.workspace_state.update(); + workspace.toggle_tiling(seat, &mut guard); + } } Action::ToggleWindowFloating => { let output = seat.active_output(); diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 712e25bc..a9a431ee 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -7,7 +7,7 @@ use std::{ }; use wayland_backend::server::ClientId; -use cosmic_comp_config::workspace::WorkspaceMode; +use cosmic_comp_config::{workspace::WorkspaceMode, TileBehavior}; use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::{ State as WState, TilingState, }; @@ -27,7 +27,10 @@ use smithay::{ ext::session_lock::v1::server::ext_session_lock_v1::ExtSessionLockV1, xdg::shell::server::xdg_toplevel::WmCapabilities, }, - wayland_server::{protocol::wl_surface::WlSurface, Client, DisplayHandle}, + wayland_server::{ + protocol::{wl_seat::WlSeat, wl_surface::WlSurface}, + Client, DisplayHandle, + }, }, utils::{Logical, Point, Rectangle, Serial, Size, SERIAL_COUNTER}, wayland::{ @@ -477,7 +480,8 @@ pub struct Workspaces { pub sets: IndexMap, backup_set: Option, mode: WorkspaceMode, - tiling_enabled: bool, + autotile: bool, + autotile_behavior: TileBehavior, theme: cosmic::Theme, } @@ -486,8 +490,9 @@ impl Workspaces { Workspaces { sets: IndexMap::new(), backup_set: None, - mode: config.workspace.workspace_mode, - tiling_enabled: config.static_conf.tiling_enabled, + mode: config.cosmic_conf.workspaces.workspace_mode, + autotile: config.cosmic_conf.autotile, + autotile_behavior: config.cosmic_conf.autotile_behavior, theme, } } @@ -515,7 +520,7 @@ impl Workspaces { workspace_state, &output, self.sets.len(), - self.tiling_enabled, + self.autotile, self.theme.clone(), ) }); @@ -659,7 +664,7 @@ impl Workspaces { xdg_activation_state: &XdgActivationState, ) { let old_mode = self.mode; - self.mode = config.workspace.workspace_mode; + self.mode = config.cosmic_conf.workspaces.workspace_mode; if self.sets.len() <= 1 { return; @@ -704,7 +709,7 @@ impl Workspaces { output, &set.group, false, - config.static_conf.tiling_enabled, + config.cosmic_conf.autotile, self.theme.clone(), ), ); @@ -917,6 +922,48 @@ impl Workspaces { } } } + + pub fn update_autotile_behavior( + &mut self, + behavior: TileBehavior, + guard: &mut WorkspaceUpdateGuard<'_, State>, + seats: Vec>, + ) { + self.autotile_behavior = behavior; + self.apply_tile_change(guard, seats); + } + + fn apply_tile_change( + &mut self, + guard: &mut WorkspaceUpdateGuard<'_, State>, + seats: Vec>, + ) { + if matches!(self.autotile_behavior, TileBehavior::Global) { + // must apply change to all workspaces now + for (_, set) in &mut self.sets { + set.tiling_enabled = self.autotile; + + for w in &mut set.workspaces { + if w.tiling_enabled == self.autotile { + continue; + } + for s in &seats { + w.toggle_tiling(s, guard); + } + } + } + } + } + + pub fn update_autotile( + &mut self, + autotile: bool, + guard: &mut WorkspaceUpdateGuard<'_, State>, + seats: Vec>, + ) { + self.autotile = autotile; + self.apply_tile_change(guard, seats); + } } #[derive(Debug)] @@ -2139,7 +2186,11 @@ impl Shell { }; let button = start_data.button; - let active_hint = state.common.theme.cosmic().active_hint as u8; + let active_hint = if state.common.config.cosmic_conf.active_hint { + state.common.theme.cosmic().active_hint as u8 + } else { + 0 + }; let pointer = seat.get_pointer().unwrap(); let pos = pointer.current_location().as_global();