Add cosmic-workspace-v2, image source, toplevel info changes

This new protocol extends `ext-workspace-v1` with the same additional
functionality `cosmic-workspace-v1` provided. Toplevel info and toplevel
management are also updated to use ext handles, and there's an image
source for ext workspaces.

For now, the old protocol is still supported.
This commit is contained in:
Ian Douglas Scott 2025-02-19 14:07:51 -08:00 committed by Victoria Brekenfeld
parent 0b23a01736
commit aac8166962
10 changed files with 459 additions and 24 deletions

View file

@ -15,7 +15,7 @@ use cosmic_comp_config::{
workspace::{WorkspaceLayout, WorkspaceMode}, workspace::{WorkspaceLayout, WorkspaceMode},
TileBehavior, ZoomConfig, ZoomMovement, TileBehavior, ZoomConfig, ZoomMovement,
}; };
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::TilingState; use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::TilingState;
use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection, ResizeDirection}; use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection, ResizeDirection};
use cosmic_settings_config::{shortcuts, window_rules::ApplicationException}; use cosmic_settings_config::{shortcuts, window_rules::ApplicationException};
use keyframe::{ease, functions::EaseInOutCubic}; use keyframe::{ease, functions::EaseInOutCubic};

View file

@ -19,7 +19,7 @@ use crate::{
}; };
use cosmic::theme::CosmicTheme; use cosmic::theme::CosmicTheme;
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::TilingState; use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::TilingState;
use id_tree::Tree; use id_tree::Tree;
use indexmap::IndexSet; use indexmap::IndexSet;
use keyframe::{ease, functions::EaseInOutCubic}; use keyframe::{ease, functions::EaseInOutCubic};

View file

