diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d5eb42c5..6f19d48c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `SeatState:get_pointer_with_them*` now takes `Shm` and `WlSurface` for the themed cursor. - `ThemedPointer` now automatically releases the associated `WlPointer`. - `CursorIcon` from `cursor-icon` crate is now used for `set_cursor` and `Frame`. +- `wayland-csd-frame` is now used for CSD types like `WindowState`, `DecorationsFrame`, etc. ## 0.17.0 - 2023-03-28 diff --git a/Cargo.toml b/Cargo.toml index 28e14f639..61718869f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ wayland-cursor = "0.30.0" wayland-protocols = { version = "0.30.0", features = ["client", "unstable"] } wayland-protocols-wlr = { version = "0.1.0", features = ["client"] } wayland-scanner = "0.30.0" +wayland-csd-frame = "0.1.0" xkbcommon = { version = "0.5", optional = true, features = ["wayland"] } calloop = { version = "0.10.5", optional = true } diff --git a/examples/themed_window.rs b/examples/themed_window.rs index 7c38c75d5..2c5175529 100644 --- a/examples/themed_window.rs +++ b/examples/themed_window.rs @@ -1,6 +1,15 @@ use std::sync::Arc; use std::{convert::TryInto, num::NonZeroU32}; +use smithay_client_toolkit::reexports::client::{ + globals::registry_queue_init, + protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_shm, wl_surface}, + Connection, Proxy, QueueHandle, +}; +use smithay_client_toolkit::reexports::csd_frame::{ + DecorationsFrame, FrameAction, FrameClick, ResizeEdge, +}; +use smithay_client_toolkit::reexports::protocols::xdg::shell::client::xdg_toplevel::ResizeEdge as XdgResizeEdge; use smithay_client_toolkit::seat::keyboard::keysyms; use smithay_client_toolkit::{ compositor::{CompositorHandler, CompositorState}, @@ -19,8 +28,7 @@ use smithay_client_toolkit::{ }, shell::{ xdg::{ - frame::fallback_frame::FallbackFrame, - frame::{DecorationsFrame, FrameAction, FrameClick}, + fallback_frame::FallbackFrame, window::{DecorationMode, Window, WindowConfigure, WindowDecorations, WindowHandler}, XdgShell, XdgSurface, }, @@ -32,11 +40,6 @@ use smithay_client_toolkit::{ }, subcompositor::SubcompositorState, }; -use wayland_client::{ - globals::registry_queue_init, - protocol::{wl_keyboard, wl_output, wl_pointer, wl_seat, wl_shm, wl_surface}, - Connection, Proxy, QueueHandle, -}; // Cursor shapes. const CURSORS: &[CursorIcon] = &[ @@ -471,7 +474,7 @@ impl PointerHandler for SimpleWindow { self.decorations_cursor = self .window_frame .as_mut() - .and_then(|frame| frame.click_point_moved(&event.surface, x, y)); + .and_then(|frame| frame.click_point_moved(&event.surface.id(), x, y)); } Leave { .. } => { if &event.surface != self.window.wl_surface() { @@ -484,7 +487,7 @@ impl PointerHandler for SimpleWindow { if let Some(new_cursor) = self .window_frame .as_mut() - .and_then(|frame| frame.click_point_moved(&event.surface, x, y)) + .and_then(|frame| frame.click_point_moved(&event.surface.id(), x, y)) { self.set_cursor = true; self.decorations_cursor = Some(new_cursor); @@ -526,8 +529,23 @@ impl SimpleWindow { FrameAction::Maximize => self.window.set_maximized(), FrameAction::UnMaximize => self.window.unset_maximized(), FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)), - FrameAction::Resize(edge) => self.window.resize(seat, serial, edge), + FrameAction::Resize(edge) => { + let edge = match edge { + ResizeEdge::None => XdgResizeEdge::None, + ResizeEdge::Top => XdgResizeEdge::Top, + ResizeEdge::Bottom => XdgResizeEdge::Bottom, + ResizeEdge::Left => XdgResizeEdge::Left, + ResizeEdge::TopLeft => XdgResizeEdge::TopLeft, + ResizeEdge::BottomLeft => XdgResizeEdge::BottomLeft, + ResizeEdge::Right => XdgResizeEdge::Right, + ResizeEdge::TopRight => XdgResizeEdge::TopRight, + ResizeEdge::BottomRight => XdgResizeEdge::BottomRight, + _ => return, + }; + self.window.resize(seat, serial, edge); + } FrameAction::Move => self.window.move_(seat, serial), + _ => return, } } } diff --git a/src/lib.rs b/src/lib.rs index ef32656ed..d0deb891f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ pub mod reexports { #[cfg(feature = "calloop")] pub use calloop; pub use wayland_client as client; + pub use wayland_csd_frame as csd_frame; pub use wayland_protocols as protocols; pub use wayland_protocols_wlr as protocols_wlr; } diff --git a/src/seat/keyboard/repeat.rs b/src/seat/keyboard/repeat.rs index 79d35c337..c74e3cc70 100644 --- a/src/seat/keyboard/repeat.rs +++ b/src/seat/keyboard/repeat.rs @@ -52,6 +52,8 @@ impl SeatState { /// ## Errors /// /// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a keyboard. + /// + /// [`EventSource`]: calloop::EventSource pub fn get_keyboard_with_repeat( &mut self, qh: &QueueHandle, @@ -84,6 +86,8 @@ impl SeatState { /// ## Errors /// /// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a keyboard. + /// + /// [`EventSource`]: calloop::EventSource pub fn get_keyboard_with_repeat_with_data( &mut self, qh: &QueueHandle, diff --git a/src/shell/xdg/frame/fallback_frame.rs b/src/shell/xdg/fallback_frame.rs similarity index 97% rename from src/shell/xdg/frame/fallback_frame.rs rename to src/shell/xdg/fallback_frame.rs index 1a13b1dc9..f7b8b2b6e 100644 --- a/src/shell/xdg/frame/fallback_frame.rs +++ b/src/shell/xdg/fallback_frame.rs @@ -7,18 +7,19 @@ use crate::reexports::client::{ protocol::{wl_shm, wl_subsurface::WlSubsurface, wl_surface::WlSurface}, Dispatch, Proxy, QueueHandle, }; -use crate::reexports::protocols::xdg::shell::client::xdg_toplevel::ResizeEdge; +use crate::reexports::csd_frame::{ + DecorationsFrame, FrameAction, FrameClick, ResizeEdge, WindowManagerCapabilities, WindowState, +}; use crate::{ compositor::SurfaceData, seat::pointer::CursorIcon, - shell::xdg::{WindowManagerCapabilities, WindowState}, shell::WaylandSurface, shm::{slot::SlotPool, Shm}, subcompositor::{SubcompositorState, SubsurfaceData}, }; -use super::{DecorationsFrame, FrameAction, FrameClick}; +use wayland_backend::client::ObjectId; /// The size of the header bar. const HEADER_SIZE: u32 = 24; @@ -170,8 +171,8 @@ where } #[inline] - fn part_index_for_surface(&mut self, surface: &WlSurface) -> Option { - self.render_data.as_ref()?.parts.iter().position(|part| &part.surface == surface) + fn part_index_for_surface(&mut self, surface_id: &ObjectId) -> Option { + self.render_data.as_ref()?.parts.iter().position(|part| &part.surface.id() == surface_id) } fn draw_buttons( @@ -316,7 +317,7 @@ impl DecorationsFrame for FallbackFrame where State: Dispatch + Dispatch + 'static, { - fn on_click(&mut self, click: FrameClick, pressed: bool) -> Option { + fn on_click(&mut self, click: FrameClick, pressed: bool) -> Option { // Handle alternate click before everything else. if click == FrameClick::Alternate { return if Location::Head != self.mouse_location @@ -358,8 +359,8 @@ where } } - fn click_point_moved(&mut self, surface: &WlSurface, x: f64, y: f64) -> Option { - let part_index = self.part_index_for_surface(surface)?; + fn click_point_moved(&mut self, surface_id: &ObjectId, x: f64, y: f64) -> Option { + let part_index = self.part_index_for_surface(surface_id)?; let location = match part_index { LEFT_BORDER => Location::Left, RIGHT_BORDER => Location::Right, diff --git a/src/shell/xdg/frame/mod.rs b/src/shell/xdg/frame/mod.rs deleted file mode 100644 index 8d00ddf1a..000000000 --- a/src/shell/xdg/frame/mod.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! The frame to use with XDG shell window. - -use std::num::NonZeroU32; - -use crate::reexports::client::protocol::wl_surface::WlSurface; -use crate::reexports::protocols::xdg::shell::client::xdg_toplevel::ResizeEdge; - -use crate::seat::pointer::CursorIcon; -use crate::shell::xdg::window::{WindowManagerCapabilities, WindowState}; - -pub mod fallback_frame; - -/// The interface for the client side decorations. -pub trait DecorationsFrame: Sized { - /// Emulate click on the decorations. - /// - /// The `click` is a variant of click to use, see [`FrameClick`] for more information. - /// - /// The return value is a [`FrameAction`] you should apply, this action could be - /// ignored. - /// - /// The location of the click is the one passed to [`Self::click_point_moved`]. - fn on_click(&mut self, click: FrameClick, pressed: bool) -> Option; - - /// Emulate pointer moved event on the decorations frame. - /// - /// The `x` and `y` are location in the surface local coordinates relative to the `surface`. - /// - /// The return value is the new cursor icon you should apply to provide better visual - /// feedback for the user. However, you might want to ignore it, if you're using touch events - /// to drive the movements. - fn click_point_moved(&mut self, surface: &WlSurface, x: f64, y: f64) -> Option; - - /// All clicks left the decorations. - /// - /// This function should be called when input leaves the decorations. - fn click_point_left(&mut self); - - /// Update the state of the frame. - /// - /// The state is usually obtained from the [`WindowConfigure`] event. - /// - /// [`WindowConfigure`]: crate::shell::window::WindowConfigure - fn update_state(&mut self, state: WindowState); - - /// Update the window manager capabilites. - /// - /// The capabilites are usually obtained from the [`WindowConfigure`] event. - /// - /// [`WindowConfigure`]: crate::shell::window::WindowConfigure - fn update_wm_capabilities(&mut self, wm_capabilities: WindowManagerCapabilities); - - /// Resize the window to the new size. - /// - /// The size must be without the borders, as in [`Self::subtract_borders]` were used on it. - /// - /// **Note:** The [`Self::update_state`] and [`Self::update_wm_capabilities`] **must be** - /// applied before calling this function. - /// - /// # Panics - /// - /// Panics when resizing the hidden frame. - fn resize(&mut self, width: NonZeroU32, height: NonZeroU32); - - /// Return the coordinates of the top-left corner of the borders relative to the content. - /// - /// Values **must** thus be negative. - fn location(&self) -> (i32, i32); - - /// Subtract the borders from the given `width` and `height`. - /// - /// `None` will be returned for the particular dimension when the given - /// value for it was too small. - fn subtract_borders( - &self, - width: NonZeroU32, - height: NonZeroU32, - ) -> (Option, Option); - - /// Add the borders to the given `width` and `height`. - /// - /// Passing zero for both width and height could be used to get the size - /// of the decorations frame. - fn add_borders(&self, width: u32, height: u32) -> (u32, u32); - - /// Whether the given frame is dirty and should be redrawn. - fn is_dirty(&self) -> bool; - - /// Set the frame as hidden. - /// - /// The frame **must be** visible by default. - fn set_hidden(&mut self, hidden: bool); - - /// Get the frame hidden state. - /// - /// Get the state of the last [`DecorationsFrame::set_hidden`]. - fn is_hidden(&self) -> bool; - - /// Mark the frame as resizable. - /// - /// By default the frame is resizable. - fn set_resizable(&mut self, resizable: bool); - - /// Draw the decorations frame. - /// - /// The user of the frame **must** commit the base surface afterwards. - fn draw(&mut self); - - /// Set the frames title. - fn set_title(&mut self, title: impl Into); -} - -/// The Frame action user should perform in responce to mouse click events. -#[derive(Debug, Clone, Copy)] -pub enum FrameAction { - /// The window should be minimized. - Minimize, - /// The window should be maximized. - Maximize, - /// The window should be unmaximized. - UnMaximize, - /// The window should be closed. - Close, - /// An interactive move should be started. - Move, - /// An interactive resize should be started with the provided edge. - Resize(ResizeEdge), - /// Show window menu. - /// - /// The coordinates are relative to the base surface, as in should be directly passed - /// to the `xdg_toplevel::show_window_menu`. - ShowMenu(i32, i32), -} - -/// The user clicked or touched the decoractions frame. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FrameClick { - /// The user done normal click, likely with left mouse button or single finger touch. - Normal, - - /// The user done right mouse click or some touch sequence that was treated as alternate click. - /// - /// The alternate click exists solely to provide alternative action, like show window - /// menu when doing right mouse button cilck on the header decorations, nothing more. - Alternate, -} diff --git a/src/shell/xdg/mod.rs b/src/shell/xdg/mod.rs index fb9842ea0..91265c385 100644 --- a/src/shell/xdg/mod.rs +++ b/src/shell/xdg/mod.rs @@ -2,14 +2,16 @@ // TODO: Examples use std::sync::{Arc, Mutex}; -use wayland_client::globals::{BindError, GlobalList}; -use wayland_client::Connection; -use wayland_client::{protocol::wl_surface, Dispatch, Proxy, QueueHandle}; -use wayland_protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1::Mode; -use wayland_protocols::xdg::decoration::zv1::client::{ + +use crate::reexports::client::globals::{BindError, GlobalList}; +use crate::reexports::client::Connection; +use crate::reexports::client::{protocol::wl_surface, Dispatch, Proxy, QueueHandle}; +use crate::reexports::csd_frame::{WindowManagerCapabilities, WindowState}; +use crate::reexports::protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1::Mode; +use crate::reexports::protocols::xdg::decoration::zv1::client::{ zxdg_decoration_manager_v1, zxdg_toplevel_decoration_v1, }; -use wayland_protocols::xdg::shell::client::{ +use crate::reexports::protocols::xdg::shell::client::{ xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base, }; @@ -21,12 +23,11 @@ use crate::registry::GlobalProxy; use self::window::inner::WindowInner; use self::window::{ DecorationMode, Window, WindowConfigure, WindowData, WindowDecorations, WindowHandler, - WindowManagerCapabilities, WindowState, }; use super::WaylandSurface; -pub mod frame; +pub mod fallback_frame; pub mod popup; pub mod window; diff --git a/src/shell/xdg/window/mod.rs b/src/shell/xdg/window/mod.rs index b459a2f4d..f33459673 100644 --- a/src/shell/xdg/window/mod.rs +++ b/src/shell/xdg/window/mod.rs @@ -5,13 +5,12 @@ use std::{ sync::{Arc, Weak}, }; -use bitflags::bitflags; - -use wayland_client::{ +use crate::reexports::client::{ protocol::{wl_output, wl_seat, wl_surface}, Connection, Proxy, QueueHandle, }; -use wayland_protocols::{ +use crate::reexports::csd_frame::{WindowManagerCapabilities, WindowState}; +use crate::reexports::protocols::{ xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1::{self, Mode}, xdg::shell::client::{xdg_surface, xdg_toplevel}, }; @@ -95,12 +94,12 @@ pub struct WindowConfigure { /// The capabilities supported by the compositor. /// - /// For more see [`WindowManagerCapabilites`] documentation on the flag values. + /// For more see [`WindowManagerCapabilities`] documentation on the flag values. pub capabilities: WindowManagerCapabilities, } impl WindowConfigure { - /// Is [`State::Maximized`] state is set. + /// Is [`WindowState::MAXIMIZED`] state is set. #[inline] pub fn is_maximized(&self) -> bool { self.state.contains(WindowState::MAXIMIZED) @@ -112,7 +111,7 @@ impl WindowConfigure { self.state.contains(WindowState::FULLSCREEN) } - /// Is [`WindowState::Resizing`] state is set. + /// Is [`WindowState::RESIZING`] state is set. #[inline] pub fn is_resizing(&self) -> bool { self.state.contains(WindowState::RESIZING) @@ -155,46 +154,6 @@ impl WindowConfigure { } } -bitflags! { - /// The configured state of the window. - pub struct WindowState: u16 { - /// The surface is maximized. The window geometry specified in the - /// configure event must be obeyed by the client. The client should - /// draw without shadow or other decoration outside of the window - /// geometry. - const MAXIMIZED = 0b0000_0000_0000_0001; - /// The surface is fullscreen. The window geometry specified in the - /// configure event is a maximum; the client cannot resize beyond it. - /// For a surface to cover the whole fullscreened area, the geometry - /// dimensions must be obeyed by the client. For more details, see - /// xdg_toplevel.set_fullscreen. - const FULLSCREEN = 0b0000_0000_0000_0010; - /// The surface is being resized. The window geometry specified in the - /// configure event is a maximum; the client cannot resize beyond it. - /// Clients that have aspect ratio or cell sizing configuration can use - /// a smaller size, however. - const RESIZING = 0b0000_0000_0000_0100; - /// Client window decorations should be painted as if the window is - /// active. Do not assume this means that the window actually has - /// keyboard or pointer focus. - const ACTIVATED = 0b0000_0000_0000_1000; - /// The window is currently in a tiled layout and the left edge is - /// considered to be adjacent to another part of the tiling grid. - const TILED_LEFT = 0b0000_0000_0001_0000; - /// The window is currently in a tiled layout and the right edge is - /// considered to be adjacent to another part of the tiling grid. - const TILED_RIGHT = 0b0000_0000_0010_0000; - /// The window is currently in a tiled layout and the top edge is - /// considered to be adjacent to another part of the tiling grid. - const TILED_TOP = 0b0000_0000_0100_0000; - /// The window is currently in a tiled layout and the bottom edge is - /// considered to be adjacent to another part of the tiling grid. - const TILED_BOTTOM = 0b0000_0000_1000_0000; - /// The window has any of the mentioned tiled bits set. - const TILED = Self::TILED_TOP.bits | Self::TILED_LEFT.bits | Self::TILED_RIGHT.bits | Self::TILED_BOTTOM.bits; - } -} - /// Decorations a window is created with. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum WindowDecorations { @@ -223,23 +182,6 @@ pub enum WindowDecorations { None, } -bitflags! { - /// The capabilities of the window manager. - /// - /// This is a hint to hide UI elements which provide functionality - /// not supported by compositor. - pub struct WindowManagerCapabilities : u16 { - /// `show_window_menu` is available. - const WINDOW_MENU = 0b0000_0000_0000_0001; - /// Window can be maximized and unmaximized. - const MAXIMIZE = 0b0000_0000_0000_0010; - /// Window can be fullscreened and unfullscreened. - const FULLSCREEN = 0b0000_0000_0000_0100; - /// Window could be minimized. - const MINIMIZE = 0b0000_0000_0000_1000; - } -} - #[derive(Debug, Clone)] pub struct Window(pub(super) Arc);