diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 8c4d9588..e5e73883 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -101,6 +101,7 @@ pub struct CosmicCompConfig { pub appearance_settings: AppearanceConfig, /// Hide the cursor after this many seconds of pointer inactivity (None disables) pub cursor_hide_timeout: Option, + pub activation_policy: ActivationPolicy, } impl Default for CosmicCompConfig { @@ -138,6 +139,7 @@ impl Default for CosmicCompConfig { accessibility_zoom: ZoomConfig::default(), appearance_settings: AppearanceConfig::default(), cursor_hide_timeout: None, + activation_policy: ActivationPolicy::default(), } } } @@ -227,6 +229,14 @@ pub enum EavesdroppingKeyboardMode { All, } +#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialEq, Eq)] +pub enum ActivationPolicy { + #[default] + Focus, + FocusIfActiveWorkspace, + Urgent, +} + #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum XwaylandDescaling { diff --git a/src/config/mod.rs b/src/config/mod.rs index d75eed4e..1d9b9c92 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -45,8 +45,8 @@ mod types; use cosmic::config::CosmicTk; pub use cosmic_comp_config::EdidProduct; use cosmic_comp_config::{ - AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, XwaylandDescaling, - XwaylandEavesdropping, ZoomConfig, + ActivationPolicy, AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, + XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride}, output::comp::{ OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs, @@ -966,6 +966,12 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut } } } + "activation_policy" => { + let new = get_config::(&config, "activation_policy"); + if new != state.common.config.cosmic_conf.activation_policy { + state.common.config.cosmic_conf.activation_policy = new; + } + } _ => {} } } diff --git a/src/wayland/handlers/xdg_activation.rs b/src/wayland/handlers/xdg_activation.rs index 359f654d..03c3c629 100644 --- a/src/wayland/handlers/xdg_activation.rs +++ b/src/wayland/handlers/xdg_activation.rs @@ -5,6 +5,7 @@ use crate::{ state::State, wayland::protocols::workspace::{State as WState, WorkspaceHandle}, }; +use cosmic_comp_config::ActivationPolicy; use smithay::{ input::Seat, reexports::wayland_server::protocol::wl_surface::WlSurface, @@ -115,10 +116,45 @@ impl XdgActivationHandler for State { } } ActivationContext::Workspace(_) => { - self.activate_surface( - &surface, - Some((ActivationKey::Wayland(surface.clone()), *context)), - ); + match self.common.config.cosmic_conf.activation_policy { + ActivationPolicy::Focus => { + self.activate_surface( + &surface, + Some((ActivationKey::Wayland(surface.clone()), *context)), + ); + } + ActivationPolicy::FocusIfActiveWorkspace => { + let shell = self.common.shell.write(); + + let Some((target_workspace, _)) = shell.workspace_for_surface(&surface) + else { + // surface not found, maybe log warning? + return; + }; + + let seat = shell.seats.last_active().clone(); + let current_output = seat.active_output(); + let current_workspace = shell.active_space(¤t_output).unwrap().handle; + + if target_workspace == current_workspace { + std::mem::drop(shell); + self.activate_surface( + &surface, + Some((ActivationKey::Wayland(surface.clone()), *context)), + ); + } else { + let mut workspace_guard = self.common.workspace_state.update(); + workspace_guard.add_workspace_state(&target_workspace, WState::Urgent); + } + } + ActivationPolicy::Urgent => { + let shell = self.common.shell.write(); + if let Some((workspace, _output)) = shell.workspace_for_surface(&surface) { + let mut workspace_guard = self.common.workspace_state.update(); + workspace_guard.add_workspace_state(&workspace, WState::Urgent); + } + } + } } } }