Skip to content

Commit

Permalink
WIP Subsurfaces for drag surfaces
Browse files Browse the repository at this point in the history
Use `Icon::Surface` instead of `Icon::Buffer`, so we can then create
subsurfaces of the `wl_surface`.

Using `.screenshot()` then copying to an shm buffer is suboptimal, but
this does seem overall better than with the older Iced version when a
drag surface didn't appear until a Vulkan surface could be created for
it.
  • Loading branch information
ids1024 committed Dec 17, 2024
1 parent 2cc6865 commit e607384
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ wasm-timer = "0.2"
web-time = "1.1"
wgpu = "22.0"
wayland-protocols = { version = "0.32.1", features = ["staging"] }
wayland-client = { version = "0.31.5" }
# web-time = "1.1"


Expand Down
2 changes: 2 additions & 0 deletions winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ cctk.workspace = true
cctk.optional = true
wayland-protocols.workspace = true
wayland-protocols.optional = true
wayland-client.workspace = true
wayland-backend = { version = "0.3.1", features = [
"client_system",
], optional = true }
xkbcommon = { version = "0.7", features = ["wayland"], optional = true }
xkbcommon-dl = { version = "0.4.1", optional = true }
xkeysym = { version = "0.2.0", optional = true }
rustix = { version = "0.38" }

[target.'cfg(target_os = "windows")'.dependencies]
winapi.workspace = true
Expand Down
18 changes: 14 additions & 4 deletions winit/src/platform_specific/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::HashMap;

