Add support for workspace pinning and dragging

Workspaces can be pinned, and dragged to reorder or move to a different
output.

These features are enabled only if cosmic-workspace-v2 advertises the
necessary protocol version and capabilities.

The layout of the labels and pin buttons could be tweaked a bit still.
Some hacks and workarounds are needed to get drag and drop working as
desired. Something iced and libcosmic could potentially improve in the
future. But this now seems fairly robust.
This commit is contained in:
Ian Douglas Scott 2025-01-31 14:17:56 -08:00 committed by Ian Douglas Scott
parent 94ec10686e
commit 3c9a923f41
8 changed files with 585 additions and 95 deletions

145
src/widgets/match_size.rs Normal file
View file

@ -0,0 +1,145 @@
//! Show one surface, sized to match the size of another (invisible) widget
use cosmic::iced::{
advanced::{
layout, mouse, renderer,
widget::{Operation, Tree},
Clipboard, Layout, Shell, Widget,
},
event::{self, Event},
Length, Rectangle, Size,
};
use std::marker::PhantomData;
pub fn match_size<
'a,
Msg,
T1: Into<cosmic::Element<'a, Msg>>,
T2: Into<cosmic::Element<'a, Msg>>,
>(
matched: T1,
shown: T2,
) -> MatchSize<'a, Msg> {
MatchSize {
matched: matched.into(),
shown: shown.into(),
_msg: PhantomData,
}
}
pub struct MatchSize<'a, Msg> {
matched: cosmic::Element<'a, Msg>,
shown: cosmic::Element<'a, Msg>,
_msg: PhantomData<Msg>,
}
impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for MatchSize<'_, Msg> {
delegate::delegate! {
to self.matched.as_widget() {
fn size(&self) -> Size<Length>;
fn size_hint(&self) -> Size<Length>;
}
}
fn operate(
&self,
tree: &mut Tree,
layout: Layout<'_>,
renderer: &cosmic::Renderer,
operation: &mut dyn Operation<()>,
) {
self.matched
.as_widget()
.operate(&mut tree.children[0], layout, renderer, operation);
self.shown
.as_widget()
.operate(&mut tree.children[1], layout, renderer, operation);
}
fn on_event(
&mut self,
tree: &mut Tree,
event: Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &cosmic::Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Msg>,
viewport: &Rectangle,
) -> event::Status {
self.shown.as_widget_mut().on_event(
&mut tree.children[1],
event,
layout,
cursor,
renderer,
clipboard,
shell,
viewport,
)
}
fn mouse_interaction(
&self,
tree: &Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &cosmic::Renderer,
) -> mouse::Interaction {
self.shown.as_widget().mouse_interaction(
&tree.children[1],
layout,
cursor,
viewport,
renderer,
)
}
fn layout(
&self,
tree: &mut Tree,
renderer: &cosmic::Renderer,
limits: &layout::Limits,
) -> layout::Node {
// TODO?
self.matched
.as_widget()
.layout(&mut tree.children[0], renderer, limits)
}
fn draw(
&self,
tree: &Tree,
renderer: &mut cosmic::Renderer,
theme: &cosmic::Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
self.shown.as_widget().draw(
&tree.children[1],
renderer,
theme,
style,
layout,
cursor,
viewport,
);
}
fn children(&self) -> Vec<Tree> {
vec![Tree::new(&self.matched), Tree::new(&self.shown)]
}
fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&mut [&mut self.matched, &mut self.shown]);
}
}
impl<'a, Msg: 'a> From<MatchSize<'a, Msg>> for cosmic::Element<'a, Msg> {
fn from(widget: MatchSize<'a, Msg>) -> Self {
cosmic::Element::new(widget)
}
}

View file

@ -19,6 +19,8 @@ mod toplevels;
pub use toplevels::toplevels;
mod visibility_wrapper;
pub use visibility_wrapper::visibility_wrapper;
mod match_size;
pub use match_size::match_size;
// Widget for debugging
#[allow(dead_code)]