Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for drag-and-drop surface offsets #206

Merged
merged 6 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 42 additions & 9 deletions core/src/clipboard.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,47 @@
//! Access the clipboard.

use std::{any::Any, sync::Arc};
use std::any::Any;

use dnd::{DndAction, DndDestinationRectangle, DndSurface};
use mime::{self, AllowedMimeTypes, AsMimeTypes, ClipboardStoreData};

use crate::{widget::tree::State, window, Element};
use crate::{widget::tree::State, window, Element, Vector};

#[derive(Debug)]
pub struct IconSurface<E> {
pub element: E,
pub state: State,
pub offset: Vector,
}

pub type DynIconSurface = IconSurface<Box<dyn Any>>;

impl<T: 'static, R: 'static> IconSurface<Element<'static, (), T, R>> {
pub fn new(element: Element<'static, (), T, R>, state: State, offset: Vector) -> Self {
Self { element, state, offset }
}

fn upcast(self) -> DynIconSurface {
IconSurface {
element: Box::new(self.element),
state: self.state,
offset: self.offset,
}
}
}

impl DynIconSurface {
/// Downcast `element` to concrete type `Element<(), T, R>`
///
/// Panics if type doesn't match
pub fn downcast<T: 'static, R: 'static>(self) -> IconSurface<Element<'static, (), T, R>> {
IconSurface {
element: *self.element.downcast().expect("drag-and-drop icon surface has invalid element type"),
state: self.state,
offset: self.offset,
}
}
}

/// A buffer for short-term storage and transfer within and between
/// applications.
Expand Down Expand Up @@ -53,7 +89,7 @@ pub trait Clipboard {
&mut self,
_internal: bool,
_source_surface: Option<DndSource>,
_icon_surface: Option<Box<dyn Any>>,
_icon_surface: Option<DynIconSurface>,
_content: Box<dyn AsMimeTypes + Send + 'static>,
_actions: DndAction,
) {
Expand Down Expand Up @@ -86,21 +122,18 @@ pub enum Kind {

/// Starts a DnD operation.
/// icon surface is a tuple of the icon element and optionally the icon element state.
pub fn start_dnd<T: 'static, R: 'static, M: 'static>(
pub fn start_dnd<T: 'static, R: 'static>(
clipboard: &mut dyn Clipboard,
internal: bool,
source_surface: Option<DndSource>,
icon_surface: Option<(Element<'static, M, T, R>, State)>,
icon_surface: Option<IconSurface<Element<'static, (), T, R>>>,
content: Box<dyn AsMimeTypes + Send + 'static>,
actions: DndAction,
) {
clipboard.start_dnd(
internal,
source_surface,
icon_surface.map(|i| {
let i: Box<dyn Any> = Box::new(Arc::new(i));
i
}),
icon_surface.map(IconSurface::upcast),
content,
actions,
);
Expand Down
43 changes: 0 additions & 43 deletions runtime/src/dnd.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//! Access the clipboard.

use std::any::Any;

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / widget

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / widget

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::any::Any`

Check warning on line 3 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::any::Any`

use dnd::{DndDestinationRectangle, DndSurface};
use iced_core::clipboard::DndSource;

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / widget

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / widget

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `iced_core::clipboard::DndSource`

Check warning on line 6 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `iced_core::clipboard::DndSource`
use window_clipboard::mime::{AllowedMimeTypes, AsMimeTypes};

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / widget

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / widget

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `AsMimeTypes`

Check warning on line 7 in runtime/src/dnd.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `AsMimeTypes`

use crate::{oneshot, task, Action, Task};

Expand All @@ -17,19 +17,6 @@
/// The rectangles to register.
rectangles: Vec<DndDestinationRectangle>,
},
/// Start a Dnd operation.
StartDnd {
/// Whether the Dnd operation is internal.
internal: bool,
/// The source surface of the Dnd operation.
source_surface: Option<DndSource>,
/// The icon surface of the Dnd operation.
icon_surface: Option<Box<dyn Any + Send>>,
/// The content of the Dnd operation.
content: Box<dyn AsMimeTypes + Send + 'static>,
/// The actions of the Dnd operation.
actions: dnd::DndAction,
},
/// End a Dnd operation.
EndDnd,
/// Peek the current Dnd operation.
Expand All @@ -53,19 +40,6 @@
.field("surface", surface)
.field("rectangles", rectangles)
.finish(),
Self::StartDnd {
internal,
source_surface,
icon_surface,
content: _,
actions,
} => f
.debug_struct("StartDnd")
.field("internal", internal)
.field("source_surface", source_surface)
.field("icon_surface", icon_surface)
.field("actions", actions)
.finish(),
Self::EndDnd => f.write_str("EndDnd"),
Self::PeekDnd(mime, _) => {
f.debug_struct("PeekDnd").field("mime", mime).finish()
Expand Down Expand Up @@ -99,23 +73,6 @@
}))
}

