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;
