Add dnd icon

This commit is contained in:
Ottatop 2023-08-02 18:18:51 -05:00
parent 7048a89dbf
commit ad30f4668b
5 changed files with 126 additions and 10 deletions

View file

@ -1378,6 +1378,7 @@ impl State<UdevData> {
&pointer_image,
&mut self.backend_data.pointer_element,
&mut self.cursor_status,
self.dnd_icon.as_ref(),
&self.clock,
);
let reschedule = match &result {
@ -1482,6 +1483,7 @@ fn render_surface<'a>(
pointer_image: &TextureBuffer<MultiTexture>,
pointer_element: &mut PointerElement<MultiTexture>,
cursor_status: &mut CursorImageStatus,
dnd_icon: Option<&WlSurface>,
clock: &Clock<Monotonic>,
) -> Result<bool, SwapBuffersError> {
let output_geometry = space.output_geometry(output).unwrap();
@ -1545,7 +1547,15 @@ fn render_surface<'a>(
1.0,
));
// TODO: dnd icon
if let Some(dnd_icon) = dnd_icon {
custom_elements.extend(AsRenderElements::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(dnd_icon),
renderer,
cursor_pos_scaled,
scale,
1.0,
));
}
}
let mut output_render_elements = custom_elements

View file

@ -293,6 +293,16 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
1.0,
));
if let Some(dnd_icon) = state.dnd_icon.as_ref() {
custom_render_elements.extend(AsRenderElements::<GlesRenderer>::render_elements(
&smithay::desktop::space::SurfaceTree::from_surface(dnd_icon),
state.backend_data.backend.renderer(),
cursor_pos_scaled,
scale,
1.0,
));
}
let render_res = state.backend_data.backend.bind().and_then(|_| {
let age = if *full_redraw > 0 {
0

View file

@ -21,7 +21,10 @@ use smithay::{
calloop::Interest,
wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge},
wayland_server::{
protocol::{wl_buffer::WlBuffer, wl_seat::WlSeat, wl_surface::WlSurface},
protocol::{
wl_buffer::WlBuffer, wl_data_source::WlDataSource, wl_seat::WlSeat,
wl_surface::WlSurface,
},
Client, Resource,
},
},
@ -33,12 +36,14 @@ use smithay::{
SurfaceAttributes,
},
data_device::{
set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState,
self, set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState,
ServerDndGrabHandler,
},
dmabuf,
fractional_scale::{self, FractionalScaleHandler},
primary_selection::{PrimarySelectionHandler, PrimarySelectionState},
primary_selection::{
self, set_primary_focus, PrimarySelectionHandler, PrimarySelectionState,
},
seat::WaylandFocus,
shell::xdg::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
@ -46,7 +51,7 @@ use smithay::{
},
shm::{ShmHandler, ShmState},
},
xwayland::{X11Wm, XWaylandClientData},
xwayland::{xwm::SelectionType, X11Wm, XWaylandClientData},
};
use crate::{
@ -196,7 +201,21 @@ fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B
// TODO: layer map thingys
}
impl<B: Backend> ClientDndGrabHandler for State<B> {}
impl<B: Backend> ClientDndGrabHandler for State<B> {
fn started(
&mut self,
_source: Option<WlDataSource>,
icon: Option<WlSurface>,
_seat: Seat<Self>,
) {
self.dnd_icon = icon;
}
fn dropped(&mut self, _seat: Seat<Self>) {
self.dnd_icon = None;
}
}
impl<B: Backend> ServerDndGrabHandler for State<B> {}
impl<B: Backend> DataDeviceHandler for State<B> {
@ -205,6 +224,39 @@ impl<B: Backend> DataDeviceHandler for State<B> {
fn data_device_state(&self) -> &DataDeviceState {
&self.data_device_state
}
fn new_selection(&mut self, source: Option<WlDataSource>, _seat: Seat<Self>) {
if let Some(xwm) = self.xwm.as_mut() {
if let Some(source) = source {
if let Ok(Err(err)) = data_device::with_source_metadata(&source, |metadata| {
xwm.new_selection(SelectionType::Clipboard, Some(metadata.mime_types.clone()))
}) {
tracing::warn!(?err, "Failed to set Xwayland clipboard selection");
}
} else if let Err(err) = xwm.new_selection(SelectionType::Clipboard, None) {
tracing::warn!(?err, "Failed to clear Xwayland clipboard selection");
}
}
}
fn send_selection(
&mut self,
mime_type: String,
fd: std::os::fd::OwnedFd,
_seat: Seat<Self>,
_user_data: &Self::SelectionUserData,
) {
if let Some(xwm) = self.xwm.as_mut() {
if let Err(err) = xwm.send_selection(
SelectionType::Clipboard,
mime_type,
fd,
self.loop_handle.clone(),
) {
tracing::warn!(?err, "Failed to send clipboard (X11 -> Wayland)");
}
}
}
}
delegate_data_device!(@<B: Backend> State<B>);
@ -214,6 +266,43 @@ impl<B: Backend> PrimarySelectionHandler for State<B> {
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.primary_selection_state
}
fn new_selection(
&mut self,
source: Option<smithay::reexports::wayland_protocols::wp::primary_selection::zv1::server::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1>,
_seat: Seat<Self>,
) {
if let Some(xwm) = self.xwm.as_mut() {
if let Some(source) = source {
if let Ok(Err(err)) = primary_selection::with_source_metadata(&source, |metadata| {
xwm.new_selection(SelectionType::Primary, Some(metadata.mime_types.clone()))
}) {
tracing::warn!(?err, "Failed to set Xwayland primary selection");
}
} else if let Err(err) = xwm.new_selection(SelectionType::Primary, None) {
tracing::warn!(?err, "Failed to clear Xwayland primary selection");
}
}
}
fn send_selection(
&mut self,
mime_type: String,
fd: std::os::fd::OwnedFd,
_seat: Seat<Self>,
_user_data: &Self::SelectionUserData,
) {
if let Some(xwm) = self.xwm.as_mut() {
if let Err(err) = xwm.send_selection(
SelectionType::Primary,
mime_type,
fd,
self.loop_handle.clone(),
) {
tracing::warn!(?err, "Failed to send primary (X11 -> Wayland)");
}
}
}
}
delegate_primary_selection!(@<B: Backend> State<B>);
@ -236,9 +325,13 @@ impl<B: Backend> SeatHandler for State<B> {
{
self.focus_state.set_focus(focus);
}
let focus_client =
focused.and_then(|surf| self.display_handle.get_client(surf.wl_surface()?.id()).ok());
set_data_device_focus(&self.display_handle, seat, focus_client);
let focus_client = focused.and_then(|foc_target| {
self.display_handle
.get_client(foc_target.wl_surface()?.id())
.ok()
});
set_data_device_focus(&self.display_handle, seat, focus_client.clone());
set_primary_focus(&self.display_handle, seat, focus_client);
}
}
delegate_seat!(@<B: Backend> State<B>);

View file

@ -101,6 +101,8 @@ pub struct State<B: Backend> {
pub cursor_status: CursorImageStatus,
pub pointer_location: Point<f64, Logical>,
pub dnd_icon: Option<WlSurface>,
pub windows: Vec<WindowElement>,
pub async_scheduler: Scheduler<()>,
@ -900,6 +902,8 @@ impl<B: Backend> State<B> {
seat,
dnd_icon: None,
move_mode: false,
socket_name: socket_name.to_string_lossy().to_string(),

View file

@ -495,7 +495,6 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &WindowElement)
.element_location(window)
.unwrap_or((0, 0).into())
}));
// TODO: TOMORROW: come up with a better way to keep window location
if let WindowElement::Wayland(window) = window {
window.toplevel().with_pending_state(|tl_state| {
tl_state.states.unset(xdg_toplevel::State::TiledTop);