feat: hide decorations on tiled windows

This commit is contained in:
Samuel Onoja committed 2026-09-25 01:20:16 +01:00
1 parent 9f550e275c
commit d32f20dbbf
4 files changed
+73 -14

No files matched your search

+20 -9
View File
@@ -273,21 +273,32 @@ fn check_grab(
impl XdgDecorationHandler for Ferese {
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
set_decoration_mode(&toplevel, Mode::ClientSide);
let mode = self.decoration_mode_for(&toplevel);
set_decoration_mode(&toplevel, mode);
}
fn request_mode(&mut self, toplevel: ToplevelSurface, mode: Mode) {
// Phase 1 negotiates decorations but does not yet draw a server frame.
// Honor CSD and safely fall back to CSD for premature SSD requests.
let mode = match mode {
Mode::ClientSide | Mode::ServerSide => Mode::ClientSide,
_ => Mode::ClientSide,
};
fn request_mode(&mut self, toplevel: ToplevelSurface, _mode: Mode) {
let mode = self.decoration_mode_for(&toplevel);
set_decoration_mode(&toplevel, mode);
}
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
set_decoration_mode(&toplevel, Mode::ClientSide);
let mode = self.decoration_mode_for(&toplevel);
set_decoration_mode(&toplevel, mode);
}
}
impl Ferese {
fn decoration_mode_for(&self, toplevel: &ToplevelSurface) -> Mode {
self.space
.elements()
.find(|window| {
window
.toplevel()
.is_some_and(|candidate| candidate.wl_surface() == toplevel.wl_surface())
})
.filter(|window| self.is_floating_window(window))
.map_or(Mode::ServerSide, |_| Mode::ClientSide)
}
}
+9
View File
@@ -120,6 +120,15 @@ impl Ferese {
}
}
FilterResult::Intercept(())
} else if !modifiers.shift
&& matches!(symbol, keysyms::KEY_q | keysyms::KEY_Q)
{
if state == KeyState::Pressed {
data.intercepted_keys.insert(keycode);
data.close_focused_window();
}
FilterResult::Intercept(())
} else if !modifiers.shift
&& matches!(symbol, keysyms::KEY_f | keysyms::KEY_F)
+39 -5
View File
@@ -23,7 +23,10 @@ use smithay::{
output::Output,
reexports::{
calloop::{EventLoop, Interest, LoopSignal, Mode, PostAction, generic::Generic},
wayland_protocols::xdg::shell::server::xdg_toplevel,
wayland_protocols::xdg::{
decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode as DecorationMode,
shell::server::xdg_toplevel,
},
wayland_server::{
Display, DisplayHandle,
backend::{ClientData, ClientId, DisconnectReason},
@@ -511,13 +514,19 @@ impl Ferese {
}
};
Some((window.clone(), *id, rect, fullscreen == Some(*id)))
let is_fullscreen = fullscreen == Some(*id);
let is_floating = matches!(
self.workspaces.placement(*id),
Some(WindowPlacement::Floating { .. })
);
Some((window.clone(), *id, rect, is_fullscreen, is_floating))
})
.collect::<Vec<_>>();
let now = self.start_time.elapsed();
for (window, id, rect, is_fullscreen) in placements {
for (window, id, rect, is_fullscreen, is_floating) in placements {
let committed_size = client_size(&window);
let geometry = self
.window_geometry
@@ -534,11 +543,21 @@ impl Ferese {
state.size = Some((size.width, size.height).into());
}
if is_fullscreen {
let fullscreen_changed = if is_fullscreen {
state.states.set(xdg_toplevel::State::Fullscreen)
} else {
state.states.unset(xdg_toplevel::State::Fullscreen)
}
};
let decoration_mode = if is_floating && !is_fullscreen {
DecorationMode::ClientSide
} else {
DecorationMode::ServerSide
};
let decoration_changed = state.decoration_mode != Some(decoration_mode);
state.decoration_mode = Some(decoration_mode);
fullscreen_changed || decoration_changed
});
if requested_size.is_some() || state_changed {
@@ -763,6 +782,21 @@ impl Ferese {
self.relayout();
}
pub fn close_focused_window(&self) {
let Some(focused) = self.focused_window else {
return;
};
let Some(toplevel) = self
.window_ids
.iter()
.find_map(|(window, id)| (*id == focused).then(|| window.toplevel()).flatten())
else {
return;
};
toplevel.send_close();
}
pub fn set_window_fullscreen(&mut self, window: WindowId, enabled: bool) {
match self.workspaces.set_fullscreen(window, enabled) {
Ok(true) => self.relayout(),
+5
View File
@@ -630,6 +630,11 @@ decorations, Ferese MUST provide usable move, resize, and close interactions.
Shadows, masks, and focus borders are compositor effects and may apply in either
mode.
Tiled and fullscreen windows default to borderless server-side decoration so
application title bars do not consume layout space. Floating windows and
dialogs default to client-side decoration until Ferese provides a complete
compositor-drawn floating frame.
### 8.3 XWayland
The desktop tier SHOULD use `xwayland-satellite`, launched on demand, so X11