vcl/ios/clipboard.cxx | 77 +++++++++++++++++++++++++++++++++++++++++++++++++- vcl/ios/clipboard.hxx | 15 +++++++++ 2 files changed, 91 insertions(+), 1 deletion(-)
New commits: commit 4e5040dc44024f8313ca51627b6871675865cdf6 Author: Patrick Luby <guibmac...@gmail.com> AuthorDate: Sat Apr 13 19:46:48 2024 -0400 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Mon May 13 12:05:05 2024 +0200 cool#5839 fire a clipboard changed event in the iOS app A clipboard changed event needs to be fired whenever the native general pasteboard changes. Otherwise, if the clipboard is empty when a document is opened, the Paste and Paste Special menu items and toolbar buttons will be disabled and will never be enabled even after something has been copied to the general pasteboard. Change-Id: I8a70a2ac4de55593a886233d144dc18c3c57178e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166073 Reviewed-by: Patrick Luby <guibomac...@gmail.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Andras Timar <andras.ti...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167570 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/vcl/ios/clipboard.cxx b/vcl/ios/clipboard.cxx index 59209504da31..109f744e87c8 100644 --- a/vcl/ios/clipboard.cxx +++ b/vcl/ios/clipboard.cxx @@ -29,6 +29,56 @@ #include <comphelper/processfactory.hxx> #include <cppuhelper/supportsservice.hxx> +@implementation PasteboardChangedEventListener + +- (PasteboardChangedEventListener*)initWithiOSClipboard:(iOSClipboard*)pcb +{ + self = [super init]; + + if (self) + { + // Just to be safe, set clipboard to a nullptr to ignore any + // synchronous callbacks that might occur when adding the observer + piOSClipboard = nullptr; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(pasteboardChanged:) + name:UIPasteboardChangedNotification + object:[UIPasteboard generalPasteboard]]; + + // According to following, no UIPasteboardChangedNotification + // notifications are received when an app is not active. So, post the + // notification so that the LibreOffice vcl/ios code can handle any + // clipboard changes: + // https://stackoverflow.com/questions/4240087/receiving-uipasteboard-generalpasteboard-notification-while-in-the-background + // Note: UIApplicationDidBecomeActiveNotification is never sent when + // running in Mac Catalyst so listen for UISceneDidActivateNotification + // instead. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(pasteboardChanged:) + name:UISceneDidActivateNotification + object:nil]; + + piOSClipboard = pcb; + } + + return self; +} + +- (void)pasteboardChanged:(NSNotification*)aNotification +{ + if (piOSClipboard) + piOSClipboard->contentsChanged(); +} + +- (void)disposing +{ + piOSClipboard = nullptr; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end + iOSClipboard::iOSClipboard() : WeakComponentImplHelper<XSystemClipboard, XServiceInfo>(m_aMutex) { @@ -37,9 +87,17 @@ iOSClipboard::iOSClipboard() mrXMimeCntFactory = css::datatransfer::MimeContentTypeFactory::create(xContext); mpDataFlavorMapper.reset(new DataFlavorMapper()); + + mnPasteboardChangeCount = 0; + mpPasteboardChangedEventListener = + [[PasteboardChangedEventListener alloc] initWithiOSClipboard:this]; } -iOSClipboard::~iOSClipboard() {} +iOSClipboard::~iOSClipboard() +{ + [mpPasteboardChangedEventListener disposing]; + [mpPasteboardChangedEventListener release]; +} css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL iOSClipboard::getContents() { @@ -173,6 +231,23 @@ css::uno::Sequence<OUString> SAL_CALL iOSClipboard::getSupportedServiceNames() return { OUString("com.sun.star.datatransfer.clipboard.SystemClipboard") }; } +void iOSClipboard::contentsChanged() +{ + NSInteger nPasteboardChangeCount = [[UIPasteboard generalPasteboard] changeCount]; + if (mnPasteboardChangeCount != nPasteboardChangeCount) + { + // cool#5839 fire a clipboard changed event in the iOS app + // A clipboard changed event needs to be fired whenever the + // native general pasteboard changes. Otherwise, if the clipboard + // is empty when a document is opened, the Paste and Paste Special + // menu items and toolbar buttons will be disabled and will never + // be enabled even after something has been copied to the general + // pasteboard. + mnPasteboardChangeCount = nPasteboardChangeCount; + fireClipboardChangedEvent(getContents()); + } +} + css::uno::Reference<css::uno::XInterface> IosSalInstance::CreateClipboard(const css::uno::Sequence<css::uno::Any>&) { diff --git a/vcl/ios/clipboard.hxx b/vcl/ios/clipboard.hxx index 086840912650..e1133f0ba0bf 100644 --- a/vcl/ios/clipboard.hxx +++ b/vcl/ios/clipboard.hxx @@ -41,6 +41,17 @@ #import <UIKit/UIKit.h> #include <postmac.h> +class iOSClipboard; + +@interface PasteboardChangedEventListener : NSObject +{ + iOSClipboard* piOSClipboard; +} +- (PasteboardChangedEventListener*)initWithiOSClipboard:(iOSClipboard*)pcb; +- (void)pasteboardChanged:(NSNotification*)aNotification; +- (void)disposing; +@end + class iOSClipboard : public ::cppu::BaseMutex, public ::cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard, @@ -86,6 +97,8 @@ public: css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + void contentsChanged(); + private: /* Notify the current clipboard owner that he is no longer the clipboard owner. */ void fireLostClipboardOwnershipEvent( @@ -102,6 +115,8 @@ private: mClipboardListeners; css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> mXClipboardOwner; std::shared_ptr<DataFlavorMapper> mpDataFlavorMapper; + NSInteger mnPasteboardChangeCount; + PasteboardChangedEventListener* mpPasteboardChangedEventListener; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */