desktop/source/app/app.cxx    |    1 +
 include/vcl/svapp.hxx         |    6 ++++++
 vcl/README.vars.md            |    1 +
 vcl/inc/qt5/QtInstance.hxx    |    1 +
 vcl/inc/salinst.hxx           |    4 +++-
 vcl/inc/svdata.hxx            |    2 ++
 vcl/qt5/QtInstance.cxx        |   19 ++++++++++++-------
 vcl/qt5/QtTimer.cxx           |   11 ++++++-----
 vcl/source/app/salvtables.cxx |   14 ++++++++++++++
 vcl/source/app/svapp.cxx      |   38 ++++++++++++++++++++++++--------------
 vcl/source/app/svdata.cxx     |    7 +++++++
 11 files changed, 77 insertions(+), 27 deletions(-)

New commits:
commit a9bb94e28a6757719a2e833c9d3ca17b3205283b
Author:     Jan-Marek Glogowski <[email protected]>
AuthorDate: Wed Nov 17 10:29:24 2021 +0100
Commit:     Jan-Marek Glogowski <[email protected]>
CommitDate: Fri Jan 21 12:42:20 2022 +0100

    VCL fix shutdown when run via system loop
    
    Adds DoQuit and SAL_USE_SYSTEM_LOOP to complement DoExecute.
    Makes it easier to switch between a LO with and without nested
    event processing. Unfortunatly the recovery dialogs run outside
    of Application::Execute(), so this currently also disables
    recovery handling.
    
    Follow-up (and no more Emscripten-specific) change to commit
    93133585b5b52e38defc3162eeb1e7704dceafcb ("WASM optionally run
    any app via system loop").
    
    Change-Id: I1b622065d7fa0c5ad03a7c7daaf8241dcc3f09a3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128717
    Tested-by: Jenkins
    Reviewed-by: Jan-Marek Glogowski <[email protected]>

diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index b14c0d94299a..ada608229f8b 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -2020,6 +2020,7 @@ void Desktop::OpenClients()
         bool bExistsSessionData  = false;
         bool const bDisableRecovery
             = getenv("OOO_DISABLE_RECOVERY") != nullptr
+              || IsOnSystemEventLoop()
               || !officecfg::Office::Recovery::RecoveryInfo::Enabled::get();
 
         impl_checkRecoveryState(bCrashed, bExistsRecoveryData, 
bExistsSessionData);
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
index f4d065f1d664..137177bbfbb0 100644
--- a/include/vcl/svapp.hxx
+++ b/include/vcl/svapp.hxx
@@ -1323,6 +1323,12 @@ public:
     */
     static void                 EndAllPopups();
 
+    /** Returns true, if the VCL plugin runs on the system event loop.
+     *
+     *  AKA the VCL plugin can't handle nested event loops, like WASM or 
mobile.
+     */
+    static bool IsOnSystemEventLoop();
+
     ///@}
 
     // For vclbootstrapprotector:
diff --git a/vcl/README.vars.md b/vcl/README.vars.md
index c7971b734be0..c83ca657ef9f 100644
--- a/vcl/README.vars.md
+++ b/vcl/README.vars.md
@@ -9,6 +9,7 @@ These are the general environment variables used in the VCL:
 * `SAL_NO_NWF` - disable native widgets
 * `SAL_FORCEDPI` - force a specific DPI (gtk3 & qt5/kf5 plugins only)
 * `SAL_FORCE_HC` - force high-contrast mode
+* `SAL_USE_SYSTEM_LOOP` - calls std::abort on nested event loop calls. 
Currently just for Qt with many crashes. WIP.
 
 * `SAL_NO_FONT_LOOKUP` - disable font search and fallback and always use a 
hard-coded font name (for some unit tests)
 
diff --git a/vcl/inc/qt5/QtInstance.hxx b/vcl/inc/qt5/QtInstance.hxx
index 9c3adb25e98b..2d246c0bd92d 100644
--- a/vcl/inc/qt5/QtInstance.hxx
+++ b/vcl/inc/qt5/QtInstance.hxx
@@ -176,6 +176,7 @@ public:
     void* CreateGStreamerSink(const SystemChildWindow*) override;
 
     bool DoExecute(int& nExitCode) override;
+    void DoQuit() override;
 };
 
 inline QtInstance* GetQtInstance() { return 
static_cast<QtInstance*>(GetSalInstance()); }
diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx
index 90367c06bcc9..084ab2e51c58 100644
--- a/vcl/inc/salinst.hxx
+++ b/vcl/inc/salinst.hxx
@@ -215,7 +215,9 @@ public:
     // Note: we cannot make this a global variable, because it might be 
