wayland: toplevel management protocol
This commit is contained in:
parent
4f142d50b3
commit
6b659eb107
9 changed files with 340 additions and 54 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
|
@ -361,11 +361,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-protocols"
|
name = "cosmic-protocols"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#55f15e8b05fc983ab36b65b4c027b59f5876a181"
|
source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#81d6a50bdc91af5968f87785fc19a16cf261c96b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-client 0.30.0-beta.8",
|
|
||||||
"wayland-protocols 0.30.0-beta.8",
|
"wayland-protocols 0.30.0-beta.8",
|
||||||
"wayland-scanner 0.30.0-beta.8",
|
"wayland-scanner 0.30.0-beta.8",
|
||||||
"wayland-server",
|
"wayland-server",
|
||||||
|
|
@ -649,21 +648,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-channel"
|
|
||||||
version = "0.3.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-core"
|
|
||||||
version = "0.3.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gbm"
|
name = "gbm"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|
@ -1569,7 +1553,7 @@ dependencies = [
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"nix 0.22.3",
|
"nix 0.22.3",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"wayland-client 0.29.4",
|
"wayland-client",
|
||||||
"wayland-cursor",
|
"wayland-cursor",
|
||||||
"wayland-protocols 0.29.4",
|
"wayland-protocols 0.29.4",
|
||||||
]
|
]
|
||||||
|
|
@ -1844,21 +1828,6 @@ dependencies = [
|
||||||
"wayland-sys 0.29.4",
|
"wayland-sys 0.29.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-client"
|
|
||||||
version = "0.30.0-beta.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0f9e0d862c23f07b2c4b49de66b0680948af5dd1d2def17f1ddc16520352bf14"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"nix 0.24.2",
|
|
||||||
"thiserror",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-scanner 0.30.0-beta.8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-commons"
|
name = "wayland-commons"
|
||||||
version = "0.29.4"
|
version = "0.29.4"
|
||||||
|
|
@ -1878,7 +1847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd"
|
checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix 0.22.3",
|
"nix 0.22.3",
|
||||||
"wayland-client 0.29.4",
|
"wayland-client",
|
||||||
"xcursor",
|
"xcursor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1900,7 +1869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741"
|
checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"wayland-client 0.29.4",
|
"wayland-client",
|
||||||
"wayland-commons",
|
"wayland-commons",
|
||||||
"wayland-scanner 0.29.4",
|
"wayland-scanner 0.29.4",
|
||||||
]
|
]
|
||||||
|
|
@ -1913,7 +1882,6 @@ checksum = "e47c45a60d531d5a513601f47f51a4743901836778ddae208ae9124606be1719"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-client 0.30.0-beta.8",
|
|
||||||
"wayland-scanner 0.30.0-beta.8",
|
"wayland-scanner 0.30.0-beta.8",
|
||||||
"wayland-server",
|
"wayland-server",
|
||||||
]
|
]
|
||||||
|
|
@ -2102,7 +2070,7 @@ dependencies = [
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"smithay-client-toolkit",
|
"smithay-client-toolkit",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wayland-client 0.29.4",
|
"wayland-client",
|
||||||
"wayland-protocols 0.29.4",
|
"wayland-protocols 0.29.4",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ atomic_float = "0.1"
|
||||||
libsystemd = "0.5"
|
libsystemd = "0.5"
|
||||||
wayland-backend = "=0.1.0-beta.8"
|
wayland-backend = "=0.1.0-beta.8"
|
||||||
wayland-scanner = "=0.30.0-beta.8"
|
wayland-scanner = "=0.30.0-beta.8"
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main" }
|
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] }
|
||||||
|
|
||||||
[dependencies.smithay]
|
[dependencies.smithay]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,11 @@ use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, WorkspaceMode as ConfigMode},
|
config::{Config, WorkspaceMode as ConfigMode},
|
||||||
|
//state::ClientState,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::protocols::{
|
wayland::protocols::{
|
||||||
toplevel_info::ToplevelInfoState,
|
toplevel_info::ToplevelInfoState,
|
||||||
|
toplevel_management::{ToplevelManagementState, ManagementCapabilities},
|
||||||
workspace::{
|
workspace::{
|
||||||
WorkspaceCapabilities, WorkspaceGroupHandle, WorkspaceHandle, WorkspaceState,
|
WorkspaceCapabilities, WorkspaceGroupHandle, WorkspaceHandle, WorkspaceState,
|
||||||
WorkspaceUpdateGuard,
|
WorkspaceUpdateGuard,
|
||||||
|
|
@ -52,6 +54,7 @@ pub struct Shell {
|
||||||
// wayland_state
|
// wayland_state
|
||||||
pub layer_shell_state: WlrLayerShellState,
|
pub layer_shell_state: WlrLayerShellState,
|
||||||
pub toplevel_info_state: ToplevelInfoState<State>,
|
pub toplevel_info_state: ToplevelInfoState<State>,
|
||||||
|
pub toplevel_management_state: ToplevelManagementState,
|
||||||
pub xdg_shell_state: XdgShellState,
|
pub xdg_shell_state: XdgShellState,
|
||||||
pub workspace_state: WorkspaceState<State>,
|
pub workspace_state: WorkspaceState<State>,
|
||||||
}
|
}
|
||||||
|
|
@ -81,10 +84,24 @@ const UNINIT_SPACE: MaybeUninit<Workspace> = MaybeUninit::uninit();
|
||||||
|
|
||||||
impl Shell {
|
impl Shell {
|
||||||
pub fn new(config: &Config, dh: &DisplayHandle) -> Self {
|
pub fn new(config: &Config, dh: &DisplayHandle) -> Self {
|
||||||
|
// TODO: Privileged protocols
|
||||||
let layer_shell_state = WlrLayerShellState::new::<State, _>(dh, None);
|
let layer_shell_state = WlrLayerShellState::new::<State, _>(dh, None);
|
||||||
let toplevel_info_state = ToplevelInfoState::new(dh, |_| true);
|
|
||||||
let xdg_shell_state = XdgShellState::new::<State, _>(dh, None);
|
let xdg_shell_state = XdgShellState::new::<State, _>(dh, None);
|
||||||
let mut workspace_state = WorkspaceState::new(dh, |_| true);
|
let toplevel_info_state = ToplevelInfoState::new(
|
||||||
|
dh,
|
||||||
|
//|client| client.get_data::<ClientState>().unwrap().privileged,
|
||||||
|
|_| true);
|
||||||
|
let toplevel_management_state = ToplevelManagementState::new::<State, _>(
|
||||||
|
dh,
|
||||||
|
vec![ManagementCapabilities::Close, ManagementCapabilities::Activate],
|
||||||
|
//|client| client.get_data::<ClientState>().unwrap().privileged,
|
||||||
|
|_| true,
|
||||||
|
);
|
||||||
|
let mut workspace_state = WorkspaceState::new(
|
||||||
|
dh,
|
||||||
|
//|client| client.get_data::<ClientState>().unwrap().privileged,
|
||||||
|
|_| true,
|
||||||
|
);
|
||||||
|
|
||||||
let mut spaces = unsafe {
|
let mut spaces = unsafe {
|
||||||
let mut spaces = [UNINIT_SPACE; MAX_WORKSPACES];
|
let mut spaces = [UNINIT_SPACE; MAX_WORKSPACES];
|
||||||
|
|
@ -116,6 +133,7 @@ impl Shell {
|
||||||
|
|
||||||
layer_shell_state,
|
layer_shell_state,
|
||||||
toplevel_info_state,
|
toplevel_info_state,
|
||||||
|
toplevel_management_state,
|
||||||
xdg_shell_state,
|
xdg_shell_state,
|
||||||
workspace_state,
|
workspace_state,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use smithay::{
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
pub(super) idx: u8,
|
pub idx: u8,
|
||||||
pub space: Space,
|
pub space: Space,
|
||||||
pub tiling_layer: TilingLayout,
|
pub tiling_layer: TilingLayout,
|
||||||
pub floating_layer: FloatingLayout,
|
pub floating_layer: FloatingLayout,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ pub mod primary_selection;
|
||||||
pub mod seat;
|
pub mod seat;
|
||||||
pub mod shm;
|
pub mod shm;
|
||||||
pub mod toplevel_info;
|
pub mod toplevel_info;
|
||||||
|
pub mod toplevel_management;
|
||||||
pub mod viewporter;
|
pub mod viewporter;
|
||||||
pub mod wl_drm;
|
pub mod wl_drm;
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
|
|
|
||||||
45
src/wayland/handlers/toplevel_management.rs
Normal file
45
src/wayland/handlers/toplevel_management.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use smithay::{
|
||||||
|
desktop::{Kind, Window},
|
||||||
|
reexports::wayland_server::DisplayHandle,
|
||||||
|
wayland::seat::Seat,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
utils::prelude::*,
|
||||||
|
wayland::protocols::toplevel_management::{
|
||||||
|
delegate_toplevel_management, ToplevelManagementHandler, ToplevelManagementState,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl ToplevelManagementHandler for State {
|
||||||
|
fn toplevel_management_state(&mut self) -> &mut ToplevelManagementState {
|
||||||
|
&mut self.common.shell.toplevel_management_state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate(&mut self, dh: &DisplayHandle, window: &Window, seat: Option<Seat<Self>>) {
|
||||||
|
if let Some(idx) = self.common.shell.space_for_window(window.toplevel().wl_surface()).map(|w| w.idx) {
|
||||||
|
let seat = seat.unwrap_or(self.common.last_active_seat.clone());
|
||||||
|
let output = active_output(&seat, &self.common);
|
||||||
|
if self.common.shell.active_space(&output).idx != idx {
|
||||||
|
self.common.shell.activate(&seat, &output, idx as usize);
|
||||||
|
}
|
||||||
|
self.common.set_focus(
|
||||||
|
dh,
|
||||||
|
Some(window.toplevel().wl_surface()),
|
||||||
|
&seat,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&mut self, _dh: &DisplayHandle, window: &Window) {
|
||||||
|
#[allow(irrefutable_let_patterns)]
|
||||||
|
if let Kind::Xdg(xdg) = &window.toplevel() {
|
||||||
|
xdg.send_close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate_toplevel_management!(State);
|
||||||
|
|
@ -3,4 +3,5 @@
|
||||||
pub mod drm;
|
pub mod drm;
|
||||||
pub mod output_configuration;
|
pub mod output_configuration;
|
||||||
pub mod toplevel_info;
|
pub mod toplevel_info;
|
||||||
|
pub mod toplevel_management;
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::Mutex,
|
||||||
|
};
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
desktop::Window,
|
||||||
|
|
@ -8,11 +11,12 @@ use smithay::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
backend::{ClientId, GlobalId, ObjectId},
|
backend::{ClientId, GlobalId, ObjectId},
|
||||||
|
protocol::wl_surface::WlSurface,
|
||||||
Client, DataInit, Dispatch, DisplayHandle,
|
Client, DataInit, Dispatch, DisplayHandle,
|
||||||
GlobalDispatch, New, Resource,
|
GlobalDispatch, New, Resource,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
utils::IsAlive,
|
utils::{IsAlive, Rectangle, Logical},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::with_states, output::Output, shell::xdg::XdgToplevelSurfaceRoleAttributes,
|
compositor::with_states, output::Output, shell::xdg::XdgToplevelSurfaceRoleAttributes,
|
||||||
},
|
},
|
||||||
|
|
@ -27,7 +31,7 @@ use cosmic_protocols::toplevel_info::v1::server::{
|
||||||
|
|
||||||
pub struct ToplevelInfoState<D> {
|
pub struct ToplevelInfoState<D> {
|
||||||
dh: DisplayHandle,
|
dh: DisplayHandle,
|
||||||
toplevels: Vec<Window>,
|
pub(super) toplevels: Vec<Window>,
|
||||||
instances: Vec<ZcosmicToplevelInfoV1>,
|
instances: Vec<ZcosmicToplevelInfoV1>,
|
||||||
global: GlobalId,
|
global: GlobalId,
|
||||||
_dispatch_data: std::marker::PhantomData<D>,
|
_dispatch_data: std::marker::PhantomData<D>,
|
||||||
|
|
@ -43,24 +47,40 @@ pub struct ToplevelInfoGlobalData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ToplevelStateInner {
|
pub(super) struct ToplevelStateInner {
|
||||||
instances: Vec<ZcosmicToplevelHandleV1>,
|
instances: Vec<ZcosmicToplevelHandleV1>,
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
workspaces: Vec<WorkspaceHandle>,
|
workspaces: Vec<WorkspaceHandle>,
|
||||||
minimized: bool,
|
minimized: bool,
|
||||||
|
pub(super) rectangles: HashMap<ClientId, (WlSurface, Rectangle<i32, Logical>)>,
|
||||||
}
|
}
|
||||||
type ToplevelState = Mutex<ToplevelStateInner>;
|
pub(super) type ToplevelState = Mutex<ToplevelStateInner>;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ToplevelHandleStateInner {
|
pub struct ToplevelHandleStateInner {
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
workspaces: Vec<WorkspaceHandle>,
|
workspaces: Vec<WorkspaceHandle>,
|
||||||
title: String,
|
title: String,
|
||||||
app_id: String,
|
app_id: String,
|
||||||
states: Vec<States>,
|
states: Vec<States>,
|
||||||
|
pub(super) window: Window,
|
||||||
}
|
}
|
||||||
pub type ToplevelHandleState = Mutex<ToplevelHandleStateInner>;
|
pub type ToplevelHandleState = Mutex<ToplevelHandleStateInner>;
|
||||||
|
|
||||||
|
impl ToplevelHandleStateInner {
|
||||||
|
fn from_window(window: &Window) -> ToplevelHandleState {
|
||||||
|
ToplevelHandleState::new(
|
||||||
|
ToplevelHandleStateInner {
|
||||||
|
outputs: Vec::new(),
|
||||||
|
workspaces: Vec::new(),
|
||||||
|
title: String::new(),
|
||||||
|
app_id: String::new(),
|
||||||
|
states: Vec::new(),
|
||||||
|
window: window.clone(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<D> GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData, D>
|
impl<D> GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData, D>
|
||||||
for ToplevelInfoState<D>
|
for ToplevelInfoState<D>
|
||||||
where
|
where
|
||||||
|
|
@ -82,6 +102,7 @@ where
|
||||||
for window in &state.toplevel_info_state().toplevels {
|
for window in &state.toplevel_info_state().toplevels {
|
||||||
send_toplevel_to_client::<D>(dh, Some(state.workspace_state()), &instance, window);
|
send_toplevel_to_client::<D>(dh, Some(state.workspace_state()), &instance, window);
|
||||||
}
|
}
|
||||||
|
state.toplevel_info_state_mut().instances.push(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_view(client: Client, global_data: &ToplevelInfoGlobalData) -> bool {
|
fn can_view(client: Client, global_data: &ToplevelInfoGlobalData) -> bool {
|
||||||
|
|
@ -229,18 +250,21 @@ where
|
||||||
|
|
||||||
pub fn refresh(&mut self, workspace_state: Option<&WorkspaceState<D>>) {
|
pub fn refresh(&mut self, workspace_state: Option<&WorkspaceState<D>>) {
|
||||||
self.toplevels.retain(|window| {
|
self.toplevels.retain(|window| {
|
||||||
|
let mut state = window
|
||||||
|
.user_data()
|
||||||
|
.get::<ToplevelState>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap();
|
||||||
|
state.rectangles
|
||||||
|
.retain(|_, (surface, _)| surface.alive());
|
||||||
if window.alive() {
|
if window.alive() {
|
||||||
|
std::mem::drop(state);
|
||||||
for instance in &self.instances {
|
for instance in &self.instances {
|
||||||
send_toplevel_to_client::<D>(&self.dh, workspace_state, instance, window);
|
send_toplevel_to_client::<D>(&self.dh, workspace_state, instance, window);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
let state = window
|
|
||||||
.user_data()
|
|
||||||
.get::<ToplevelState>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap();
|
|
||||||
for handle in &state.instances {
|
for handle in &state.instances {
|
||||||
// don't send events to stopped instances
|
// don't send events to stopped instances
|
||||||
if self
|
if self
|
||||||
|
|
@ -291,7 +315,7 @@ fn send_toplevel_to_client<D>(
|
||||||
.create_resource::<ZcosmicToplevelHandleV1, _, D>(
|
.create_resource::<ZcosmicToplevelHandleV1, _, D>(
|
||||||
dh,
|
dh,
|
||||||
info.version(),
|
info.version(),
|
||||||
ToplevelHandleState::default(),
|
ToplevelHandleStateInner::from_window(window),
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
state.instances.push(toplevel_handle);
|
state.instances.push(toplevel_handle);
|
||||||
|
|
@ -448,6 +472,16 @@ fn send_toplevel_to_client<D>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn window_from_handle(handle: ZcosmicToplevelHandleV1) -> Window {
|
||||||
|
handle
|
||||||
|
.data::<ToplevelHandleState>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.window
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! delegate_toplevel_info {
|
macro_rules! delegate_toplevel_info {
|
||||||
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
||||||
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
|
|
|
||||||
219
src/wayland/protocols/toplevel_management.rs
Normal file
219
src/wayland/protocols/toplevel_management.rs
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use smithay::{
|
||||||
|
desktop::Window,
|
||||||
|
reexports::{
|
||||||
|
wayland_server::{
|
||||||
|
backend::{ClientId, GlobalId, ObjectId},
|
||||||
|
protocol::wl_surface::WlSurface,
|
||||||
|
Client, DataInit, Dispatch, DisplayHandle,
|
||||||
|
GlobalDispatch, New, Resource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
utils::{Logical, Rectangle},
|
||||||
|
wayland::{
|
||||||
|
output::Output,
|
||||||
|
seat::Seat,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
use cosmic_protocols::toplevel_management::v1::server::{
|
||||||
|
zcosmic_toplevel_manager_v1::{self, ZcosmicToplevelManagerV1},
|
||||||
|
};
|
||||||
|
pub use cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_v1::ZcosmicToplelevelManagementCapabilitiesV1 as ManagementCapabilities;
|
||||||
|
|
||||||
|
use super::toplevel_info::{ToplevelInfoHandler, ToplevelHandleState, ToplevelState, window_from_handle};
|
||||||
|
|
||||||
|
|
||||||
|
pub struct ToplevelManagementState {
|
||||||
|
instances: Vec<ZcosmicToplevelManagerV1>,
|
||||||
|
capabilities: Vec<ManagementCapabilities>,
|
||||||
|
global: GlobalId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub trait ToplevelManagementHandler: ToplevelInfoHandler {
|
||||||
|
fn toplevel_management_state(&mut self) -> &mut ToplevelManagementState;
|
||||||
|
|
||||||
|
fn activate(&mut self, dh: &DisplayHandle, window: &Window, seat: Option<Seat<Self>>) {}
|
||||||
|
fn close(&mut self, dh: &DisplayHandle, window: &Window) {}
|
||||||
|
|
||||||
|
fn fullscreen(&mut self, dh: &DisplayHandle, window: &Window, output: Option<Output>) {}
|
||||||
|
fn unfullscreen(&mut self, dh: &DisplayHandle, window: &Window) {}
|
||||||
|
fn maximize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
||||||
|
fn unmaximize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
||||||
|
fn minimize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
||||||
|
fn unminimize(&mut self, dh: &DisplayHandle, window: &Window) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ToplevelManagerGlobalData {
|
||||||
|
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToplevelManagementState {
|
||||||
|
pub fn new<D, F>(dh: &DisplayHandle, capabilities: Vec<ManagementCapabilities>, client_filter: F) -> ToplevelManagementState
|
||||||
|
where
|
||||||
|
D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData>
|
||||||
|
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
||||||
|
+ ToplevelManagementHandler
|
||||||
|
+ 'static,
|
||||||
|
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static
|
||||||
|
{
|
||||||
|
let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>(
|
||||||
|
1,
|
||||||
|
ToplevelManagerGlobalData {
|
||||||
|
filter: Box::new(client_filter),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
ToplevelManagementState {
|
||||||
|
capabilities,
|
||||||
|
instances: Vec::new(),
|
||||||
|
global,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rectangle_for(&mut self, window: &Window, client: &ClientId) -> Option<(WlSurface, Rectangle<i32, Logical>)> {
|
||||||
|
if let Some(state) = window.user_data().get::<ToplevelState>() {
|
||||||
|
state.lock().unwrap().rectangles.get(client).cloned()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn global_id(&self) -> GlobalId {
|
||||||
|
self.global.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData, D> for ToplevelManagementState
|
||||||
|
where
|
||||||
|
D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData>
|
||||||
|
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
||||||
|
+ ToplevelManagementHandler
|
||||||
|
+ 'static
|
||||||
|
{
|
||||||
|
fn bind(
|
||||||
|
state: &mut D,
|
||||||
|
_dh: &DisplayHandle,
|
||||||
|
_client: &Client,
|
||||||
|
resource: New<ZcosmicToplevelManagerV1>,
|
||||||
|
_global_data: &ToplevelManagerGlobalData,
|
||||||
|
data_init: &mut DataInit<'_, D>,
|
||||||
|
) {
|
||||||
|
let instance = data_init.init(resource, ());
|
||||||
|
let capabilities = {
|
||||||
|
let mut caps = state.toplevel_management_state().capabilities.clone();
|
||||||
|
let ratio = std::mem::size_of::<ManagementCapabilities>() / std::mem::size_of::<u8>();
|
||||||
|
let ptr = caps.as_mut_ptr() as *mut u8;
|
||||||
|
let len = caps.len() * ratio;
|
||||||
|
let cap = caps.capacity() * ratio;
|
||||||
|
std::mem::forget(caps);
|
||||||
|
unsafe { Vec::from_raw_parts(ptr, len, cap) }
|
||||||
|
};
|
||||||
|
instance.capabilities(capabilities);
|
||||||
|
state.toplevel_management_state().instances.push(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_view(client: Client, global_data: &ToplevelManagerGlobalData) -> bool {
|
||||||
|
(global_data.filter)(&client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<D> Dispatch<ZcosmicToplevelManagerV1, (), D> for ToplevelManagementState
|
||||||
|
where
|
||||||
|
D: GlobalDispatch<ZcosmicToplevelManagerV1, ToplevelManagerGlobalData>
|
||||||
|
+ Dispatch<ZcosmicToplevelManagerV1, ()>
|
||||||
|
+ ToplevelManagementHandler
|
||||||
|
+ 'static
|
||||||
|
{
|
||||||
|
fn request(
|
||||||
|
state: &mut D,
|
||||||
|
_client: &Client,
|
||||||
|
_obj: &ZcosmicToplevelManagerV1,
|
||||||
|
request: zcosmic_toplevel_manager_v1::Request,
|
||||||
|
_data: &(),
|
||||||
|
dh: &DisplayHandle,
|
||||||
|
_data_init: &mut DataInit<'_, D>,
|
||||||
|
) {
|
||||||
|
match request {
|
||||||
|
zcosmic_toplevel_manager_v1::Request::Activate { toplevel, seat } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.activate(dh, &window, Seat::from_resource(&seat));
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::Close { toplevel } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.close(dh, &window);
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::SetFullscreen { toplevel, output } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.fullscreen(dh, &window, output.as_ref().and_then(Output::from_resource))
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::UnsetFullscreen { toplevel } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.unfullscreen(dh, &window);
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::SetMaximized { toplevel } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.maximize(dh, &window);
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::UnsetMaximized { toplevel } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.unmaximize(dh, &window);
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::SetMinimized { toplevel } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.minimize(dh, &window);
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::UnsetMinimized { toplevel } => {
|
||||||
|
let window = window_from_handle(toplevel);
|
||||||
|
state.unminimize(dh, &window);
|
||||||
|
},
|
||||||
|
zcosmic_toplevel_manager_v1::Request::SetRectangle { toplevel, surface, x, y, width, height } => {
|
||||||
|
let window = toplevel
|
||||||
|
.data::<ToplevelHandleState>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.window
|
||||||
|
.clone();
|
||||||
|
if let Some(toplevel_state) = window.user_data().get::<ToplevelState>() {
|
||||||
|
let mut toplevel_state = toplevel_state.lock().unwrap();
|
||||||
|
if let Some(client) = surface.client_id() {
|
||||||
|
if width == 0 && height == 0 {
|
||||||
|
toplevel_state.rectangles.remove(&client);
|
||||||
|
} else {
|
||||||
|
toplevel_state.rectangles.insert(client, (surface, Rectangle::from_loc_and_size((x, y), (width, height))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroyed(state: &mut D, client: ClientId, resource: ObjectId, _data: &()) {
|
||||||
|
let mng_state = state.toplevel_management_state();
|
||||||
|
mng_state.instances.retain(|i| i.id() != resource);
|
||||||
|
if !mng_state.instances.iter().any(|i| i.client_id().map(|c| c == client).unwrap_or(false)) {
|
||||||
|
for toplevel in state.toplevel_info_state_mut().toplevels.iter() {
|
||||||
|
if let Some(toplevel_state) = toplevel.user_data().get::<ToplevelState>() {
|
||||||
|
toplevel_state.lock().unwrap().rectangles.remove(&client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! delegate_toplevel_management {
|
||||||
|
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
||||||
|
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
|
cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1: $crate::wayland::protocols::toplevel_management::ToplevelManagerGlobalData
|
||||||
|
] => $crate::wayland::protocols::toplevel_management::ToplevelManagementState);
|
||||||
|
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
|
cosmic_protocols::toplevel_management::v1::server::zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1: ()
|
||||||
|
] => $crate::wayland::protocols::toplevel_management::ToplevelManagementState);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub(crate) use delegate_toplevel_management;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue