comphelper/source/misc/lok.cxx               |   21 +++++++++++++++++++++
 desktop/qa/desktop_lib/test_desktop_lib.cxx  |    3 ++-
 desktop/source/lib/init.cxx                  |   13 +++++++++++++
 include/LibreOfficeKit/LibreOfficeKit.h      |    4 ++++
 include/LibreOfficeKit/LibreOfficeKit.hxx    |    8 ++++++++
 include/LibreOfficeKit/LibreOfficeKitTypes.h |    3 +++
 include/comphelper/lok.hxx                   |    6 ++++++
 vcl/headless/svpinst.cxx                     |    6 +++++-
 8 files changed, 62 insertions(+), 2 deletions(-)

New commits:
commit c7fa6db8878565fb7fb057325ffcfeb82e72119c
Author:     Miklos Vajna <[email protected]>
AuthorDate: Wed Aug 14 09:14:02 2024 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Thu Aug 15 13:39:08 2024 +0200

    Related: cool#9735 vcl lok: add an AnyInput() callback
    
    Open the 300 pages bugdoc, paste a oneliner plain text content in a
    paragraph which is part of a numbered list, observe a 274 ms hang till
    layout is done for all pages, then we get an updated tile. This could be
    better, there is no such hang in the desktop case.
    
    What happens is that 1) vcl doesn't try to invoke the poll callback of
    the LOK client when there was a processed timer and 2) Writer layout
    doesn't try to split its work into pieces because the LOK client has no
    way to inform vcl that it has pending input events.
    
    Fix the first problem in this commit: add a new API that allows a LOK
    client to inform vcl that it has pending input events and use that
    SvpSalInstance::ImplYield(): if a LOK client has pending input events,
    then invoke the poll callback after each processed timer. For example,
    this allows the LOK client to process emitted callbacks between two idle
    layout jobs, word counting, etc.
    
    The second problem around Writer to use
    comphelper::LibreOfficeKit::anyInput() is not yet fixed.
    
    (cherry picked from commit a22fe103e7a26270b7213448c570400a563c18ba)
    
    Change-Id: I2e39253bfc4d1b5546bc60eef9ff05ccdc0868b9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171860
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Tested-by: Caolán McNamara <[email protected]>

diff --git a/comphelper/source/misc/lok.cxx b/comphelper/source/misc/lok.cxx
index c042b0c626e5..a7d037afaca4 100644
--- a/comphelper/source/misc/lok.cxx
+++ b/comphelper/source/misc/lok.cxx
@@ -37,6 +37,9 @@ static bool g_bLocalRendering(false);
 
 static Compat g_eCompatFlags(Compat::none);
 
+static std::function<bool(void*)> g_pAnyInputCallback;
+static void* g_pAnyInputCallbackData;
+
 namespace
 {
 
@@ -315,6 +318,24 @@ void statusIndicatorFinish()
         pStatusIndicatorCallback(pStatusIndicatorCallbackData, 
statusIndicatorCallbackType::Finish, 0, nullptr);
 }
 
+void setAnyInputCallback(std::function<bool(void*)> pAnyInputCallback, void* 
pData)
+{
+    g_pAnyInputCallback = pAnyInputCallback;
+    g_pAnyInputCallbackData = pData;
+}
+
+bool anyInput()
+{
+    bool bRet = false;
+
+    if (g_pAnyInputCallback && g_pAnyInputCallbackData)
+    {
+        bRet = g_pAnyInputCallback(g_pAnyInputCallbackData);
+    }
+
+    return bRet;
+}
+
 } // namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index eaa61c739b2f..c501f43d5315 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -3597,10 +3597,11 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(classOffset(21), offsetof(struct 
_LibreOfficeKitClass, startThreads));
     CPPUNIT_ASSERT_EQUAL(classOffset(22), offsetof(struct 
_LibreOfficeKitClass, setForkedChild));
     CPPUNIT_ASSERT_EQUAL(classOffset(23), offsetof(struct 
_LibreOfficeKitClass, extractDocumentStructureRequest));
+    CPPUNIT_ASSERT_EQUAL(classOffset(24), offsetof(struct 
_LibreOfficeKitClass, registerAnyInputCallback));
 
     // When extending LibreOfficeKit with a new function pointer,  add new 
assert for the offsetof the
     // new function pointer and bump this assert for the size of the class.
-    CPPUNIT_ASSERT_EQUAL(classOffset(24), sizeof(struct _LibreOfficeKitClass));
+    CPPUNIT_ASSERT_EQUAL(classOffset(25), sizeof(struct _LibreOfficeKitClass));
 
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct 
_LibreOfficeKitDocumentClass, destroy));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct 
_LibreOfficeKitDocumentClass, saveAs));
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index c97d552fa6e1..899d14bb7f62 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -2629,6 +2629,10 @@ static void lo_runLoop(LibreOfficeKit* pThis,
                        LibreOfficeKitWakeCallback pWakeCallback,
                        void* pData);
 
+static void lo_registerAnyInputCallback(LibreOfficeKit* pThis,
+                       LibreOfficeKitAnyInputCallback pAnyInputCallback,
+                       void* pData);
+
 static void lo_sendDialogEvent(LibreOfficeKit* pThis,
                                unsigned long long int nLOKWindowId,
                                const char* pArguments);
@@ -2675,6 +2679,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl()
         m_pOfficeClass->startThreads = lo_startThreads;
         m_pOfficeClass->setForkedChild = lo_setForkedChild;
         m_pOfficeClass->extractDocumentStructureRequest = 
lo_extractDocumentStructureRequest;
+        m_pOfficeClass->registerAnyInputCallback = lo_registerAnyInputCallback;
 
         gOfficeClass = m_pOfficeClass;
     }
@@ -7748,6 +7753,14 @@ static void lo_runLoop(LibreOfficeKit* /*pThis*/,
 #endif
 }
 
+static void lo_registerAnyInputCallback(LibreOfficeKit* /*pThis*/,
+                       LibreOfficeKitAnyInputCallback pAnyInputCallback,
+                       void* pData)
+{
+    SolarMutexGuard aGuard;
+    comphelper::LibreOfficeKit::setAnyInputCallback(pAnyInputCallback, pData);
+}
+
 static bool bInitialized = false;
 
 static void lo_status_indicator_callback(void *data, 
comphelper::LibreOfficeKit::statusIndicatorCallbackType type, int percent, 
const char* pText)
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h 
b/include/LibreOfficeKit/LibreOfficeKit.h
index 87bf5e6e7a0b..017351b5eb07 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -154,6 +154,10 @@ struct _LibreOfficeKitClass
      */
     char* (*extractDocumentStructureRequest)(LibreOfficeKit* pThis, const 
char* pFilePath,
                                              const char* pFilter);
+
+    /// @see lok::Office::registerAnyInputCallback()
+    void (*registerAnyInputCallback)(LibreOfficeKit* pThis,
+                                     LibreOfficeKitAnyInputCallback pCallback, 
void* pData);
 };
 
 #define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) 
LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize)
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx 
b/include/LibreOfficeKit/LibreOfficeKit.hxx
index 115e73fdf58c..6878c34b546b 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -1272,6 +1272,14 @@ public:
     {
         return mpThis->pClass->extractDocumentStructureRequest(mpThis, 
pFilePath, pFilter);
     }
+
+    /**
+     * Registers a callback that can determine if there are any pending input 
events.
+     */
+    void registerAnyInputCallback(LibreOfficeKitAnyInputCallback pCallback, 
void* pData)
+    {
+        return mpThis->pClass->registerAnyInputCallback(mpThis, pCallback, 
pData);
+    }
 };
 
 /// Factory method to create a lok::Office instance.
diff --git a/include/LibreOfficeKit/LibreOfficeKitTypes.h 
b/include/LibreOfficeKit/LibreOfficeKitTypes.h
index 8513ef75421d..a702a229834b 100644
--- a/include/LibreOfficeKit/LibreOfficeKitTypes.h
+++ b/include/LibreOfficeKit/LibreOfficeKitTypes.h
@@ -25,6 +25,9 @@ typedef void (*LibreOfficeKitCallback)(int nType, const char* 
pPayload, void* pD
 typedef int (*LibreOfficeKitPollCallback)(void* pData, int timeoutUs);
 typedef void (*LibreOfficeKitWakeCallback)(void* pData);
 
+/// @see lok::Office::registerAnyInputCallback()
+typedef bool (*LibreOfficeKitAnyInputCallback)(void* pData);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/comphelper/lok.hxx b/include/comphelper/lok.hxx
index f998c12dedc3..a497912c4a6f 100644
--- a/include/comphelper/lok.hxx
+++ b/include/comphelper/lok.hxx
@@ -10,6 +10,8 @@
 #ifndef INCLUDED_COMPHELPER_LOK_HXX
 #define INCLUDED_COMPHELPER_LOK_HXX
 
+#include <functional>
+
 #include <comphelper/comphelperdllapi.h>
 #include <rtl/ustring.hxx>
 
@@ -131,6 +133,10 @@ COMPHELPER_DLLPUBLIC void statusIndicatorSetValue(int 
percent);
 COMPHELPER_DLLPUBLIC void statusIndicatorFinish();
 
 COMPHELPER_DLLPUBLIC void setBlockedCommandList(const char* 
blockedCommandList);
+
+COMPHELPER_DLLPUBLIC void setAnyInputCallback(std::function<bool(void*)> 
pAnyInputCallback,
+                                              void* pData);
+COMPHELPER_DLLPUBLIC bool anyInput();
 }
 
 #endif // INCLUDED_COMPHELPER_LOK_HXX
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index 19eef8997689..cf47211d0b21 100644
--- a/vcl/headless/svpinst.cxx
+++ b/vcl/headless/svpinst.cxx
@@ -53,6 +53,7 @@
 #include <unx/salunxtime.h>
 #include <comphelper/lok.hxx>
 #include <tools/debug.hxx>
+#include <comphelper/lok.hxx>
 
 SvpSalInstance* SvpSalInstance::s_pDefaultInstance = nullptr;
 
@@ -396,12 +397,15 @@ bool SvpSalInstance::ImplYield(bool bWait, bool 
bHandleAllCurrentEvents)
     if (!bHandleAllCurrentEvents && bWasEvent)
         return true;
 
+    // CheckTimeout() invokes the sal timer, which invokes the scheduler.
     bWasEvent = CheckTimeout() || bWasEvent;
     const bool bMustSleep = bWait && !bWasEvent;
 
     // This is wrong and must be removed!
     // We always want to drop the SolarMutex on yield; that is the whole point 
of yield.
-    if (!bMustSleep)
+    // If we know the LOK client has pending input events, then don't yet 
return, so those events
+    // can be processed as well.
+    if (!bMustSleep && !comphelper::LibreOfficeKit::anyInput())
         return bWasEvent;
 
     sal_Int64 nTimeoutMicroS = 0;

Reply via email to