From 55f3e200cb064f68c74ae3a8d5e05717663c8ed5 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 3 Jan 2025 12:55:55 -0800 Subject: [PATCH 1/6] Don't unnecessarily chain `.map()` The first `map()` call is unneded, and the second and third can be combined. This seems a bit clearer. --- winit/src/program.rs | 183 ++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 100 deletions(-) diff --git a/winit/src/program.rs b/winit/src/program.rs index f3b1ae9db7..e4b0f12041 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -888,11 +888,7 @@ async fn run_instance<'a, P, C>( let state = &window.state; let icon_surface = icon_surface .map(|i| { - let i: Box = i; - i - }) - .map(|i| { - i.downcast::( >, core::widget::tree::State, )>>() - .unwrap() - }) - .map( - |e: Box< - Arc<( - core::Element< - 'static, - (), - P::Theme, - P::Renderer, - >, - core::widget::tree::State, - )>, - >| { - let mut renderer = compositor.create_renderer(); - - let e = Arc::into_inner(*e).unwrap(); - let (mut e, widget_state) = e; - let lim = core::layout::Limits::new( - Size::new(1., 1.), - Size::new( - state.viewport().physical_width() - as f32, - state.viewport().physical_height() - as f32, - ), - ); - - let mut tree = core::widget::Tree { - id: e.as_widget().id(), - tag: e.as_widget().tag(), - state: widget_state, - children: e.as_widget().children(), - }; - - let size = e - .as_widget() - .layout(&mut tree, &renderer, &lim); - e.as_widget_mut().diff(&mut tree); + .unwrap(); + let e = Arc::into_inner(*e).unwrap(); + let (mut e, widget_state) = e; + + let mut renderer = compositor.create_renderer(); + + let lim = core::layout::Limits::new( + Size::new(1., 1.), + Size::new( + state.viewport().physical_width() + as f32, + state.viewport().physical_height() + as f32, + ), + ); - let size = lim.resolve( - Length::Shrink, - Length::Shrink, - size.size(), - ); - let viewport = Viewport::with_logical_size( - size, - state.viewport().scale_factor(), - ); + let mut tree = core::widget::Tree { + id: e.as_widget().id(), + tag: e.as_widget().tag(), + state: widget_state, + children: e.as_widget().children(), + }; + + let size = e + .as_widget() + .layout(&mut tree, &renderer, &lim); + e.as_widget_mut().diff(&mut tree); + + let size = lim.resolve( + Length::Shrink, + Length::Shrink, + size.size(), + ); + let viewport = Viewport::with_logical_size( + size, + state.viewport().scale_factor(), + ); - let mut ui = UserInterface::build( - e, - size, - user_interface::Cache::default(), - &mut renderer, - ); - _ = ui.draw( - &mut renderer, - state.theme(), - &renderer::Style { - icon_color: state.icon_color(), - text_color: state.text_color(), - scale_factor: state.scale_factor(), - }, - Default::default(), - );; - let mut bytes = compositor.screenshot( - &mut renderer, - &viewport, - core::Color::TRANSPARENT, - &debug.overlay(), - ); - for pix in bytes.chunks_exact_mut(4) { - // rgba -> argb little endian - pix.swap(0, 2); - } - // update subsurfaces - if let Some(surface) = platform_specific_handler.create_surface() { - // TODO Remove id - let id = window::Id::unique(); - platform_specific_handler - .update_subsurfaces(id, &surface); - platform_specific_handler.update_surface_shm(&surface, viewport.physical_width(), viewport.physical_height(), &bytes); - let surface = Arc::new(surface); - dnd_surface = Some(surface.clone()); - Icon::Surface(dnd::DndSurface(surface)) - } else { - platform_specific_handler - .clear_subsurface_list(); - Icon::Buffer { - data: Arc::new(bytes), - width: viewport.physical_width(), - height: viewport.physical_height(), - transparent: true, - } + let mut ui = UserInterface::build( + e, + size, + user_interface::Cache::default(), + &mut renderer, + ); + _ = ui.draw( + &mut renderer, + state.theme(), + &renderer::Style { + icon_color: state.icon_color(), + text_color: state.text_color(), + scale_factor: state.scale_factor(), + }, + Default::default(), + );; + let mut bytes = compositor.screenshot( + &mut renderer, + &viewport, + core::Color::TRANSPARENT, + &debug.overlay(), + ); + for pix in bytes.chunks_exact_mut(4) { + // rgba -> argb little endian + pix.swap(0, 2); + } + // update subsurfaces + if let Some(surface) = platform_specific_handler.create_surface() { + // TODO Remove id + let id = window::Id::unique(); + platform_specific_handler + .update_subsurfaces(id, &surface); + platform_specific_handler.update_surface_shm(&surface, viewport.physical_width(), viewport.physical_height(), &bytes); + let surface = Arc::new(surface); + dnd_surface = Some(surface.clone()); + Icon::Surface(dnd::DndSurface(surface)) + } else { + platform_specific_handler + .clear_subsurface_list(); + Icon::Buffer { + data: Arc::new(bytes), + width: viewport.physical_width(), + height: viewport.physical_height(), + transparent: true, } - }, - ); + } + }); clipboard.start_dnd_winit( internal, From 1173c1ce26a53ec81bb6c390ce21cc9847dcc18b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 3 Jan 2025 13:16:13 -0800 Subject: [PATCH 2/6] Don't use `Box>` and `Arc::into_inner` unnecessarily --- core/src/clipboard.rs | 4 ++-- winit/src/program.rs | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/clipboard.rs b/core/src/clipboard.rs index 0197354f67..1ea53145e6 100644 --- a/core/src/clipboard.rs +++ b/core/src/clipboard.rs @@ -1,6 +1,6 @@ //! Access the clipboard. -use std::{any::Any, sync::Arc}; +use std::any::Any; use dnd::{DndAction, DndDestinationRectangle, DndSurface}; use mime::{self, AllowedMimeTypes, AsMimeTypes, ClipboardStoreData}; @@ -98,7 +98,7 @@ pub fn start_dnd( internal, source_surface, icon_surface.map(|i| { - let i: Box = Box::new(Arc::new(i)); + let i: Box = Box::new(i); i }), content, diff --git a/winit/src/program.rs b/winit/src/program.rs index e4b0f12041..367f550c0a 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -888,7 +888,7 @@ async fn run_instance<'a, P, C>( let state = &window.state; let icon_surface = icon_surface .map(|i| { - let e = i.downcast::( P::Renderer, >, core::widget::tree::State, - )>>() + )>() .unwrap(); - let e = Arc::into_inner(*e).unwrap(); - let (mut e, widget_state) = e; + let (mut e, widget_state) = *e; let mut renderer = compositor.create_renderer(); From b48a5f3ed52166e857e80fbdf8f22ae0699ed66b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 3 Jan 2025 14:21:35 -0800 Subject: [PATCH 3/6] runtime: Remove `start_dnd` This is not currently used. And is impossible to (soundly) use, since it requires a `Send` bound, which `State` and `Element` lack. --- runtime/src/dnd.rs | 43 ------------------------------------------- winit/src/program.rs | 15 --------------- 2 files changed, 58 deletions(-) diff --git a/runtime/src/dnd.rs b/runtime/src/dnd.rs index 69c956f686..e6f2b2678a 100644 --- a/runtime/src/dnd.rs +++ b/runtime/src/dnd.rs @@ -17,19 +17,6 @@ pub enum DndAction { /// The rectangles to register. rectangles: Vec, }, - /// Start a Dnd operation. - StartDnd { - /// Whether the Dnd operation is internal. - internal: bool, - /// The source surface of the Dnd operation. - source_surface: Option, - /// The icon surface of the Dnd operation. - icon_surface: Option>, - /// The content of the Dnd operation. - content: Box, - /// The actions of the Dnd operation. - actions: dnd::DndAction, - }, /// End a Dnd operation. EndDnd, /// Peek the current Dnd operation. @@ -53,19 +40,6 @@ impl std::fmt::Debug for DndAction { .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() @@ -99,23 +73,6 @@ pub fn register_dnd_destination( })) } -/// Start a Dnd operation. -pub fn start_dnd( - internal: bool, - source_surface: Option, - icon_surface: Option>, - content: Box, - actions: dnd::DndAction, -) -> Task { - task::effect(Action::Dnd(DndAction::StartDnd { - internal, - source_surface, - icon_surface, - content, - actions, - })) -} - /// End a Dnd operation. pub fn end_dnd() -> Task { task::effect(Action::Dnd(DndAction::EndDnd)) diff --git a/winit/src/program.rs b/winit/src/program.rs index 367f550c0a..28254304e9 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -2279,21 +2279,6 @@ where } => { clipboard.register_dnd_destination(surface, rectangles); } - iced_runtime::dnd::DndAction::StartDnd { - internal, - source_surface, - icon_surface, - content, - actions, - } => { - clipboard.start_dnd( - internal, - source_surface, - icon_surface.map(|d| d as Box), - content, - actions, - ); - } iced_runtime::dnd::DndAction::EndDnd => { clipboard.end_dnd(); } From b58c55d9447526525c2aef24d689967cc7d016f8 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 3 Jan 2025 14:33:11 -0800 Subject: [PATCH 4/6] Define a `IconSurface` for drag and drop instead of tuple, box dyn This makes it easier to add a field, and makes the handling of upcasting/downcasting a more organized. --- core/src/clipboard.rs | 44 +++++++++++++++++++++++++++++++++++------- winit/src/clipboard.rs | 6 +++--- winit/src/program.rs | 26 ++++++++----------------- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/core/src/clipboard.rs b/core/src/clipboard.rs index 1ea53145e6..160ca46f07 100644 --- a/core/src/clipboard.rs +++ b/core/src/clipboard.rs @@ -7,6 +7,39 @@ use mime::{self, AllowedMimeTypes, AsMimeTypes, ClipboardStoreData}; use crate::{widget::tree::State, window, Element}; +#[derive(Debug)] +pub struct IconSurface { + pub element: E, + pub state: State, +} + +pub type DynIconSurface = IconSurface>; + +impl IconSurface> { + pub fn new(element: Element<'static, (), T, R>, state: State) -> Self { + Self { element, state } + } + + fn upcast(self) -> DynIconSurface { + IconSurface { + element: Box::new(self.element), + state: self.state, + } + } +} + +impl DynIconSurface { + /// Downcast `element` to concrete type `Element<(), T, R>` + /// + /// Panics if type doesn't match + pub fn downcast(self) -> IconSurface> { + IconSurface { + element: *self.element.downcast().expect("drag-and-drop icon surface has invalid element type"), + state: self.state, + } + } +} + /// A buffer for short-term storage and transfer within and between /// applications. pub trait Clipboard { @@ -53,7 +86,7 @@ pub trait Clipboard { &mut self, _internal: bool, _source_surface: Option, - _icon_surface: Option>, + _icon_surface: Option, _content: Box, _actions: DndAction, ) { @@ -86,21 +119,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( +pub fn start_dnd( clipboard: &mut dyn Clipboard, internal: bool, source_surface: Option, - icon_surface: Option<(Element<'static, M, T, R>, State)>, + icon_surface: Option>>, content: Box, actions: DndAction, ) { clipboard.start_dnd( internal, source_surface, - icon_surface.map(|i| { - let i: Box = Box::new(i); - i - }), + icon_surface.map(IconSurface::upcast), content, actions, ); diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs index 26381d2554..097e65ca1e 100644 --- a/winit/src/clipboard.rs +++ b/winit/src/clipboard.rs @@ -3,7 +3,7 @@ use std::sync::Mutex; use std::{any::Any, borrow::Cow}; -use crate::core::clipboard::DndSource; +use crate::core::clipboard::{DndSource, DynIconSurface}; use crate::core::clipboard::Kind; use std::sync::Arc; use winit::dpi::LogicalSize; @@ -26,7 +26,7 @@ pub struct Clipboard { pub(crate) struct StartDnd { pub(crate) internal: bool, pub(crate) source_surface: Option, - pub(crate) icon_surface: Option>, + pub(crate) icon_surface: Option, pub(crate) content: Box, pub(crate) actions: DndAction, } @@ -261,7 +261,7 @@ impl crate::core::Clipboard for Clipboard { &mut self, internal: bool, source_surface: Option, - icon_surface: Option>, + icon_surface: Option, content: Box, actions: DndAction, ) { diff --git a/winit/src/program.rs b/winit/src/program.rs index 28254304e9..c9de2e2bd5 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -888,17 +888,7 @@ async fn run_instance<'a, P, C>( let state = &window.state; let icon_surface = icon_surface .map(|i| { - let e = i.downcast::<( - core::Element< - 'static, - (), - P::Theme, - P::Renderer, - >, - core::widget::tree::State, - )>() - .unwrap(); - let (mut e, widget_state) = *e; + let mut icon_surface = i.downcast::(); let mut renderer = compositor.create_renderer(); @@ -913,16 +903,16 @@ async fn run_instance<'a, P, C>( ); let mut tree = core::widget::Tree { - id: e.as_widget().id(), - tag: e.as_widget().tag(), - state: widget_state, - children: e.as_widget().children(), + id: icon_surface.element.as_widget().id(), + tag: icon_surface.element.as_widget().tag(), + state: icon_surface.state, + children: icon_surface.element.as_widget().children(), }; - let size = e + let size = icon_surface.element .as_widget() .layout(&mut tree, &renderer, &lim); - e.as_widget_mut().diff(&mut tree); + icon_surface.element.as_widget_mut().diff(&mut tree); let size = lim.resolve( Length::Shrink, @@ -935,7 +925,7 @@ async fn run_instance<'a, P, C>( ); let mut ui = UserInterface::build( - e, + icon_surface.element, size, user_interface::Cache::default(), &mut renderer, From 3a598ad4638c88ededb8c937380ccfd50bb70d51 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 3 Jan 2025 15:00:11 -0800 Subject: [PATCH 5/6] Add an `offset` to `IconSurface`, so icon can be offset from custor --- core/src/clipboard.rs | 9 ++++++--- winit/src/platform_specific/mod.rs | 6 +++--- winit/src/platform_specific/wayland/mod.rs | 6 +++--- winit/src/platform_specific/wayland/subsurface_widget.rs | 5 +++-- winit/src/program.rs | 8 +++++++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/core/src/clipboard.rs b/core/src/clipboard.rs index 160ca46f07..4dc64c5842 100644 --- a/core/src/clipboard.rs +++ b/core/src/clipboard.rs @@ -5,25 +5,27 @@ 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 { pub element: E, pub state: State, + pub offset: Vector, } pub type DynIconSurface = IconSurface>; impl IconSurface> { - pub fn new(element: Element<'static, (), T, R>, state: State) -> Self { - Self { element, state } + 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, } } } @@ -36,6 +38,7 @@ impl DynIconSurface { IconSurface { element: *self.element.downcast().expect("drag-and-drop icon surface has invalid element type"), state: self.state, + offset: self.offset, } } } diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index 5490bfac77..b3f516c3bd 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -4,7 +4,7 @@ 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; #[cfg(all(feature = "wayland", target_os = "linux"))] @@ -128,10 +128,10 @@ impl PlatformSpecific { 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, 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, data, offset); } } } diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 1b3b8cf5b8..267e501a71 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -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}; @@ -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, 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, data, offset); } } } diff --git a/winit/src/platform_specific/wayland/subsurface_widget.rs b/winit/src/platform_specific/wayland/subsurface_widget.rs index 5cde0e96bb..18730bce58 100644 --- a/winit/src/platform_specific/wayland/subsurface_widget.rs +++ b/winit/src/platform_specific/wayland/subsurface_widget.rs @@ -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, @@ -377,13 +377,14 @@ 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, data: &[u8], offset: Vector) { 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); surface.commit(); } diff --git a/winit/src/program.rs b/winit/src/program.rs index c9de2e2bd5..f61d32f693 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -886,6 +886,7 @@ async fn run_instance<'a, P, C>( }; let state = &window.state; + let mut dnd_buffer = None; let icon_surface = icon_surface .map(|i| { let mut icon_surface = i.downcast::(); @@ -956,9 +957,9 @@ async fn run_instance<'a, P, C>( let id = window::Id::unique(); platform_specific_handler .update_subsurfaces(id, &surface); - platform_specific_handler.update_surface_shm(&surface, viewport.physical_width(), viewport.physical_height(), &bytes); let surface = Arc::new(surface); dnd_surface = Some(surface.clone()); + dnd_buffer = Some((viewport.physical_size(), bytes, icon_surface.offset)); Icon::Surface(dnd::DndSurface(surface)) } else { platform_specific_handler @@ -979,6 +980,11 @@ async fn run_instance<'a, P, C>( content, actions, ); + + // This needs to be after `wl_data_device::start_drag` for the offset to have an effect + if let (Some(surface), Some((size, bytes, offset))) = (dnd_surface.as_ref(), dnd_buffer) { + platform_specific_handler.update_surface_shm(&surface, size.width, size.height, &bytes, offset); + } } } Event::WindowCreated { From cbd34fbae1e6204e1990466ece2a3f0c903c5076 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 7 Jan 2025 13:52:08 -0800 Subject: [PATCH 6/6] winit/wayland: Apply scale when creating drag surface --- winit/src/platform_specific/mod.rs | 4 ++-- winit/src/platform_specific/wayland/mod.rs | 4 ++-- winit/src/platform_specific/wayland/subsurface_widget.rs | 9 ++++++++- winit/src/program.rs | 6 +++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index b3f516c3bd..77e851802c 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -128,10 +128,10 @@ impl PlatformSpecific { None } - pub(crate) fn update_surface_shm(&mut self, surface: &dyn HasWindowHandle, width: u32, height: u32, data: &[u8], offset: Vector) { + 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, offset); + return self.wayland.update_surface_shm(surface, width, height, scale, data, offset); } } } diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 267e501a71..16c316c0a7 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -239,12 +239,12 @@ impl WaylandSpecific { } } - pub(crate) fn update_surface_shm(&mut self, window: &dyn HasWindowHandle, width: u32, height: u32, data: &[u8], offset: Vector) { + 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, offset); + subsurface_state.update_surface_shm(&surface, width, height, scale, data, offset); } } } diff --git a/winit/src/platform_specific/wayland/subsurface_widget.rs b/winit/src/platform_specific/wayland/subsurface_widget.rs index 18730bce58..288dbb6106 100644 --- a/winit/src/platform_specific/wayland/subsurface_widget.rs +++ b/winit/src/platform_specific/wayland/subsurface_widget.rs @@ -377,7 +377,12 @@ impl SubsurfaceState { .create_surface(&self.qh, SurfaceData::new(None, 1)) } - pub fn update_surface_shm(&self, surface: &WlSurface, width: u32, height: u32, data: &[u8], offset: Vector) { + 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(); @@ -385,7 +390,9 @@ impl SubsurfaceState { 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 { diff --git a/winit/src/program.rs b/winit/src/program.rs index f61d32f693..1640702925 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -959,7 +959,7 @@ async fn run_instance<'a, P, C>( .update_subsurfaces(id, &surface); let surface = Arc::new(surface); dnd_surface = Some(surface.clone()); - dnd_buffer = Some((viewport.physical_size(), bytes, icon_surface.offset)); + dnd_buffer = Some((viewport.physical_size(), state.scale_factor(), bytes, icon_surface.offset)); Icon::Surface(dnd::DndSurface(surface)) } else { platform_specific_handler @@ -982,8 +982,8 @@ async fn run_instance<'a, P, C>( ); // This needs to be after `wl_data_device::start_drag` for the offset to have an effect - if let (Some(surface), Some((size, bytes, offset))) = (dnd_surface.as_ref(), dnd_buffer) { - platform_specific_handler.update_surface_shm(&surface, size.width, size.height, &bytes, offset); + if let (Some(surface), Some((size, scale, bytes, offset))) = (dnd_surface.as_ref(), dnd_buffer) { + platform_specific_handler.update_surface_shm(&surface, size.width, size.height, scale, &bytes, offset); } } }