Skip to content

Commit

Permalink
feat: add WindowProxy to file drop handler closure (#140)
Browse files Browse the repository at this point in the history
* add WindowProxy to file drop handler closure

linux only for right now

* add support for windows + osx (i think)

* add changefile

* docs and move low level handler to webview module

* cargo fmt

* Fix resize method

Co-authored-by: Ngo Iok Ui <[email protected]>
  • Loading branch information
chippers and Ngo Iok Ui authored Apr 2, 2021
1 parent 1a88cd2 commit 20cb051
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 66 deletions.
5 changes: 5 additions & 0 deletions .changes/window-file-drop-handler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

Adds a `WindowProxy` to the file drop handler closure - `WindowFileDropHandler`.
2 changes: 1 addition & 1 deletion examples/dragndrop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() -> Result<()> {
},
None,
None,
Some(Box::new(|data| {
Some(Box::new(|_, data| {
println!("Window 1: {:?}", data);
false // Returning true will block the OS default behaviour.
})),
Expand Down
30 changes: 21 additions & 9 deletions src/application/general.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
application::{App, AppProxy, InnerWebViewAttributes, InnerWindowAttributes},
ApplicationProxy, Attributes, CustomProtocol, Error, Event as WryEvent, Icon, Message, Result,
WebView, WebViewBuilder, WindowEvent as WryWindowEvent, WindowMessage, WindowProxy,
WindowRpcHandler,
WebView, WebViewBuilder, WindowEvent as WryWindowEvent, WindowFileDropHandler, WindowMessage,
WindowProxy, WindowRpcHandler,
};

#[cfg(target_os = "windows")]
Expand Down Expand Up @@ -46,8 +46,6 @@ use {
winit::platform::windows::WindowExtWindows,
};

use crate::FileDropHandler;

type EventLoopProxy = winit::event_loop::EventLoopProxy<Message>;

#[derive(Clone)]
Expand All @@ -68,7 +66,7 @@ impl AppProxy for InnerApplicationProxy {
fn add_window(
&self,
attributes: Attributes,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
) -> Result<WindowId> {
Expand Down Expand Up @@ -150,7 +148,7 @@ impl App for InnerApplication {
fn create_webview(
&mut self,
attributes: Attributes,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
) -> Result<Self::Id> {
Expand Down Expand Up @@ -407,7 +405,7 @@ fn _create_webview(
window: Window,
custom_protocol: Option<CustomProtocol>,
rpc_handler: Option<WindowRpcHandler>,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,

attributes: InnerWebViewAttributes,
) -> Result<WebView> {
Expand All @@ -425,10 +423,11 @@ fn _create_webview(
webview = webview.register_protocol(protocol.name, protocol.handler)
}

let proxy_ = proxy.clone();
webview = webview.set_rpc_handler(Box::new(move |mut request| {
let proxy = WindowProxy::new(
ApplicationProxy {
inner: proxy.clone(),
inner: proxy_.clone(),
},
window_id,
);
Expand All @@ -448,7 +447,20 @@ fn _create_webview(
}
}));

webview = webview.set_file_drop_handler(file_drop_handler);
webview = webview.set_file_drop_handler(Some(Box::new(move |event| {
let proxy = WindowProxy::new(
ApplicationProxy {
inner: proxy.clone(),
},
window_id,
);

if let Some(file_drop_handler) = &file_drop_handler {
file_drop_handler(proxy, event)
} else {
false
}
})));

webview = match attributes.url {
Some(url) => webview.load_url(&url)?,
Expand Down
28 changes: 21 additions & 7 deletions src/application/gtkrs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
application::{App, AppProxy, InnerWebViewAttributes, InnerWindowAttributes},
ApplicationProxy, Attributes, CustomProtocol, Error, Event as WryEvent, FileDropHandler, Icon,
Message, Result, WebView, WebViewBuilder, WindowEvent as WryWindowEvent, WindowMessage,
ApplicationProxy, Attributes, CustomProtocol, Error, Event as WryEvent, Icon, Message, Result,
WebView, WebViewBuilder, WindowEvent as WryWindowEvent, WindowFileDropHandler, WindowMessage,
WindowProxy, WindowRpcHandler,
};

Expand Down Expand Up @@ -51,7 +51,7 @@ impl AppProxy for InnerApplicationProxy {
fn add_window(
&self,
attributes: Attributes,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
) -> Result<WindowId> {
Expand Down Expand Up @@ -104,7 +104,7 @@ impl App for InnerApplication {
fn create_webview(
&mut self,
attributes: Attributes,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
) -> Result<Self::Id> {
Expand Down Expand Up @@ -452,7 +452,7 @@ fn _create_webview(
window: ApplicationWindow,
custom_protocol: Option<CustomProtocol>,
rpc_handler: Option<WindowRpcHandler>,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,

attributes: InnerWebViewAttributes,
) -> Result<WebView> {
Expand All @@ -470,10 +470,11 @@ fn _create_webview(
webview = webview.register_protocol(protocol.name, protocol.handler);
}

let proxy_ = proxy.clone();
webview = webview.set_rpc_handler(Box::new(move |mut request| {
let proxy = WindowProxy::new(
ApplicationProxy {
inner: proxy.clone(),
inner: proxy_.clone(),
},
window_id,
);
Expand All @@ -493,7 +494,20 @@ fn _create_webview(
}
}));

webview = webview.set_file_drop_handler(file_drop_handler);
webview = webview.set_file_drop_handler(Some(Box::new(move |event| {
let proxy = WindowProxy::new(
ApplicationProxy {
inner: proxy.clone(),
},
window_id,
);

if let Some(file_drop_handler) = &file_drop_handler {
file_drop_handler(proxy, event)
} else {
false
}
})));

let webview = webview.build()?;
Ok(webview)
Expand Down
12 changes: 6 additions & 6 deletions src/application/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod attributes;
pub use attributes::{Attributes, CustomProtocol, Icon, WindowRpcHandler};
pub(crate) use attributes::{InnerWebViewAttributes, InnerWindowAttributes};

use crate::{FileDropHandler, Result};
use crate::{Result, WindowFileDropHandler};

use std::sync::mpsc::Sender;

Expand Down Expand Up @@ -64,7 +64,7 @@ pub enum Message {
NewWindow(
Attributes,
Sender<WindowId>,
Option<FileDropHandler>,
Option<WindowFileDropHandler>,
Option<WindowRpcHandler>,
Option<CustomProtocol>,
),
Expand Down Expand Up @@ -97,7 +97,7 @@ impl ApplicationProxy {
attributes: Attributes,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
) -> Result<WindowProxy> {
let id = self
.inner
Expand All @@ -116,7 +116,7 @@ trait AppProxy {
fn add_window(
&self,
attributes: Attributes,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
) -> Result<WindowId>;
Expand Down Expand Up @@ -353,7 +353,7 @@ impl Application {
attributes: Attributes,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
) -> Result<WindowProxy> {
let id =
self
Expand Down Expand Up @@ -392,7 +392,7 @@ trait App: Sized {
fn create_webview(
&mut self,
attributes: Attributes,
file_drop_handler: Option<FileDropHandler>,
file_drop_handler: Option<WindowFileDropHandler>,
rpc_handler: Option<WindowRpcHandler>,
custom_protocol: Option<CustomProtocol>,
) -> Result<Self::Id>;
Expand Down
30 changes: 28 additions & 2 deletions src/file_drop.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::path::PathBuf;

use crate::WindowProxy;

/// An event enumeration sent to [`FileDropHandler`].
#[derive(Debug, Serialize, Clone)]
pub enum FileDropEvent {
Expand All @@ -11,11 +13,35 @@ pub enum FileDropEvent {
Cancelled,
}

/// A listener closure to process incoming [`FileDropEvent`] of the window.
/// A listener closure to process incoming [`FileDropEvent`] of the webview.
///
/// Users can pass a [`WindowFileDropHandler`] to [`Application::add_window_with_configs`](crate::Application::add_window_with_configs)
/// to register incoming file drop events to a closure.
///
/// # Blocking OS Default Behavior
/// Return `true` in the callback to block the OS' default behavior of handling a file drop.
///
/// Note, that if you do block this behavior, it won't be possible to drop files on `<input type="file">` forms.
/// Also note, that it's not possible to manually set the value of a `<input type="file">` via JavaScript for security reasons.
pub type FileDropHandler = Box<dyn Fn(FileDropEvent) -> bool + Send>;
///
/// # Example
///
/// ```no_run
/// use wry::{Application, Result, WindowProxy, FileDropEvent};
///
/// fn main() -> Result<()> {
/// let mut app = Application::new()?;
/// let file_drop = Box::new(|window: WindowProxy, event: FileDropEvent| {
/// // Use the `WindowProxy` to modify the window, eg: `set_fullscreen` etc.
/// //
/// // Use the `FileDropEvent` to see the current state of the file drop.
/// //
/// // Return `true` to block the default file drop behavior of the OS.
/// false
/// });
/// app.add_window_with_configs(Default::default(), None, None, Some(file_drop))?;
/// app.run();
/// Ok(())
/// }
/// ```
pub type WindowFileDropHandler = Box<dyn Fn(WindowProxy, FileDropEvent) -> bool + Send>;
33 changes: 17 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,34 +70,35 @@ extern crate thiserror;
#[macro_use]
extern crate objc;

mod file_drop;
#[cfg(feature = "file-drop")]
pub use file_drop::{FileDropEvent, FileDropHandler};
#[cfg(not(feature = "file-drop"))]
pub(crate) use file_drop::{FileDropEvent, FileDropHandler};
use std::sync::mpsc::{RecvError, SendError};

pub use serde_json::Value;
use url::ParseError;
#[cfg(not(target_os = "linux"))]
use winit::window::BadIcon;

#[cfg(feature = "protocol")]
pub use application::CustomProtocol;
#[cfg(not(feature = "protocol"))]
pub(crate) use application::CustomProtocol;

mod application;
pub mod webview;

pub use application::{
Application, ApplicationProxy, Attributes, Event, Icon, Message, WindowEvent, WindowId,
WindowMessage, WindowProxy, WindowRpcHandler,
};
pub use serde_json::Value;
#[cfg(not(feature = "file-drop"))]
pub(crate) use file_drop::FileDropEvent;
#[cfg(feature = "file-drop")]
pub use file_drop::{FileDropEvent, WindowFileDropHandler};
#[cfg(not(feature = "file-drop"))]
pub(crate) use webview::FileDropHandler;
#[cfg(feature = "file-drop")]
pub use webview::FileDropHandler;
pub(crate) use webview::{RpcHandler, WebView, WebViewBuilder};
pub use webview::{RpcRequest, RpcResponse};

#[cfg(not(target_os = "linux"))]
use winit::window::BadIcon;

use std::sync::mpsc::{RecvError, SendError};

use url::ParseError;
mod application;
mod file_drop;
pub mod webview;

/// Convenient type alias of Result type for wry.
pub type Result<T> = std::result::Result<T, Error>;
Expand Down
4 changes: 2 additions & 2 deletions src/webview/linux/file_drop.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{FileDropEvent, FileDropHandler};

use std::{cell::Cell, path::PathBuf, rc::Rc};

use gtk::WidgetExt;
use webkit2gtk::WebView;

use crate::{webview::FileDropHandler, FileDropEvent};

pub(crate) fn connect_drag_event(webview: Rc<WebView>, handler: FileDropHandler) {
let listener = Rc::new((handler, Cell::new(None)));

Expand Down
14 changes: 7 additions & 7 deletions src/webview/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
mod file_drop;

use crate::{
webview::{mimetype::MimeType, WV},
Error, FileDropHandler, Result, RpcHandler,
};

use std::{path::PathBuf, rc::Rc};

use gdk::RGBA;
Expand All @@ -18,6 +11,13 @@ use webkit2gtk::{
WebContextExt, WebView, WebViewExt, WebViewExtManual,
};

use crate::{
webview::{mimetype::MimeType, FileDropHandler, WV},
Error, Result, RpcHandler,
};

mod file_drop;

pub struct InnerWebView {
webview: Rc<WebView>,
}
Expand Down
11 changes: 4 additions & 7 deletions src/webview/macos/file_drop.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
use crate::{FileDropEvent, FileDropHandler};

use std::{
ffi::{c_void, CStr},
path::PathBuf,
};

use once_cell::sync::Lazy;

use cocoa::base::{id, BOOL, YES};
use objc::{
declare::ClassDecl,
runtime::{Object, Sel},
runtime::{class_getInstanceMethod, method_getImplementation, Object, Sel},
};
use once_cell::sync::Lazy;

use crate::{webview::FileDropHandler, FileDropEvent};

pub(crate) type NSDragOperation = cocoa::foundation::NSUInteger;
#[allow(non_upper_case_globals)]
const NSDragOperationLink: NSDragOperation = 2;

use objc::runtime::{class_getInstanceMethod, method_getImplementation};

static OBJC_DRAGGING_ENTERED: Lazy<extern "C" fn(*const Object, Sel, id) -> NSDragOperation> =
Lazy::new(|| unsafe {
std::mem::transmute(method_getImplementation(class_getInstanceMethod(
Expand Down
Loading

0 comments on commit 20cb051

Please sign in to comment.