initialised BEFORE the putenv() call in cppunittester.
     static bool IsRunningUnitTest() { return getenv("LO_TESTNAME") != nullptr; 
}
 
-    virtual bool DoExecute(int & /* nExitCode */) { return false; }
+    // both must to be implemented, if the VCL plugin needs to run via system 
event loop
+    virtual bool DoExecute(int &nExitCode);
+    virtual void DoQuit();
 };
 
 // called from SVMain
diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx
index 89e4d67a3800..ae6e361cb079 100644
--- a/vcl/inc/svdata.hxx
+++ b/vcl/inc/svdata.hxx
@@ -133,6 +133,7 @@ typedef std::pair<VclPtr<vcl::Window>, ImplPostEventData *> 
ImplPostEventPair;
 
 struct ImplSVAppData
 {
+    ImplSVAppData();
     ~ImplSVAppData();
 
     std::optional<AllSettings> mxSettings;           // Application settings
@@ -159,6 +160,7 @@ struct ImplSVAppData
     bool                    mbSettingsInit = false;         // true: Settings 
are initialized
     DialogCancelMode meDialogCancel = DialogCancelMode::Off; // true: All 
Dialog::Execute() calls will be terminated immediately with return false
     bool mbRenderToBitmaps = false; // set via svp / headless plugin
+    bool m_bUseSystemLoop = false;
 
     SvFileStream*       mpEventTestInput = nullptr;
     Idle*               mpEventTestingIdle = nullptr;
diff --git a/vcl/qt5/QtInstance.cxx b/vcl/qt5/QtInstance.cxx
index a03b71e46bd2..a52f6529c3bc 100644
--- a/vcl/qt5/QtInstance.cxx
+++ b/vcl/qt5/QtInstance.cxx
@@ -259,6 +259,8 @@ QtInstance::QtInstance(std::unique_ptr<QApplication>& 
pQApp, bool bUseCairo)
 
 #ifndef EMSCRIPTEN
     m_bSupportsOpenGL = true;
+#else
+    ImplGetSVData()->maAppData.m_bUseSystemLoop = true;
 #endif
 }
 
@@ -726,13 +728,16 @@ std::unique_ptr<QApplication> 
QtInstance::CreateQApplication(int& nArgc, char**
 
 bool QtInstance::DoExecute(int& nExitCode)
 {
-#ifdef EMSCRIPTEN
-    nExitCode = m_pQApplication->exec();
-    return true;
-#else
-    (void)nExitCode;
-    return false;
-#endif
+    const bool bIsOnSystemEventLoop = Application::IsOnSystemEventLoop();
+    if (bIsOnSystemEventLoop)
+        nExitCode = QApplication::exec();
+    return bIsOnSystemEventLoop;
+}
+
+void QtInstance::DoQuit()
+{
+    if (Application::IsOnSystemEventLoop())
+        QApplication::quit();
 }
 
 extern "C" {
diff --git a/vcl/qt5/QtTimer.cxx b/vcl/qt5/QtTimer.cxx
index 6568ca8ac1b8..1a34213977dc 100644
--- a/vcl/qt5/QtTimer.cxx
+++ b/vcl/qt5/QtTimer.cxx
@@ -42,11 +42,12 @@ QtTimer::QtTimer()
 void QtTimer::timeoutActivated()
 {
     SolarMutexGuard aGuard;
-#ifdef EMSCRIPTEN
-    const ImplSVData* pSVData = ImplGetSVData();
-    assert(pSVData->mpDefInst);
-    static_cast<QtInstance*>(pSVData->mpDefInst)->DispatchUserEvents(true);
-#endif
+    if (Application::IsOnSystemEventLoop())
+    {
+        const ImplSVData* pSVData = ImplGetSVData();
+        assert(pSVData && pSVData->mpDefInst);
+        static_cast<QtInstance*>(pSVData->mpDefInst)->DispatchUserEvents(true);
+    }
     CallCallback();
 }
 
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index e19d055b8253..bfcd6834caac 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -142,6 +142,20 @@ bool SalInstance::CallEventCallback(void const* pEvent, 
int nBytes)
     return m_pEventInst.is() && m_pEventInst->dispatchEvent(pEvent, nBytes);
 }
 
+bool SalInstance::DoExecute(int&)
+{
+    // can't run on system event loop without implementing DoExecute and DoQuit
+    if (Application::IsOnSystemEventLoop())
+        std::abort();
+    return false;
+}
+
+void SalInstance::DoQuit()
+{
+    if (Application::IsOnSystemEventLoop())
+        std::abort();
+}
+
 SalTimer::~SalTimer() COVERITY_NOEXCEPT_FALSE {}
 
 void SalBitmap::DropScaledCache()
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index c1f3b4a5bccf..cc046decdad5 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -443,6 +443,11 @@ void Application::Execute()
     int nExitCode = 0;
     if (!pSVData->mpDefInst->DoExecute(nExitCode))
     {
+        if (Application::IsOnSystemEventLoop())
+        {
+            SAL_WARN("vcl.schedule", "Can't omit DoExecute when running on 
system event loop!");
+            std::abort();
+        }
         while (!pSVData->maAppData.mbAppQuit)
             Application::Yield();
     }
@@ -452,7 +457,6 @@ void Application::Execute()
     GetpApp()->Shutdown();
 }
 
-#ifndef EMSCRIPTEN
 static bool ImplYield(bool i_bWait, bool i_bAllEvents)
 {
     ImplSVData* pSVData = ImplGetSVData();
@@ -477,23 +481,27 @@ static bool ImplYield(bool i_bWait, bool i_bAllEvents)
     SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent 
);
     return bProcessedEvent;
 }
