Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
c8fe672
Wayland: support basic Drag&Drop
SludgePhD Aug 12, 2022
809ae2c
Address clippy lints
SludgePhD Aug 13, 2022
31a4de1
Use `make_wid` to simplify code
SludgePhD Aug 13, 2022
9d88e5e
Also emit all appropriate cursor events
SludgePhD Aug 13, 2022
2b0dd48
Read the pipe without blocking
SludgePhD Aug 19, 2022
2687654
Follow style
SludgePhD Aug 19, 2022
d95dd41
Address clippy lint
SludgePhD Aug 19, 2022
60749aa
Fix parsing of CRLF-delimited lines
SludgePhD Aug 23, 2022
2c15c5e
Fix merge conflicts in Cargo.toml
eira-fransham May 19, 2026
ccd7116
Fix merge conflicts in `platform_impl`, start implementing data trans…
eira-fransham May 19, 2026
ccaff27
Fix cargo fmt
eira-fransham May 20, 2026
d8fa184
Convert to use new data transfer system
eira-fransham May 20, 2026
3c01cb8
Add plaintext + URI helpers, remove MIME
eira-fransham May 20, 2026
b7fcfe0
Add more documentation
eira-fransham May 20, 2026
2234a27
Fix drag-and-drop on X11
eira-fransham May 21, 2026
8d3111b
Fix use of `XDndStatus`
eira-fransham May 21, 2026
e867501
Change comment
eira-fransham May 21, 2026
4dc8f6f
Fix conversion from type hint to "real" type
eira-fransham May 21, 2026
1fec92c
Fill out type hints for X11
eira-fransham May 21, 2026
61ab9c8
Fix transferring text and add an example
eira-fransham May 21, 2026
fb7779e
WIP: Implement drag-and-drop for AppKit using new API
eira-fransham May 22, 2026
98106b8
Remove `DataTransferEvent`
eira-fransham May 26, 2026
2e99f38
Implement dnd for appkit
eira-fransham May 26, 2026
1c5a76a
Fix `registerForDraggedTypes` on macOS
eira-fransham May 26, 2026
0e6bbf6
Fix clippy on macOS
eira-fransham May 26, 2026
9a058cb
Fix clippy
eira-fransham May 26, 2026
fbccd66
Fix 1.85 compat
eira-fransham May 26, 2026
d4b9c49
Taplo fmt
eira-fransham May 26, 2026
d00d415
X11 clippy
eira-fransham May 26, 2026
e52cae1
Explain `regsisterForDraggedTypes` usage
eira-fransham May 26, 2026
47dd3cf
Fix clippy issue
eira-fransham May 27, 2026
03eb54a
Small changes
eira-fransham May 27, 2026
a439436
Fix compilation issue
eira-fransham May 27, 2026
0c94650
WIP: Implement for Windows
eira-fransham May 27, 2026
fb92e36
X11 cleanup
eira-fransham May 27, 2026
aaa006a
X11 cleanup
eira-fransham May 27, 2026
72ed878
Fix clippy warnings, make `wait_for_data` X11-internal
eira-fransham May 27, 2026
1a6b0dd
Remove `wait_for_data` from appkit
eira-fransham May 27, 2026
fc55406
WIP: win32
eira-fransham May 27, 2026
4f22d27
Simpler API
eira-fransham May 28, 2026
ea24514
`drop_handler`->`dnd`
eira-fransham May 28, 2026
8028fc8
Fix unused Cow import
eira-fransham May 28, 2026
42c4ccf
Use `OsString` for paths
eira-fransham May 28, 2026
798c79b
WIP: Implement for Wayland
eira-fransham Jun 1, 2026
9966b83
Fix appkit
eira-fransham Jun 1, 2026
f3eec15
Fix clippy warnings, fix on wayland
eira-fransham Jun 1, 2026
3a2231f
WIP: Initiate drag
eira-fransham Jun 1, 2026
74a3383
WIP: Initiate drag
eira-fransham Jun 2, 2026
9f48597
WIP: Initiate drag
eira-fransham Jun 2, 2026
5d28920
WIP: Initiate drag
eira-fransham Jun 2, 2026
75ffbf5
Initiate drag on Wayland
eira-fransham Jun 2, 2026
4596833
Fix icon on drag
eira-fransham Jun 2, 2026
4d92ce5
Allow switching on requested type, allowing the application to be gen…
eira-fransham Jun 2, 2026
cce666a
Complete win32 drag-and-drop by reading dropped data
tronical May 28, 2026
708962e
Use the actual copied length when reading dropped file paths
tronical May 28, 2026
649ad6f
Receive PNG image drops on win32
tronical Jun 1, 2026
5fb6208
Accept drops on win32 via set_valid_actions
tronical Jun 1, 2026
eb7792c
Update win32 for new set_valid_actions signature
eira-fransham Jun 2, 2026
ed9e71d
Fix nitpicks
eira-fransham Jun 2, 2026
e99836b
Fix invalid panic over FFI boundary
eira-fransham Jun 2, 2026
41e1f5f
Fmt
eira-fransham Jun 2, 2026
b5375a9
WIP: Initiate drag on macOS
eira-fransham Jun 2, 2026
340c2cb
Initiate drag on macOS
eira-fransham Jun 3, 2026
098af43
Remove `cancel_drag`
eira-fransham Jun 3, 2026
b8e3eba
Fix buggy drag visuals
eira-fransham Jun 3, 2026
ea394ea
Clippy warnings
eira-fransham Jun 3, 2026
fcababb
Clippy warnings
eira-fransham Jun 3, 2026
54f695e
Fix comment formatting
eira-fransham Jun 3, 2026
3a4bb3d
Fix `DndActionMask` on macOS
eira-fransham Jun 3, 2026
16f2102
Initiate drags from win32 windows
tronical Jun 2, 2026
1e1c579
Emit DragLeft when the drop was rejected
tronical Jun 2, 2026
353fb87
Pair COM Release with an Acquire fence before drop
tronical Jun 2, 2026
dfd05ae
Implement DragIcon on win32
tronical Jun 2, 2026
2c6d5c5
fixup! Implement DragIcon on win32
tronical Jun 4, 2026
e4f341d
fixup! Implement DragIcon on win32
tronical Jun 4, 2026
463d72f
fixup! Implement DragIcon on win32
tronical Jun 4, 2026
f058957
fixup! Pair COM Release with an Acquire fence before drop
tronical Jun 4, 2026
bf5bcc1
fixup! Implement DragIcon on win32
tronical Jun 4, 2026
e35894d
fixup! Initiate drags from win32 windows
tronical Jun 4, 2026
b8ebe98
fixup! Initiate drags from win32 windows
tronical Jun 4, 2026
0b5b9b3
fixup! Initiate drags from win32 windows
tronical Jun 4, 2026
d8b2bab
fixup! Implement DragIcon on win32
tronical Jun 4, 2026
e1293a1
Plaintext is UTF-8 on Wayland
eira-fransham Jun 4, 2026
5e7d943
Merge branch 'drag-n-drop' into simon/win32-drag
eira-fransham Jun 4, 2026
2884d74
fixup! Initiate drags from win32 windows
tronical Jun 4, 2026
58ca72b
fixup! Implement DragIcon on win32
tronical Jun 4, 2026
8bce692
Fix dragging file paths on Windows
eira-fransham Jun 4, 2026
b5535e2
Format
eira-fransham Jun 4, 2026
e5ee07f
Merge pull request #3 from slint-ui/simon/win32-drag
eira-fransham Jun 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ cursor-icon = "1.1.0"
dpi = { version = "0.1.2", path = "dpi" }
keyboard-types = "0.8.0"
mint = "0.5.6"
rustversion = "1.0"
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"] }
serde = { version = "1", features = ["serde_derive"] }
smol_str = "0.3"
Expand Down
1 change: 1 addition & 0 deletions typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ TME_LEAVE = "TME_LEAVE" # From windows_sys::Win32::UI::Input::Keyboa
XF86_Calculater = "XF86_Calculater" # From xkbcommon_dl::keysyms::XF86_Calculater
ptd = "ptd" # From windows_sys::Win32::System::Com::FORMATETC { ptd, ..}
requestor = "requestor" # From x11_dl::xlib::XSelectionEvent { requestor ..}
unknwn = "unknwn" # Windows SDK header filename `unknwn.h`

[files]
extend-exclude = ["*.drawio"]
3 changes: 3 additions & 0 deletions winit-appkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ objc2-app-kit = { workspace = true, features = [
"NSControl",
"NSCursor",
"NSDragging",
"NSDraggingItem",
"NSDraggingSession",
"NSEvent",
"NSGraphics",
"NSGraphicsContext",
Expand All @@ -46,6 +48,7 @@ objc2-app-kit = { workspace = true, features = [
"NSOpenGLView",
"NSPanel",
"NSPasteboard",
"NSPasteboardItem",
"NSResponder",
"NSRunningApplication",
"NSScreen",
Expand Down
39 changes: 39 additions & 0 deletions winit-appkit/src/app_state.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
use std::cell::{Cell, OnceCell, RefCell};
use std::collections::HashMap;
use std::mem;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Instant;

use dispatch2::MainThreadBound;
use objc2::MainThreadMarker;
use objc2::rc::{Retained, Weak};
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSRunningApplication};
use objc2_foundation::NSNotification;
use winit_common::core_foundation::{EventLoopProxy, MainRunLoop};
use winit_common::event_handler::EventHandler;
use winit_core::application::ApplicationHandler;
use winit_core::data_transfer::DataTransferId;
use winit_core::event::{StartCause, WindowEvent};
use winit_core::event_loop::ControlFlow;
use winit_core::window::WindowId;

use super::event_loop::{ActiveEventLoop, notify_windows_of_exit, stop_app_immediately};
use super::menu;
use super::observer::EventLoopWaker;
use crate::dnd::{DragOperation, Pasteboards};
use crate::window_delegate::WindowDelegate;

#[derive(Debug)]
pub(super) struct AppState {
mtm: MainThreadMarker,
drag_state: Cell<Option<DragState>>,
pasteboards: Pasteboards,
activation_policy: Option<NSApplicationActivationPolicy>,
default_menu: bool,
activate_ignoring_other_apps: bool,
Expand All @@ -43,10 +50,17 @@ pub(super) struct AppState {
start_time: Cell<Option<Instant>>,
wait_timeout: Cell<Option<Instant>>,
pending_redraw: RefCell<Vec<WindowId>>,
windows: RefCell<HashMap<WindowId, MainThreadBound<Weak<WindowDelegate>>>>,
// NOTE: This is strongly referenced by our `NSWindowDelegate` and our `NSView` subclass, and
// as such should be careful to not add fields that, in turn, strongly reference those.
}

#[derive(Copy, Clone, Debug)]
pub(crate) struct DragState {
pub id: DataTransferId,
pub valid_operations: DragOperation,
}

// SAFETY: Creating `MainThreadBound` in a `const` context, where there is no concept of the
// main thread.
static GLOBAL: MainThreadBound<OnceCell<Rc<AppState>>> =
Expand All @@ -65,6 +79,8 @@ impl AppState {

let this = Rc::new(Self {
mtm,
pasteboards: Default::default(),
drag_state: Default::default(),
activation_policy,
default_menu,
activate_ignoring_other_apps,
Expand All @@ -82,6 +98,7 @@ impl AppState {
waker: RefCell::new(EventLoopWaker::new()),
start_time: Cell::new(None),
wait_timeout: Cell::new(None),
windows: Default::default(),
pending_redraw: RefCell::new(vec![]),
});

Expand All @@ -96,6 +113,20 @@ impl AppState {
.clone()
}

pub fn with_window_delegate_on_main<F, R>(&self, id: WindowId, func: F) -> Option<R>
where
F: FnOnce(Retained<WindowDelegate>) -> R + Send,
R: Send,
{
self.windows.borrow_mut().get(&id)?.get_on_main(move |delegate| delegate.load().map(func))
}

pub fn new_window(&self, window: &Retained<WindowDelegate>, mtm: MainThreadMarker) {
let id = window.id();
let window_downgraded = Weak::from_retained(window);
self.windows.borrow_mut().insert(id, MainThreadBound::new(window_downgraded, mtm));
}

// NOTE: This notification will, globally, only be emitted once,
// no matter how many `EventLoop`s the user creates.
pub fn did_finish_launching(self: &Rc<Self>, _notification: &NSNotification) {
Expand Down Expand Up @@ -371,6 +402,14 @@ impl AppState {
};
self.waker.borrow_mut().start_at(min_timeout(wait_timeout, app_timeout));
}

pub fn pasteboards(&self) -> &Pasteboards {
&self.pasteboards
}

pub fn drag_state(&self) -> &Cell<Option<DragState>> {
&self.drag_state
}
}

/// Returns the minimum `Option<Instant>`, taking into account that `None`
Expand Down
35 changes: 35 additions & 0 deletions winit-appkit/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use objc2_foundation::{
};
use winit_core::cursor::{CursorIcon, CursorImage, CustomCursorProvider, CustomCursorSource};
use winit_core::error::{NotSupportedError, RequestError};
use winit_core::icon::{Icon, RgbaIcon};

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CustomCursor(pub(crate) Retained<NSCursor>);
Expand Down Expand Up @@ -42,6 +43,40 @@ impl CustomCursor {
}
}

pub(crate) fn image_from_icon(icon: &Icon) -> Result<Retained<NSImage>, RequestError> {
let rgba_icon = icon
.cast_ref::<RgbaIcon>()
.ok_or(NotSupportedError::new("Only RGBA icons can be converted to `NSImage`"))?;

let width = rgba_icon.width();
let height = rgba_icon.height();

let bitmap = unsafe {
NSBitmapImageRep::initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel(
NSBitmapImageRep::alloc(),
std::ptr::null_mut::<*mut c_uchar>(),
width as isize,
height as isize,
8,
4,
true,
false,
NSDeviceRGBColorSpace,
width as isize * 4,
32,
)
}.ok_or_else(|| os_error!("parent view should be installed in a window"))?;

let bitmap_data =
unsafe { slice::from_raw_parts_mut(bitmap.bitmapData(), rgba_icon.buffer().len()) };
bitmap_data.copy_from_slice(rgba_icon.buffer());

let image = NSImage::initWithSize(NSImage::alloc(), NSSize::new(width.into(), height.into()));
image.addRepresentation(&bitmap);

Ok(image)
}

pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result<Retained<NSCursor>, RequestError> {
let width = cursor.width();
let height = cursor.height();
Expand Down
Loading
Loading