1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
//! # Shell abstractions
//!
//! A shell describes a set of wayland protocol extensions which define the capabilities of a surface and how
//! the surface is displayed.
//!
//! ## Cross desktop group (XDG) shell
//!
//! The XDG shell describes the semantics of desktop application windows.
//!
//! The XDG shell defines two types of surfaces:
//! - [`Window`] - An application window[^window].
//! - [`Popup`] - A child surface positioned relative to a window.
//!
//! ### Why use the XDG shell
//!
//! The XDG shell is the primary protocol through which application windows are created. You can be near
//! certain every desktop compositor will implement this shell so that applications may create windows.
//!
//! See the [XDG shell module documentation] for more information about creating application windows.
//!
//! ## Layer shell
//!
//! The layer shell is a protocol which allows the creation of "layers". A layer refers to a surface rendered
//! at some specific z-depth relative to other layers. A layer may also be anchored to some edge and corner of
//! the screen.
//!
//! The layer shell defines one type of surface: the [`wlr_layer::LayerSurface`].
//!
//! There is no guarantee that the layer shell will be available in every compositor.
//!
//! ### Why use the layer shell
//!
//! The layer shell may be used to implement many desktop shell components, such as backgrounds, docks and
//! launchers.
//!
//! [^window]: The XDG shell protocol actually refers to a window as a toplevel surface, but we use the more
//! familiar term "window" for the sake of clarity.
//!
//! [XDG shell module documentation]: self::xdg
//! [`Window`]: self::xdg::window::Window
//! [`Popup`]: self::xdg::popup::Popup
//!
//! [`Layer`]: self::layer::LayerSurface
use wayland_client::{
protocol::{wl_buffer, wl_output, wl_region, wl_surface},
Proxy,
};
pub mod wlr_layer;
pub mod xdg;
/// An unsupported operation, often due to the version of the protocol.
#[derive(Debug, Default)]
pub struct Unsupported;
/// Functionality shared by all [`wl_surface::WlSurface`] backed shell role objects.
pub trait WaylandSurface: Sized {
/// The underlying [`WlSurface`](wl_surface::WlSurface).
fn wl_surface(&self) -> &wl_surface::WlSurface;
fn attach(&self, buffer: Option<&wl_buffer::WlBuffer>, x: u32, y: u32) {
// In version 5 and later, the x and y offset of `wl_surface::attach` must be zero and uses the
// `offset` request instead.
let (attach_x, attach_y) = if self.wl_surface().version() >= 5 { (0, 0) } else { (x, y) };
self.wl_surface().attach(buffer, attach_x as i32, attach_y as i32);
if self.wl_surface().version() >= 5 {
// Ignore the error since the version is garunteed to be at least 5 here.
let _ = self.offset(x, y);
}
}
// TODO: Damage (Buffer and Surface-local)
// TODO: Frame (a nice helper for this could exist).
fn set_opaque_region(&self, region: Option<&wl_region::WlRegion>) {
self.wl_surface().set_opaque_region(region);
}
fn set_input_region(&self, region: Option<&wl_region::WlRegion>) {
self.wl_surface().set_input_region(region);
}
fn set_buffer_transform(&self, transform: wl_output::Transform) -> Result<(), Unsupported> {
if self.wl_surface().version() < 2 {
return Err(Unsupported);
}
self.wl_surface().set_buffer_transform(transform);
Ok(())
}
fn set_buffer_scale(&self, scale: u32) -> Result<(), Unsupported> {
if self.wl_surface().version() < 3 {
return Err(Unsupported);
}
self.wl_surface().set_buffer_scale(scale as i32);
Ok(())
}
fn offset(&self, x: u32, y: u32) -> Result<(), Unsupported> {
if self.wl_surface().version() < 5 {
return Err(Unsupported);
}
self.wl_surface().offset(x as i32, y as i32);
Ok(())
}
/// Commits pending surface state.
///
/// On commit, the pending double buffered state from the surface, including role dependent state is
/// applied.
///
/// # Initial commit
///
/// In many protocol extensions, the concept of an initial commit is used. A initial commit provides the
/// initial state of a surface to the compositor. For example with the [xdg shell](xdg),
/// creating a window requires an initial commit.
///
/// # Protocol Errors
///
/// If the commit is the initial commit, no buffers must have been attached to the surface. This rule
/// applies whether attaching the buffer was done using [`WaylandSurface::attach`] or under the hood in
/// via window system integration in graphics APIs such as Vulkan (using `vkQueuePresentKHR`) and EGL
/// (using `eglSwapBuffers`).
fn commit(&self) {
self.wl_surface().commit();
}
}