Update iced/libcosmic

This commit is contained in:
Ian Douglas Scott 2024-10-18 13:13:53 -07:00 committed by Ian Douglas Scott
parent e0c0f27f67
commit b70828e23f
17 changed files with 2019 additions and 1262 deletions

2796
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ cosmic-comp-config = { git = "https://github.com/pop-os/cosmic-comp" }
env_logger = "0.11.0" env_logger = "0.11.0"
futures-channel = "0.3.25" futures-channel = "0.3.25"
gbm = "0.15.0" gbm = "0.15.0"
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland", "single-instance"] } libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland", "single-instance", "multi-window", "winit"] }
cosmic-config = { git = "https://github.com/pop-os/libcosmic" } cosmic-config = { git = "https://github.com/pop-os/libcosmic" }
freedesktop-desktop-entry = "0.5.0" freedesktop-desktop-entry = "0.5.0"
freedesktop-icons = "0.2.4" freedesktop-icons = "0.2.4"
@ -45,7 +45,3 @@ mock-backend = []
[profile.dev] [profile.dev]
# Not usable at opt-level 0, at least with software renderer # Not usable at opt-level 0, at least with software renderer
opt-level = 1 opt-level = 1
# [patch."https://github.com/pop-os/libcosmic"]
# libcosmic = { path = "../libcosmic" }
# cosmic-config = { path = "../libcosmic/cosmic-config" }

View file

