mod dispatch;
use std::{
convert::TryFrom,
sync::{Arc, Weak},
};
use bitflags::bitflags;
use wayland_client::{
globals::{BindError, GlobalList},
protocol::{wl_output, wl_surface},
Connection, Dispatch, Proxy, QueueHandle,
};
use wayland_protocols::xdg::shell::client::xdg_popup::XdgPopup;
use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
use crate::{compositor::Surface, globals::GlobalData};
use super::WaylandSurface;
#[derive(Debug)]
pub struct LayerShell {
wlr_layer_shell: zwlr_layer_shell_v1::ZwlrLayerShellV1,
}
impl LayerShell {
pub fn bind<State>(
globals: &GlobalList,
qh: &QueueHandle<State>,
) -> Result<LayerShell, BindError>
where
State: Dispatch<zwlr_layer_shell_v1::ZwlrLayerShellV1, GlobalData, State>
+ LayerShellHandler
+ 'static,
{
let wlr_layer_shell = globals.bind(qh, 1..=4, GlobalData)?;
Ok(LayerShell { wlr_layer_shell })
}
#[must_use]
pub fn create_layer_surface<State>(
&self,
qh: &QueueHandle<State>,
surface: impl Into<Surface>,
layer: Layer,
namespace: Option<impl Into<String>>,
output: Option<&wl_output::WlOutput>,
) -> LayerSurface
where
State: Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, LayerSurfaceData> + 'static,
{
let freeze = qh.freeze();
let surface = surface.into();
let inner = Arc::new_cyclic(|weak| {
let layer_surface = self.wlr_layer_shell.get_layer_surface(
surface.wl_surface(),
output,
layer.into(),
namespace.map(Into::into).unwrap_or_default(),
qh,
LayerSurfaceData { inner: weak.clone() },
);
LayerSurfaceInner { wl_surface: surface, kind: SurfaceKind::Wlr(layer_surface) }
});
drop(freeze);
LayerSurface(inner)
}
}
pub trait LayerShellHandler: Sized {
fn closed(&mut self, conn: &Connection, qh: &QueueHandle<Self>, layer: &LayerSurface);
fn configure(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
layer: &LayerSurface,
configure: LayerSurfaceConfigure,
serial: u32,
);
}
#[derive(Debug, Clone)]
pub struct LayerSurface(Arc<LayerSurfaceInner>);
impl PartialEq for LayerSurface {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl LayerSurface {
pub fn from_wlr_surface(
surface: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
) -> Option<LayerSurface> {
surface.data::<LayerSurfaceData>().and_then(|data| data.inner.upgrade()).map(LayerSurface)
}
pub fn get_popup(&self, popup: &XdgPopup) {
match self.0.kind {
SurfaceKind::Wlr(ref s) => s.get_popup(popup),
}
}
pub fn set_size(&self, width: u32, height: u32) {
match self.0.kind {
SurfaceKind::Wlr(ref wlr) => wlr.set_size(width, height),
}
}
pub fn set_anchor(&self, anchor: Anchor) {
match self.0.kind {
SurfaceKind::Wlr(ref wlr) => {
wlr.set_anchor(zwlr_layer_surface_v1::Anchor::from_bits_truncate(anchor.bits()))
}
}
}
pub fn set_exclusive_zone(&self, zone: i32) {
match self.0.kind {
SurfaceKind::Wlr(ref wlr) => wlr.set_exclusive_zone(zone),
}
}
pub fn set_margin(&self, top: i32, right: i32, bottom: i32, left: i32) {
match self.0.kind {
SurfaceKind::Wlr(ref wlr) => wlr.set_margin(top, right, bottom, left),
}
}
pub fn set_keyboard_interactivity(&self, value: KeyboardInteractivity) {
match self.0.kind {
SurfaceKind::Wlr(ref wlr) => wlr.set_keyboard_interactivity(value.into()),
}
}
pub fn set_layer(&self, layer: Layer) {
match self.0.kind {
SurfaceKind::Wlr(ref wlr) => wlr.set_layer(layer.into()),
}
}
pub fn kind(&self) -> &SurfaceKind {
&self.0.kind
}
}
impl WaylandSurface for LayerSurface {
fn wl_surface(&self) -> &wl_surface::WlSurface {
self.0.wl_surface.wl_surface()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SurfaceKind {
Wlr(zwlr_layer_surface_v1::ZwlrLayerSurfaceV1),
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum KeyboardInteractivity {
None,
Exclusive,
OnDemand,
}
impl Default for KeyboardInteractivity {
fn default() -> Self {
Self::None
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Layer {
Background,
Bottom,
Top,
Overlay,
}
#[derive(Debug, thiserror::Error)]
#[error("unknown layer")]
pub struct UnknownLayer;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Anchor: u32 {
const TOP = 1;
const BOTTOM = 2;
const LEFT = 4;
const RIGHT = 8;
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct LayerSurfaceConfigure {
pub new_size: (u32, u32),
}
#[derive(Debug)]
pub struct LayerSurfaceData {
inner: Weak<LayerSurfaceInner>,
}
impl LayerSurfaceData {
pub fn layer_surface(&self) -> Option<LayerSurface> {
self.inner.upgrade().map(LayerSurface)
}
}
#[macro_export]
macro_rules! delegate_layer {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
$crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::ZwlrLayerShellV1: $crate::globals::GlobalData
] => $crate::shell::wlr_layer::LayerShell);
$crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1: $crate::shell::wlr_layer::LayerSurfaceData
] => $crate::shell::wlr_layer::LayerShell);
};
}
#[derive(Debug)]
struct LayerSurfaceInner {
wl_surface: Surface,
kind: SurfaceKind,
}
impl TryFrom<zwlr_layer_shell_v1::Layer> for Layer {
type Error = UnknownLayer;
fn try_from(layer: zwlr_layer_shell_v1::Layer) -> Result<Self, Self::Error> {
match layer {
zwlr_layer_shell_v1::Layer::Background => Ok(Self::Background),
zwlr_layer_shell_v1::Layer::Bottom => Ok(Self::Bottom),
zwlr_layer_shell_v1::Layer::Top => Ok(Self::Top),
zwlr_layer_shell_v1::Layer::Overlay => Ok(Self::Overlay),
_ => Err(UnknownLayer),
}
}
}
impl From<Layer> for zwlr_layer_shell_v1::Layer {
fn from(depth: Layer) -> Self {
match depth {
Layer::Background => Self::Background,
Layer::Bottom => Self::Bottom,
Layer::Top => Self::Top,
Layer::Overlay => Self::Overlay,
}
}
}
impl From<KeyboardInteractivity> for zwlr_layer_surface_v1::KeyboardInteractivity {
fn from(interactivity: KeyboardInteractivity) -> Self {
match interactivity {
KeyboardInteractivity::None => zwlr_layer_surface_v1::KeyboardInteractivity::None,
KeyboardInteractivity::Exclusive => {
zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive
}
KeyboardInteractivity::OnDemand => {
zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand
}
}
}
}
impl Drop for LayerSurfaceInner {
fn drop(&mut self) {
match self.kind {
SurfaceKind::Wlr(ref wlr) => wlr.destroy(),
}
}
}