protocols/workspace: Store request queue in workspace manager udata

This is slightly simpler, if there's not some reason I'm missing to do
this as it was previously done. And in particular provides a cleaner
API (if we wanted to move this to Smithay; perhaps without the Cosmic
extension).

But it also should be more correct. Presumably if a client (unusually)
had multiple components with their own `ext_workspace_manager_v1`
instance, they should have their own queues, and
`ext_workspace_manager_v1::commit` should be independent.

Inevitably, there's a racy element to multiple components trying to
update the workspace state like this, but it should behave the same as
two clients with separate connections.

(This is different from `CompositorClientState`, since the commit queue
there is fundamentally tied to the client, and different components with
their own compositor instance way have related surfaces.)
This commit is contained in:
Ian Douglas Scott 2025-04-16 16:05:39 -07:00 committed by Ian Douglas Scott
parent 2f6d600502
commit e944ee9b2f
5 changed files with 106 additions and 113 deletions

View file

@ -24,7 +24,7 @@ use crate::{
screencopy::ScreencopyState,
toplevel_info::ToplevelInfoState,
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
workspace::{WorkspaceState, WorkspaceUpdateGuard},
},
},
xwayland::XWaylandState,
@ -141,7 +141,6 @@ macro_rules! fl {
pub struct ClientState {
pub compositor_client_state: CompositorClientState,
pub workspace_client_state: WorkspaceClientState,
pub advertised_drm_node: Option<DrmNode>,
pub privileged: bool,
pub evls: LoopSignal,
@ -679,7 +678,6 @@ impl State {
pub fn new_client_state(&self) -> ClientState {
ClientState {
compositor_client_state: CompositorClientState::default(),
workspace_client_state: WorkspaceClientState::default(),
advertised_drm_node: match &self.backend {
BackendData::Kms(kms_state) => kms_state.primary_node,
_ => None,

View file

@ -2,24 +2,15 @@
use crate::{
shell::WorkspaceDelta,
state::ClientState,
utils::prelude::*,
wayland::protocols::workspace::{
delegate_workspace, Request, WorkspaceClientHandler, WorkspaceClientState,
WorkspaceHandler, WorkspaceState,
delegate_workspace, Request, WorkspaceHandler, WorkspaceState,
},
};
use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::TilingState;
use smithay::reexports::wayland_server::DisplayHandle;
impl WorkspaceClientHandler for ClientState {
fn workspace_state(&self) -> &WorkspaceClientState {
&self.workspace_client_state
}
}
impl WorkspaceHandler for State {
type Client = ClientState;
fn workspace_state(&self) -> &WorkspaceState<Self> {
&self.common.workspace_state
}

View file

@ -13,8 +13,8 @@ use smithay::reexports::{
use std::sync::Mutex;
use super::{
Request, Workspace, WorkspaceCapabilities, WorkspaceClientHandler, WorkspaceData,
WorkspaceGlobalData, WorkspaceHandler, WorkspaceState,
Request, Workspace, WorkspaceCapabilities, WorkspaceData, WorkspaceGlobalData,
WorkspaceHandler, WorkspaceManagerData, WorkspaceState,
};
#[derive(Default)]
@ -113,7 +113,7 @@ where
{
fn request(
state: &mut D,
client: &Client,
_client: &Client,
_obj: &ZcosmicWorkspaceHandleV2,
request: zcosmic_workspace_handle_v2::Request,
data: &CosmicWorkspaceV2Data,
@ -128,16 +128,19 @@ where
if let Some(workspace_handle) =
state.workspace_state().get_ext_workspace_handle(&workspace)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::Rename {
workspace: workspace_handle,
name,
});
if let Ok(manager) =
workspace.data::<WorkspaceData>().unwrap().manager.upgrade()
{
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::Rename {
workspace: workspace_handle,
name,
});
}
}
}
zcosmic_workspace_handle_v2::Request::SetTilingState {
@ -146,16 +149,19 @@ where
if let Some(workspace_handle) =
state.workspace_state().get_ext_workspace_handle(&workspace)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::SetTilingState {
workspace: workspace_handle,
state: tiling_state,
});
if let Ok(manager) =
workspace.data::<WorkspaceData>().unwrap().manager.upgrade()
{
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::SetTilingState {
workspace: workspace_handle,
state: tiling_state,
});
}
}
}
zcosmic_workspace_handle_v2::Request::Destroy => {}

View file

@ -20,10 +20,17 @@ use smithay::{
use std::{collections::HashSet, sync::Mutex};
use super::{
Request, Workspace, WorkspaceCapabilities, WorkspaceClientHandler, WorkspaceGlobalData,
WorkspaceGroup, WorkspaceGroupHandle, WorkspaceHandler, WorkspaceState,
Request, Workspace, WorkspaceCapabilities, WorkspaceGlobalData, WorkspaceGroup,
WorkspaceGroupHandle, WorkspaceHandler, WorkspaceState,
};
#[derive(Debug, Default)]
pub struct WorkspaceManagerDataInner {
pub(super) requests: Vec<Request>,
}
pub type WorkspaceManagerData = Mutex<WorkspaceManagerDataInner>;
#[derive(Default)]
pub struct WorkspaceGroupDataInner {
outputs: Vec<Output>,
@ -64,7 +71,7 @@ where
data_init: &mut DataInit<'_, D>,
) {
let state = state.workspace_state_mut();
let instance = data_init.init(resource, ());
let instance = data_init.init(resource, WorkspaceManagerData::default());
for group in &mut state.groups {
send_group_to_client::<D>(dh, &instance, group);
}
@ -77,29 +84,24 @@ where
}
}
impl<D> Dispatch<ExtWorkspaceManagerV1, (), D> for WorkspaceState<D>
impl<D> Dispatch<ExtWorkspaceManagerV1, WorkspaceManagerData, D> for WorkspaceState<D>
where
D: WorkspaceHandler,
{
fn request(
state: &mut D,
client: &Client,
_client: &Client,
obj: &ExtWorkspaceManagerV1,
request: ext_workspace_manager_v1::Request,
_data: &(),
data: &WorkspaceManagerData,
dh: &DisplayHandle,
_data_init: &mut DataInit<'_, D>,
) {
match request {
ext_workspace_manager_v1::Request::Commit => {
if state.workspace_state().ext_instances.contains(obj) {
let mut client_state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.commit_requests(dh, std::mem::take(&mut client_state.requests));
let mut data = data.lock().unwrap();
state.commit_requests(dh, std::mem::take(&mut data.requests));
}
}
ext_workspace_manager_v1::Request::Stop => {
@ -114,7 +116,12 @@ where
}
}
fn destroyed(state: &mut D, _client: ClientId, resource: &ExtWorkspaceManagerV1, _data: &()) {
fn destroyed(
state: &mut D,
_client: ClientId,
resource: &ExtWorkspaceManagerV1,
_data: &WorkspaceManagerData,
) {
state
.workspace_state_mut()
.ext_instances
@ -128,10 +135,10 @@ where
{
fn request(
state: &mut D,
client: &Client,
_client: &Client,
obj: &ExtWorkspaceGroupHandleV1,
request: ext_workspace_group_handle_v1::Request,
_data: &WorkspaceGroupData,
data: &WorkspaceGroupData,
_dh: &DisplayHandle,
_data_init: &mut DataInit<'_, D>,
) {
@ -144,16 +151,17 @@ where
.find(|g| g.ext_instances.contains(obj))
.map(|g| g.id)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::Create {
in_group: WorkspaceGroupHandle { id },
name: workspace,
});
if let Ok(manager) = data.manager.upgrade() {
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::Create {
in_group: WorkspaceGroupHandle { id },
name: workspace,
});
}
}
}
ext_workspace_group_handle_v1::Request::Destroy => {
@ -183,10 +191,10 @@ where
{
fn request(
state: &mut D,
client: &Client,
_client: &Client,
obj: &ExtWorkspaceHandleV1,
request: ext_workspace_handle_v1::Request,
_data: &WorkspaceData,
data: &WorkspaceData,
_dh: &DisplayHandle,
_data_init: &mut DataInit<'_, D>,
) {
@ -195,39 +203,42 @@ where
if let Some(workspace_handle) =
state.workspace_state().get_ext_workspace_handle(obj)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::Activate(workspace_handle));
if let Ok(manager) = data.manager.upgrade() {
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::Activate(workspace_handle));
}
}
}
ext_workspace_handle_v1::Request::Deactivate => {
if let Some(workspace_handle) =
state.workspace_state().get_ext_workspace_handle(obj)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::Deactivate(workspace_handle));
if let Ok(manager) = data.manager.upgrade() {
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::Deactivate(workspace_handle));
}
}
}
ext_workspace_handle_v1::Request::Remove => {
if let Some(workspace_handle) =
state.workspace_state().get_ext_workspace_handle(obj)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::Remove(workspace_handle));
if let Ok(manager) = data.manager.upgrade() {
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::Remove(workspace_handle));
}
}
}
ext_workspace_handle_v1::Request::Assign { workspace_group } => {
@ -241,16 +252,17 @@ where
.find(|g| g.ext_instances.contains(&workspace_group))
.map(|g| g.id)
{
let mut state = client
.get_data::<<D as WorkspaceHandler>::Client>()
.unwrap()
.workspace_state()
.lock()
.unwrap();
state.requests.push(Request::Assign {
workspace: workspace_handle,
group: WorkspaceGroupHandle { id: group_id },
});
if let Ok(manager) = data.manager.upgrade() {
let mut state = manager
.data::<WorkspaceManagerData>()
.unwrap()
.lock()
.unwrap();
state.requests.push(Request::Assign {
workspace: workspace_handle,
group: WorkspaceGroupHandle { id: group_id },
});
}
}
}
}

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-only
use std::sync::Mutex;
use smithay::{
output::Output,
reexports::{
@ -11,7 +9,7 @@ use smithay::{
ext_workspace_manager_v1::ExtWorkspaceManagerV1,
},
wayland_server::{
backend::{ClientData, GlobalId, ObjectId},
backend::{GlobalId, ObjectId},
Client, Dispatch, DisplayHandle, GlobalDispatch, Resource,
},
},
@ -26,7 +24,7 @@ use cosmic_protocols::workspace::v2::server::{
mod cosmic_v2;
pub use cosmic_v2::CosmicWorkspaceV2Data;
mod ext;
pub use ext::{WorkspaceData, WorkspaceGroupData};
pub use ext::{WorkspaceData, WorkspaceGroupData, WorkspaceManagerData};
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
@ -111,7 +109,7 @@ pub struct WorkspaceHandle {
pub trait WorkspaceHandler
where
Self: GlobalDispatch<ExtWorkspaceManagerV1, WorkspaceGlobalData>
+ Dispatch<ExtWorkspaceManagerV1, ()>
+ Dispatch<ExtWorkspaceManagerV1, WorkspaceManagerData>
+ Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData>
+ Dispatch<ExtWorkspaceHandleV1, WorkspaceData>
+ GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
@ -120,8 +118,6 @@ where
+ Sized
+ 'static,
{
type Client: ClientData + WorkspaceClientHandler + 'static;
fn workspace_state(&self) -> &WorkspaceState<Self>;
fn workspace_state_mut(&mut self) -> &mut WorkspaceState<Self>;
fn commit_requests(&mut self, dh: &DisplayHandle, requests: Vec<Request>);
@ -154,16 +150,6 @@ pub enum Request {
},
}
#[derive(Debug, Default)]
pub struct WorkspaceClientStateInner {
requests: Vec<Request>,
}
pub type WorkspaceClientState = Mutex<WorkspaceClientStateInner>;
pub trait WorkspaceClientHandler {
fn workspace_state(&self) -> &WorkspaceClientState;
}
impl<D> WorkspaceState<D>
where
D: WorkspaceHandler,
@ -580,7 +566,7 @@ macro_rules! delegate_workspace {
smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_manager_v1::ExtWorkspaceManagerV1: $crate::wayland::protocols::workspace::WorkspaceGlobalData
] => $crate::wayland::protocols::workspace::WorkspaceState<Self>);
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_manager_v1::ExtWorkspaceManagerV1: ()
smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_manager_v1::ExtWorkspaceManagerV1: $crate::wayland::protocols::workspace::WorkspaceManagerData
] => $crate::wayland::protocols::workspace::WorkspaceState<Self>);
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1: $crate::wayland::protocols::workspace::WorkspaceGroupData