From 4ef7c71c66fba2534055033bb7cdd320a7846991 Mon Sep 17 00:00:00 2001 From: Rob Saunders Date: Thu, 27 Jul 2017 00:59:42 +0800 Subject: [PATCH 1/3] Initial drag and drop support for Mac OS, printing filenames to stdout. --- src/platform/macos/window.rs | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index cbd66056..bba4fb30 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -116,6 +116,50 @@ impl WindowDelegate { } } + /// Invoked when the dragged image enters destination bounds or frame + extern fn dragging_entered(_: &Object, _: Sel, _: id) { + println!("dragging_entered"); + } + + /// Invoked when the image is released + extern fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) { + println!("prepare_for_drag_operation"); + } + + /// Invoked after the released image has been removed from the screen + extern fn perform_drag_operation(_: &Object, _: Sel, sender: id) -> BOOL { + use cocoa::appkit::NSPasteboard; + + let pb: id = unsafe { msg_send![sender, draggingPasteboard] }; + + let filenames = unsafe { NSPasteboard::propertyListForType(pb, appkit::NSFilenamesPboardType) }; + + use cocoa::foundation::NSFastEnumeration; + for file in unsafe { filenames.iter() } { + use cocoa::foundation::NSString; + unsafe { + use std::ffi::CStr; + let f = NSString::UTF8String(file); + let str = CStr::from_ptr(f).to_string_lossy().into_owned(); + + println!("file: {:?}", str); + } + }; + + YES + + } + + /// Invoked when the dragging operation is complete + extern fn conclude_drag_operation(_: &Object, _: Sel, _: id) { + println!("conclude_drag_operation"); + } + + /// Invoked when the dragging operation is cancelled + extern fn dragging_exited(_: &Object, _: Sel, _: id) { + println!("dragging_exited"); + } + static mut DELEGATE_CLASS: *const Class = 0 as *const Class; static INIT: std::sync::Once = std::sync::ONCE_INIT; @@ -137,6 +181,18 @@ impl WindowDelegate { decl.add_method(sel!(windowDidResignKey:), window_did_resign_key as extern fn(&Object, Sel, id)); + // callback for drag events + decl.add_method(sel!(draggingEntered:), + dragging_entered as extern fn(&Object, Sel, id)); + decl.add_method(sel!(prepareForDragOperation:), + prepare_for_drag_operation as extern fn(&Object, Sel, id)); + decl.add_method(sel!(performDragOperation:), + perform_drag_operation as extern fn(&Object, Sel, id) -> BOOL); + decl.add_method(sel!(concludeDragOperation:), + conclude_drag_operation as extern fn(&Object, Sel, id)); + decl.add_method(sel!(draggingExited:), + dragging_exited as extern fn(&Object, Sel, id)); + // Store internal state as user data decl.add_ivar::<*mut c_void>("winitState"); @@ -263,6 +319,11 @@ impl Window { if let Some((width, height)) = win_attribs.max_dimensions { nswindow_set_max_dimensions(window.0, width.into(), height.into()); } + + use cocoa::foundation::NSArray; + // register for drag and drop operations. + msg_send![(*window as id), + registerForDraggedTypes:NSArray::arrayWithObject(nil, appkit::NSFilenamesPboardType)]; } let ds = DelegateState { From 5f00028f6b4eec2bb8df803a883345cb3bf387bb Mon Sep 17 00:00:00 2001 From: Rob Saunders Date: Thu, 27 Jul 2017 10:51:00 +0800 Subject: [PATCH 2/3] Mac module emits the winit events DroppedFile and HoveredFile. --- src/events.rs | 3 +++ src/platform/macos/window.rs | 47 +++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/events.rs b/src/events.rs index 93eed988..ecd53013 100644 --- a/src/events.rs +++ b/src/events.rs @@ -26,6 +26,9 @@ pub enum WindowEvent { /// The window has been closed. Closed, + /// A file is being hovered over the window. + HoveredFile(PathBuf), + /// A file has been dropped into the window. DroppedFile(PathBuf), diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index bba4fb30..af96ad8a 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -117,8 +117,29 @@ impl WindowDelegate { } /// Invoked when the dragged image enters destination bounds or frame - extern fn dragging_entered(_: &Object, _: Sel, _: id) { - println!("dragging_entered"); + extern fn dragging_entered(this: &Object, _: Sel, sender: id) -> BOOL { + use cocoa::appkit::NSPasteboard; + use cocoa::foundation::NSFastEnumeration; + use std::path::PathBuf; + + let pb: id = unsafe { msg_send![sender, draggingPasteboard] }; + let filenames = unsafe { NSPasteboard::propertyListForType(pb, appkit::NSFilenamesPboardType) }; + + for file in unsafe { filenames.iter() } { + use cocoa::foundation::NSString; + use std::ffi::CStr; + + unsafe { + let f = NSString::UTF8String(file); + let path = CStr::from_ptr(f).to_string_lossy().into_owned(); + + let state: *mut c_void = *this.get_ivar("winitState"); + let state = &mut *(state as *mut DelegateState); + emit_event(state, WindowEvent::HoveredFile(PathBuf::from(path))); + } + }; + + YES } /// Invoked when the image is released @@ -127,27 +148,29 @@ impl WindowDelegate { } /// Invoked after the released image has been removed from the screen - extern fn perform_drag_operation(_: &Object, _: Sel, sender: id) -> BOOL { + extern fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { use cocoa::appkit::NSPasteboard; + use cocoa::foundation::NSFastEnumeration; + use std::path::PathBuf; let pb: id = unsafe { msg_send![sender, draggingPasteboard] }; - let filenames = unsafe { NSPasteboard::propertyListForType(pb, appkit::NSFilenamesPboardType) }; - use cocoa::foundation::NSFastEnumeration; for file in unsafe { filenames.iter() } { use cocoa::foundation::NSString; - unsafe { - use std::ffi::CStr; - let f = NSString::UTF8String(file); - let str = CStr::from_ptr(f).to_string_lossy().into_owned(); + use std::ffi::CStr; - println!("file: {:?}", str); + unsafe { + let f = NSString::UTF8String(file); + let path = CStr::from_ptr(f).to_string_lossy().into_owned(); + + let state: *mut c_void = *this.get_ivar("winitState"); + let state = &mut *(state as *mut DelegateState); + emit_event(state, WindowEvent::DroppedFile(PathBuf::from(path))); } }; YES - } /// Invoked when the dragging operation is complete @@ -183,7 +206,7 @@ impl WindowDelegate { // callback for drag events decl.add_method(sel!(draggingEntered:), - dragging_entered as extern fn(&Object, Sel, id)); + dragging_entered as extern fn(&Object, Sel, id) -> BOOL); decl.add_method(sel!(prepareForDragOperation:), prepare_for_drag_operation as extern fn(&Object, Sel, id)); decl.add_method(sel!(performDragOperation:), From 06e01e4cb337c11f9aacc8523283584f1f32f71f Mon Sep 17 00:00:00 2001 From: Rob Saunders Date: Thu, 27 Jul 2017 10:56:34 +0800 Subject: [PATCH 3/3] Added event for cancelling a drag and drop. --- src/events.rs | 7 +++++-- src/platform/macos/window.rs | 18 +++++++++--------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/events.rs b/src/events.rs index ecd53013..bc72672c 100644 --- a/src/events.rs +++ b/src/events.rs @@ -26,11 +26,14 @@ pub enum WindowEvent { /// The window has been closed. Closed, + /// A file has been dropped into the window. + DroppedFile(PathBuf), + /// A file is being hovered over the window. HoveredFile(PathBuf), - /// A file has been dropped into the window. - DroppedFile(PathBuf), + /// A file was hovered, but has exited the window. + HoveredFileCancelled, /// The window received a unicode character. ReceivedCharacter(char), diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index af96ad8a..95e2bce2 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -143,9 +143,7 @@ impl WindowDelegate { } /// Invoked when the image is released - extern fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) { - println!("prepare_for_drag_operation"); - } + extern fn prepare_for_drag_operation(_: &Object, _: Sel, _: id) {} /// Invoked after the released image has been removed from the screen extern fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { @@ -174,13 +172,15 @@ impl WindowDelegate { } /// Invoked when the dragging operation is complete - extern fn conclude_drag_operation(_: &Object, _: Sel, _: id) { - println!("conclude_drag_operation"); - } + extern fn conclude_drag_operation(_: &Object, _: Sel, _: id) {} /// Invoked when the dragging operation is cancelled - extern fn dragging_exited(_: &Object, _: Sel, _: id) { - println!("dragging_exited"); + extern fn dragging_exited(this: &Object, _: Sel, _: id) { + unsafe { + let state: *mut c_void = *this.get_ivar("winitState"); + let state = &mut *(state as *mut DelegateState); + emit_event(state, WindowEvent::HoveredFileCancelled); + } } static mut DELEGATE_CLASS: *const Class = 0 as *const Class; @@ -204,7 +204,7 @@ impl WindowDelegate { decl.add_method(sel!(windowDidResignKey:), window_did_resign_key as extern fn(&Object, Sel, id)); - // callback for drag events + // callbacks for drag and drop events decl.add_method(sel!(draggingEntered:), dragging_entered as extern fn(&Object, Sel, id) -> BOOL); decl.add_method(sel!(prepareForDragOperation:),