-#endif
 
 bool Application::Reschedule( bool i_bAllEvents )
 {
-#ifdef EMSCRIPTEN
-    SAL_WARN("wasm", "Application::Reschedule(" << i_bAllEvents << ")");
-    (void) i_bAllEvents;
-    std::abort();
-#else
+    static const bool bAbort = Application::IsOnSystemEventLoop();
+    if (bAbort)
+    {
+        SAL_WARN("vcl.schedule", "Application::Reschedule(" << i_bAllEvents << 
")");
+        std::abort();
+    }
     return ImplYield(false, i_bAllEvents);
-#endif
+}
+
+bool Application::IsOnSystemEventLoop()
+{
+    return ImplGetSVData()->maAppData.m_bUseSystemLoop;
 }
 
 void Scheduler::ProcessEventsToIdle()
 {
     int nSanity = 1;
-    while( Application::Reschedule( true ) )
+    while (ImplYield(false, true))
     {
         if (0 == ++nSanity % 1000)
         {
@@ -541,17 +549,19 @@ SAL_DLLPUBLIC_EXPORT void 
unit_lok_process_events_to_idle()
 
 void Application::Yield()
 {
-#ifdef EMSCRIPTEN
-    SAL_WARN("wasm", "Application::Yield()");
-    std::abort();
-#else
+    static const bool bAbort = Application::IsOnSystemEventLoop();
+    if (bAbort)
+    {
+        SAL_WARN("vcl.schedule", "Application::Yield()");
+        std::abort();
+    }
     ImplYield(true, false);
-#endif
 }
 
 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
 {
     assert(ImplGetSVData()->maAppData.mbAppQuit);
+    ImplGetSVData()->mpDefInst->DoQuit();
 }
 
 void Application::Quit()
diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx
index f91e1fe67fa9..7ba785277c3e 100644
--- a/vcl/source/app/svdata.cxx
+++ b/vcl/source/app/svdata.cxx
@@ -474,6 +474,13 @@ ImplSVHelpData& ImplGetSVHelpData()
 }
 
 ImplSVData::~ImplSVData() {}
+
+ImplSVAppData::ImplSVAppData()
+{
+    m_bUseSystemLoop = getenv("SAL_USE_SYSTEM_LOOP") != nullptr;
+    SAL_WARN_IF(m_bUseSystemLoop, "vcl.schedule", "Overriding to run LO on 
system event loop!");
+}
+
 ImplSVAppData::~ImplSVAppData() {}
 ImplSVGDIData::~ImplSVGDIData() {}
 ImplSVFrameData::~ImplSVFrameData() {}

Reply via email to