diff --git a/super_clipboard/lib/src/events.dart b/super_clipboard/lib/src/events.dart index 3e63fb02..d5fbcf5d 100644 --- a/super_clipboard/lib/src/events.dart +++ b/super_clipboard/lib/src/events.dart @@ -4,6 +4,7 @@ import 'reader.dart'; import 'writer.dart'; import 'writer_data_provider.dart'; import 'system_clipboard.dart'; +export 'package:super_native_extensions/raw_clipboard.dart' show TextEvent; /// Event dispatched during a browser paste action (only available on web). /// Allows reading data from clipboard. @@ -44,9 +45,16 @@ class ClipboardWriteEvent extends ClipboardWriter { @override Future write(Iterable items) async { - items.withHandlesSync((handles) async { - _event.write(handles); - }); + final token = _event.beginWrite(); + if (_event.isSynchronous) { + items.withHandlesSync((handles) async { + _event.write(token, handles); + }); + } else { + items.withHandles((handles) async { + _event.write(token, handles); + }); + } } } @@ -134,3 +142,32 @@ class ClipboardEvents { static final _cutEventListeners = []; } + +class TextEvents { + TextEvents._() { + raw.ClipboardEvents.instance.registerTextEventListener(_onTextEvent); + } + + /// Returns clipboard events instance if available on current platform. + /// This is only supported on web, on other platforms use [SystemClipboard.instance] + /// to access the clipboard. + static TextEvents get instance => TextEvents._(); + + void registerTextEventListener(bool Function(raw.TextEvent) listener) { + _textEventListeners.add(listener); + } + + void unregisterTextEventListener(bool Function(raw.TextEvent) listener) { + _textEventListeners.remove(listener); + } + + bool _onTextEvent(raw.TextEvent event) { + bool handled = false; + for (final listener in _textEventListeners) { + handled |= listener(event); + } + return handled; + } + + static final _textEventListeners = []; +} diff --git a/super_native_extensions/ios/Classes/SuperNativeExtensionsPlugin.m b/super_native_extensions/ios/Classes/SuperNativeExtensionsPlugin.m index 9b2532a3..c4e90c21 100644 --- a/super_native_extensions/ios/Classes/SuperNativeExtensionsPlugin.m +++ b/super_native_extensions/ios/Classes/SuperNativeExtensionsPlugin.m @@ -1,11 +1,20 @@ #import "SuperNativeExtensionsPlugin.h" +#include + extern void super_native_extensions_init(void); +extern bool super_native_extensions_text_input_plugin_cut(void); +extern bool super_native_extensions_text_input_plugin_copy(void); +extern bool super_native_extensions_text_input_plugin_paste(void); +extern bool super_native_extensions_text_input_plugin_select_all(void); + +static void swizzleTextInputPlugin(); @implementation SuperNativeExtensionsPlugin + (void)initialize { super_native_extensions_init(); + swizzleTextInputPlugin(); } + (void)registerWithRegistrar:(NSObject *)registrar { @@ -59,3 +68,85 @@ - (void)relinquishPresentedItemToReader: } @end + +@interface SNETextInputPlugin : NSObject +@end + +@implementation SNETextInputPlugin + +- (void)cut_:(id)sender { + if (!super_native_extensions_text_input_plugin_cut()) { + [self cut_:sender]; + } +} + +- (void)copy_:(id)sender { + if (!super_native_extensions_text_input_plugin_copy()) { + [self copy_:sender]; + } +} + +- (void)paste_:(id)sender { + if (!super_native_extensions_text_input_plugin_paste()) { + [self paste_:sender]; + } +} + +- (void)selectAll_:(id)sender { + if (!super_native_extensions_text_input_plugin_select_all()) { + [self selectAll_:sender]; + } +} + +@end + +static void swizzle(SEL originalSelector, Class originalClass, + SEL replacementSelector, Class replacementClass) { + Method origMethod = class_getInstanceMethod(originalClass, originalSelector); + + if (!origMethod) { +#if DEBUG + NSLog(@"Original method %@ not found for class %s", + NSStringFromSelector(originalSelector), class_getName(originalClass)); +#endif + return; + } + + Method altMethod = + class_getInstanceMethod(replacementClass, replacementSelector); + if (!altMethod) { +#if DEBUG + NSLog(@"Alternate method %@ not found for class %s", + NSStringFromSelector(replacementSelector), + class_getName(originalClass)); +#endif + return; + } + + class_addMethod( + originalClass, originalSelector, + class_getMethodImplementation(originalClass, originalSelector), + method_getTypeEncoding(origMethod)); + class_addMethod( + originalClass, replacementSelector, + class_getMethodImplementation(replacementClass, replacementSelector), + method_getTypeEncoding(altMethod)); + + method_exchangeImplementations( + class_getInstanceMethod(originalClass, originalSelector), + class_getInstanceMethod(originalClass, replacementSelector)); +} + +static void swizzleTextInputPlugin() { + Class cls = NSClassFromString(@"FlutterTextInputView"); + if (cls == nil) { + NSLog(@"FlutterTextInputPlugin not found"); + return; + } + + Class replacement = [SNETextInputPlugin class]; + swizzle(@selector(cut:), cls, @selector(cut_:), replacement); + swizzle(@selector(copy:), cls, @selector(copy_:), replacement); + swizzle(@selector(paste:), cls, @selector(paste_:), replacement); + swizzle(@selector(selectAll:), cls, @selector(selectAll_:), replacement); +} diff --git a/super_native_extensions/lib/src/clipboard_events.dart b/super_native_extensions/lib/src/clipboard_events.dart index 4dff1442..abd9b09c 100644 --- a/super_native_extensions/lib/src/clipboard_events.dart +++ b/super_native_extensions/lib/src/clipboard_events.dart @@ -11,7 +11,13 @@ abstract class ClipboardReadEvent { } abstract class ClipboardWriteEvent { - void write(List providers); + bool get isSynchronous; + Object beginWrite(); // Returns token + void write(Object token, List providers); +} + +enum TextEvent { + selectAll, } abstract class ClipboardEvents { @@ -32,4 +38,8 @@ abstract class ClipboardEvents { void registerCutEventListener(void Function(ClipboardWriteEvent) listener); void unregisterCutEventListener(void Function(ClipboardWriteEvent) listener); + + void registerTextEventListener(bool Function(TextEvent) listener); + + void unregisterTextEventListener(bool Function(TextEvent) listener); } diff --git a/super_native_extensions/lib/src/native/clipboard_events.dart b/super_native_extensions/lib/src/native/clipboard_events.dart index fe9c7fc9..76588d2c 100644 --- a/super_native_extensions/lib/src/native/clipboard_events.dart +++ b/super_native_extensions/lib/src/native/clipboard_events.dart @@ -1,30 +1,149 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:irondash_message_channel/irondash_message_channel.dart'; + import '../clipboard_events.dart'; +import '../clipboard_reader.dart'; +import '../clipboard_writer.dart'; +import '../data_provider.dart'; +import '../reader.dart'; +import 'context.dart'; + +class _ClipboardWriteEvent extends ClipboardWriteEvent { + final _completers = []; + + @override + void write(Object token, List providers) async { + final completer = token as Completer; + await ClipboardWriter.instance.write(providers); + completer.complete(); + } + + @override + Object beginWrite() { + final completer = Completer(); + _completers.add(completer); + return completer; + } + + @override + bool get isSynchronous => false; +} + +class _ClipboardReadEvent extends ClipboardReadEvent { + _ClipboardReadEvent(this.reader); + + final DataReader reader; + bool didGetReader = false; + + @override + DataReader getReader() { + didGetReader = true; + return reader; + } +} class ClipboardEventsImpl extends ClipboardEvents { + ClipboardEventsImpl() { + _channel.setMethodCallHandler(_onMethodCall); + _channel.invokeMethod('newClipboardEventsManager'); + } + + Future _onMethodCall(MethodCall call) async { + if (call.method == 'copy') { + final writeEvent = _ClipboardWriteEvent(); + for (final listener in _copyEventListeners) { + listener(writeEvent); + } + if (writeEvent._completers.isNotEmpty) { + await Future.wait(writeEvent._completers.map((e) => e.future)); + return true; + } else { + return false; + } + } else if (call.method == 'cut') { + final writeEvent = _ClipboardWriteEvent(); + for (final listener in _cutEventListeners) { + listener(writeEvent); + } + if (writeEvent._completers.isNotEmpty) { + await Future.wait(writeEvent._completers.map((e) => e.future)); + return true; + } else { + return false; + } + } else if (call.method == 'paste') { + final reader = await ClipboardReader.instance.newClipboardReader(); + final writeEvent = _ClipboardReadEvent(reader); + for (final listener in _pasteEventListeners) { + listener(writeEvent); + } + return writeEvent.didGetReader; + } else if (call.method == 'selectAll') { + bool handled = false; + for (final listener in _textEventListeners) { + handled |= listener(TextEvent.selectAll); + } + return handled; + } + } + @override - bool get supported => false; + bool get supported => defaultTargetPlatform == TargetPlatform.iOS; + + final _pasteEventListeners = []; + final _copyEventListeners = []; + final _cutEventListeners = []; + final _textEventListeners = []; @override void registerPasteEventListener( - void Function(ClipboardReadEvent p1) listener) {} + void Function(ClipboardReadEvent p1) listener) { + _pasteEventListeners.add(listener); + } @override void unregisterPasteEventListener( - void Function(ClipboardReadEvent p1) listener) {} + void Function(ClipboardReadEvent p1) listener) { + _pasteEventListeners.remove(listener); + } @override void registerCopyEventListener( - void Function(ClipboardWriteEvent p1) listener) {} + void Function(ClipboardWriteEvent p1) listener) { + _copyEventListeners.add(listener); + } @override - void registerCutEventListener( - void Function(ClipboardWriteEvent p1) listener) {} + void unregisterCopyEventListener( + void Function(ClipboardWriteEvent p1) listener) { + _copyEventListeners.remove(listener); + } @override - void unregisterCopyEventListener( - void Function(ClipboardWriteEvent p1) listener) {} + void registerCutEventListener( + void Function(ClipboardWriteEvent p1) listener) { + _cutEventListeners.add(listener); + } @override void unregisterCutEventListener( - void Function(ClipboardWriteEvent p1) listener) {} + void Function(ClipboardWriteEvent p1) listener) { + _cutEventListeners.remove(listener); + } + + @override + void registerTextEventListener(bool Function(TextEvent) listener) { + _textEventListeners.add(listener); + } + + @override + void unregisterTextEventListener(bool Function(TextEvent) listener) { + _textEventListeners.remove(listener); + } + + final _channel = NativeMethodChannel('ClipboardEventManager', + context: superNativeExtensionsContext); } diff --git a/super_native_extensions/lib/src/web/clipboard_events.dart b/super_native_extensions/lib/src/web/clipboard_events.dart index b94a4876..57205935 100644 --- a/super_native_extensions/lib/src/web/clipboard_events.dart +++ b/super_native_extensions/lib/src/web/clipboard_events.dart @@ -34,6 +34,15 @@ class _PasteEvent extends ClipboardReadEvent { class _WriteEvent extends ClipboardWriteEvent { _WriteEvent({required this.event}); + @override + Object beginWrite() { + // Not needed for synchronous events; + return const Object(); + } + + @override + bool get isSynchronous => true; + void _setData(String type, Object? data) { if (data is! String) { throw UnsupportedError('HTML Clipboard event only supports String data.'); @@ -42,7 +51,7 @@ class _WriteEvent extends ClipboardWriteEvent { } @override - void write(List providers) { + void write(Object token, List providers) { event.preventDefault(); for (final provider in providers) { for (final repr in provider.provider.representations) { @@ -150,4 +159,10 @@ class ClipboardEventsImpl extends ClipboardEvents { void Function(ClipboardWriteEvent p1) listener) { _cutEventListeners.remove(listener); } + + @override + void registerTextEventListener(bool Function(TextEvent) listener) {} + + @override + void unregisterTextEventListener(bool Function(TextEvent) listener) {} } diff --git a/super_native_extensions/rust/src/android/clipboard_events.rs b/super_native_extensions/rust/src/android/clipboard_events.rs new file mode 100644 index 00000000..4e0ee4a7 --- /dev/null +++ b/super_native_extensions/rust/src/android/clipboard_events.rs @@ -0,0 +1,17 @@ +use crate::clipboard_events_manager::{ + ClipboardEventManagerDelegate, PlatformClipboardEventManagerId, +}; +use std::rc::Weak; + +pub struct PlatformClipboardEventManager {} + +impl PlatformClipboardEventManager { + pub fn new( + _id: PlatformClipboardEventManagerId, + _delegate: Weak, + ) -> Self { + Self {} + } + + pub fn assign_weak_self(&self, _weak: Weak) {} +} diff --git a/super_native_extensions/rust/src/android/mod.rs b/super_native_extensions/rust/src/android/mod.rs index 7e90d374..20c79675 100644 --- a/super_native_extensions/rust/src/android/mod.rs +++ b/super_native_extensions/rust/src/android/mod.rs @@ -1,3 +1,4 @@ +mod clipboard_events; mod data_provider; mod drag; mod drag_common; @@ -8,6 +9,7 @@ mod menu; mod reader; mod util; +pub use clipboard_events::*; pub use data_provider::*; pub use drag::*; pub use drop::*; diff --git a/super_native_extensions/rust/src/clipboard_events_manager.rs b/super_native_extensions/rust/src/clipboard_events_manager.rs new file mode 100644 index 00000000..6ce19d93 --- /dev/null +++ b/super_native_extensions/rust/src/clipboard_events_manager.rs @@ -0,0 +1,132 @@ +use std::{ + cell::RefCell, + collections::HashMap, + rc::{Rc, Weak}, +}; + +use async_trait::async_trait; +use irondash_message_channel::{ + AsyncMethodHandler, AsyncMethodInvoker, IsolateId, Late, MethodCall, PlatformError, + PlatformResult, RegisteredAsyncMethodHandler, Value, +}; +use log::warn; + +use crate::{ + context::Context, error::NativeExtensionsResult, log::OkLog, + platform::PlatformClipboardEventManager, +}; + +// Each isolate has its own DragContext. +pub type PlatformClipboardEventManagerId = IsolateId; + +pub struct ClipboardEventManager { + invoker: Late, + platform_managers: + RefCell>>, + weak_self: Late>, +} + +#[async_trait(?Send)] +pub trait ClipboardEventManagerDelegate { + async fn on_cut(&self, isolate_id: IsolateId) -> bool; + async fn on_copy(&self, isolate_id: IsolateId) -> bool; + async fn on_paste(&self, isolate_id: IsolateId) -> bool; + async fn on_select_all(&self, isolate_id: IsolateId) -> bool; +} + +pub trait GetClipboardEventManager { + fn clipboard_event_manager(&self) -> Rc; +} + +impl GetClipboardEventManager for Context { + fn clipboard_event_manager(&self) -> Rc { + self.get_attachment(ClipboardEventManager::new).handler() + } +} + +impl ClipboardEventManager { + pub fn new() -> RegisteredAsyncMethodHandler { + Self { + invoker: Late::new(), + platform_managers: RefCell::new(HashMap::new()), + weak_self: Late::new(), + } + .register("ClipboardEventManager") + } + + fn new_clipboard_events_manager(&self, isolate: IsolateId) -> NativeExtensionsResult<()> { + if self.platform_managers.borrow().get(&isolate).is_some() { + // Can happen during hot reload + warn!("DragContext already exists for isolate {:?}", isolate); + return Ok(()); + } + let context = Rc::new(PlatformClipboardEventManager::new( + isolate, + self.weak_self.clone(), + )); + context.assign_weak_self(Rc::downgrade(&context)); + self.platform_managers.borrow_mut().insert(isolate, context); + Ok(()) + } +} + +#[async_trait(?Send)] +impl ClipboardEventManagerDelegate for ClipboardEventManager { + async fn on_cut(&self, isolate_id: IsolateId) -> bool { + let res = self + .invoker + .call_method_cv(isolate_id, "cut", Value::Null) + .await; + res.ok_log().unwrap_or(false) + } + + async fn on_copy(&self, isolate_id: IsolateId) -> bool { + let res = self + .invoker + .call_method_cv(isolate_id, "copy", Value::Null) + .await; + res.ok_log().unwrap_or(false) + } + + async fn on_paste(&self, isolate_id: IsolateId) -> bool { + let res = self + .invoker + .call_method_cv(isolate_id, "paste", Value::Null) + .await; + res.ok_log().unwrap_or(false) + } + + async fn on_select_all(&self, isolate_id: IsolateId) -> bool { + let res = self + .invoker + .call_method_cv(isolate_id, "selectAll", Value::Null) + .await; + res.ok_log().unwrap_or(false) + } +} + +#[async_trait(?Send)] +impl AsyncMethodHandler for ClipboardEventManager { + fn assign_invoker(&self, invoker: AsyncMethodInvoker) { + self.invoker.set(invoker); + } + + fn assign_weak_self(&self, weak_self: Weak) { + self.weak_self.set(weak_self); + } + + async fn on_method_call(&self, call: MethodCall) -> PlatformResult { + #[allow(clippy::match_single_binding)] + match call.method.as_str() { + "newClipboardEventsManager" => { + self.new_clipboard_events_manager(call.isolate)?; + Ok(Value::Null) + } + _ => Err(PlatformError { + code: "invalid_method".into(), + message: Some(format!("Unknown Method: {}", call.method)), + detail: Value::Null, + }), + } + } +} diff --git a/super_native_extensions/rust/src/darwin/ios/clipboard_events.rs b/super_native_extensions/rust/src/darwin/ios/clipboard_events.rs new file mode 100644 index 00000000..2857d14b --- /dev/null +++ b/super_native_extensions/rust/src/darwin/ios/clipboard_events.rs @@ -0,0 +1,174 @@ +use std::{ + cell::{Cell, RefCell}, + rc::{Rc, Weak}, +}; + +use irondash_message_channel::Late; +use irondash_run_loop::{platform::PollSession, spawn, RunLoop}; + +use crate::clipboard_events_manager::{ + ClipboardEventManagerDelegate, PlatformClipboardEventManagerId, +}; + +thread_local! { + pub static MANAGERS : RefCell>> = const { RefCell::new(Vec::new()) }; +} + +fn managers() -> Vec> { + MANAGERS.with(|m| m.borrow().iter().filter_map(|m| m.upgrade()).collect()) +} + +pub struct PlatformClipboardEventManager { + id: PlatformClipboardEventManagerId, + delegate: Weak, + weak_self: Late>, +} + +impl PlatformClipboardEventManager { + pub fn new( + id: PlatformClipboardEventManagerId, + delegate: Weak, + ) -> Self { + Self { + id, + delegate, + weak_self: Late::new(), + } + } + + pub fn assign_weak_self(&self, weak: Weak) { + self.weak_self.set(weak.clone()); + MANAGERS.with(|m| { + m.borrow_mut().push(weak); + }); + } + + async fn on_cut(&self) -> bool { + let delegate = self.delegate.upgrade(); + match delegate { + None => false, + Some(delegate) => delegate.on_cut(self.id).await, + } + } + + async fn on_copy(&self) -> bool { + let delegate = self.delegate.upgrade(); + match delegate { + None => false, + Some(delegate) => delegate.on_copy(self.id).await, + } + } + + async fn on_paste(&self) -> bool { + let delegate = self.delegate.upgrade(); + match delegate { + None => false, + Some(delegate) => delegate.on_paste(self.id).await, + } + } + + async fn on_select_all(&self) -> bool { + let delegate = self.delegate.upgrade(); + match delegate { + None => false, + Some(delegate) => delegate.on_select_all(self.id).await, + } + } +} + +impl Drop for PlatformClipboardEventManager { + fn drop(&mut self) { + MANAGERS.with(|m| { + let mut managers = m.borrow_mut(); + managers.retain(|m| m.as_ptr() != self.weak_self.as_ptr()); + }); + } +} + +#[no_mangle] +pub extern "C" fn super_native_extensions_text_input_plugin_cut() -> bool { + let mut handled = false; + let managers = managers(); + for manager in managers { + let done = Rc::new(Cell::new(None)); + let done2 = done.clone(); + spawn(async move { + let handled = manager.on_cut().await; + done2.set(Some(handled)); + }); + let mut poll_session = PollSession::new(); + while done.get().is_none() { + RunLoop::current() + .platform_run_loop + .poll_once(&mut poll_session); + } + handled = handled || done.get().unwrap(); + } + handled +} + +#[no_mangle] +pub extern "C" fn super_native_extensions_text_input_plugin_copy() -> bool { + let mut handled = false; + let managers = managers(); + for manager in managers { + let done = Rc::new(Cell::new(None)); + let done2 = done.clone(); + spawn(async move { + let handled = manager.on_copy().await; + done2.set(Some(handled)); + }); + let mut poll_session = PollSession::new(); + while done.get().is_none() { + RunLoop::current() + .platform_run_loop + .poll_once(&mut poll_session); + } + handled = handled || done.get().unwrap(); + } + handled +} + +#[no_mangle] +pub extern "C" fn super_native_extensions_text_input_plugin_paste() -> bool { + let mut handled = false; + let managers = managers(); + for manager in managers { + let done = Rc::new(Cell::new(None)); + let done2 = done.clone(); + spawn(async move { + let handled = manager.on_paste().await; + done2.set(Some(handled)); + }); + let mut poll_session = PollSession::new(); + while done.get().is_none() { + RunLoop::current() + .platform_run_loop + .poll_once(&mut poll_session); + } + handled = handled || done.get().unwrap(); + } + handled +} + +#[no_mangle] +pub extern "C" fn super_native_extensions_text_input_plugin_select_all() -> bool { + let mut handled = false; + let managers = managers(); + for manager in managers { + let done = Rc::new(Cell::new(None)); + let done2 = done.clone(); + spawn(async move { + let handled = manager.on_select_all().await; + done2.set(Some(handled)); + }); + let mut poll_session = PollSession::new(); + while done.get().is_none() { + RunLoop::current() + .platform_run_loop + .poll_once(&mut poll_session); + } + handled = handled || done.get().unwrap(); + } + handled +} diff --git a/super_native_extensions/rust/src/darwin/ios/mod.rs b/super_native_extensions/rust/src/darwin/ios/mod.rs index f3e5b4e7..01d7bfd0 100644 --- a/super_native_extensions/rust/src/darwin/ios/mod.rs +++ b/super_native_extensions/rust/src/darwin/ios/mod.rs @@ -1,4 +1,5 @@ mod alpha_to_path; +mod clipboard_events; mod data_provider; mod drag; mod drag_common; @@ -10,6 +11,7 @@ mod objc_drop_notifier; mod reader; mod util; +pub use clipboard_events::*; pub use data_provider::*; pub use drag::*; pub use drop::*; diff --git a/super_native_extensions/rust/src/darwin/macos/clipboard_events.rs b/super_native_extensions/rust/src/darwin/macos/clipboard_events.rs new file mode 100644 index 00000000..4e0ee4a7 --- /dev/null +++ b/super_native_extensions/rust/src/darwin/macos/clipboard_events.rs @@ -0,0 +1,17 @@ +use crate::clipboard_events_manager::{ + ClipboardEventManagerDelegate, PlatformClipboardEventManagerId, +}; +use std::rc::Weak; + +pub struct PlatformClipboardEventManager {} + +impl PlatformClipboardEventManager { + pub fn new( + _id: PlatformClipboardEventManagerId, + _delegate: Weak, + ) -> Self { + Self {} + } + + pub fn assign_weak_self(&self, _weak: Weak) {} +} diff --git a/super_native_extensions/rust/src/darwin/macos/mod.rs b/super_native_extensions/rust/src/darwin/macos/mod.rs index 1baa98bc..d886a328 100644 --- a/super_native_extensions/rust/src/darwin/macos/mod.rs +++ b/super_native_extensions/rust/src/darwin/macos/mod.rs @@ -1,3 +1,4 @@ +mod clipboard_events; mod data_provider; mod drag; mod drag_common; @@ -10,6 +11,7 @@ mod menu; mod reader; mod util; +pub use clipboard_events::*; pub use data_provider::*; pub use drag::*; pub use drop::*; diff --git a/super_native_extensions/rust/src/lib.rs b/super_native_extensions/rust/src/lib.rs index 9a90cae5..b7a50907 100644 --- a/super_native_extensions/rust/src/lib.rs +++ b/super_native_extensions/rust/src/lib.rs @@ -13,6 +13,7 @@ use std::ffi::c_void; use ::log::debug; +use clipboard_events_manager::GetClipboardEventManager; use clipboard_reader::GetClipboardReader; use clipboard_writer::GetClipboardWriter; use context::Context; @@ -28,6 +29,7 @@ use reader_manager::GetDataReaderManager; mod api_model; mod blur; +mod clipboard_events_manager; mod clipboard_reader; mod clipboard_writer; mod context; @@ -96,6 +98,7 @@ impl DataTransferPlugin { context.keyboard_map_manager(); context.hot_key_manager(); context.menu_manager(); + context.clipboard_event_manager(); DataTransferPlugin { _context: context } } } diff --git a/super_native_extensions/rust/src/linux/clipboard_events.rs b/super_native_extensions/rust/src/linux/clipboard_events.rs new file mode 100644 index 00000000..4e0ee4a7 --- /dev/null +++ b/super_native_extensions/rust/src/linux/clipboard_events.rs @@ -0,0 +1,17 @@ +use crate::clipboard_events_manager::{ + ClipboardEventManagerDelegate, PlatformClipboardEventManagerId, +}; +use std::rc::Weak; + +pub struct PlatformClipboardEventManager {} + +impl PlatformClipboardEventManager { + pub fn new( + _id: PlatformClipboardEventManagerId, + _delegate: Weak, + ) -> Self { + Self {} + } + + pub fn assign_weak_self(&self, _weak: Weak) {} +} diff --git a/super_native_extensions/rust/src/linux/mod.rs b/super_native_extensions/rust/src/linux/mod.rs index f07ecf18..df35e1bc 100644 --- a/super_native_extensions/rust/src/linux/mod.rs +++ b/super_native_extensions/rust/src/linux/mod.rs @@ -1,4 +1,5 @@ mod clipboard_async; +mod clipboard_events; mod common; mod data_provider; mod drag; @@ -10,6 +11,7 @@ mod menu; mod reader; mod signal; +pub use clipboard_events::*; pub use data_provider::*; pub use drag::*; pub use drop::*; diff --git a/super_native_extensions/rust/src/win32/clipboard_events.rs b/super_native_extensions/rust/src/win32/clipboard_events.rs new file mode 100644 index 00000000..4e0ee4a7 --- /dev/null +++ b/super_native_extensions/rust/src/win32/clipboard_events.rs @@ -0,0 +1,17 @@ +use crate::clipboard_events_manager::{ + ClipboardEventManagerDelegate, PlatformClipboardEventManagerId, +}; +use std::rc::Weak; + +pub struct PlatformClipboardEventManager {} + +impl PlatformClipboardEventManager { + pub fn new( + _id: PlatformClipboardEventManagerId, + _delegate: Weak, + ) -> Self { + Self {} + } + + pub fn assign_weak_self(&self, _weak: Weak) {} +} diff --git a/super_native_extensions/rust/src/win32/mod.rs b/super_native_extensions/rust/src/win32/mod.rs index 0d4766a3..afdb6794 100644 --- a/super_native_extensions/rust/src/win32/mod.rs +++ b/super_native_extensions/rust/src/win32/mod.rs @@ -1,3 +1,4 @@ +mod clipboard_events; mod common; mod data_object; mod data_provider; @@ -12,6 +13,7 @@ mod ole_initializer; mod reader; mod virtual_file_stream; +pub use clipboard_events::*; pub use data_provider::*; pub use drag::*; pub use drop::*;