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 a22fe103e7a26270b7213448c570400a563c18ba Author: Miklos Vajna <[email protected]> AuthorDate: Wed Aug 14 09:14:02 2024 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Wed Aug 14 11:17:33 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. Change-Id: I2e39253bfc4d1b5546bc60eef9ff05ccdc0868b9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171846 Tested-by: Jenkins Reviewed-by: Miklos Vajna <[email protected]> diff --git a/comphelper/source/misc/lok.cxx b/comphelper/source/misc/lok.cxx index 36898debc22e..4be9e5744d07 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 3636b8cd9df0..30084f8246a3 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -3592,10 +3592,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 be7b370ab56f..71f27c395d33 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -2584,6 +2584,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); @@ -2630,6 +2634,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; } @@ -7705,6 +7710,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 8691d56131c6..0e14a349ddfa 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 238168ebdb3b..1e99d910ba0d 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 472ba6357f12..82c24771027a 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -49,6 +49,7 @@ // FIXME: remove when we re-work the svp mainloop #include <unx/salunxtime.h> #include <tools/debug.hxx> +#include <comphelper/lok.hxx> SvpSalInstance* SvpSalInstance::s_pDefaultInstance = nullptr; @@ -392,12 +393,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;
