Skip to content

Commit

Permalink
wayland: register drag & drop events
Browse files Browse the repository at this point in the history
  • Loading branch information
PeakKS committed Nov 26, 2024
1 parent fc6cf89 commit dc60892
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 9 deletions.
12 changes: 9 additions & 3 deletions examples/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,12 +540,18 @@ impl ApplicationHandler for Application {
WindowEvent::DoubleTapGesture { .. } => {
info!("Smart zoom");
},
WindowEvent::HoveredFile(path) => {
info!("File hover initiated: {path:?}");
},
WindowEvent::HoveredFileCancelled => {
info!("File hover canceled");
},
WindowEvent::DroppedFile(path) => {
info!("File dropped: {path:?}");
},
WindowEvent::TouchpadPressure { .. }
| WindowEvent::HoveredFileCancelled
| WindowEvent::KeyboardInput { .. }
| WindowEvent::PointerEntered { .. }
| WindowEvent::DroppedFile(_)
| WindowEvent::HoveredFile(_)
| WindowEvent::Destroyed
| WindowEvent::Moved(_) => (),
}
Expand Down
180 changes: 180 additions & 0 deletions src/platform_impl/linux/wayland/seat/data_device/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use std::path::PathBuf;

use ahash::{AHashMap, RandomState};
use sctk::data_device_manager::{
data_device::DataDeviceHandler,
data_offer::{DataOfferHandler, DragOffer},
data_source::DataSourceHandler, WritePipe,
};
use sctk::reexports::client::protocol::wl_data_source::WlDataSource;
use sctk::reexports::client::protocol::wl_data_device::WlDataDevice;
use sctk::reexports::client::protocol::wl_data_device_manager::DndAction;
use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::{Connection, QueueHandle};

use crate::event::WindowEvent;
use crate::platform_impl::wayland::seat::ObjectId;
use crate::platform_impl::wayland::seat::WinitSeatState;
use crate::platform_impl::wayland::state::WinitState;
use crate::platform_impl::wayland;

fn seat_from_wl_data_device<'a>(seats: &'a mut AHashMap<ObjectId, WinitSeatState, RandomState>, wl_data_device: &WlDataDevice) -> Option<&'a mut WinitSeatState> {
let Some((_, seat_state )) = seats.iter_mut().find(|(_, seat_state)| match &seat_state.data_device {
Some(data_device) => data_device.inner() == wl_data_device,
None => false
}) else {
return None;
};
return Some(seat_state);
}

impl DataDeviceHandler for WinitState {
fn enter(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
wl_data_device: &WlDataDevice,
_x: f64,
_y: f64,
wl_surface: &WlSurface,
) {
let Some(seat_state) = seat_from_wl_data_device(&mut self.seats, wl_data_device) else {
return;
};

let Some(data_device) = &seat_state.data_device else {
return;
};

let Some(drag_offer) = data_device.data().drag_offer() else {
return;
};

// Accept any mime type, the API consumer can figure this out
let mime_type = drag_offer.with_mime_types(|mime_types| {
if let Some(mime) = mime_types.get(0) {
Some(mime.clone())
} else {
None
}
});
drag_offer.accept_mime_type(0, mime_type.clone());

drag_offer.set_actions(DndAction::Copy, DndAction::Copy);

let window_id = wayland::make_wid(&wl_surface);
seat_state.hovered_window = Some(window_id);
self.events_sink.push_window_event(WindowEvent::HoveredFile(PathBuf::new()), window_id);
}

fn leave(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, wl_data_device: &WlDataDevice) {
let Some(seat_state) = seat_from_wl_data_device(&mut self.seats, wl_data_device) else {
return;
};
if let Some(window_id) = seat_state.hovered_window {
seat_state.hovered_window = None;
self.events_sink.push_window_event(WindowEvent::HoveredFileCancelled, window_id);
}
}

fn motion(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_wl_data_device: &WlDataDevice,
_x: f64,
_y: f64,
) {

}

fn selection(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _wl_data_device: &WlDataDevice) {

}

fn drop_performed(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
wl_data_device: &WlDataDevice,
) {

let Some(seat_state) = seat_from_wl_data_device(&mut self.seats, wl_data_device) else {
return;
};
if let Some(window_id) = seat_state.hovered_window {
seat_state.hovered_window = None;
self.events_sink.push_window_event(WindowEvent::DroppedFile(PathBuf::new()), window_id);
}
}
}

// Inbound
impl DataOfferHandler for WinitState {
fn source_actions(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
offer: &mut DragOffer,
_actions: DndAction,
) {
offer.set_actions(DndAction::Copy, DndAction::Copy);
}

fn selected_action(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_offer: &mut DragOffer,
_actions: DndAction,
) {

}
}