@ -9,7 +9,7 @@ use crate::{
WorkspaceHandler, WorkspaceState, WorkspaceHandler, WorkspaceState,
}, },
}; };
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::TilingState; use cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::TilingState;
use smithay::reexports::wayland_server::DisplayHandle; use smithay::reexports::wayland_server::DisplayHandle;
impl WorkspaceClientHandler for ClientState { impl WorkspaceClientHandler for ClientState {

View file

@ -4,6 +4,9 @@ use super::{
}; };
use crate::shell::CosmicSurface; use crate::shell::CosmicSurface;
use cosmic_protocols::image_source::v1::server::{ use cosmic_protocols::image_source::v1::server::{
zcosmic_ext_workspace_image_source_manager_v1::{
Request as ExtWorkspaceSourceRequest, ZcosmicExtWorkspaceImageSourceManagerV1,
},
zcosmic_image_source_v1::ZcosmicImageSourceV1, zcosmic_image_source_v1::ZcosmicImageSourceV1,
zcosmic_output_image_source_manager_v1::{ zcosmic_output_image_source_manager_v1::{
Request as OutputSourceRequest, ZcosmicOutputImageSourceManagerV1, Request as OutputSourceRequest, ZcosmicOutputImageSourceManagerV1,
@ -27,6 +30,7 @@ use wayland_backend::server::GlobalId;
pub struct ImageSourceState { pub struct ImageSourceState {
output_source_global: GlobalId, output_source_global: GlobalId,
workspace_source_global: GlobalId, workspace_source_global: GlobalId,
ext_workspace_source_global: GlobalId,
toplevel_source_global: GlobalId, toplevel_source_global: GlobalId,
} }
@ -57,6 +61,10 @@ impl ImageSourceState {
ZcosmicWorkspaceImageSourceManagerV1, ZcosmicWorkspaceImageSourceManagerV1,
WorkspaceImageSourceManagerGlobalData, WorkspaceImageSourceManagerGlobalData,
> + Dispatch<ZcosmicWorkspaceImageSourceManagerV1, ()> > + Dispatch<ZcosmicWorkspaceImageSourceManagerV1, ()>
+ GlobalDispatch<
ZcosmicExtWorkspaceImageSourceManagerV1,
WorkspaceImageSourceManagerGlobalData,
> + Dispatch<ZcosmicExtWorkspaceImageSourceManagerV1, ()>
+ GlobalDispatch< + GlobalDispatch<
ZcosmicToplevelImageSourceManagerV1, ZcosmicToplevelImageSourceManagerV1,
ToplevelImageSourceManagerGlobalData, ToplevelImageSourceManagerGlobalData,
@ -80,6 +88,13 @@ impl ImageSourceState {
filter: Box::new(client_filter.clone()), filter: Box::new(client_filter.clone()),
}, },
), ),
ext_workspace_source_global: display
.create_global::<D, ZcosmicExtWorkspaceImageSourceManagerV1, _>(
1,
WorkspaceImageSourceManagerGlobalData {
filter: Box::new(client_filter.clone()),
},
),
toplevel_source_global: display toplevel_source_global: display
.create_global::<D, ZcosmicToplevelImageSourceManagerV1, _>( .create_global::<D, ZcosmicToplevelImageSourceManagerV1, _>(
1, 1,
@ -98,6 +113,10 @@ impl ImageSourceState {
&self.workspace_source_global &self.workspace_source_global
} }
pub fn ext_workspace_source_id(&self) -> &GlobalId {
&self.ext_workspace_source_global
}
pub fn toplevel_source_id(&self) -> &GlobalId { pub fn toplevel_source_id(&self) -> &GlobalId {
&self.toplevel_source_global &self.toplevel_source_global
} }
@ -152,6 +171,36 @@ where
} }
} }
impl<D>
GlobalDispatch<
ZcosmicExtWorkspaceImageSourceManagerV1,
WorkspaceImageSourceManagerGlobalData,
D,
> for ImageSourceState
where
D: GlobalDispatch<
ZcosmicExtWorkspaceImageSourceManagerV1,
WorkspaceImageSourceManagerGlobalData,
> + Dispatch<ZcosmicExtWorkspaceImageSourceManagerV1, ()>
+ Dispatch<ZcosmicImageSourceV1, ImageSourceData>
+ 'static,
{
fn bind(
_state: &mut D,
_handle: &DisplayHandle,
_client: &Client,
resource: New<ZcosmicExtWorkspaceImageSourceManagerV1>,
_global_data: &WorkspaceImageSourceManagerGlobalData,
data_init: &mut DataInit<'_, D>,
) {
data_init.init(resource, ());
}
fn can_view(client: Client, global_data: &WorkspaceImageSourceManagerGlobalData) -> bool {
(global_data.filter)(&client)
}
}
impl<D> GlobalDispatch<ZcosmicToplevelImageSourceManagerV1, ToplevelImageSourceManagerGlobalData, D> impl<D> GlobalDispatch<ZcosmicToplevelImageSourceManagerV1, ToplevelImageSourceManagerGlobalData, D>
for ImageSourceState for ImageSourceState
where where
@ -249,6 +298,43 @@ where
} }
} }
impl<D> Dispatch<ZcosmicExtWorkspaceImageSourceManagerV1, (), D> for ImageSourceState
where
D: Dispatch<ZcosmicExtWorkspaceImageSourceManagerV1, ()>
+ Dispatch<ZcosmicImageSourceV1, ImageSourceData>
+ WorkspaceHandler
+ 'static,
{
fn request(
state: &mut D,
_client: &Client,
_resource: &ZcosmicExtWorkspaceImageSourceManagerV1,
request: <ZcosmicExtWorkspaceImageSourceManagerV1 as Resource>::Request,
_data: &(),
_dhandle: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
ExtWorkspaceSourceRequest::CreateSource { source, output } => {
let data = match state.workspace_state().get_ext_workspace_handle(&output) {
Some(workspace) => ImageSourceData::Workspace(workspace),
None => ImageSourceData::Destroyed,
};
data_init.init(source, data);
}
_ => {}
}
}
fn destroyed(
_state: &mut D,
_client: wayland_backend::server::ClientId,
_resource: &ZcosmicExtWorkspaceImageSourceManagerV1,
_data: &(),
) {
}
}
impl<D> Dispatch<ZcosmicToplevelImageSourceManagerV1, (), D> for ImageSourceState impl<D> Dispatch<ZcosmicToplevelImageSourceManagerV1, (), D> for ImageSourceState
where where
D: Dispatch<ZcosmicToplevelImageSourceManagerV1, ()> D: Dispatch<ZcosmicToplevelImageSourceManagerV1, ()>
@ -329,6 +415,12 @@ macro_rules! delegate_image_source {
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::image_source::v1::server::zcosmic_workspace_image_source_manager_v1::ZcosmicWorkspaceImageSourceManagerV1: () cosmic_protocols::image_source::v1::server::zcosmic_workspace_image_source_manager_v1::ZcosmicWorkspaceImageSourceManagerV1: ()
] => $crate::wayland::protocols::image_source::ImageSourceState); ] => $crate::wayland::protocols::image_source::ImageSourceState);
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::image_source::v1::server::zcosmic_ext_workspace_image_source_manager_v1::ZcosmicExtWorkspaceImageSourceManagerV1: $crate::wayland::protocols::image_source::WorkspaceImageSourceManagerGlobalData
] => $crate::wayland::protocols::image_source::ImageSourceState);
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::image_source::v1::server::zcosmic_ext_workspace_image_source_manager_v1::ZcosmicExtWorkspaceImageSourceManagerV1: ()
] => $crate::wayland::protocols::image_source::ImageSourceState);
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::image_source::v1::server::zcosmic_toplevel_image_source_manager_v1::ZcosmicToplevelImageSourceManagerV1: $crate::wayland::protocols::image_source::ToplevelImageSourceManagerGlobalData cosmic_protocols::image_source::v1::server::zcosmic_toplevel_image_source_manager_v1::ZcosmicToplevelImageSourceManagerV1: $crate::wayland::protocols::image_source::ToplevelImageSourceManagerGlobalData
] => $crate::wayland::protocols::image_source::ImageSourceState); ] => $crate::wayland::protocols::image_source::ImageSourceState);