@ -16,7 +16,7 @@ use cosmic::{
self, self,
futures::{executor::block_on, FutureExt, SinkExt}, futures::{executor::block_on, FutureExt, SinkExt},
}, },
iced_sctk::subsurface_widget::{Shmbuf, SubsurfaceBuffer}, iced_winit::platform_specific::wayland::subsurface_widget::{Shmbuf, SubsurfaceBuffer},
}; };
use futures_channel::mpsc; use futures_channel::mpsc;
@ -61,11 +61,7 @@ fn create_solid_capture_image(r: u8, g: u8, b: u8) -> CaptureImage {
)) ))
.0, .0,
#[cfg(feature = "no-subsurfaces")] #[cfg(feature = "no-subsurfaces")]
image: cosmic::widget::image::Handle::from_pixels( image: cosmic::widget::image::Handle::from_rgba(512, 512, [r, g, b, 255].repeat(512 * 512)),
512,
512,
[r, g, b, 255].repeat(512 * 512),
),
} }
} }
@ -108,7 +104,7 @@ pub struct Workspace {
} }
pub fn subscription(conn: Connection) -> iced::Subscription<Event> { pub fn subscription(conn: Connection) -> iced::Subscription<Event> {
iced::subscription::run_with_id("wayland-mock-sub", async { start(conn) }.flatten_stream()) iced::Subscription::run_with_id("wayland-mock-sub", async { start(conn) }.flatten_stream())
} }
struct AppData { struct AppData {

View file

@ -8,7 +8,8 @@
//! backend for testing without any special protocols. //! backend for testing without any special protocols.
use cosmic::{ use cosmic::{
cctk::wayland_client::protocol::wl_output, iced_sctk::subsurface_widget::SubsurfaceBuffer, cctk::wayland_client::protocol::wl_output,
iced_winit::platform_specific::wayland::subsurface_widget::SubsurfaceBuffer,
}; };
use std::collections::HashSet; use std::collections::HashSet;

View file

@ -7,7 +7,9 @@ use cctk::{
}; };
use cosmic::{ use cosmic::{
cctk, cctk,
iced_sctk::subsurface_widget::{BufferSource, Dmabuf, Plane, Shmbuf}, iced_winit::platform_specific::wayland::subsurface_widget::{
BufferSource, Dmabuf, Plane, Shmbuf,
},
}; };
use std::{ use std::{
os::fd::AsFd, os::fd::AsFd,

View file

@ -13,7 +13,7 @@ use std::sync::{Arc, Mutex};
use super::{AppData, ScreencopySession, SessionData}; use super::{AppData, ScreencopySession, SessionData};
#[derive(Clone, Hash, PartialEq, Eq)] #[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum CaptureSource { pub enum CaptureSource {
Toplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1), Toplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1),
Workspace( Workspace(

View file

@ -41,7 +41,7 @@ mod workspace;
use super::{CaptureFilter, CaptureImage, Cmd, Event}; use super::{CaptureFilter, CaptureImage, Cmd, Event};
pub fn subscription(conn: Connection) -> iced::Subscription<Event> { pub fn subscription(conn: Connection) -> iced::Subscription<Event> {
iced::subscription::run_with_id("wayland-sub", async { start(conn) }.flatten_stream()) iced::Subscription::run_with_id("wayland-sub", async { start(conn) }.flatten_stream())
} }
pub struct AppData { pub struct AppData {

View file

@ -11,7 +11,9 @@ use cosmic::{
}, },
wayland_client::{Connection, Proxy, QueueHandle, WEnum}, wayland_client::{Connection, Proxy, QueueHandle, WEnum},
}, },
iced_sctk::subsurface_widget::{SubsurfaceBuffer, SubsurfaceBufferRelease}, iced_winit::platform_specific::wayland::subsurface_widget::{
SubsurfaceBuffer, SubsurfaceBufferRelease,
},
}; };
use std::{ use std::{
array, array,
@ -206,7 +208,7 @@ impl ScreencopyHandler for AppData {
width: front.size.0, width: front.size.0,
height: front.size.1, height: front.size.1,
#[cfg(feature = "no-subsurfaces")] #[cfg(feature = "no-subsurfaces")]
image: cosmic::widget::image::Handle::from_pixels( image: cosmic::widget::image::Handle::from_rgba(
front.size.0, front.size.0,
front.size.1, front.size.1,
front.mmap.to_vec(), front.mmap.to_vec(),

View file

@ -6,10 +6,7 @@
use cctk::{ use cctk::{
cosmic_protocols::workspace::v1::client::zcosmic_workspace_handle_v1, cosmic_protocols::workspace::v1::client::zcosmic_workspace_handle_v1,
sctk::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer}, sctk::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer},
wayland_client::{ wayland_client::{protocol::wl_output, Connection, Proxy, WEnum},
protocol::{wl_data_device_manager::DndAction, wl_output},
Connection, Proxy, WEnum,
},
}; };
use clap::Parser; use clap::Parser;
use cosmic::{ use cosmic::{
@ -17,31 +14,29 @@ use cosmic::{
cctk, cctk,
iced::{ iced::{
self, self,
clipboard::mime::AsMimeTypes,
event::wayland::{Event as WaylandEvent, OutputEvent}, event::wayland::{Event as WaylandEvent, OutputEvent},
keyboard::key::{Key, Named}, keyboard::key::{Key, Named},
wayland::{ Size, Subscription, Task,
actions::data_device::{DataFromMimeType, DndIcon},
data_device::{accept_mime_type, request_dnd_data, set_actions, start_drag},
},
widget, Command, Size, Subscription, Vector,
}, },
iced_runtime::{ iced_core::window::Id as SurfaceId,
command::platform_specific::wayland::layer_surface::{ iced_runtime::platform_specific::wayland::layer_surface::{
IcedOutput, SctkLayerSurfaceSettings, IcedOutput, SctkLayerSurfaceSettings,
}, },
window::Id as SurfaceId, iced_winit::platform_specific::wayland::commands::layer_surface::{
destroy_layer_surface, get_layer_surface,
}, },
iced_sctk::commands::layer_surface::{destroy_layer_surface, get_layer_surface},
}; };
use cosmic_comp_config::CosmicCompConfig; use cosmic_comp_config::CosmicCompConfig;
use cosmic_config::{cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry}; use cosmic_config::{cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry};
use i18n_embed::DesktopLanguageRequester; use i18n_embed::DesktopLanguageRequester;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::{ use std::{
borrow::Cow,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
mem, mem,
path::PathBuf, path::PathBuf,
str::{self, FromStr}, str,
}; };
mod desktop_info; mod desktop_info;
@ -90,20 +85,41 @@ impl CosmicFlags for Args {
} }
} }
struct WlDndId { // TODO store protocol object id?
mime_type: &'static str, #[derive(Clone, Debug)]
} struct DragToplevel {}
impl DataFromMimeType for WlDndId { impl AsMimeTypes for DragToplevel {
fn from_mime_type(&self, mime_type: &str) -> Option<Vec<u8>> { fn available(&self) -> Cow<'static, [String]> {
if mime_type == self.mime_type { vec![TOPLEVEL_MIME.clone()].into()
Some(Vec::new()) }
fn as_bytes(&self, mime_type: &str) -> Option<Cow<'static, [u8]>> {
if mime_type == *TOPLEVEL_MIME {
Some(Vec::new().into())
} else { } else {
None None
} }
} }
} }
impl cosmic::iced::clipboard::mime::AllowedMimeTypes for DragToplevel {
fn allowed() -> Cow<'static, [String]> {
vec![crate::TOPLEVEL_MIME.clone()].into()
}
}
impl TryFrom<(Vec<u8>, std::string::String)> for DragToplevel {
type Error = ();
fn try_from((bytes, mime_type): (Vec<u8>, String)) -> Result<Self, ()> {
if mime_type == *TOPLEVEL_MIME {
Ok(Self {})
} else {
Err(())
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum Msg { enum Msg {
WaylandEvent(WaylandEvent), WaylandEvent(WaylandEvent),
@ -114,23 +130,24 @@ enum Msg {
CloseWorkspace(ZcosmicWorkspaceHandleV1), CloseWorkspace(ZcosmicWorkspaceHandleV1),
ActivateToplevel(ZcosmicToplevelHandleV1), ActivateToplevel(ZcosmicToplevelHandleV1),
CloseToplevel(ZcosmicToplevelHandleV1), CloseToplevel(ZcosmicToplevelHandleV1),
StartDrag(Size, Vector, DragSurface), //StartDrag(Size, Vector, DragSurface),
StartDrag(DragSurface),
DndWorkspaceEnter( DndWorkspaceEnter(
ZcosmicWorkspaceHandleV1, ZcosmicWorkspaceHandleV1,
wl_output::WlOutput, wl_output::WlOutput,
DndAction, f64,
f64,
Vec<String>, Vec<String>,
(f32, f32),
), ),
DndWorkspaceLeave(ZcosmicWorkspaceHandleV1, wl_output::WlOutput), DndWorkspaceLeave(ZcosmicWorkspaceHandleV1, wl_output::WlOutput),
DndWorkspaceDrop, DndWorkspaceDrop(DragToplevel),
DndWorkspaceData(String, Vec<u8>),
SourceFinished, SourceFinished,
#[allow(dead_code)] #[allow(dead_code)]
NewWorkspace, NewWorkspace,
CompConfig(Box<CosmicCompConfig>), CompConfig(Box<CosmicCompConfig>),
Config(CosmicWorkspacesConfig), Config(CosmicWorkspacesConfig),
BgConfig(cosmic_bg_config::state::State), BgConfig(cosmic_bg_config::state::State),
Ignore,
} }
#[derive(Debug)] #[derive(Debug)]
@ -142,7 +159,7 @@ struct Workspace {
is_active: bool, is_active: bool,
} }
#[derive(Debug)] #[derive(Clone, Debug)]
struct Toplevel { struct Toplevel {
handle: ZcosmicToplevelHandleV1, handle: ZcosmicToplevelHandleV1,
info: ToplevelInfo, info: ToplevelInfo,
@ -193,7 +210,7 @@ struct App {
conn: Option<Connection>, conn: Option<Connection>,
visible: bool, visible: bool,
wayland_cmd_sender: Option<calloop::channel::Sender<backend::Cmd>>, wayland_cmd_sender: Option<calloop::channel::Sender<backend::Cmd>>,
drag_surface: Option<(SurfaceId, DragSurface, Size)>, drag_surface: Option<(DragSurface, Size)>,
conf: Conf, conf: Conf,
core: cosmic::app::Core, core: cosmic::app::Core,
drop_target: Option<(ZcosmicWorkspaceHandleV1, wl_output::WlOutput)>, drop_target: Option<(ZcosmicWorkspaceHandleV1, wl_output::WlOutput)>,
@ -218,10 +235,7 @@ impl App {
self.toplevels.iter_mut().find(|i| &i.handle == handle) self.toplevels.iter_mut().find(|i| &i.handle == handle)
} }
fn create_surface( fn create_surface(&mut self, output: wl_output::WlOutput) -> Task<cosmic::app::Message<Msg>> {
&mut self,
output: wl_output::WlOutput,
) -> Command<cosmic::app::Message<Msg>> {
let id = SurfaceId::unique(); let id = SurfaceId::unique();
self.layer_surfaces.insert( self.layer_surfaces.insert(
id, id,
@ -241,10 +255,7 @@ impl App {
}) })
} }
fn destroy_surface( fn destroy_surface(&mut self, output: &wl_output::WlOutput) -> Task<cosmic::app::Message<Msg>> {
&mut self,
output: &wl_output::WlOutput,
) -> Command<cosmic::app::Message<Msg>> {
if let Some((id, _)) = self if let Some((id, _)) = self
.layer_surfaces .layer_surfaces
.iter() .iter()
@ -254,11 +265,11 @@ impl App {
self.layer_surfaces.remove(&id).unwrap(); self.layer_surfaces.remove(&id).unwrap();
destroy_layer_surface(id) destroy_layer_surface(id)
} else { } else {
Command::none() Task::none()
} }
} }
fn toggle(&mut self) -> Command<cosmic::app::Message<Msg>> { fn toggle(&mut self) -> Task<cosmic::app::Message<Msg>> {
if self.visible { if self.visible {
self.hide() self.hide()
} else { } else {
@ -266,11 +277,11 @@ impl App {
} }
} }
fn show(&mut self) -> Command<cosmic::app::Message<Msg>> { fn show(&mut self) -> Task<cosmic::app::Message<Msg>> {
if !self.visible { if !self.visible {
self.visible = true; self.visible = true;
let outputs = self.outputs.clone(); let outputs = self.outputs.clone();
let cmd = Command::batch( let cmd = Task::batch(
outputs outputs
.into_iter() .into_iter()
.map(|output| self.create_surface(output.handle)) .map(|output| self.create_surface(output.handle))
@ -280,16 +291,16 @@ impl App {
cmd cmd
} else { } else {
Command::none() Task::none()
} }
} }
// Close all shell surfaces // Close all shell surfaces
fn hide(&mut self) -> Command<cosmic::app::Message<Msg>> { fn hide(&mut self) -> Task<cosmic::app::Message<Msg>> {
self.visible = false; self.visible = false;
self.update_capture_filter(); self.update_capture_filter();
self.drag_surface = None; self.drag_surface = None;
Command::batch( Task::batch(
mem::take(&mut self.layer_surfaces) mem::take(&mut self.layer_surfaces)
.into_keys() .into_keys()
.map(destroy_layer_surface) .map(destroy_layer_surface)
@ -325,21 +336,18 @@ impl Application for App {
type Flags = Args; type Flags = Args;
const APP_ID: &'static str = "com.system76.CosmicWorkspaces"; const APP_ID: &'static str = "com.system76.CosmicWorkspaces";
fn init( fn init(core: cosmic::app::Core, _flags: Self::Flags) -> (Self, Task<Message<Self::Message>>) {
core: cosmic::app::Core,
_flags: Self::Flags,
) -> (Self, iced::Command<Message<Self::Message>>) {
( (
Self { Self {
core, core,
..Default::default() ..Default::default()
}, },
Command::none(), Task::none(),
) )
} }
// TODO: show panel and dock? Drag? // TODO: show panel and dock? Drag?
fn update(&mut self, message: Msg) -> Command<cosmic::app::Message<Msg>> { fn update(&mut self, message: Msg) -> Task<cosmic::app::Message<Msg>> {
match message { match message {
Msg::SourceFinished => { Msg::SourceFinished => {
self.drag_surface = None; self.drag_surface = None;
@ -455,13 +463,14 @@ impl Application for App {
} }
} }
backend::Event::WorkspaceCapture(handle, output_name, image) => { backend::Event::WorkspaceCapture(handle, output_name, image) => {
//println!("Workspace capture");
if let Some(workspace) = self.workspace_for_handle_mut(&handle) { if let Some(workspace) = self.workspace_for_handle_mut(&handle) {
workspace.img_for_output.insert(output_name, image); workspace.img_for_output.insert(output_name, image);
} }
} }
backend::Event::ToplevelCapture(handle, image) => { backend::Event::ToplevelCapture(handle, image) => {
if let Some(toplevel) = self.toplevel_for_handle_mut(&handle) { if let Some(toplevel) = self.toplevel_for_handle_mut(&handle) {
//println!("Got toplevel image!"); // println!("Got toplevel image!");
toplevel.img = Some(image); toplevel.img = Some(image);
} }
} }
@ -495,37 +504,11 @@ impl Application for App {
// TODO confirmation? // TODO confirmation?
self.send_wayland_cmd(backend::Cmd::CloseToplevel(toplevel_handle)); self.send_wayland_cmd(backend::Cmd::CloseToplevel(toplevel_handle));
} }
Msg::StartDrag(size, offset, drag_surface) => { Msg::StartDrag(drag_surface) => {
let (output, mime_type) = match &drag_surface { self.drag_surface = Some((drag_surface, Default::default()));
DragSurface::Workspace { handle: _, output } => (output, &*WORKSPACE_MIME),
DragSurface::Toplevel { handle: _, output } => (output, &*TOPLEVEL_MIME),
};
let id = SurfaceId::unique();
if let Some((parent_id, _)) = self
.layer_surfaces
.iter()
.find(|(_, x)| &x.output == output)
{
self.drag_surface = Some((id, drag_surface, size));
return start_drag(
vec![mime_type.to_string()],
DndAction::Move,
*parent_id,
Some((DndIcon::Custom(id), offset * -1.0)),
Box::new(WlDndId { mime_type }),
);
}
} }
Msg::DndWorkspaceEnter(handle, output, _action, mimes, (_x, _y)) => { Msg::DndWorkspaceEnter(handle, output, _x, _y, _mimes) => {
self.drop_target = Some((handle, output)); self.drop_target = Some((handle, output));
// XXX
// if mimes.iter().any(|x| x == WORKSPACE_MIME) && action == DndAction::Move {
if mimes.iter().any(|x| x == &*TOPLEVEL_MIME) {
return Command::batch(vec![
set_actions(DndAction::Move, DndAction::Move),
accept_mime_type(Some(TOPLEVEL_MIME.to_string())),
]);
}
} }
Msg::DndWorkspaceLeave(handle, output) => { Msg::DndWorkspaceLeave(handle, output) => {
// Currently in iced-sctk, a `DndOfferEvent::Motion` may cause a leave event after // Currently in iced-sctk, a `DndOfferEvent::Motion` may cause a leave event after
@ -533,25 +516,15 @@ impl Application for App {
if self.drop_target == Some((handle, output)) { if self.drop_target == Some((handle, output)) {
self.drop_target = None; self.drop_target = None;
} }
return accept_mime_type(None);
} }
Msg::DndWorkspaceDrop => { Msg::DndWorkspaceDrop(_toplevel) => {
return request_dnd_data(TOPLEVEL_MIME.to_string()); if let Some((DragSurface::Toplevel { handle, .. }, _)) = &self.drag_surface {
} if let Some(drop_target) = self.drop_target.take() {
Msg::DndWorkspaceData(mime_type, data) => { self.send_wayland_cmd(backend::Cmd::MoveToplevelToWorkspace(
if mime_type == *TOPLEVEL_MIME { handle.clone(),
// XXX getting empty data? drop_target.0,
let _protocol_id = str::from_utf8(&data) drop_target.1,
.ok() ));
.and_then(|s| u32::from_str(s).ok());
if let Some((_, DragSurface::Toplevel { handle, .. }, _)) = &self.drag_surface {
if let Some(drop_target) = self.drop_target.take() {
self.send_wayland_cmd(backend::Cmd::MoveToplevelToWorkspace(
handle.clone(),
drop_target.0,
drop_target.1,
));
}
} }
} }
} }
@ -575,23 +548,24 @@ impl Application for App {
Msg::BgConfig(c) => { Msg::BgConfig(c) => {
self.conf.bg = c; self.conf.bg = c;
} }
Msg::Ignore => {}
} }
Command::none() Task::none()
} }
fn dbus_activation( fn dbus_activation(
&mut self, &mut self,
msg: cosmic::app::DbusActivationMessage, msg: cosmic::app::DbusActivationMessage,
) -> iced::Command<cosmic::app::Message<Self::Message>> { ) -> Task<cosmic::app::Message<Self::Message>> {
if let DbusActivationDetails::Activate = msg.msg { if let DbusActivationDetails::Activate = msg.msg {
self.toggle() self.toggle()
} else { } else {
Command::none() Task::none()
} }
} }
fn subscription(&self) -> Subscription<Msg> { fn subscription(&self) -> Subscription<Msg> {
let events = iced::event::listen_with(|evt, _| { let events = iced::event::listen_with(|evt, _, _| {
if let iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(evt)) = evt if let iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland(evt)) = evt
{ {
Some(Msg::WaylandEvent(evt)) Some(Msg::WaylandEvent(evt))
@ -599,6 +573,8 @@ impl Application for App {
key: Key::Named(Named::Escape), key: Key::Named(Named::Escape),
modifiers: _, modifiers: _,
location: _, location: _,
modified_key: _,
physical_key: _,
}) = evt }) = evt
{ {
Some(Msg::Close) Some(Msg::Close)
@ -662,13 +638,6 @@ impl Application for App {
if let Some(surface) = self.layer_surfaces.get(&id) { if let Some(surface) = self.layer_surfaces.get(&id) {
return view::layer_surface(self, surface); return view::layer_surface(self, surface);
} }
if let Some((drag_id, drag_surface, size)) = &self.drag_surface {
if drag_id == &id {
if let Some(element) = view::drag_surface(self, drag_surface, *size) {
return element;
}
}
}
log::info!("NO VIEW"); log::info!("NO VIEW");
text("workspaces").into() text("workspaces").into()
} }

View file

@ -8,10 +8,10 @@ use cosmic::{
self, self,
advanced::layout::flex::Axis, advanced::layout::flex::Axis,
widget::{column, row}, widget::{column, row},
Border, Size, Border,
}, },
iced_core::Shadow, iced_core::Shadow,
iced_sctk::subsurface_widget::Subsurface, iced_winit::platform_specific::wayland::subsurface_widget::Subsurface,
widget, widget,
}; };
use cosmic_bg_config::Source; use cosmic_bg_config::Source;
@ -19,7 +19,7 @@ use cosmic_comp_config::workspace::WorkspaceLayout;
use crate::{ use crate::{
backend::{self, CaptureImage}, backend::{self, CaptureImage},
App, DragSurface, LayerSurface, Msg, Toplevel, Workspace, App, DragSurface, DragToplevel, LayerSurface, Msg, Toplevel, Workspace,
}; };
pub(crate) fn layer_surface<'a>( pub(crate) fn layer_surface<'a>(
@ -33,7 +33,7 @@ pub(crate) fn layer_surface<'a>(
} }
} }
let mut drag_toplevel = None; let mut drag_toplevel = None;
if let Some((_, DragSurface::Toplevel { handle, .. }, _)) = &app.drag_surface { if let Some((DragSurface::Toplevel { handle, .. }, _)) = &app.drag_surface {
drag_toplevel = Some(handle); drag_toplevel = Some(handle);
} }
let layout = app.conf.workspace_config.workspace_layout; let layout = app.conf.workspace_config.workspace_layout;
@ -77,41 +77,10 @@ pub(crate) fn layer_surface<'a>(
container.into() container.into()
} }
pub(crate) fn drag_surface<'a>(
app: &'a App,
drag_surface: &DragSurface,
size: Size,
) -> Option<cosmic::Element<'a, Msg>> {
let item = match drag_surface {
DragSurface::Workspace { handle, output } => {
if let Some(workspace) = app.workspaces.iter().find(|x| &x.handle == handle) {
workspace_item(workspace, output, false)
} else {
return None;
}
}
DragSurface::Toplevel { handle, .. } => {
if let Some(toplevel) = app.toplevels.iter().find(|x| &x.handle == handle) {
toplevel_preview(toplevel, true)
} else {
return None;
}
}
};
// TODO Use `mouse_interaction_wrapper` (need to modify iced_sctk to update view of
// drag surfaces)
Some(
widget::container(item)
.height(iced::Length::Fixed(size.height))
.width(iced::Length::Fixed(size.width))
.into(),
)
}
fn close_button(on_press: Msg) -> cosmic::Element<'static, Msg> { fn close_button(on_press: Msg) -> cosmic::Element<'static, Msg> {
widget::container( widget::container(
widget::button(widget::icon::from_name("window-close-symbolic").size(16)) widget::button::custom(widget::icon::from_name("window-close-symbolic").size(16))
.style(cosmic::theme::Button::Destructive) .class(cosmic::theme::Button::Destructive)
.on_press(on_press), .on_press(on_press),
) )
.align_x(iced::alignment::Horizontal::Right) .align_x(iced::alignment::Horizontal::Right)
@ -123,9 +92,9 @@ fn workspace_item_appearance(
theme: &cosmic::Theme, theme: &cosmic::Theme,
is_active: bool, is_active: bool,
hovered: bool, hovered: bool,
) -> cosmic::widget::button::Appearance { ) -> cosmic::widget::button::Style {
let cosmic = theme.cosmic(); let cosmic = theme.cosmic();
let mut appearance = cosmic::widget::button::Appearance::new(); let mut appearance = cosmic::widget::button::Style::new();
appearance.border_radius = cosmic.corner_radii.radius_s.into(); appearance.border_radius = cosmic.corner_radii.radius_s.into();
if is_active { if is_active {
appearance.border_width = 2.0; appearance.border_width = 2.0;
@ -146,9 +115,9 @@ fn workspace_item<'a>(
let is_active = workspace.is_active; let is_active = workspace.is_active;
column![ column![
// TODO editable name? // TODO editable name?
widget::button(column![image, widget::text(&workspace.name)]) widget::button::custom(column![image, widget::text(&workspace.name)])
.selected(workspace.is_active) .selected(workspace.is_active)
.style(cosmic::theme::Button::Custom { .class(cosmic::theme::Button::Custom {
active: Box::new(move |_focused, theme| workspace_item_appearance( active: Box::new(move |_focused, theme| workspace_item_appearance(
theme, theme,
is_active, is_active,
@ -173,6 +142,7 @@ fn workspace_sidebar_entry<'a>(
workspace: &'a Workspace, workspace: &'a Workspace,
output: &'a wl_output::WlOutput, output: &'a wl_output::WlOutput,
is_drop_target: bool, is_drop_target: bool,
drag_id: u64,
) -> cosmic::Element<'a, Msg> { ) -> cosmic::Element<'a, Msg> {
/* XXX /* XXX
let mouse_interaction = if is_drop_target { let mouse_interaction = if is_drop_target {
@ -198,18 +168,30 @@ fn workspace_sidebar_entry<'a>(
*/ */
//crate::widgets::mouse_interaction_wrapper( //crate::widgets::mouse_interaction_wrapper(
// mouse_interaction, // mouse_interaction,
iced::widget::dnd_listener(workspace_item(workspace, output, is_drop_target)) let workspace_handle = workspace.handle.clone();
.on_enter(|actions, mime, pos| { let workspace_handle2 = workspace_handle.clone();
Msg::DndWorkspaceEnter(workspace.handle.clone(), output.clone(), actions, mime, pos) let output_clone = output.clone();
}) let output_clone2 = output.clone();
.on_exit(Msg::DndWorkspaceLeave( cosmic::widget::dnd_destination::dnd_destination_for_data(
workspace.handle.clone(), workspace_item(workspace, output, is_drop_target),
output.clone(), |data: Option<DragToplevel>, _action| match data {
)) Some(toplevel) => Msg::DndWorkspaceDrop(toplevel),
.on_drop(Msg::DndWorkspaceDrop) None => Msg::Ignore,
.on_data(Msg::DndWorkspaceData) },
//) )
.into() .drag_id(drag_id)
.on_enter(move |actions, mime, pos| {
Msg::DndWorkspaceEnter(
workspace_handle.clone(),
output_clone.clone(),
actions,
mime,
pos,
)
})
.on_leave(move || Msg::DndWorkspaceLeave(workspace_handle2.clone(), output_clone2.clone()))
//)
.into()
} }
fn workspaces_sidebar<'a>( fn workspaces_sidebar<'a>(
@ -219,7 +201,8 @@ fn workspaces_sidebar<'a>(
drop_target: Option<&backend::ZcosmicWorkspaceHandleV1>, drop_target: Option<&backend::ZcosmicWorkspaceHandleV1>,
) -> cosmic::Element<'a, Msg> { ) -> cosmic::Element<'a, Msg> {
let sidebar_entries = workspaces let sidebar_entries = workspaces
.map(|w| workspace_sidebar_entry(w, output, drop_target == Some(&w.handle))) .enumerate()
.map(|(i, w)| workspace_sidebar_entry(w, output, drop_target == Some(&w.handle), i as u64))
.collect(); .collect();
let axis = match layout { let axis = match layout {
WorkspaceLayout::Vertical => Axis::Vertical, WorkspaceLayout::Vertical => Axis::Vertical,
@ -260,8 +243,8 @@ fn workspaces_sidebar<'a>(
widget::container(sidebar_entries_container) widget::container(sidebar_entries_container)
.width(width) .width(width)
.height(height) .height(height)
.style(cosmic::theme::Container::custom(|theme| { .class(cosmic::theme::Container::custom(|theme| {
cosmic::iced_style::container::Appearance { cosmic::iced::widget::container::Style {
text_color: Some(theme.cosmic().on_bg_color().into()), text_color: Some(theme.cosmic().on_bg_color().into()),
icon_color: Some(theme.cosmic().on_bg_color().into()), icon_color: Some(theme.cosmic().on_bg_color().into()),
background: Some(iced::Color::from(theme.cosmic().background.base).into()), background: Some(iced::Color::from(theme.cosmic().background.base).into()),
@ -280,8 +263,9 @@ fn workspaces_sidebar<'a>(
.into() .into()
} }
fn toplevel_preview(toplevel: &Toplevel, is_being_dragged: bool) -> cosmic::Element<Msg> { fn toplevel_preview(toplevel: &Toplevel, is_being_dragged: bool) -> cosmic::Element<'static, Msg> {
let label = widget::text(&toplevel.info.title); // Clone so it can be 'static, for use in drag icon
let label = widget::text(toplevel.info.title.clone());
let label = if let Some(icon) = &toplevel.icon { let label = if let Some(icon) = &toplevel.icon {
row![widget::icon(widget::icon::from_path(icon.clone())), label].spacing(4) row![widget::icon(widget::icon::from_path(icon.clone())), label].spacing(4)
} else { } else {
@ -292,17 +276,17 @@ fn toplevel_preview(toplevel: &Toplevel, is_being_dragged: bool) -> cosmic::Elem
crate::widgets::toplevel_item( crate::widgets::toplevel_item(
vec![ vec![
close_button(Msg::CloseToplevel(toplevel.handle.clone())), close_button(Msg::CloseToplevel(toplevel.handle.clone())),
widget::button(capture_image(toplevel.img.as_ref(), alpha)) widget::button::custom(capture_image(toplevel.img.as_ref(), alpha))
.selected( .selected(
toplevel toplevel
.info .info
.state .state
.contains(&zcosmic_toplevel_handle_v1::State::Activated), .contains(&zcosmic_toplevel_handle_v1::State::Activated),
) )
.style(cosmic::theme::Button::Image) .class(cosmic::theme::Button::Image)
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())) .on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
.into(), .into(),
widget::button(label) widget::button::custom(label)
.on_press(Msg::ActivateToplevel(toplevel.handle.clone())) .on_press(Msg::ActivateToplevel(toplevel.handle.clone()))
.into(), .into(),
], ],
@ -325,19 +309,28 @@ fn toplevel_previews_entry<'a>(
toplevel_preview(toplevel, is_being_dragged), toplevel_preview(toplevel, is_being_dragged),
!is_being_dragged, !is_being_dragged,
); );
iced::widget::dnd_source(preview) let toplevel2 = toplevel.clone();
.on_drag(|size, offset| { cosmic::widget::dnd_source::<_, DragToplevel>(preview)
Msg::StartDrag( .drag_threshold(5.)
size, .drag_content(|| DragToplevel {})
offset, // XXX State?
DragSurface::Toplevel { .drag_icon(move |offset| {
handle: toplevel.handle.clone(), (
output: output.clone(), toplevel_preview(&toplevel2, true).map(|_| ()),
}, cosmic::iced_core::widget::tree::State::None,
-offset,
) )
}) })
.on_finished(Msg::SourceFinished) .on_start(Some(Msg::StartDrag(
.on_cancelled(Msg::SourceFinished) //size,
//offset,
DragSurface::Toplevel {
handle: toplevel.handle.clone(),
output: output.clone(),
},
)))
.on_finish(Some(Msg::SourceFinished))
.on_cancel(Some(Msg::SourceFinished))
.into() .into()
} }
@ -382,42 +375,38 @@ fn bg_element<'a>(
.width(iced::Length::Fill) .width(iced::Length::Fill)
.height(iced::Length::Fill) .height(iced::Length::Fill)
.into(), .into(),
Some(Source::Color(color)) => { Some(Source::Color(color)) => widget::layer_container(widget::horizontal_space())
widget::layer_container(widget::horizontal_space(iced::Length::Fill)) .width(iced::Length::Fill)
.width(iced::Length::Fill) .height(iced::Length::Fill)
.height(iced::Length::Fill) .class(cosmic::theme::Container::Custom(Box::new(move |_| {
.style(cosmic::theme::Container::Custom(Box::new(move |_| { let color = color.clone();
let color = color.clone(); cosmic::iced::widget::container::Style {
cosmic::iced_style::container::Appearance { background: Some(match color {
background: Some(match color { cosmic_bg_config::Color::Single(c) => {
cosmic_bg_config::Color::Single(c) => iced::Background::Color( iced::Background::Color(cosmic::iced::Color::new(c[0], c[1], c[2], 1.0))
cosmic::iced::Color::new(c[0], c[1], c[2], 1.0), }
), cosmic_bg_config::Color::Gradient(cosmic_bg_config::Gradient {
cosmic_bg_config::Color::Gradient(cosmic_bg_config::Gradient { colors,
colors, radius,
radius, }) => {
}) => { let stop_increment = 1.0 / (colors.len() - 1) as f32;
let stop_increment = 1.0 / (colors.len() - 1) as f32; let mut stop = 0.0;
let mut stop = 0.0;
let mut linear = iced::gradient::Linear::new(iced::Degrees(radius)); let mut linear = iced::gradient::Linear::new(iced::Degrees(radius));
for &[r, g, b] in colors.iter() { for &[r, g, b] in colors.iter() {
linear = linear linear =
.add_stop(stop, cosmic::iced::Color::from_rgb(r, g, b)); linear.add_stop(stop, cosmic::iced::Color::from_rgb(r, g, b));
stop += stop_increment; stop += stop_increment;
}
iced::Background::Gradient(cosmic::iced_core::Gradient::Linear(
linear,
))
} }
}),
..Default::default() iced::Background::Gradient(cosmic::iced_core::Gradient::Linear(linear))
} }
}))) }),
.into() ..Default::default()
} }
})))
.into(),
None => { None => {
widget::image::Image::<widget::image::Handle>::new(widget::image::Handle::from_path( widget::image::Image::<widget::image::Handle>::new(widget::image::Handle::from_path(
"/usr/share/backgrounds/pop/kate-hazen-COSMIC-desktop-wallpaper.png", "/usr/share/backgrounds/pop/kate-hazen-COSMIC-desktop-wallpaper.png",
@ -430,7 +419,7 @@ fn bg_element<'a>(
} }
} }
fn capture_image(image: Option<&CaptureImage>, alpha: f32) -> cosmic::Element<'_, Msg> { fn capture_image(image: Option<&CaptureImage>, alpha: f32) -> cosmic::Element<'static, Msg> {
if let Some(image) = image { if let Some(image) = image {
#[cfg(feature = "no-subsurfaces")] #[cfg(feature = "no-subsurfaces")]
{ {
@ -439,11 +428,9 @@ fn capture_image(image: Option<&CaptureImage>, alpha: f32) -> cosmic::Element<'_
} }
#[cfg(not(feature = "no-subsurfaces"))] #[cfg(not(feature = "no-subsurfaces"))]
{ {
Subsurface::new(image.width, image.height, &image.wl_buffer) Subsurface::new(image.wl_buffer.clone()).alpha(alpha).into()
.alpha(alpha)
.into()
} }
} else { } else {
widget::Image::new(widget::image::Handle::from_pixels(1, 1, vec![0, 0, 0, 255])).into() widget::Image::new(widget::image::Handle::from_rgba(1, 1, vec![0, 0, 0, 255])).into()
} }
} }

View file

@ -5,11 +5,11 @@ use cosmic::{
advanced::{ advanced::{
layout::{self}, layout::{self},
mouse, overlay, renderer, mouse, overlay, renderer,
widget::{tree, Operation, OperationOutputWrapper, Tree}, widget::{tree, Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
event::{self, Event}, event::{self, Event},
Length, Rectangle, Size, Length, Rectangle, Size, Vector,
}, },
iced_core::Renderer, iced_core::Renderer,
}; };
@ -52,7 +52,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for ImageBg<'a, Msg>
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
); );
fn mouse_interaction( fn mouse_interaction(
&self, &self,
@ -82,6 +82,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for ImageBg<'a, Msg>
tree: &'b mut Tree, tree: &'b mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
translation: Vector,
) -> Option<overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>>; ) -> Option<overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>>;
} }
} }

View file

@ -1,11 +1,11 @@
use cosmic::iced::{ use cosmic::iced::{
advanced::{ advanced::{
layout, mouse, overlay, renderer, layout, mouse, overlay, renderer,
widget::{tree, Id, Operation, OperationOutputWrapper, Tree}, widget::{tree, Id, Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
event::{self, Event}, event::{self, Event},
Length, Rectangle, Size, Length, Rectangle, Size, Vector,
}; };
use std::marker::PhantomData; use std::marker::PhantomData;
@ -61,7 +61,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for LayoutWrapper<'a,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
); );
fn draw( fn draw(
&self, &self,
@ -102,6 +102,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for LayoutWrapper<'a,
tree: &'b mut Tree, tree: &'b mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
transation: Vector,
) -> Option<overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>>; ) -> Option<overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>>;
fn set_id(&mut self, id: Id); fn set_id(&mut self, id: Id);
} }

View file

@ -1,11 +1,11 @@
use cosmic::iced::{ use cosmic::iced::{
advanced::{ advanced::{
layout, mouse, overlay, renderer, layout, mouse, overlay, renderer,
widget::{tree, Id, Operation, OperationOutputWrapper, Tree}, widget::{tree, Id, Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
event::{self, Event}, event::{self, Event},
Length, Rectangle, Size, Length, Rectangle, Size, Vector,
}; };
use std::marker::PhantomData; use std::marker::PhantomData;
@ -46,7 +46,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for MouseInteractionW
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
); );
fn draw( fn draw(
&self, &self,
@ -79,6 +79,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for MouseInteractionW
tree: &'b mut Tree, tree: &'b mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
translation: Vector,
) -> Option<overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>>; ) -> Option<overlay::Element<'b, Msg, cosmic::Theme, cosmic::Renderer>>;
fn set_id(&mut self, id: Id); fn set_id(&mut self, id: Id);
} }

View file

@ -6,7 +6,7 @@ use cosmic::iced::{
advanced::{ advanced::{
layout::{self, flex::Axis}, layout::{self, flex::Axis},
mouse, renderer, mouse, renderer,
widget::{Operation, OperationOutputWrapper, Tree}, widget::{Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
event::{self, Event}, event::{self, Event},
@ -120,7 +120,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for ToplevelItem<'a,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children

View file

@ -2,7 +2,7 @@ use cosmic::iced::{
advanced::{ advanced::{
layout::{self, flex::Axis}, layout::{self, flex::Axis},
mouse, renderer, mouse, renderer,
widget::{Operation, OperationOutputWrapper, Tree}, widget::{Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
event::{self, Event}, event::{self, Event},
@ -130,7 +130,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for Toplevels<'a, Msg
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children

View file

@ -4,7 +4,7 @@
use cosmic::iced::{ use cosmic::iced::{
advanced::{ advanced::{
layout, mouse, renderer, layout, mouse, renderer,
widget::{Operation, OperationOutputWrapper, Tree}, widget::{Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
event::{self, Event}, event::{self, Event},
@ -42,7 +42,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for VisibilityWrapper
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
) { ) {
self.content self.content
.as_widget() .as_widget()

View file

@ -5,9 +5,10 @@ use cosmic::iced::{
advanced::{ advanced::{
layout::{self, flex::Axis}, layout::{self, flex::Axis},
mouse, renderer, mouse, renderer,
widget::{Operation, OperationOutputWrapper, Tree}, widget::{Operation, Tree},
Clipboard, Layout, Shell, Widget, Clipboard, Layout, Shell, Widget,
}, },
core::clipboard::DndDestinationRectangles,
event::{self, Event}, event::{self, Event},
Length, Point, Rectangle, Size, Length, Point, Rectangle, Size,
}; };
@ -122,7 +123,7 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WorkspaceBar<'a,
tree: &mut Tree, tree: &mut Tree,
layout: Layout<'_>, layout: Layout<'_>,
renderer: &cosmic::Renderer, renderer: &cosmic::Renderer,
operation: &mut dyn Operation<OperationOutputWrapper<Msg>>, operation: &mut dyn Operation<()>,
) { ) {
operation.container(None, layout.bounds(), &mut |operation| { operation.container(None, layout.bounds(), &mut |operation| {
self.children self.children
@ -219,6 +220,24 @@ impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WorkspaceBar<'a,
fn diff(&mut self, tree: &mut Tree) { fn diff(&mut self, tree: &mut Tree) {
tree.diff_children(&mut self.children); tree.diff_children(&mut self.children);
} }
fn drag_destinations(
&self,
state: &Tree,
layout: Layout<'_>,
renderer: &cosmic::Renderer,
dnd_rectangles: &mut DndDestinationRectangles,
) {
for ((e, layout), state) in self
.children
.iter()
.zip(layout.children())
.zip(state.children.iter())
{
e.as_widget()
.drag_destinations(state, layout, renderer, dnd_rectangles);
}
}
} }
impl<'a, Msg: 'static> From<WorkspaceBar<'a, Msg>> for cosmic::Element<'a, Msg> { impl<'a, Msg: 'static> From<WorkspaceBar<'a, Msg>> for cosmic::Element<'a, Msg> {