diff --git a/src/cursor.rs b/src/cursor.rs index 3091c8ad..4a3ffa6f 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -29,6 +29,7 @@ const HEADER_SIZE: u32 = 16; pub trait Cursor { fn set_position(&self, x: i32, y: i32); fn render(&self, renderer: &mut Renderer, x: i32, y: i32); + fn get_hotspot(&self) -> (i32, i32); fn extents(&self) -> Rect; fn handle_unset(&self) {} fn tick(&self) {} @@ -208,6 +209,10 @@ impl Cursor for StaticCursor { renderer.render_texture(&self.image.tex, x, y, ARGB8888); } + fn get_hotspot(&self) -> (i32, i32) { + (self.image.xhot, self.image.yhot) + } + fn extents(&self) -> Rect { self.extents.get() } @@ -235,6 +240,11 @@ impl Cursor for AnimatedCursor { renderer.render_texture(&img.tex, x, y, ARGB8888); } + fn get_hotspot(&self) -> (i32, i32) { + let img = &self.images[self.idx.get()]; + (img.xhot, img.yhot) + } + fn extents(&self) -> Rect { self.extents.get() } diff --git a/src/ifs/ipc/mod.rs b/src/ifs/ipc/mod.rs index 78c22f4c..64150243 100644 --- a/src/ifs/ipc/mod.rs +++ b/src/ifs/ipc/mod.rs @@ -173,7 +173,6 @@ pub fn cancel_offers(src: &T::Source) { let data = T::get_source_data(src); while let Some((_, offer)) = data.offers.pop() { let data = T::get_offer_data(&offer); - log::error!("cancel_offers"); data.source.take(); destroy_offer::(&offer); } @@ -268,7 +267,6 @@ fn destroy_offer(offer: &T::Offer) { } } } - log::error!("destroy_offer"); if let Some(src) = data.source.take() { let src_data = T::get_source_data(&src); src_data.offers.remove(&T::get_offer_id(offer)); diff --git a/src/ifs/ipc/wl_data_device.rs b/src/ifs/ipc/wl_data_device.rs index 18595ff0..62c5e056 100644 --- a/src/ifs/ipc/wl_data_device.rs +++ b/src/ifs/ipc/wl_data_device.rs @@ -15,6 +15,7 @@ use crate::wire::{WlDataDeviceId, WlDataOfferId, WlSurfaceId}; use std::rc::Rc; use thiserror::Error; use uapi::OwnedFd; +use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceError}; #[allow(dead_code)] const ROLE: u32 = 0; @@ -86,7 +87,14 @@ impl WlDataDevice { } else { None }; - self.seat.global.start_drag(&origin, source)?; + let icon = if req.icon.is_some() { + let icon = self.manager.client.lookup(req.icon)?; + icon.set_role(SurfaceRole::DndIcon)?; + Some(icon) + } else { + None + }; + self.seat.global.start_drag(&origin, source, icon)?; Ok(()) } @@ -225,6 +233,8 @@ pub enum StartDragError { #[error("Parsing failed")] ParseFailed(#[source] Box), #[error(transparent)] + WlSurfaceError(Box), + #[error(transparent)] ClientError(Box), #[error(transparent)] WlSeatError(Box), @@ -232,6 +242,7 @@ pub enum StartDragError { efrom!(StartDragError, ParseFailed, MsgParserError); efrom!(StartDragError, ClientError); efrom!(StartDragError, WlSeatError); +efrom!(StartDragError, WlSurfaceError); #[derive(Debug, Error)] pub enum SetSelectionError { diff --git a/src/ifs/ipc/wl_data_source.rs b/src/ifs/ipc/wl_data_source.rs index 696e17f4..e98998d9 100644 --- a/src/ifs/ipc/wl_data_source.rs +++ b/src/ifs/ipc/wl_data_source.rs @@ -68,12 +68,6 @@ impl WlDataSource { } else { 0 }; - log::info!( - "sa = {}, ra = {}, action = {}", - server_actions, - shared.receiver_actions.get(), - action - ); if shared.selected_action.replace(action) != action { for (_, offer) in &self.data.offers { offer.send_action(action); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index f5820318..567dfb00 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -191,8 +191,9 @@ impl WlSeatGlobal { self: &Rc, origin: &Rc, source: Option>, + icon: Option>, ) -> Result<(), WlSeatError> { - self.pointer_owner.start_drag(self, origin, source) + self.pointer_owner.start_drag(self, origin, source, icon) } pub fn cancel_dnd(self: &Rc) { @@ -253,6 +254,14 @@ impl WlSeatGlobal { self.cursor.set(cursor); } + pub fn dnd_icon(&self) -> Option> { + self.pointer_owner.dnd_icon() + } + + pub fn remove_dnd_icon(&self) { + self.pointer_owner.remove_dnd_icon(); + } + pub fn get_cursor(&self) -> Option> { self.cursor.get() } diff --git a/src/ifs/wl_seat/pointer_owner.rs b/src/ifs/wl_seat/pointer_owner.rs index b20b3e6e..90f659c4 100644 --- a/src/ifs/wl_seat/pointer_owner.rs +++ b/src/ifs/wl_seat/pointer_owner.rs @@ -4,7 +4,7 @@ use crate::ifs::ipc; use crate::ifs::ipc::wl_data_device::WlDataDevice; use crate::ifs::ipc::wl_data_source::WlDataSource; use crate::ifs::wl_seat::{Dnd, DroppedDnd, WlSeatError, WlSeatGlobal}; -use crate::ifs::wl_surface::WlSurface; +use crate::ifs::wl_surface::{WlSurface}; use crate::tree::{FoundNode, Node}; use crate::utils::clonecell::CloneCell; use crate::utils::smallmap::SmallMap; @@ -43,8 +43,9 @@ impl PointerOwnerHolder { seat: &Rc, origin: &Rc, source: Option>, + icon: Option>, ) -> Result<(), WlSeatError> { - self.owner.get().start_drag(seat, origin, source) + self.owner.get().start_drag(seat, origin, source, icon) } pub fn cancel_dnd(&self, seat: &Rc) { @@ -58,6 +59,14 @@ impl PointerOwnerHolder { pub fn dnd_target_removed(&self, seat: &Rc) { self.owner.get().dnd_target_removed(seat); } + + pub fn dnd_icon(&self) -> Option> { + self.owner.get().dnd_icon() + } + + pub fn remove_dnd_icon(&self) { + self.owner.get().remove_dnd_icon() + } } trait PointerOwner { @@ -69,10 +78,13 @@ trait PointerOwner { seat: &Rc, origin: &Rc, source: Option>, + icon: Option>, ) -> Result<(), WlSeatError>; fn cancel_dnd(&self, seat: &Rc); fn revert_to_default(&self, seat: &Rc); fn dnd_target_removed(&self, seat: &Rc); + fn dnd_icon(&self) -> Option>; + fn remove_dnd_icon(&self); } struct DefaultPointerOwner; @@ -86,6 +98,7 @@ struct DndPointerOwner { button: u32, dnd: Dnd, target: CloneCell>, + icon: CloneCell>>, pos_x: Cell, pos_y: Cell, } @@ -171,8 +184,12 @@ impl PointerOwner for DefaultPointerOwner { &self, _seat: &Rc, _origin: &Rc, - _source: Option>, + source: Option>, + _icon: Option>, ) -> Result<(), WlSeatError> { + if let Some(src) = source { + src.send_cancelled(); + } Ok(()) } @@ -187,6 +204,14 @@ impl PointerOwner for DefaultPointerOwner { fn dnd_target_removed(&self, seat: &Rc) { self.cancel_dnd(seat); } + + fn dnd_icon(&self) -> Option> { + None + } + + fn remove_dnd_icon(&self) { + // nothing + } } impl PointerOwner for GrabPointerOwner { @@ -226,6 +251,7 @@ impl PointerOwner for GrabPointerOwner { seat: &Rc, origin: &Rc, src: Option>, + icon: Option>, ) -> Result<(), WlSeatError> { let button = match self.buttons.iter().next() { Some((b, _)) => b, @@ -237,6 +263,9 @@ impl PointerOwner for GrabPointerOwner { if self.node.id() != origin.node_id { return Ok(()); } + if let Some(icon) = &icon { + icon.dnd_icons.insert(seat.id(), seat.clone()); + } if let Some(new) = &src { ipc::attach_seat::(&new, seat, ipc::Role::Dnd)?; } @@ -249,6 +278,7 @@ impl PointerOwner for GrabPointerOwner { src, }, target: CloneCell::new(seat.state.root.clone()), + icon: CloneCell::new(icon), pos_x: Cell::new(Fixed::from_int(0)), pos_y: Cell::new(Fixed::from_int(0)), }); @@ -284,6 +314,14 @@ impl PointerOwner for GrabPointerOwner { fn dnd_target_removed(&self, seat: &Rc) { self.cancel_dnd(seat) } + + fn dnd_icon(&self) -> Option> { + None + } + + fn remove_dnd_icon(&self) { + // nothing + } } impl PointerOwner for DndPointerOwner { @@ -309,6 +347,9 @@ impl PointerOwner for DndPointerOwner { ipc::detach_seat::(src); } } + if let Some(icon) = self.icon.get() { + icon.dnd_icons.remove(&seat.id()); + } seat.pointer_owner .owner .set(seat.pointer_owner.default.clone()); @@ -354,8 +395,12 @@ impl PointerOwner for DndPointerOwner { &self, _seat: &Rc, _origin: &Rc, - _source: Option>, + source: Option>, + _icon: Option>, ) -> Result<(), WlSeatError> { + if let Some(src) = source { + src.send_cancelled(); + } Ok(()) } @@ -366,6 +411,9 @@ impl PointerOwner for DndPointerOwner { if let Some(src) = &self.dnd.src { ipc::detach_seat::(src); } + if let Some(icon) = self.icon.get() { + icon.dnd_icons.remove(&seat.id()); + } seat.pointer_owner .owner .set(seat.pointer_owner.default.clone()); @@ -381,4 +429,12 @@ impl PointerOwner for DndPointerOwner { self.target.set(seat.state.root.clone()); seat.state.tree_changed(); } + + fn dnd_icon(&self) -> Option> { + self.icon.get() + } + + fn remove_dnd_icon(&self) { + self.icon.set(None); + } } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index b9449603..f2efbb5a 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -44,6 +44,7 @@ pub enum SurfaceRole { Subsurface, XdgSurface, Cursor, + DndIcon, } impl SurfaceRole { @@ -53,6 +54,7 @@ impl SurfaceRole { SurfaceRole::Subsurface => "subsurface", SurfaceRole::XdgSurface => "xdg_surface", SurfaceRole::Cursor => "cursor", + SurfaceRole::DndIcon => "dnd_icon", } } } @@ -77,6 +79,7 @@ pub struct WlSurface { seat_state: NodeSeatState, xdg: CloneCell>>, cursors: SmallMap, 1>, + pub dnd_icons: SmallMap, 1>, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -172,6 +175,7 @@ impl WlSurface { seat_state: Default::default(), xdg: Default::default(), cursors: Default::default(), + dnd_icons: Default::default(), } } @@ -234,7 +238,7 @@ impl WlSurface { self.xdg.set(xdg); } - fn set_role(&self, role: SurfaceRole) -> Result<(), WlSurfaceError> { + pub fn set_role(&self, role: SurfaceRole) -> Result<(), WlSurfaceError> { use SurfaceRole::*; match (self.role.get(), role) { (None, _) => {} @@ -308,8 +312,15 @@ impl WlSurface { } } + fn unset_dnd_icons(&self) { + while let Some((_, seat)) = self.dnd_icons.pop() { + seat.remove_dnd_icon() + } + } + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.parse(parser)?; + self.unset_dnd_icons(); self.unset_cursors(); self.destroy_node(true); if self.ext.get().is_some() { @@ -536,6 +547,7 @@ impl Object for WlSurface { } fn break_loops(&self) { + self.unset_dnd_icons(); self.unset_cursors(); self.destroy_node(true); *self.children.borrow_mut() = None; diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 08574ec8..75257431 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -76,6 +76,10 @@ impl Cursor for CursorSurface { renderer.render_surface(&self.surface, x, y); } + fn get_hotspot(&self) -> (i32, i32) { + self.hotspot.get() + } + fn extents(&self) -> Rect { self.extents.get() } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index aae645d2..d2efee49 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -323,7 +323,6 @@ impl XdgToplevel { } fn map_tiled(self: &Rc) { - log::info!("map tiled"); let state = &self.xdg.surface.client.state; let seat = state.seat_queue.last(); if let Some(seat) = seat { diff --git a/src/render/renderer/framebuffer.rs b/src/render/renderer/framebuffer.rs index 464af530..25e550f4 100644 --- a/src/render/renderer/framebuffer.rs +++ b/src/render/renderer/framebuffer.rs @@ -41,6 +41,17 @@ impl Framebuffer { if let Some(cursor) = seat.get_cursor() { cursor.tick(); let extents = cursor.extents(); + if let Some(dnd_icon) = seat.dnd_icon() { + let (x_hot, y_hot) = cursor.get_hotspot(); + let extents = dnd_icon.extents.get().move_( + extents.x1() + x_hot + dnd_icon.buf_x.get(), + extents.y1() + y_hot + dnd_icon.buf_y.get(), + ); + if extents.intersects(&rect) { + let (x, y) = rect.translate(extents.x1(), extents.y1()); + renderer.render_surface(&dnd_icon, x, y); + } + } if extents.intersects(&rect) { let (x, y) = rect.translate(extents.x1(), extents.y1()); cursor.render(&mut renderer, x, y); diff --git a/src/utils/buffd/buf_out.rs b/src/utils/buffd/buf_out.rs index c086679b..0c688506 100644 --- a/src/utils/buffd/buf_out.rs +++ b/src/utils/buffd/buf_out.rs @@ -66,7 +66,6 @@ impl OutBufferSwapchain { pub fn commit(&mut self) { if self.cur.write_pos > 0 { let new = self.free.pop().unwrap_or_else(|| { - log::warn!("new buffer"); Default::default() }); let old = mem::replace(&mut self.cur, new);