use iced_graphics::Compositor;
use iced_runtime::{core::window, 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 / 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 / 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`

#[cfg(all(feature = "wayland", target_os = "linux"))]
pub mod wayland;
Expand Down Expand Up @@ -69,7 +70,7 @@ impl PlatformSpecific {
pub(crate) fn update_subsurfaces(
&mut self,
id: window::Id,
window: &dyn winit::window::Window,
window: &dyn HasWindowHandle,
) {
#[cfg(all(feature = "wayland", target_os = "linux"))]
{
Expand All @@ -78,12 +79,13 @@ impl PlatformSpecific {
};
use wayland_backend::client::ObjectId;

let Ok(backend) = window.rwh_06_display_handle().display_handle()
let Some(backend) = self.wayland.display_handle()
else {
log::error!("No display handle");
return;
};

// TODO use existing conn
let conn = match backend.as_raw() {
raw_window_handle::RawDisplayHandle::Wayland(
wayland_display_handle,
Expand All @@ -102,7 +104,7 @@ impl PlatformSpecific {
}
};

let Ok(raw) = window.rwh_06_window_handle().window_handle() else {
let Ok(raw) = window.window_handle() else {
log::error!("Invalid window handle {id:?}");
return;
};
Expand Down Expand Up @@ -137,6 +139,14 @@ impl PlatformSpecific {
self.wayland.update_subsurfaces(id, &wl_surface);
}
}

pub(crate) fn create_surface(&mut self, width: u32, height: u32, data: &[u8]) -> Option<Box<dyn HasWindowHandle + Send + Sync + 'static>> {
#[cfg(all(feature = "wayland", target_os = "linux"))]
{
return self.wayland.create_surface(width, height, data);
}
None
}
}

pub type UserInterfaces<'a, P> = HashMap<
Expand Down Expand Up @@ -185,4 +195,4 @@ pub(crate) fn handle_event<'a, P, C>(
);
}
}
}
}
36 changes: 36 additions & 0 deletions winit/src/platform_specific/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ impl PlatformSpecific {
}

impl WaylandSpecific {
pub(crate) fn display_handle(&self) -> Option<DisplayHandle> {
self.display_handle.as_ref()?.display_handle().ok()
}

pub(crate) fn handle_event<'a, P, C>(
&mut self,
e: SctkEvent,
Expand Down Expand Up @@ -199,5 +203,37 @@ impl WaylandSpecific {
surface_subsurfaces,
&subsurfaces,
);

wl_surface.commit(); // XXX for drag surface
}

// WIP cfg raw-window-handle
pub(crate) fn create_surface(&mut self, width: u32, height: u32, data: &[u8]) -> Option<Box<dyn HasWindowHandle + Send + Sync + 'static>> {
if let Some(subsurface_state) = self.subsurface_state.as_mut() {
let wl_surface = subsurface_state.create_surface(width, height, data);
Some(Box::new(Window(wl_surface)))
} else {
None
}
}
}
struct Window(WlSurface);
impl HasWindowHandle for Window {
fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
Ok(unsafe {
raw_window_handle::WindowHandle::borrow_raw(raw_window_handle::RawWindowHandle::Wayland(
raw_window_handle::WaylandWindowHandle::new(
std::ptr::NonNull::new(self.0.id().as_ptr() as *mut _).unwrap(),
),
))
})
}
}
impl Drop for Window {
fn drop(&mut self) {
// TODO destroy when drag ends
//self.0.destroy();
}
}
use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};
use wayland_client::Proxy;
47 changes: 46 additions & 1 deletion winit/src/platform_specific/wayland/subsurface_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ use std::{
use crate::futures::futures::channel::oneshot;
use cctk::sctk::{
compositor::SurfaceData,
globals::GlobalData,
error::GlobalError,
globals::{GlobalData, ProvidesBoundGlobal},
shm::slot::SlotPool,
reexports::client::{
delegate_noop,
protocol::{
Expand Down Expand Up @@ -251,6 +253,7 @@ impl PartialEq for SubsurfaceBuffer {
}
}


impl Dispatch<WlShmPool, GlobalData> for SctkState {
fn event(
_: &mut SctkState,
Expand Down Expand Up @@ -288,6 +291,23 @@ impl Dispatch<ZwpLinuxBufferParamsV1, GlobalData> for SctkState {
}
}

impl Dispatch<WlBuffer, GlobalData> for SctkState {
fn event(
_: &mut SctkState,
_: &WlBuffer,
event: wl_buffer::Event,
_: &GlobalData,
_: &Connection,
_: &QueueHandle<SctkState>,
) {
match event {
wl_buffer::Event::Release => {
}
_ => unreachable!(),
}
}
}

impl Dispatch<WlBuffer, BufferData> for SctkState {
fn event(
_: &mut SctkState,
Expand Down Expand Up @@ -325,6 +345,15 @@ impl Hash for WeakBufferSource {
}
}

// Implement `ProvidesBoundGlobal` to use `SlotPool`
struct ShmGlobal<'a>(&'a WlShm);

impl<'a> ProvidesBoundGlobal<WlShm, 1> for ShmGlobal<'a> {
fn bound_global(&self) -> Result<WlShm, GlobalError> {
Ok(self.0.clone())
}
}

// create wl_buffer from BufferSource (avoid create_immed?)
// release
#[derive(Debug, Clone)]
Expand All @@ -342,6 +371,21 @@ pub struct SubsurfaceState {
}

impl SubsurfaceState {
pub fn create_surface(&self, width: u32, height: u32, data: &[u8]) -> WlSurface {
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);

let surface = self
.wl_compositor
.create_surface(&self.qh, SurfaceData::new(None, 1));
surface.damage_buffer(0, 0, width as i32, height as i32);
buffer.attach_to(&surface);
surface.commit();
surface
}

fn create_subsurface(&self, parent: &WlSurface) -> SubsurfaceInstance {
let wl_surface = self
.wl_compositor
Expand Down Expand Up @@ -572,6 +616,7 @@ impl Drop for SubsurfaceInstance {
}
}

#[derive(Debug)]
pub(crate) struct SubsurfaceInfo {
pub buffer: SubsurfaceBuffer,
pub bounds: Rectangle<f32>,
Expand Down
29 changes: 19 additions & 10 deletions winit/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,9 +964,7 @@ async fn run_instance<'a, P, C>(
scale_factor: state.scale_factor(),
},
Default::default(),
);
platform_specific_handler
.clear_subsurface_list();
);;

Check warning on line 967 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

unnecessary trailing semicolon

Check warning on line 967 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / wasm

unnecessary trailing semicolon

Check warning on line 967 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / web

unnecessary trailing semicolon

Check warning on line 967 in winit/src/program.rs

View workflow job for this annotation

GitHub Actions / wasm

unnecessary trailing semicolon
let mut bytes = compositor.screenshot(
&mut renderer,
&viewport,
Expand All @@ -977,17 +975,28 @@ async fn run_instance<'a, P, C>(
// rgba -> argb little endian
pix.swap(0, 2);
}
Icon::Buffer {
data: Arc::new(bytes),
width: viewport.physical_width(),
height: viewport.physical_height(),
transparent: true,
// update subsurfaces
if let Some(surface) = platform_specific_handler.create_surface(viewport.physical_width(), viewport.physical_height(), &bytes) {
let id = window::Id::unique(); // XXX remove at end of drag
platform_specific_handler
.update_subsurfaces(id, &surface);
Icon::Surface(dnd::DndSurface(Arc::new(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,
// false
DndSurface(Arc::new(Box::new(window.raw.clone()))),
icon_surface,
content,
Expand Down Expand Up @@ -1191,7 +1200,7 @@ async fn run_instance<'a, P, C>(
cursor,
);
platform_specific_handler
.update_subsurfaces(id, window.raw.as_ref());
.update_subsurfaces(id, window.raw.rwh_06_window_handle());
debug.draw_finished();

if new_mouse_interaction != window.mouse_interaction {
Expand Down Expand Up @@ -1276,7 +1285,7 @@ async fn run_instance<'a, P, C>(
window.state.cursor(),
);
platform_specific_handler
.update_subsurfaces(id, window.raw.as_ref());
.update_subsurfaces(id, window.raw.rwh_06_window_handle());
debug.draw_finished();

if new_mouse_interaction != window.mouse_interaction
Expand Down

0 comments on commit e607384

Please sign in to comment.