View file

@ -309,7 +309,7 @@ where
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static, F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static,
{ {
let global = dh.create_global::<D, ZcosmicToplevelInfoV1, _>( let global = dh.create_global::<D, ZcosmicToplevelInfoV1, _>(
2, 3,
ToplevelInfoGlobalData { ToplevelInfoGlobalData {
filter: Box::new(client_filter.clone()), filter: Box::new(client_filter.clone()),
}, },
@ -594,6 +594,10 @@ where
instance.workspace_enter(&handle); instance.workspace_enter(&handle);
changed = true; changed = true;
} }
for handle in workspace_state.raw_ext_workspace_handles(&new_workspace, &instance.id()) {
instance.ext_workspace_enter(&handle);
changed = true;
}
} }
for old_workspace in handle_state for old_workspace in handle_state
.workspaces .workspaces
@ -604,6 +608,10 @@ where
instance.workspace_leave(&handle); instance.workspace_leave(&handle);
changed = true; changed = true;
} }
for handle in workspace_state.raw_ext_workspace_handles(&old_workspace, &instance.id()) {
instance.ext_workspace_leave(&handle);
changed = true;
}
} }
handle_state.workspaces = state.workspaces.clone(); handle_state.workspaces = state.workspaces.clone();

View file

@ -116,7 +116,7 @@ impl ToplevelManagementState {
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static, F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
{ {
let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>( let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>(
3, 4,
ToplevelManagerGlobalData { ToplevelManagerGlobalData {
filter: Box::new(client_filter), filter: Box::new(client_filter),
}, },
@ -263,6 +263,20 @@ where
} }
} }
} }
zcosmic_toplevel_manager_v1::Request::MoveToExtWorkspace {
toplevel,
workspace,
output,
} => {
let window = window_from_handle(toplevel).unwrap();
if let Some(workspace_handle) =
state.workspace_state().get_ext_workspace_handle(&workspace)
{
if let Some(output) = Output::from_resource(&output) {
state.move_to_workspace(dh, &window, workspace_handle, output);
}
}
}
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use smithay::{ use smithay::{
reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_handle_v1::{self}, reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_handle_v1,
reexports::wayland_server::{ reexports::wayland_server::{
backend::{ClientData, ClientId}, backend::{ClientData, ClientId},
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, WEnum,
}, },
}; };
@ -14,10 +14,13 @@ use super::{
WorkspaceHandler, WorkspaceState, WorkspaceHandler, WorkspaceState,
}; };
use cosmic_protocols::workspace::v1::server::{ use cosmic_protocols::workspace::{
zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1}, v1::server::{
zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1}, zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1},
zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1}, zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1},
zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1},
},
v2::server::zcosmic_workspace_handle_v2,
}; };
impl<D> GlobalDispatch<ZcosmicWorkspaceManagerV1, WorkspaceGlobalData, D> for WorkspaceState<D> impl<D> GlobalDispatch<ZcosmicWorkspaceManagerV1, WorkspaceGlobalData, D> for WorkspaceState<D>
@ -243,6 +246,17 @@ where
.workspace_state() .workspace_state()
.lock() .lock()
.unwrap(); .unwrap();
let tiling_state = match tiling_state {
WEnum::Value(zcosmic_workspace_handle_v1::TilingState::FloatingOnly) => {
WEnum::Value(zcosmic_workspace_handle_v2::TilingState::FloatingOnly)
}
WEnum::Value(zcosmic_workspace_handle_v1::TilingState::TilingEnabled) => {
WEnum::Value(zcosmic_workspace_handle_v2::TilingState::TilingEnabled)
}
// Won't be adding more variants to v1, at least
WEnum::Value(_) => unreachable!(),
WEnum::Unknown(value) => WEnum::Unknown(value),
};
state.requests.push(Request::SetTilingState { state.requests.push(Request::SetTilingState {
workspace: workspace_handle, workspace: workspace_handle,
state: tiling_state, state: tiling_state,
@ -477,7 +491,21 @@ where
.map(|state| state != workspace.tiling) .map(|state| state != workspace.tiling)
.unwrap_or(true) .unwrap_or(true)
{ {
instance.tiling_state(workspace.tiling); let tiling_state = match workspace.tiling {
zcosmic_workspace_handle_v2::TilingState::FloatingOnly => {
zcosmic_workspace_handle_v1::TilingState::FloatingOnly
}
zcosmic_workspace_handle_v2::TilingState::TilingEnabled => {
zcosmic_workspace_handle_v1::TilingState::TilingEnabled
}
_ => {
// Not clear what to do if state doesn't match. Which
// shouldn't happen (or protocol will be irrelevant by
// then).
zcosmic_workspace_handle_v1::TilingState::TilingEnabled
}
};
instance.tiling_state(tiling_state);
handle_state.tiling = Some(workspace.tiling); handle_state.tiling = Some(workspace.tiling);
changed = true; changed = true;
} }

View file

@ -0,0 +1,221 @@
// SPDX-License-Identifier: GPL-3.0-only
use cosmic_protocols::workspace::v2::server::{
zcosmic_workspace_handle_v2::{self, ZcosmicWorkspaceHandleV2},
zcosmic_workspace_manager_v2::{self, ZcosmicWorkspaceManagerV2},
};
use smithay::reexports::{
wayland_protocols::ext::workspace::v1::server::ext_workspace_handle_v1::ExtWorkspaceHandleV1,
wayland_server::{
backend::ClientData, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New,
Resource, Weak,
},
};
use std::sync::Mutex;
use super::{
Request, Workspace, WorkspaceCapabilities, WorkspaceClientHandler, WorkspaceData,
WorkspaceGlobalData, WorkspaceHandler, WorkspaceState,
};
#[derive(Default)]
pub struct CosmicWorkspaceDataInner {
capabilities: Option<WorkspaceCapabilities>,
tiling: Option<zcosmic_workspace_handle_v2::TilingState>,
}
pub struct CosmicWorkspaceData {
workspace: Weak<ExtWorkspaceHandleV1>,
inner: Mutex<CosmicWorkspaceDataInner>,
}
impl<D> GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData, D> for WorkspaceState<D>
where
D: GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler
+ 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
{
fn bind(
_state: &mut D,
_dh: &DisplayHandle,
_client: &Client,
resource: New<ZcosmicWorkspaceManagerV2>,
_global_data: &WorkspaceGlobalData,
data_init: &mut DataInit<'_, D>,
) {
data_init.init(resource, ());
}
fn can_view(client: Client, global_data: &WorkspaceGlobalData) -> bool {
(global_data.filter)(&client)
}
}
impl<D> Dispatch<ZcosmicWorkspaceManagerV2, (), D> for WorkspaceState<D>
where
D: GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler
+ 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
{
fn request(
state: &mut D,
_client: &Client,
obj: &ZcosmicWorkspaceManagerV2,
request: zcosmic_workspace_manager_v2::Request,
_data: &(),
_dh: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
zcosmic_workspace_manager_v2::Request::GetCosmicWorkspace {
cosmic_workspace,
workspace,
} => {
let cosmic_workspace = data_init.init(
cosmic_workspace,
CosmicWorkspaceData {
workspace: workspace.downgrade(),
inner: Mutex::new(CosmicWorkspaceDataInner::default()),
},
);
if let Some(data) = workspace.data::<WorkspaceData>() {
let mut data = data.lock().unwrap();
if data.cosmic_v2_handle.as_ref().is_some_and(|x| x.is_alive()) {
obj.post_error(
zcosmic_workspace_manager_v2::Error::WorkspaceExists,
"zcosmic_workspace_handle_v2 already exists for ext_workspace_handle_v1",
);
return;
}
data.cosmic_v2_handle = Some(cosmic_workspace.downgrade());
if let Some((workspace, ext_mngr, _)) = state
.workspace_state()
.groups
.iter()
.flat_map(|g| &g.workspaces)
.flat_map(|w| w.ext_instances.iter().map(move |(mngr, i)| (w, mngr, i)))
.find(|(_, _, i)| **i == workspace)
{
if let Ok(ext_mngr) = ext_mngr.upgrade() {
send_workspace_to_client(&cosmic_workspace, workspace);
ext_mngr.done();
}
}
}
}
_ => unreachable!(),
}
}
}
impl<D> Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData, D> for WorkspaceState<D>
where
D: GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler
+ 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
{
fn request(
state: &mut D,
client: &Client,
_obj: &ZcosmicWorkspaceHandleV2,
request: zcosmic_workspace_handle_v2::Request,
data: &CosmicWorkspaceData,
_dh: &DisplayHandle,
_data_init: &mut DataInit<'_, D>,
) {
let Ok(workspace) = data.workspace.upgrade() else {
return;
};
match request {
zcosmic_workspace_handle_v2::Request::Rename { name } => {
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,
});
}
}
zcosmic_workspace_handle_v2::Request::SetTilingState {
state: tiling_state,
} => {
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,
});
}
}
_ => unreachable!(),
}
}
}
pub fn send_workspace_to_client(
instance: &ZcosmicWorkspaceHandleV2,
workspace: &Workspace,
) -> bool {
let mut changed = false;
let mut handle_state = instance
.data::<CosmicWorkspaceData>()
.unwrap()
.inner
.lock()
.unwrap();
if handle_state.capabilities != Some(workspace.capabilities) {
let caps = workspace
.capabilities
.iter()
.filter_map(|cap| match cap {
WorkspaceCapabilities::Rename => {
Some(zcosmic_workspace_handle_v2::WorkspaceCapabilities::Rename)
}
WorkspaceCapabilities::SetTilingState => {
Some(zcosmic_workspace_handle_v2::WorkspaceCapabilities::SetTilingState)
}
_ => None,
})
.collect::<zcosmic_workspace_handle_v2::WorkspaceCapabilities>();
instance.capabilities(caps);
handle_state.capabilities = Some(workspace.capabilities);
changed = true;
}
if handle_state
.tiling
.map(|state| state != workspace.tiling)
.unwrap_or(true)
{
instance.tiling_state(workspace.tiling);
handle_state.tiling = Some(workspace.tiling);
changed = true;
}
changed
}

