Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Implement proposed ServerSideOverlay decoration mode #1304

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
154 changes: 124 additions & 30 deletions anvil/src/shell/element.rs

Large diffs are not rendered by default.

67 changes: 45 additions & 22 deletions anvil/src/shell/ssd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use smithay::{
AsRenderElements, Kind,
},
Renderer,
},
input::Seat,
utils::{Logical, Point, Serial},
wayland::shell::xdg::XdgShellHandler,
}, input::Seat, reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode, utils::{Logical, Point, Serial}, wayland::shell::xdg::XdgShellHandler
};

use std::cell::{RefCell, RefMut};
Expand All @@ -18,18 +15,18 @@ use crate::AnvilState;
use super::WindowElement;

pub struct WindowState {
pub is_ssd: bool,
pub ssd_mode: Mode,
pub ptr_entered_window: bool,
pub header_bar: HeaderBar,
pub decorations: Decorations,
}

#[derive(Debug, Clone)]
pub struct HeaderBar {
pub struct Decorations {
pub pointer_loc: Option<Point<f64, Logical>>,
pub width: u32,
pub close_button_hover: bool,
pub maximize_button_hover: bool,
pub background: SolidColorBuffer,
pub background: Option<SolidColorBuffer>,
pub close_button: SolidColorBuffer,
pub maximize_button: SolidColorBuffer,
}
Expand All @@ -42,9 +39,9 @@ const CLOSE_COLOR_HOVER: [f32; 4] = [0.75f32, 0.11f32, 0.016f32, 1f32];

pub const HEADER_BAR_HEIGHT: i32 = 32;
const BUTTON_HEIGHT: u32 = HEADER_BAR_HEIGHT as u32;
const BUTTON_WIDTH: u32 = 32;
pub const BUTTON_WIDTH: u32 = 32;

impl HeaderBar {
impl Decorations {
pub fn pointer_enter(&mut self, loc: Point<f64, Logical>) {
self.pointer_loc = Some(loc);
}
Expand Down Expand Up @@ -110,8 +107,9 @@ impl HeaderBar {
return;
}

self.background
.update((width as i32, HEADER_BAR_HEIGHT), BG_COLOR);
if let Some(background) = &mut self.background {
background.update((width as i32, HEADER_BAR_HEIGHT), BG_COLOR);
}

let mut needs_redraw_buttons = false;
if width != self.width {
Expand Down Expand Up @@ -165,7 +163,7 @@ impl HeaderBar {
}
}

impl<R: Renderer> AsRenderElements<R> for HeaderBar {
impl<R: Renderer> AsRenderElements<R> for Decorations {
type RenderElement = SolidColorRenderElement;

fn render_elements<C: From<Self::RenderElement>>(
Expand All @@ -178,7 +176,7 @@ impl<R: Renderer> AsRenderElements<R> for HeaderBar {
let header_end_offset: Point<i32, Logical> = Point::from((self.width as i32, 0));
let button_offset: Point<i32, Logical> = Point::from((BUTTON_WIDTH as i32, 0));

vec![
let mut elements = vec![
SolidColorRenderElement::from_buffer(
&self.close_button,
location + (header_end_offset - button_offset).to_physical_precise_round(scale),
Expand All @@ -194,25 +192,38 @@ impl<R: Renderer> AsRenderElements<R> for HeaderBar {
alpha,
Kind::Unspecified,
)
.into(),
SolidColorRenderElement::from_buffer(&self.background, location, scale, alpha, Kind::Unspecified)
.into()
];

if let Some(background) = &self.background {
elements.push(
SolidColorRenderElement::from_buffer(
background,
location,
scale,
alpha,
Kind::Unspecified,
)
.into(),
]
);
}

elements
}
}

impl WindowElement {
pub fn decoration_state(&self) -> RefMut<'_, WindowState> {
self.user_data().insert_if_missing(|| {
RefCell::new(WindowState {
is_ssd: false,
ssd_mode: Mode::ClientSide,
ptr_entered_window: false,
header_bar: HeaderBar {
decorations: Decorations {
pointer_loc: None,
width: 0,
close_button_hover: false,
maximize_button_hover: false,
background: SolidColorBuffer::default(),
background: Some(SolidColorBuffer::default()),
close_button: SolidColorBuffer::default(),
maximize_button: SolidColorBuffer::default(),
},
Expand All @@ -225,7 +236,19 @@ impl WindowElement {
.borrow_mut()
}

pub fn set_ssd(&self, ssd: bool) {
self.decoration_state().is_ssd = ssd;
pub fn set_no_ssd(&self) {
self.decoration_state().ssd_mode = Mode::ClientSide;
}

pub fn set_ssd(&self) {
let mut state = self.decoration_state();
state.ssd_mode = Mode::ServerSide;
state.decorations.background = Some(SolidColorBuffer::default());
}

pub fn set_ssd_overlay(&self) {
let mut state = self.decoration_state();
state.ssd_mode = Mode::ServerSideOverlay;
state.decorations.background = None;
}
}
14 changes: 11 additions & 3 deletions anvil/src/shell/x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ impl<BackendData: Backend> XwmHandler for CalloopData<BackendData> {
unreachable!()
};
xsurface.configure(Some(bbox)).unwrap();
window.set_ssd(!xsurface.is_decorated());
if xsurface.is_decorated() {
window.set_no_ssd();
} else {
window.set_ssd();
}
}

fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
Expand Down Expand Up @@ -175,7 +179,7 @@ impl<BackendData: Backend> XwmHandler for CalloopData<BackendData> {
let geometry = self.state.space.output_geometry(output).unwrap();

window.set_fullscreen(true).unwrap();
elem.set_ssd(false);
elem.set_no_ssd();
window.configure(geometry).unwrap();
output.user_data().insert_if_missing(FullscreenSurface::default);
output
Expand All @@ -195,7 +199,11 @@ impl<BackendData: Backend> XwmHandler for CalloopData<BackendData> {
.find(|e| matches!(e, WindowElement::X11(w) if w == &window))
{
window.set_fullscreen(false).unwrap();
elem.set_ssd(!window.is_decorated());
if window.is_decorated() {
elem.set_no_ssd();
} else {
elem.set_ssd();
}
if let Some(output) = self.state.space.outputs().find(|o| {
o.user_data()
.get::<FullscreenSurface>()
Expand Down
17 changes: 13 additions & 4 deletions anvil/src/shell/xdg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,21 @@ impl<BackendData: Backend> XdgShellHandler for AnvilState<BackendData> {
.find(|element| element.wl_surface().as_ref() == Some(&surface));
if let Some(window) = window {
use xdg_decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode;
let is_ssd = configure
match configure
.state
.decoration_mode
.map(|mode| mode == Mode::ServerSide)
.unwrap_or(false);
window.set_ssd(is_ssd);
.unwrap_or(Mode::ClientSide) {
Mode::ServerSide => {
window.set_ssd();
}
Mode::ClientSide => {
window.set_no_ssd();
}
Mode::ServerSideOverlay => {
window.set_ssd_overlay();
}
_ => { panic!() }
}
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions anvil/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ use smithay::{
shell::{
wlr_layer::WlrLayerShellState,
xdg::{
decoration::{XdgDecorationHandler, XdgDecorationState},
ToplevelSurface, XdgShellState, XdgToplevelSurfaceData,
decoration::{XdgDecorationHandler, XdgDecorationState}, DecorationOverlayArea,
ToplevelSurface, XdgShellState, XdgToplevelSurfaceData
},
},
shm::{ShmHandler, ShmState},
Expand All @@ -89,7 +89,7 @@ use smithay::{

#[cfg(feature = "xwayland")]
use crate::cursor::Cursor;
use crate::{focus::FocusTarget, shell::WindowElement};
use crate::{focus::FocusTarget, shell::{ssd::{BUTTON_WIDTH, HEADER_BAR_HEIGHT}, WindowElement}};
#[cfg(feature = "xwayland")]
use smithay::{
delegate_xwayland_keyboard_grab,
Expand Down Expand Up @@ -372,16 +372,16 @@ impl<BackendData: Backend> XdgDecorationHandler for AnvilState<BackendData> {
// Set the default to client side
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(Mode::ClientSide);
state.decoration_overlay = Some(DecorationOverlayArea {
location: xdg_decoration::zv1::server::zxdg_toplevel_decoration_v1::OverlayLocation::Right,
width: BUTTON_WIDTH * 2,
height: HEADER_BAR_HEIGHT as u32
})
});
}
fn request_mode(&mut self, toplevel: ToplevelSurface, mode: DecorationMode) {
use xdg_decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode;

toplevel.with_pending_state(|state| {
state.decoration_mode = Some(match mode {
DecorationMode::ServerSide => Mode::ServerSide,
_ => Mode::ClientSide,
});
state.decoration_mode = Some(mode)
});

let initial_configure_sent = with_states(toplevel.wl_surface(), |states| {
Expand Down
9 changes: 8 additions & 1 deletion src/wayland/shell/xdg/decoration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ use wayland_server::{
backend::GlobalId, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, WEnum,
};

use super::{ToplevelSurface, XdgShellHandler};
use super::{DecorationOverlayArea, ToplevelSurface, XdgShellHandler};
use crate::wayland::shell::xdg::XdgShellSurfaceUserData;

/// Delegate type for handling xdg decoration events.
Expand Down Expand Up @@ -191,6 +191,13 @@ pub(super) fn send_decoration_configure(
id.configure(mode)
}

pub(super) fn send_decoration_overlay_configure(
id: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
area: DecorationOverlayArea
) {
id.configure_overlay(area.location, area.width, area.height)
}

impl<D> GlobalDispatch<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, XdgDecorationManagerGlobalData, D>
for XdgDecorationState
where
Expand Down
62 changes: 57 additions & 5 deletions src/wayland/shell/xdg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,9 @@ pub struct ToplevelState {
/// The xdg decoration mode of the surface
pub decoration_mode: Option<zxdg_toplevel_decoration_v1::Mode>,

/// The location of the decoration overlay
pub decoration_overlay: Option<DecorationOverlayArea>,

/// The wm capabilities for this toplevel
pub capabilities: WmCapabilitySet,
}
Expand All @@ -850,6 +853,7 @@ impl Clone for ToplevelState {
size: self.size,
bounds: self.bounds,
decoration_mode: self.decoration_mode,
decoration_overlay: self.decoration_overlay.clone(),
capabilities: self.capabilities.clone(),
}
}
Expand Down Expand Up @@ -962,6 +966,28 @@ impl From<ToplevelStateSet> for Vec<xdg_toplevel::State> {
}
}

/// Container holding the configuration of a decoration overlay for a
/// toplevel
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DecorationOverlayArea {
/// The location where the decoration overlay should be placed
pub location: zxdg_toplevel_decoration_v1::OverlayLocation,
/// The width of the decoration overlay
pub width: u32,
/// The height of the decoration overlay
pub height: u32
}

impl Default for DecorationOverlayArea {
fn default() -> Self {
Self {
location: zxdg_toplevel_decoration_v1::OverlayLocation::Right,
width: 0,
height: 0
}
}
}

/// Container holding the [`xdg_toplevel::WmCapabilities`] for a toplevel
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct WmCapabilitySet {
Expand Down Expand Up @@ -1435,7 +1461,7 @@ impl ToplevelSurface {
let shell_surface_data = self.shell_surface.data::<XdgShellSurfaceUserData>();
let decoration =
shell_surface_data.and_then(|data| data.decoration.lock().unwrap().as_ref().cloned());
let (configure, decoration_mode_changed, bounds_changed, capabilities_changed) =
let (configure, decoration_mode_changed, decoration_overlay_changed, bounds_changed, capabilities_changed) =
compositor::with_states(&self.wl_surface, |states| {
let mut attributes = states
.data_map
Expand All @@ -1455,6 +1481,16 @@ impl ToplevelSurface {
// or we never sent it
let decoration_mode_changed = !attributes.initial_decoration_configure_sent
|| (pending.decoration_mode != current.decoration_mode);

// test if we should send the overlay decoration location, either because it,
// changed, we never sent it, or the decoration mode changed to overlay
let decoration_overlay_changed =
pending.decoration_mode == Some(zxdg_toplevel_decoration_v1::Mode::ServerSideOverlay) &&
(
!attributes.initial_decoration_configure_sent ||
pending.decoration_overlay != current.decoration_overlay ||
pending.decoration_mode != current.decoration_mode
);

// test if we should send a bounds configure event, either because the
// bounds changed or we never sent one
Expand All @@ -1479,19 +1515,35 @@ impl ToplevelSurface {
(
configure,
decoration_mode_changed,
decoration_overlay_changed,
bounds_changed,
capabilities_changed,
)
});

if decoration_mode_changed {
if let Some(decoration) = &decoration {
let mode = configure
.state
.decoration_mode
.unwrap_or(zxdg_toplevel_decoration_v1::Mode::ClientSide);
self::decoration::send_decoration_configure(
decoration,
configure
.state
.decoration_mode
.unwrap_or(zxdg_toplevel_decoration_v1::Mode::ClientSide),
mode
);
}
}

if decoration_overlay_changed {
if let Some(decoration) = &decoration {
let overlay = configure
.state
.decoration_overlay
.clone()
.unwrap_or_default();
self::decoration::send_decoration_overlay_configure(
decoration,
overlay
);
}
}
Expand Down
Loading