comphelper/source/misc/lok.cxx                  |   33 ++++++++++++++++++++++++
 desktop/source/lib/init.cxx                     |    1 
 include/comphelper/lok.hxx                      |    7 +++++
 include/sfx2/lokhelper.hxx                      |    2 +
 sfx2/source/view/lokhelper.cxx                  |   10 +++++++
 sw/qa/extras/tiledrendering/tiledrendering2.cxx |    1 
 vcl/source/app/svapp.cxx                        |   17 +++++++++++-
 7 files changed, 70 insertions(+), 1 deletion(-)

New commits:
commit 1e06592574472cea476cf2d505d53c7838004fc0
Author:     Miklos Vajna <[email protected]>
AuthorDate: Thu Jan 2 16:18:03 2025 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Thu Jan 9 11:55:02 2025 +0100

    cool#10782 vcl lok: avoid changing the current view during Yield
    
    Commit 520cc546e2940bdfbc45eab1e569bb06bab17a9c (cool#10782 sfx2 lok:
    fix bad view id on PDF export, 2024-12-20) provided a specific fix for
    one case where spinning the main loop can result in callbacks being
    emitted on the wrong view.
    
    Hunting down all the SfxViewShell::Current() calls and auditing them if
    they are problematic in practice is a large task, so it's desirable to
    handle this problem in a more generic way.
    
    Fix the problem by pushing/popping the current LOK view in
    Application::Reschedule(), which is what e.g. the framework/ status bar
    code uses during PDF export. This keeps the original problem fixed but
    is more generic.
    
    This requires storing function pointers in comphelper/, since normally
    vcl/ code can't call SfxLokHelper, since sfx2/ already depends on vcl/.
    The fix can be tested by reverting the original fix:
    git show 520cc546e2940bdfbc45eab1e569bb06bab17a9c -- sfx2|git apply -R
    and then running the testcase:
    make -C sw -sr CppunitTest_sw_tiledrendering 
CPPUNIT_TEST_NAME=testPDFExportViewSwitch
    which now passes even if the sfx2-level fix is not there. Keep that
    specific fix, though: the less time we assume SfxViewShell::Current()
    returns the correct view, the better.
    
    Change-Id: Ic1811ff1e67f73fa5066af775d31589136b8502a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179993
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/comphelper/source/misc/lok.cxx b/comphelper/source/misc/lok.cxx
index 88521ebb455e..cd1333711e4d 100644
--- a/comphelper/source/misc/lok.cxx
+++ b/comphelper/source/misc/lok.cxx
@@ -40,6 +40,9 @@ static Compat g_eCompatFlags(Compat::none);
 static std::function<bool(void*)> g_pAnyInputCallback;
 static void* g_pAnyInputCallbackData;
 
+static std::function<void(int)> g_pViewSetter;
+static std::function<int()> g_pViewGetter;
+
 namespace
 {
 
@@ -337,6 +340,36 @@ bool anyInput()
     return bRet;
 }
 
+void setViewSetter(std::function<void(int)> pViewSetter)
+{
+    g_pViewSetter = pViewSetter;
+}
+
+void setView(int nView)
+{
+    if (!g_pViewSetter)
+    {
+        return;
+    }
+
+    g_pViewSetter(nView);
+}
+
+void setViewGetter(std::function<int()> pViewGetter)
+{
+    g_pViewGetter = pViewGetter;
+}
+
+int getView()
+{
+    if (!g_pViewGetter)
+    {
+        return -1;
+    }
+
+    return g_pViewGetter();
+}
+
 } // namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index dc0f4fdd5e89..6a6cffd57e95 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -7794,6 +7794,7 @@ static void lo_runLoop(LibreOfficeKit* /*pThis*/,
         SolarMutexGuard aGuard;
 
         vcl::lok::registerPollCallbacks(pPollCallback, pWakeCallback, pData);
+        SfxLokHelper::registerViewCallbacks();
         Application::UpdateMainThread();
         soffice_main();
     }
diff --git a/include/comphelper/lok.hxx b/include/comphelper/lok.hxx
index d1aa6804f534..0565fa78d6da 100644
--- a/include/comphelper/lok.hxx
+++ b/include/comphelper/lok.hxx
@@ -137,6 +137,13 @@ COMPHELPER_DLLPUBLIC void setBlockedCommandList(const 
char* blockedCommandList);
 COMPHELPER_DLLPUBLIC void setAnyInputCallback(const 
std::function<bool(void*)>& pAnyInputCallback,
                                               void* pData);
 COMPHELPER_DLLPUBLIC bool anyInput();
+
+// These allow setting callbacks, so that set/get of a LOK view is possible 
even in code that is
+// below sfx2.
+COMPHELPER_DLLPUBLIC void setViewSetter(std::function<void(int)> pViewSetter);
+COMPHELPER_DLLPUBLIC void setView(int nView);
+COMPHELPER_DLLPUBLIC void setViewGetter(std::function<int()> pViewGetter);
+COMPHELPER_DLLPUBLIC int getView();
 }
 
 #endif // INCLUDED_COMPHELPER_LOK_HXX
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index ec73f7c597f0..2f87faf82e78 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -255,6 +255,8 @@ public:
     static void getCommandValues(tools::JsonWriter& rJsonWriter, 
std::string_view rCommand);
     /// Parses key-value parameters of rCommand.
     static std::map<OUString, OUString> 
parseCommandParameters(std::u16string_view rCommand);
+    /// Registers function pointers in comphelper/ to set/get of the current 
LOK view.
+    static void registerViewCallbacks();
 
 private:
     static int createView(SfxViewFrame& rViewFrame, ViewShellDocId docId);
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 5eec80fba576..0ea04c16238f 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -1105,6 +1105,16 @@ void 
SfxLokHelper::notifyOtherViewsUpdatePerViewId(SfxViewShell const* pThisView
     }
 }
 
+void SfxLokHelper::registerViewCallbacks()
+{
+    comphelper::LibreOfficeKit::setViewSetter([](int nView) {
+        SfxLokHelper::setView(nView);
+    });
+    comphelper::LibreOfficeKit::setViewGetter([]() -> int {
+        return SfxLokHelper::getView();
+    });
+}
+
 namespace
 {
     struct LOKAsyncEventData
diff --git a/sw/qa/extras/tiledrendering/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index eedd023388ca..5464257a388c 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -300,6 +300,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testPDFExportViewSwitch)
 {
     // Given a document with 2 views:
     SwXTextDocument* pXTextDocument = createDoc("to-pdf.odt");
+    SfxLokHelper::registerViewCallbacks();
     SwDoc* pDoc = pXTextDocument->GetDocShell()->GetDoc();
     SwTestViewCallback aView1;
     SfxLokHelper::createView();
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index 06a21d733177..8de62eb4c5d1 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -401,7 +401,22 @@ bool Application::Reschedule( bool i_bAllEvents )
         SAL_WARN("vcl.schedule", "Application::Reschedule(" << i_bAllEvents << 
")");
         return false;
     }
-    return ImplYield(false, i_bAllEvents);
+    int nOldView = -1;
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        nOldView = comphelper::LibreOfficeKit::getView();
+    }
+    bool bRet = ImplYield(false, i_bAllEvents);
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        int nNewView = comphelper::LibreOfficeKit::getView();
+        if (nOldView != -1 && nNewView != -1 && nOldView != nNewView)
+        {
+            // Yield changed the current view, restore the old value.
+            comphelper::LibreOfficeKit::setView(nOldView);
+        }
+    }
+    return bRet;
 }
 
 bool Application::IsUseSystemEventLoop()

Reply via email to