View file

@ -392,6 +392,7 @@ where
} }
} }
}; };
let instance = instance.clone();
let mut handle_state = instance.data::<WorkspaceData>().unwrap().lock().unwrap(); let mut handle_state = instance.data::<WorkspaceData>().unwrap().lock().unwrap();
let mut changed = false; let mut changed = false;
@ -442,5 +443,13 @@ where
} }
// TODO ext_workspace_handle_v1::id // TODO ext_workspace_handle_v1::id
if let Some(cosmic_v2_handle) = handle_state
.cosmic_v2_handle
.as_ref()
.and_then(|x| x.upgrade().ok())
{
changed |= super::cosmic_v2::send_workspace_to_client(&cosmic_v2_handle, workspace);
}
changed changed
} }

View file

@ -19,13 +19,21 @@ use smithay::{
}; };
use wayland_backend::protocol::WEnum; use wayland_backend::protocol::WEnum;
use cosmic_protocols::workspace::v1::server::{ use cosmic_protocols::workspace::{
zcosmic_workspace_group_handle_v1::ZcosmicWorkspaceGroupHandleV1, v1::server::{
zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1}, zcosmic_workspace_group_handle_v1::ZcosmicWorkspaceGroupHandleV1,
zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1, zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1,
zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1,
},
v2::server::{
zcosmic_workspace_handle_v2::{self, ZcosmicWorkspaceHandleV2},
zcosmic_workspace_manager_v2::ZcosmicWorkspaceManagerV2,
},
}; };
mod cosmic; mod cosmic;
mod cosmic_v2;
pub use cosmic_v2::CosmicWorkspaceData;
mod ext; mod ext;
pub use smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_group_handle_v1::GroupCapabilities; pub use smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_group_handle_v1::GroupCapabilities;
@ -56,6 +64,9 @@ where
+ Dispatch<ExtWorkspaceManagerV1, ()> + Dispatch<ExtWorkspaceManagerV1, ()>
+ Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData> + Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData>
+ Dispatch<ExtWorkspaceHandleV1, WorkspaceData> + Dispatch<ExtWorkspaceHandleV1, WorkspaceData>
+ GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler + WorkspaceHandler
+ 'static, + 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static, <D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
@ -63,6 +74,7 @@ where
dh: DisplayHandle, dh: DisplayHandle,
cosmic_global: GlobalId, cosmic_global: GlobalId,
ext_global: GlobalId, ext_global: GlobalId,
cosmic_v2_global: GlobalId,
instances: Vec<ZcosmicWorkspaceManagerV1>, instances: Vec<ZcosmicWorkspaceManagerV1>,
ext_instances: Vec<ExtWorkspaceManagerV1>, ext_instances: Vec<ExtWorkspaceManagerV1>,
groups: Vec<WorkspaceGroup>, groups: Vec<WorkspaceGroup>,
@ -134,7 +146,7 @@ pub struct Workspace {
capabilities: WorkspaceCapabilities, capabilities: WorkspaceCapabilities,
coordinates: Vec<u32>, coordinates: Vec<u32>,
states: ext_workspace_handle_v1::State, states: ext_workspace_handle_v1::State,
tiling: zcosmic_workspace_handle_v1::TilingState, tiling: zcosmic_workspace_handle_v2::TilingState,
ext_id: Option<String>, ext_id: Option<String>,
} }
@ -149,7 +161,8 @@ pub struct WorkspaceDataInner {
capabilities: Option<WorkspaceCapabilities>, capabilities: Option<WorkspaceCapabilities>,
coordinates: Vec<u32>, coordinates: Vec<u32>,
states: Option<ext_workspace_handle_v1::State>, states: Option<ext_workspace_handle_v1::State>,
tiling: Option<zcosmic_workspace_handle_v1::TilingState>, tiling: Option<zcosmic_workspace_handle_v2::TilingState>,
cosmic_v2_handle: Option<Weak<ZcosmicWorkspaceHandleV2>>,
} }
pub type WorkspaceData = Mutex<WorkspaceDataInner>; pub type WorkspaceData = Mutex<WorkspaceDataInner>;
@ -164,6 +177,9 @@ where
+ Dispatch<ExtWorkspaceManagerV1, ()> + Dispatch<ExtWorkspaceManagerV1, ()>
+ Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData> + Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData>
+ Dispatch<ExtWorkspaceHandleV1, WorkspaceData> + Dispatch<ExtWorkspaceHandleV1, WorkspaceData>
+ GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ Sized + Sized
+ 'static, + 'static,
{ {
@ -189,7 +205,7 @@ pub enum Request {
}, },
SetTilingState { SetTilingState {
workspace: WorkspaceHandle, workspace: WorkspaceHandle,
state: WEnum<zcosmic_workspace_handle_v1::TilingState>, state: WEnum<zcosmic_workspace_handle_v2::TilingState>,
}, },
Create { Create {
in_group: WorkspaceGroupHandle, in_group: WorkspaceGroupHandle,
@ -221,6 +237,9 @@ where
+ Dispatch<ExtWorkspaceManagerV1, ()> + Dispatch<ExtWorkspaceManagerV1, ()>
+ Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData> + Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData>
+ Dispatch<ExtWorkspaceHandleV1, WorkspaceData> + Dispatch<ExtWorkspaceHandleV1, WorkspaceData>
+ GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler + WorkspaceHandler
+ 'static, + 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static, <D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
@ -239,7 +258,14 @@ where
let ext_global = dh.create_global::<D, ExtWorkspaceManagerV1, _>( let ext_global = dh.create_global::<D, ExtWorkspaceManagerV1, _>(
1, 1,
WorkspaceGlobalData { WorkspaceGlobalData {
filter: Box::new(client_filter), filter: Box::new(client_filter.clone()),
},
);
let cosmic_v2_global = dh.create_global::<D, ZcosmicWorkspaceManagerV2, _>(
1,
WorkspaceGlobalData {
filter: Box::new(client_filter.clone()),
}, },
); );
@ -247,6 +273,7 @@ where
dh: dh.clone(), dh: dh.clone(),
cosmic_global, cosmic_global,
ext_global, ext_global,
cosmic_v2_global,
instances: Vec::new(), instances: Vec::new(),
ext_instances: Vec::new(), ext_instances: Vec::new(),
groups: Vec::new(), groups: Vec::new(),
@ -324,7 +351,7 @@ where
pub fn workspace_tiling_state( pub fn workspace_tiling_state(
&self, &self,
workspace: &WorkspaceHandle, workspace: &WorkspaceHandle,
) -> Option<zcosmic_workspace_handle_v1::TilingState> { ) -> Option<zcosmic_workspace_handle_v2::TilingState> {
self.groups.iter().find_map(|g| { self.groups.iter().find_map(|g| {
g.workspaces g.workspaces
.iter() .iter()
@ -342,6 +369,7 @@ where
.find(|g| g.instances.iter().any(|(_, i)| i == group)) .find(|g| g.instances.iter().any(|(_, i)| i == group))
.map(|g| WorkspaceGroupHandle { id: g.id }) .map(|g| WorkspaceGroupHandle { id: g.id })
} }
pub fn workspace_handle( pub fn workspace_handle(
&self, &self,
workspace: &ZcosmicWorkspaceHandleV1, workspace: &ZcosmicWorkspaceHandleV1,
@ -368,6 +396,7 @@ where
.map(|(_, i)| i) .map(|(_, i)| i)
.filter(|i| i.id().same_client_as(client)) .filter(|i| i.id().same_client_as(client))
} }
pub fn raw_workspace_handles<'a>( pub fn raw_workspace_handles<'a>(
&'a self, &'a self,
workspace: &'a WorkspaceHandle, workspace: &'a WorkspaceHandle,
@ -382,6 +411,20 @@ where
.filter(|i| i.id().same_client_as(client)) .filter(|i| i.id().same_client_as(client))
} }
pub fn raw_ext_workspace_handles<'a>(
&'a self,
workspace: &'a WorkspaceHandle,
client: &'a ObjectId,
) -> impl Iterator<Item = &ExtWorkspaceHandleV1> + 'a {
self.groups
.iter()
.find_map(|g| g.workspaces.iter().find(|w| w.id == workspace.id))
.into_iter()
.flat_map(|w| &w.ext_instances)
.map(|(_, i)| i)
.filter(|i| Resource::id(*i).same_client_as(client))
}
pub fn update(&mut self) -> WorkspaceUpdateGuard<'_, D> { pub fn update(&mut self) -> WorkspaceUpdateGuard<'_, D> {
WorkspaceUpdateGuard(self) WorkspaceUpdateGuard(self)
} }
@ -447,6 +490,10 @@ where
pub fn ext_global_id(&self) -> GlobalId { pub fn ext_global_id(&self) -> GlobalId {
self.ext_global.clone() self.ext_global.clone()
} }
pub fn cosmic_v2_global_id(&self) -> GlobalId {
self.cosmic_v2_global.clone()
}
} }
impl<'a, D> WorkspaceUpdateGuard<'a, D> impl<'a, D> WorkspaceUpdateGuard<'a, D>
@ -458,6 +505,9 @@ where
+ Dispatch<ExtWorkspaceManagerV1, ()> + Dispatch<ExtWorkspaceManagerV1, ()>
+ Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData> + Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData>
+ Dispatch<ExtWorkspaceHandleV1, WorkspaceData> + Dispatch<ExtWorkspaceHandleV1, WorkspaceData>
+ GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler + WorkspaceHandler
+ 'static, + 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static, <D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
@ -475,7 +525,7 @@ where
pub fn create_workspace( pub fn create_workspace(
&mut self, &mut self,
group: &WorkspaceGroupHandle, group: &WorkspaceGroupHandle,
tiling: zcosmic_workspace_handle_v1::TilingState, tiling: zcosmic_workspace_handle_v2::TilingState,
ext_id: Option<String>, ext_id: Option<String>,
) -> Option<WorkspaceHandle> { ) -> Option<WorkspaceHandle> {
if let Some(group) = self.0.groups.iter_mut().find(|g| g.id == group.id) { if let Some(group) = self.0.groups.iter_mut().find(|g| g.id == group.id) {
@ -688,14 +738,14 @@ where
pub fn workspace_tiling_state( pub fn workspace_tiling_state(
&self, &self,
workspace: &WorkspaceHandle, workspace: &WorkspaceHandle,
) -> Option<zcosmic_workspace_handle_v1::TilingState> { ) -> Option<zcosmic_workspace_handle_v2::TilingState> {
self.0.workspace_tiling_state(workspace) self.0.workspace_tiling_state(workspace)
} }
pub fn set_workspace_tiling_state( pub fn set_workspace_tiling_state(
&mut self, &mut self,
workspace: &WorkspaceHandle, workspace: &WorkspaceHandle,
state: zcosmic_workspace_handle_v1::TilingState, state: zcosmic_workspace_handle_v2::TilingState,
) { ) {
if let Some(workspace) = self if let Some(workspace) = self
.0 .0
@ -718,6 +768,9 @@ where
+ Dispatch<ExtWorkspaceManagerV1, ()> + Dispatch<ExtWorkspaceManagerV1, ()>
+ Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData> + Dispatch<ExtWorkspaceGroupHandleV1, WorkspaceGroupData>
+ Dispatch<ExtWorkspaceHandleV1, WorkspaceData> + Dispatch<ExtWorkspaceHandleV1, WorkspaceData>
+ GlobalDispatch<ZcosmicWorkspaceManagerV2, WorkspaceGlobalData>
+ Dispatch<ZcosmicWorkspaceManagerV2, ()>
+ Dispatch<ZcosmicWorkspaceHandleV2, CosmicWorkspaceData>
+ WorkspaceHandler + WorkspaceHandler
+ 'static, + 'static,
<D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static, <D as WorkspaceHandler>::Client: ClientData + WorkspaceClientHandler + 'static,
@ -754,6 +807,16 @@ macro_rules! delegate_workspace {
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_handle_v1::ExtWorkspaceHandleV1: $crate::wayland::protocols::workspace::WorkspaceData smithay::reexports::wayland_protocols::ext::workspace::v1::server::ext_workspace_handle_v1::ExtWorkspaceHandleV1: $crate::wayland::protocols::workspace::WorkspaceData
] => $crate::wayland::protocols::workspace::WorkspaceState<Self>); ] => $crate::wayland::protocols::workspace::WorkspaceState<Self>);
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::workspace::v2::server::zcosmic_workspace_manager_v2::ZcosmicWorkspaceManagerV2: $crate::wayland::protocols::workspace::WorkspaceGlobalData
] => $crate::wayland::protocols::workspace::WorkspaceState<Self>);
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::workspace::v2::server::zcosmic_workspace_manager_v2::ZcosmicWorkspaceManagerV2: ()
] => $crate::wayland::protocols::workspace::WorkspaceState<Self>);
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
cosmic_protocols::workspace::v2::server::zcosmic_workspace_handle_v2::ZcosmicWorkspaceHandleV2: $crate::wayland::protocols::workspace::CosmicWorkspaceData
] => $crate::wayland::protocols::workspace::WorkspaceState<Self>);
}; };
} }
pub(crate) use delegate_workspace; pub(crate) use delegate_workspace;