UI code for supporting workspace drags

Not used yet.
This commit is contained in:
Ian Douglas Scott 2025-02-10 12:02:36 -08:00
parent 9b12e76765
commit ca5db9cc8e
3 changed files with 88 additions and 18 deletions

View file

@ -10,7 +10,6 @@ use crate::backend::{ZcosmicToplevelHandleV1, ZcosmicWorkspaceHandleV1};
// Include `pid` in mime. Want to drag between our surfaces, but not another // Include `pid` in mime. Want to drag between our surfaces, but not another
// process, if we use Wayland object ids. // process, if we use Wayland object ids.
#[allow(dead_code)]
static WORKSPACE_MIME: LazyLock<String> = static WORKSPACE_MIME: LazyLock<String> =
LazyLock::new(|| format!("text/x.cosmic-workspace-id-{}", std::process::id())); LazyLock::new(|| format!("text/x.cosmic-workspace-id-{}", std::process::id()));
@ -59,11 +58,47 @@ impl TryFrom<(Vec<u8>, std::string::String)> for DragToplevel {
} }
} }
#[derive(Clone, Debug)]
pub struct DragWorkspace {}
impl AsMimeTypes for DragWorkspace {
fn available(&self) -> Cow<'static, [String]> {
vec![WORKSPACE_MIME.clone()].into()
}
fn as_bytes(&self, mime_type: &str) -> Option<Cow<'static, [u8]>> {
if mime_type == *WORKSPACE_MIME {
Some(Vec::new().into())
} else {
None
}
}
}
impl cosmic::iced::clipboard::mime::AllowedMimeTypes for DragWorkspace {
fn allowed() -> Cow<'static, [String]> {
vec![WORKSPACE_MIME.clone()].into()
}
}
impl TryFrom<(Vec<u8>, std::string::String)> for DragWorkspace {
type Error = ();
fn try_from((_bytes, mime_type): (Vec<u8>, String)) -> Result<Self, ()> {
if mime_type == *WORKSPACE_MIME {
Ok(Self {})
} else {
Err(())
}
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[repr(u8)] #[repr(u8)]
pub enum DropTarget { pub enum DropTarget {
WorkspaceSidebarEntry(ZcosmicWorkspaceHandleV1, wl_output::WlOutput), WorkspaceSidebarEntry(ZcosmicWorkspaceHandleV1, wl_output::WlOutput),
OutputToplevels(ZcosmicWorkspaceHandleV1, wl_output::WlOutput), OutputToplevels(ZcosmicWorkspaceHandleV1, wl_output::WlOutput),
#[allow(dead_code)]
WorkspacesBar(wl_output::WlOutput),
} }
impl DropTarget { impl DropTarget {
@ -81,6 +116,10 @@ impl DropTarget {
let id = output.id().protocol_id(); let id = output.id().protocol_id();
(u64::from(discriminant) << 32) | u64::from(id) (u64::from(discriminant) << 32) | u64::from(id)
} }
Self::WorkspacesBar(output) => {
let id = output.id().protocol_id();
(u64::from(discriminant) << 32) | u64::from(id)
}
} }
} }
} }

View file

@ -47,7 +47,7 @@ use backend::{ToplevelInfo, ZcosmicToplevelHandleV1, ZcosmicWorkspaceHandleV1};
mod dnd; mod dnd;
mod utils; mod utils;
mod widgets; mod widgets;
use dnd::{DragSurface, DragToplevel, DropTarget}; use dnd::{DragSurface, DragToplevel, DragWorkspace, DropTarget};
#[derive(Clone, Debug, Default, PartialEq, CosmicConfigEntry)] #[derive(Clone, Debug, Default, PartialEq, CosmicConfigEntry)]
struct CosmicWorkspacesConfig { struct CosmicWorkspacesConfig {
@ -98,6 +98,10 @@ enum Msg {
DndEnter(DropTarget, f64, f64, Vec<String>), DndEnter(DropTarget, f64, f64, Vec<String>),
DndLeave(DropTarget), DndLeave(DropTarget),
DndToplevelDrop(DragToplevel), DndToplevelDrop(DragToplevel),
#[allow(dead_code)]
DndWorkspaceDrag,
#[allow(dead_code)]
DndWorkspaceDrop(DragWorkspace),
SourceFinished, SourceFinished,
#[allow(dead_code)] #[allow(dead_code)]
NewWorkspace, NewWorkspace,
@ -109,7 +113,7 @@ enum Msg {
Ignore, Ignore,
} }
#[derive(Debug)] #[derive(Clone, Debug)]
struct Workspace { struct Workspace {
name: String, name: String,
// img_for_output: HashMap<wl_output::WlOutput, backend::CaptureImage>, // img_for_output: HashMap<wl_output::WlOutput, backend::CaptureImage>,
@ -515,7 +519,7 @@ impl Application for App {
output, output,
)); ));
} }
None => {} Some(DropTarget::WorkspacesBar(_)) | None => {}
} }
} }
} }
@ -608,6 +612,8 @@ impl Application for App {
} }
} }
} }
Msg::DndWorkspaceDrag => {}
Msg::DndWorkspaceDrop(_workspace) => {}
Msg::Ignore => {} Msg::Ignore => {}
} }