// Outbound
impl DataSourceHandler for WinitState {
fn accept_mime(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_wl_data_source: &WlDataSource,
_mime: Option<String>,
) {

}

fn send_request(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_wl_data_source: &WlDataSource,
_mime: String,
_fd: WritePipe,
) {

}

fn cancelled(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _wl_data_source: &WlDataSource) {

}

fn dnd_dropped(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _wl_data_source: &WlDataSource) {


}

fn dnd_finished(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _wl_data_source: &WlDataSource) {

}

fn action(
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
_wl_data_source: &WlDataSource,
_action: DndAction,
) {

}
}
22 changes: 18 additions & 4 deletions src/platform_impl/linux/wayland/seat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ use sctk::reexports::client::protocol::wl_touch::WlTouch;
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
use sctk::reexports::protocols::wp::relative_pointer::zv1::client::zwp_relative_pointer_v1::ZwpRelativePointerV1;
use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3;
use sctk::data_device_manager::data_device::DataDevice;
use sctk::seat::pointer::{ThemeSpec, ThemedPointer};
use sctk::seat::{Capability as SeatCapability, SeatHandler, SeatState};
use tracing::warn;

use crate::event::WindowEvent;
use crate::keyboard::ModifiersState;
use crate::platform_impl::wayland::state::WinitState;
use crate::window::WindowId;

mod data_device;
mod keyboard;
mod pointer;
mod text_input;
Expand Down Expand Up @@ -57,11 +60,20 @@ pub struct WinitSeatState {

/// Whether we have pending modifiers.
modifiers_pending: bool,

/// Copy & Paste / Drag & Drop data
pub data_device: Option<DataDevice>,

/// Hold id of hoevered drop window
pub hovered_window: Option<WindowId>,
}

impl WinitSeatState {
pub fn new() -> Self {
Default::default()
pub fn new(data_device: DataDevice) -> Self {
return Self {
data_device: Some(data_device),
..Default::default()
}
}
}

Expand Down Expand Up @@ -198,10 +210,12 @@ impl SeatHandler for WinitState {
fn new_seat(
&mut self,
_connection: &Connection,
_queue_handle: &QueueHandle<Self>,
queue_handle: &QueueHandle<Self>,
seat: WlSeat,
) {
self.seats.insert(seat.id(), WinitSeatState::new());
let data_device_manager = &self.data_device_manager_state;
let data_device = data_device_manager.get_data_device(queue_handle, &seat);
self.seats.insert(seat.id(), WinitSeatState::new(data_device));
}

fn remove_seat(
Expand Down
12 changes: 10 additions & 2 deletions src/platform_impl/linux/wayland/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::{Arc, Mutex};

use ahash::AHashMap;
use sctk::compositor::{CompositorHandler, CompositorState};
use sctk::data_device_manager::DataDeviceManagerState;
use sctk::output::{OutputHandler, OutputState};
use sctk::reexports::calloop::LoopHandle;
use sctk::reexports::client::backend::ObjectId;
Expand Down Expand Up @@ -116,6 +117,9 @@ pub struct WinitState {

/// Whether the user initiated a wake up.
pub proxy_wake_up: bool,

/// Data device manager handles copy & paste and drag & drop
pub data_device_manager_state: DataDeviceManagerState,
}

impl WinitState {
Expand All @@ -142,11 +146,12 @@ impl WinitState {
let output_state = OutputState::new(globals, queue_handle);
let monitors = output_state.outputs().map(MonitorHandle::new).collect();

let data_device_manager_state = DataDeviceManagerState::bind(globals, queue_handle).map_err(|err| os_error!(err))?;
let seat_state = SeatState::new(globals, queue_handle);

let mut seats = AHashMap::default();
for seat in seat_state.seats() {
seats.insert(seat.id(), WinitSeatState::new());
let data_device = data_device_manager_state.get_data_device(queue_handle, &seat);
seats.insert(seat.id(), WinitSeatState::new(data_device));
}

let (viewporter_state, fractional_scaling_manager) =
Expand Down Expand Up @@ -194,6 +199,8 @@ impl WinitState {
// Make it true by default.
dispatched_events: true,
proxy_wake_up: false,

data_device_manager_state,
})
}

Expand Down Expand Up @@ -435,3 +442,4 @@ sctk::delegate_registry!(WinitState);
sctk::delegate_shm!(WinitState);
sctk::delegate_xdg_shell!(WinitState);
sctk::delegate_xdg_window!(WinitState);
sctk::delegate_data_device!(WinitState);

0 comments on commit dc60892

Please sign in to comment.