vcl/ios/clipboard.cxx |   77 +++++++++++++++++++++++++++++++++++++++++++++++++-
 vcl/ios/clipboard.hxx |   15 +++++++++
 2 files changed, 91 insertions(+), 1 deletion(-)

New commits:
commit b16637b716479fcbd50acb47673df7e6d2fbdb61
Author:     Patrick Luby <[email protected]>
AuthorDate: Sat Apr 13 19:46:48 2024 -0400
Commit:     Andras Timar <[email protected]>
CommitDate: Mon Apr 15 07:20:46 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 <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Andras Timar <[email protected]>

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: */

Reply via email to