/// Start a Dnd operation.
pub fn start_dnd<Message>(
internal: bool,
source_surface: Option<DndSource>,
icon_surface: Option<Box<dyn Any + Send>>,
content: Box<dyn AsMimeTypes + Send + 'static>,
actions: dnd::DndAction,
) -> Task<Message> {
task::effect(Action::Dnd(DndAction::StartDnd {
internal,
source_surface,
icon_surface,
content,
actions,
}))
}

/// End a Dnd operation.
pub fn end_dnd<Message>() -> Task<Message> {
task::effect(Action::Dnd(DndAction::EndDnd))
Expand Down
6 changes: 3 additions & 3 deletions winit/src/clipboard.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Access the clipboard.

use std::sync::Mutex;
use std::{any::Any, borrow::Cow};

Check warning on line 4 in winit/src/clipboard.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `any::Any`

Check warning on line 4 in winit/src/clipboard.rs

View workflow job for this annotation

GitHub Actions / web

unused import: `any::Any`

Check warning on line 4 in winit/src/clipboard.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `any::Any`

Check warning on line 4 in winit/src/clipboard.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `any::Any`

use crate::core::clipboard::DndSource;
use crate::core::clipboard::{DndSource, DynIconSurface};
use crate::core::clipboard::Kind;
use std::sync::Arc;
use winit::dpi::LogicalSize;
Expand All @@ -26,7 +26,7 @@
pub(crate) struct StartDnd {
pub(crate) internal: bool,
pub(crate) source_surface: Option<DndSource>,
pub(crate) icon_surface: Option<Box<dyn Any>>,
pub(crate) icon_surface: Option<DynIconSurface>,
pub(crate) content: Box<dyn mime::AsMimeTypes + Send + 'static>,
pub(crate) actions: DndAction,
}
Expand Down Expand Up @@ -261,7 +261,7 @@
&mut self,
internal: bool,
source_surface: Option<DndSource>,
icon_surface: Option<Box<dyn Any>>,
icon_surface: Option<DynIconSurface>,
content: Box<dyn mime::AsMimeTypes + Send + 'static>,
actions: DndAction,
) {
Expand Down
6 changes: 3 additions & 3 deletions winit/src/platform_specific/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use std::collections::HashMap;

use iced_graphics::Compositor;
use iced_runtime::{core::window, user_interface, Debug};
use iced_runtime::{core::{window, Vector}, user_interface, Debug};
use raw_window_handle::HasWindowHandle;

Check failure on line 8 in winit/src/platform_specific/mod.rs

View workflow job for this annotation

GitHub Actions / web

unresolved import `raw_window_handle`

Check failure on line 8 in winit/src/platform_specific/mod.rs

View workflow job for this annotation

GitHub Actions / web

unresolved import `raw_window_handle`

Check failure on line 8 in winit/src/platform_specific/mod.rs

View workflow job for this annotation

GitHub Actions / wasm

unresolved import `raw_window_handle`

Check failure on line 8 in winit/src/platform_specific/mod.rs

View workflow job for this annotation

GitHub Actions / wasm

unresolved import `raw_window_handle`

#[cfg(all(feature = "wayland", target_os = "linux"))]
pub mod wayland;
Expand Down Expand Up @@ -128,10 +128,10 @@
None
}

pub(crate) fn update_surface_shm(&mut self, surface: &dyn HasWindowHandle, width: u32, height: u32, data: &[u8]) {
pub(crate) fn update_surface_shm(&mut self, surface: &dyn HasWindowHandle, width: u32, height: u32, scale: f64, data: &[u8], offset: Vector) {
#[cfg(all(feature = "wayland", target_os = "linux"))]
{
return self.wayland.update_surface_shm(surface, width, height, data);
return self.wayland.update_surface_shm(surface, width, height, scale, data, offset);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions winit/src/platform_specific/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use cctk::sctk::reexports::client::protocol::wl_surface::WlSurface;
use cctk::sctk::seat::keyboard::Modifiers;
use iced_futures::futures::channel::mpsc;
use iced_graphics::Compositor;
use iced_runtime::core::window;
use iced_runtime::core::{window, Vector};
use iced_runtime::Debug;
use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};
use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle};
Expand Down Expand Up @@ -239,12 +239,12 @@ impl WaylandSpecific {
}
}

pub(crate) fn update_surface_shm(&mut self, window: &dyn HasWindowHandle, width: u32, height: u32, data: &[u8]) {
pub(crate) fn update_surface_shm(&mut self, window: &dyn HasWindowHandle, width: u32, height: u32, scale: f64, data: &[u8], offset: Vector) {
if let Some(subsurface_state) = self.subsurface_state.as_mut() {
if let RawWindowHandle::Wayland(window) = window.window_handle().unwrap().as_raw() {
let id = unsafe { ObjectId::from_ptr(WlSurface::interface(), window.surface.as_ptr().cast()).unwrap() };
let surface = WlSurface::from_id(self.conn.as_ref().unwrap(), id).unwrap();
subsurface_state.update_surface_shm(&surface, width, height, data);
subsurface_state.update_surface_shm(&surface, width, height, scale, data, offset);
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions winit/src/platform_specific/wayland/subsurface_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::core::{
layout::{self, Layout},
mouse, renderer,
widget::{self, Widget},
ContentFit, Element, Length, Rectangle, Size,
ContentFit, Element, Length, Rectangle, Size, Vector,
};
use std::{
cell::RefCell,
Expand Down Expand Up @@ -377,14 +377,22 @@ impl SubsurfaceState {
.create_surface(&self.qh, SurfaceData::new(None, 1))
}

pub fn update_surface_shm(&self, surface: &WlSurface, width: u32, height: u32, data: &[u8]) {
pub fn update_surface_shm(&self, surface: &WlSurface, width: u32, height: u32, scale: f64, data: &[u8], offset: Vector) {
let wp_viewport = self.wp_viewporter.get_viewport(
&surface,
&self.qh,
cctk::sctk::globals::GlobalData,
);
let shm = ShmGlobal(&self.wl_shm);
let mut pool = SlotPool::new(width as usize * height as usize * 4, &shm).unwrap();
let (buffer, canvas) = pool.create_buffer(width as i32, height as i32, width as i32 * 4, wl_shm::Format::Argb8888).unwrap();
canvas[0..width as usize * height as usize * 4].copy_from_slice(data);
surface.damage_buffer(0, 0, width as i32, height as i32);
buffer.attach_to(&surface);
surface.offset(offset.x as i32, offset.y as i32);
wp_viewport.set_destination((width as f64 / scale) as i32, (height as f64 / scale) as i32);
surface.commit();
wp_viewport.destroy();
}

fn create_subsurface(&self, parent: &WlSurface) -> SubsurfaceInstance {
Expand Down
Loading
Loading