Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cosmic-comp-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ impl Default for AppearanceConfig {
}
}

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum DecorationPreference {
#[default]
ClientSide,
ServerSide,
}

#[derive(Clone, Debug, PartialEq, CosmicConfigEntry)]
#[version = 1]
pub struct CosmicCompConfig {
Expand Down Expand Up @@ -102,6 +109,7 @@ pub struct CosmicCompConfig {
/// Hide the cursor after this many seconds of pointer inactivity (None disables)
pub cursor_hide_timeout: Option<u32>,
pub activation_policy: ActivationPolicy,
pub decoration_preference: DecorationPreference,
}

impl Default for CosmicCompConfig {
Expand Down Expand Up @@ -140,6 +148,7 @@ impl Default for CosmicCompConfig {
appearance_settings: AppearanceConfig::default(),
cursor_hide_timeout: None,
activation_policy: ActivationPolicy::default(),
decoration_preference: DecorationPreference::default(),
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ mod types;
use cosmic::config::CosmicTk;
pub use cosmic_comp_config::EdidProduct;
use cosmic_comp_config::{
ActivationPolicy, AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig,
XwaylandDescaling, XwaylandEavesdropping, ZoomConfig,
ActivationPolicy, AppearanceConfig, CosmicCompConfig, DecorationPreference, KeyboardConfig,
TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig,
input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride},
output::comp::{
OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs,
Expand Down Expand Up @@ -972,6 +972,13 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
state.common.config.cosmic_conf.activation_policy = new;
}
}
"decoration_preference" => {
let new = get_config::<DecorationPreference>(&config, "decoration_preference");
if new != state.common.config.cosmic_conf.decoration_preference {
state.common.config.cosmic_conf.decoration_preference = new;
state.update_decorations();
}
}
_ => {}
}
}
Expand Down
108 changes: 102 additions & 6 deletions src/wayland/handlers/decoration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{cell::RefCell, sync::Mutex};

use cosmic_comp_config::DecorationPreference;
use smithay::{
desktop::Window,
reexports::{
Expand All @@ -20,7 +21,7 @@ use smithay::{
};
use wayland_backend::protocol::WEnum;

use crate::state::State;
use crate::{shell::CosmicMapped, state::State};

pub struct PreferredDecorationMode(RefCell<Option<XdgMode>>);

Expand All @@ -29,7 +30,7 @@ impl PreferredDecorationMode {
window
.user_data()
.get::<PreferredDecorationMode>()
.is_none()
.is_none_or(|mode| mode.0.borrow().is_none())
}

pub fn mode(window: &Window) -> Option<XdgMode> {
Expand All @@ -53,6 +54,73 @@ impl PreferredDecorationMode {
}
}

impl State {
pub fn default_decoration(&self) -> DecorationPreference {
self.common.config.cosmic_conf.decoration_preference
}

pub fn update_decorations(&self) {
let shell = self.common.shell.read();

let update = |mapped: &CosmicMapped| {
let mode = if mapped.is_stack() {
XdgMode::ServerSide
} else {
XdgMode::from_preference(self.default_decoration())
};
for (window, _) in mapped.windows() {
if PreferredDecorationMode::is_unset(&window.0) {
if let Some(toplevel) = window.0.toplevel() {
if toplevel.with_committed_state(|state| {
state.is_some_and(|state| state.decoration_mode.is_some())
}) {
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(mode);
});
toplevel.send_configure();
}
}
}
}
};

for set in shell.workspaces.sets.values() {
set.sticky_layer.mapped().for_each(update);
}

for space in shell.workspaces.spaces() {
space.mapped().for_each(update);
space
.minimized_windows
.iter()
.filter_map(|m| m.mapped())
.for_each(update);
}
}
}

trait FromDecorationPreference {
fn from_preference(preference: DecorationPreference) -> Self;
}

impl FromDecorationPreference for XdgMode {
fn from_preference(preference: DecorationPreference) -> Self {
match preference {
DecorationPreference::ClientSide => XdgMode::ClientSide,
DecorationPreference::ServerSide => XdgMode::ServerSide,
}
}
}

impl FromDecorationPreference for KdeMode {
fn from_preference(preference: DecorationPreference) -> Self {
match preference {
DecorationPreference::ClientSide => KdeMode::Client,
DecorationPreference::ServerSide => KdeMode::Server,
}
}
}

pub type KdeDecorationData = Mutex<KdeDecorationSurfaceState>;
#[derive(Debug, Default)]
pub struct KdeDecorationSurfaceState {
Expand All @@ -67,7 +135,7 @@ impl XdgDecorationHandler for State {
let mode = if mapped.is_stack() {
XdgMode::ServerSide
} else {
XdgMode::ClientSide
XdgMode::from_preference(self.default_decoration())
};

if let Some((window, _)) = mapped
Expand All @@ -80,6 +148,10 @@ impl XdgDecorationHandler for State {
});
toplevel.send_configure();
}
} else {
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(XdgMode::from_preference(self.default_decoration()))
})
}
}

Expand All @@ -99,6 +171,13 @@ impl XdgDecorationHandler for State {
}
} else {
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
if let Some(pending) = shell
.pending_windows
.iter()
.find(|pending| pending.surface.0.toplevel().is_some_and(|t| t == &toplevel))
{
PreferredDecorationMode::update(&pending.surface.0, Some(mode));
}
}
}

Expand All @@ -110,11 +189,28 @@ impl XdgDecorationHandler for State {
.find(|(window, _)| window.wl_surface().as_deref() == Some(toplevel.wl_surface()))
&& let Some(toplevel) = window.0.toplevel()
{
let mode = if mapped.is_stack() {
XdgMode::ServerSide
} else {
XdgMode::from_preference(self.default_decoration())
};

PreferredDecorationMode::update(&window.0, None);
toplevel.with_pending_state(|state| {
state.decoration_mode = None;
state.decoration_mode = Some(mode);
});
toplevel.send_configure();
} else {
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(XdgMode::from_preference(self.default_decoration()))
});
if let Some(pending) = shell
.pending_windows
.iter()
.find(|pending| pending.surface.0.toplevel().is_some_and(|t| t == &toplevel))
{
PreferredDecorationMode::update(&pending.surface.0, None);
}
}
}
}
Expand All @@ -129,10 +225,10 @@ impl KdeDecorationHandler for State {
if mapped.is_stack() {
KdeMode::Server
} else {
KdeMode::Client
KdeMode::from_preference(self.default_decoration())
}
} else {
KdeMode::Client
KdeMode::from_preference(self.default_decoration())
};

with_states(surface, |states| {
Expand Down
Loading