Skip to content

Commit

Permalink
wayland: implement xdg-toplevel-drag
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Mar 2, 2024
1 parent 9ef089e commit e8bf6fe
Show file tree
Hide file tree
Showing 22 changed files with 546 additions and 70 deletions.
11 changes: 11 additions & 0 deletions src/gfx_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ impl dyn GfxFramebuffer {
let seats = state.globals.lock_seats();
for seat in seats.values() {
let (mut x, mut y) = seat.get_position();
if let Some(drag) = seat.toplevel_drag() {
if let Some(tl) = drag.toplevel.get() {
if tl.xdg.surface.buffer.get().is_some() {
let (x, y) = rect.translate(
x.round_down() - drag.x_off.get(),
y.round_down() - drag.y_off.get(),
);
renderer.render_xdg_surface(&tl.xdg, x, y, None)
}
}
}
if let Some(dnd_icon) = seat.dnd_icon() {
let extents = dnd_icon.extents.get().move_(
x.round_down() + dnd_icon.buf_x.get(),
Expand Down
2 changes: 2 additions & 0 deletions src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use {
wp_tearing_control_manager_v1::WpTearingControlManagerV1Global,
wp_viewporter::WpViewporterGlobal,
xdg_activation_v1::XdgActivationV1Global,
xdg_toplevel_drag_manager_v1::XdgToplevelDragManagerV1Global,
xdg_wm_base::XdgWmBaseGlobal,
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1Global,
Expand Down Expand Up @@ -169,6 +170,7 @@ impl Globals {
add_singleton!(ExtForeignToplevelListV1Global);
add_singleton!(ZwpIdleInhibitManagerV1Global);
add_singleton!(ExtIdleNotifierV1Global);
add_singleton!(XdgToplevelDragManagerV1Global);
}

pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
Expand Down
2 changes: 2 additions & 0 deletions src/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub mod wp_viewporter;
pub mod xdg_activation_token_v1;
pub mod xdg_activation_v1;
pub mod xdg_positioner;
pub mod xdg_toplevel_drag_manager_v1;
pub mod xdg_toplevel_drag_v1;
pub mod xdg_wm_base;
pub mod zwlr_layer_shell_v1;
pub mod zwlr_screencopy_frame_v1;
Expand Down
21 changes: 17 additions & 4 deletions src/ifs/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub trait IpcVtable: Sized {
data: OfferData<Self>,
) -> Result<Rc<Self::Offer>, ClientError>;
fn send_selection(dd: &Self::Device, offer: Option<&Rc<Self::Offer>>);
fn send_cancelled(source: &Rc<Self::Source>);
fn send_cancelled(source: &Rc<Self::Source>, seat: &Rc<WlSeatGlobal>);
fn get_offer_id(offer: &Self::Offer) -> u64;
fn send_offer(dd: &Self::Device, offer: &Rc<Self::Offer>);
fn send_mime_type(offer: &Rc<Self::Offer>, mime_type: &str);
Expand Down Expand Up @@ -101,13 +101,16 @@ const OFFER_STATE_DROPPED: u32 = 1 << 2;

const SOURCE_STATE_USED: u32 = 1 << 1;
const SOURCE_STATE_FINISHED: u32 = 1 << 2;
const SOURCE_STATE_DROPPED: u32 = 1 << 3;
const SOURCE_STATE_CANCELLED: u32 = 1 << 4;
const SOURCE_STATE_DROPPED_OR_CANCELLED: u32 = SOURCE_STATE_DROPPED | SOURCE_STATE_CANCELLED;

pub struct SourceData<T: IpcVtable> {
pub seat: CloneCell<Option<Rc<WlSeatGlobal>>>,
offers: SmallMap<u64, Rc<T::Offer>, 1>,
offer_client: Cell<ClientId>,
mime_types: RefCell<AHashSet<String>>,
client: Rc<Client>,
pub client: Rc<Client>,
state: NumCell<u32>,
actions: Cell<Option<u32>>,
role: Cell<Role>,
Expand Down Expand Up @@ -150,6 +153,16 @@ impl<T: IpcVtable> SourceData<T> {
is_xwm,
}
}

pub fn was_used(&self) -> bool {
self.state.get().contains(SOURCE_STATE_USED)
}

pub fn was_dropped_or_cancelled(&self) -> bool {
self.state
.get()
.intersects(SOURCE_STATE_DROPPED_OR_CANCELLED)
}
}

pub fn attach_seat<T: IpcVtable>(
Expand Down Expand Up @@ -187,12 +200,12 @@ pub fn cancel_offers<T: IpcVtable>(src: &T::Source) {
}
}

pub fn detach_seat<T: IpcVtable>(src: &Rc<T::Source>) {
pub fn detach_seat<T: IpcVtable>(src: &Rc<T::Source>, seat: &Rc<WlSeatGlobal>) {
let data = T::get_source_data(src);
data.seat.set(None);
cancel_offers::<T>(src);
if !data.state.get().contains(SOURCE_STATE_FINISHED) {
T::send_cancelled(src);
T::send_cancelled(src, seat);
}
// data.client.flush();
}
Expand Down
4 changes: 2 additions & 2 deletions src/ifs/ipc/wl_data_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,8 @@ impl IpcVtable for ClipboardIpc {
dd.send_selection(offer);
}

fn send_cancelled(source: &Rc<Self::Source>) {
source.send_cancelled();
fn send_cancelled(source: &Rc<Self::Source>, seat: &Rc<WlSeatGlobal>) {
source.send_cancelled(seat);
}

fn get_offer_id(offer: &Self::Offer) -> u64 {
Expand Down
33 changes: 25 additions & 8 deletions src/ifs/ipc/wl_data_source.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
use {
crate::{
client::{Client, ClientError},
ifs::ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
wl_data_device::ClipboardIpc,
wl_data_device_manager::{DND_ALL, DND_NONE},
wl_data_offer::WlDataOffer,
SharedState, SourceData, OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED,
ifs::{
ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
wl_data_device::ClipboardIpc,
wl_data_device_manager::{DND_ALL, DND_NONE},
wl_data_offer::WlDataOffer,
SharedState, SourceData, OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED,
SOURCE_STATE_CANCELLED, SOURCE_STATE_DROPPED,
},
wl_seat::WlSeatGlobal,
xdg_toplevel_drag_v1::XdgToplevelDragV1,
},
leaks::Tracker,
object::Object,
utils::{
bitflags::BitflagsExt,
buffd::{MsgParser, MsgParserError},
clonecell::CloneCell,
},
wire::{wl_data_source::*, WlDataSourceId},
xwayland::XWaylandEvent,
Expand All @@ -32,6 +38,7 @@ pub struct WlDataSource {
pub data: SourceData<ClipboardIpc>,
pub version: u32,
pub tracker: Tracker<Self>,
pub toplevel_drag: CloneCell<Option<Rc<XdgToplevelDragV1>>>,
}

impl WlDataSource {
Expand All @@ -41,6 +48,7 @@ impl WlDataSource {
tracker: Default::default(),
data: SourceData::new(client, is_xwm),
version,
toplevel_drag: Default::default(),
}
}

Expand Down Expand Up @@ -99,13 +107,17 @@ impl WlDataSource {
shared.selected_action.get() != 0 && shared.state.get().contains(OFFER_STATE_ACCEPTED)
}

pub fn on_drop(&self) {
pub fn on_drop(&self, seat: &Rc<WlSeatGlobal>) {
self.data.state.or_assign(SOURCE_STATE_DROPPED);
if let Some(drag) = self.toplevel_drag.take() {
drag.finish_drag(seat);
}
self.send_dnd_drop_performed();
let shared = self.data.shared.get();
shared.state.or_assign(OFFER_STATE_DROPPED);
}

pub fn send_cancelled(self: &Rc<Self>) {
pub fn send_cancelled(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>) {
if self.data.is_xwm {
self.data
.client
Expand All @@ -114,6 +126,10 @@ impl WlDataSource {
.queue
.push(XWaylandEvent::ClipboardCancelSource(self.clone()));
} else {
self.data.state.or_assign(SOURCE_STATE_CANCELLED);
if let Some(drag) = self.toplevel_drag.take() {
drag.finish_drag(seat);
}
self.data.client.event(Cancelled { self_id: self.id })
}
}
Expand Down Expand Up @@ -208,6 +224,7 @@ object_base! {
impl Object for WlDataSource {
fn break_loops(&self) {
break_source_loops::<ClipboardIpc>(self);
self.toplevel_drag.take();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/ifs/ipc/zwp_primary_selection_device_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ impl IpcVtable for PrimarySelectionIpc {
dd.send_selection(offer);
}

fn send_cancelled(source: &Rc<Self::Source>) {
fn send_cancelled(source: &Rc<Self::Source>, _seat: &Rc<WlSeatGlobal>) {
source.send_cancelled();
}

Expand Down
24 changes: 21 additions & 3 deletions src/ifs/wl_seat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use {
zwp_relative_pointer_v1::ZwpRelativePointerV1,
},
wl_surface::WlSurface,
xdg_toplevel_drag_v1::XdgToplevelDragV1,
},
leaks::Tracker,
object::Object,
Expand Down Expand Up @@ -107,7 +108,7 @@ pub struct DroppedDnd {
impl Drop for DroppedDnd {
fn drop(&mut self) {
if let Some(src) = self.dnd.src.take() {
ipc::detach_seat::<ClipboardIpc>(&src);
ipc::detach_seat::<ClipboardIpc>(&src, &self.dnd.seat);
}
}
}
Expand Down Expand Up @@ -232,6 +233,10 @@ impl WlSeatGlobal {
slf
}

pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
self.pointer_owner.toplevel_drag()
}

pub fn set_hardware_cursor(&self, hardware_cursor: bool) {
self.hardware_cursor.set(hardware_cursor);
}
Expand Down Expand Up @@ -397,6 +402,7 @@ impl WlSeatGlobal {
tl.tl_data().float_width.get(),
tl.tl_data().float_height.get(),
ws,
None,
);
} else {
self.state.map_tiled_on(tl, ws);
Expand Down Expand Up @@ -519,6 +525,11 @@ impl WlSeatGlobal {
if let Some(dnd) = self.pointer_owner.dnd_icon() {
dnd.set_output(output);
}
if let Some(drag) = self.pointer_owner.toplevel_drag() {
if let Some(tl) = drag.toplevel.get() {
tl.xdg.set_output(output);
}
}
}

pub fn position(&self) -> (Fixed, Fixed) {
Expand Down Expand Up @@ -631,7 +642,7 @@ impl WlSeatGlobal {
} else if let Some(ws) = data.workspace.get() {
cn.cnode_remove_child2(tl.tl_as_node(), true);
let (width, height) = data.float_size(&ws);
self.state.map_floating(tl, width, height, &ws);
self.state.map_floating(tl, width, height, &ws, None);
}
}
}
Expand Down Expand Up @@ -701,7 +712,7 @@ impl WlSeatGlobal {
ipc::attach_seat::<T>(new, self, ipc::Role::Selection)?;
}
if let Some(old) = field.set(src.clone()) {
ipc::detach_seat::<T>(&old);
ipc::detach_seat::<T>(&old, self);
}
if let Some(client) = self.keyboard_node.get().node_client() {
match src {
Expand Down Expand Up @@ -745,6 +756,11 @@ impl WlSeatGlobal {
if let Some(serial) = serial {
self.selection_serial.set(serial);
}
if let Some(selection) = &selection {
if selection.toplevel_drag.is_some() {
return Err(WlSeatError::OfferHasDrag);
}
}
self.set_selection_::<ClipboardIpc>(&self.selection, selection)
}

Expand Down Expand Up @@ -1118,6 +1134,8 @@ pub enum WlSeatError {
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
WlKeyboardError(Box<WlKeyboardError>),
#[error("Data source has a toplevel attached")]
OfferHasDrag,
}
efrom!(WlSeatError, ClientError);
efrom!(WlSeatError, MsgParserError);
Expand Down
Loading

0 comments on commit e8bf6fe

Please sign in to comment.