View file

@ -19,7 +19,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
backend::{self, CaptureImage}, backend::{self, CaptureImage},
dnd::{DragSurface, DragToplevel, DropTarget}, dnd::{DragSurface, DragToplevel, DragWorkspace, DropTarget},
App, LayerSurface, Msg, Toplevel, Workspace, App, LayerSurface, Msg, Toplevel, Workspace,
}; };
@ -41,6 +41,25 @@ fn toplevel_dnd_destination<'a>(
.into() .into()
} }
#[allow(dead_code)]
fn workspace_dnd_destination<'a>(
target: DropTarget,
child: cosmic::Element<'a, Msg>,
) -> cosmic::Element<'a, Msg> {
let target2 = target.clone();
cosmic::widget::dnd_destination::dnd_destination_for_data(
child,
|data: Option<DragWorkspace>, _action| match data {
Some(workspace) => Msg::DndWorkspaceDrop(workspace),
None => Msg::Ignore,
},
)
.drag_id(target.drag_id())
.on_enter(move |actions, mime, pos| Msg::DndEnter(target.clone(), actions, mime, pos))
.on_leave(move || Msg::DndLeave(target2.clone()))
.into()
}
pub(crate) fn layer_surface<'a>( pub(crate) fn layer_surface<'a>(
app: &'a App, app: &'a App,
surface: &'a LayerSurface, surface: &'a LayerSurface,
@ -142,7 +161,7 @@ fn workspace_item<'a>(
workspace: &'a Workspace, workspace: &'a Workspace,
_output: &wl_output::WlOutput, _output: &wl_output::WlOutput,
is_drop_target: bool, is_drop_target: bool,
) -> cosmic::Element<'a, Msg> { ) -> cosmic::Element<'static, Msg> {
let image = capture_image(workspace.img.as_ref(), 1.0); let image = capture_image(workspace.img.as_ref(), 1.0);
let is_active = workspace.is_active; let is_active = workspace.is_active;
// TODO editable name? // TODO editable name?
@ -184,26 +203,32 @@ fn workspace_sidebar_entry<'a>(
iced::mouse::Interaction::Idle iced::mouse::Interaction::Idle
}; };
*/ */
let item = workspace_item(workspace, output, is_drop_target);
/* TODO allow moving workspaces (needs compositor support) /* TODO allow moving workspaces (needs compositor support)
iced::widget::dnd_source(workspace_item(workspace, output)) let workspace_clone = workspace.clone(); // TODO avoid clone
.on_drag(|size| { let output_clone = output.clone();
Msg::StartDrag( let source = cosmic::widget::dnd_source(item)
size, .drag_threshold(5.)
DragSurface::Workspace { .drag_content(|| DragWorkspace {})
handle: workspace.handle.clone(), .drag_icon(move |offset| {
output: output.clone(), (
}, workspace_item(&workspace_clone, &output_clone, false).map(|_| ()),
cosmic::iced_core::widget::tree::State::None,
-offset,
) )
}) })
.on_finished(Msg::SourceFinished) .on_start(Some(Msg::StartDrag(DragSurface::Workspace(
.on_cancelled(Msg::SourceFinished) workspace.handle.clone(),
.into() ))))
.on_finish(Some(Msg::SourceFinished))
.on_cancel(Some(Msg::SourceFinished))
.into();
*/ */
//crate::widgets::mouse_interaction_wrapper( //crate::widgets::mouse_interaction_wrapper(
// mouse_interaction, // mouse_interaction,
toplevel_dnd_destination( toplevel_dnd_destination(
DropTarget::WorkspaceSidebarEntry(workspace.handle.clone(), output.clone()), DropTarget::WorkspaceSidebarEntry(workspace.handle.clone(), output.clone()),
workspace_item(workspace, output, is_drop_target), item,
) )
} }