tdf#128502: Try to support multiple documents in LibreOfficeKit-using process

The LibreOfficeKit-specific code typically has assumed that all the
"views" (SfxViewShell instances) are for the same document, because
all LibreOfficeKit-based application processes (including the "kit"
processes in Online and the iOS app) so far have only had one document
open at a time.

It is now possible to pass several document file names on the command
line to gtktiledviewer and that is an easy way to demonstrate how
badly it still works even with this patch.

Introduce a unique numeric document id that is increased in the
LibLODocument_Impl constructor. Add APIs to access that. When
iterating over views, try to skip views that are not of the document
visible in the "current" view, if we know what the "current" view is.

Also add a couple of FIXMEs at places where it is a bit unclear (to
me) whether it is correct to iterate over all views, or whether only
views for the "current" document are what we would want.

Change-Id: Id5ebb92a115723cdeb23907163d5b5f282016252
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95353
Tested-by: Jenkins
Reviewed-by: Tor Lillqvist <tml@collabora.com>
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index 568c1fe..69dd610 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -149,8 +149,9 @@
        css::uno::Reference<css::lang::XComponent> mxComponent;
        std::shared_ptr< LibreOfficeKitDocumentClass > m_pDocumentClass;
        std::map<size_t, std::shared_ptr<CallbackFlushHandler>> mpCallbackFlushHandlers;
        const int mnDocumentId;

        explicit LibLODocument_Impl(const css::uno::Reference <css::lang::XComponent> &xComponent);
        explicit LibLODocument_Impl(const css::uno::Reference <css::lang::XComponent> &xComponent, int nDocumentId = -1);
        ~LibLODocument_Impl();
    };

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 5a9bd8c..1b80133 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1173,8 +1173,9 @@

} // anonymous namespace

LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent)
LibLODocument_Impl::LibLODocument_Impl(const uno::Reference <css::lang::XComponent> &xComponent, int nDocumentId)
    : mxComponent(xComponent)
    , mnDocumentId(nDocumentId)
{
    m_pDocumentClass = gDocumentClass.lock();
    if (!m_pDocumentClass)
@@ -2114,6 +2115,8 @@

    SolarMutexGuard aGuard;

    static int nDocumentIdCounter = 0;

    LibLibreOffice_Impl* pLib = static_cast<LibLibreOffice_Impl*>(pThis);
    pLib->maLastExceptionMsg.clear();

@@ -2210,7 +2213,10 @@
            return nullptr;
        }

        LibLODocument_Impl* pDocument = new LibLODocument_Impl(xComponent);
        LibLODocument_Impl* pDocument = new LibLODocument_Impl(xComponent, nDocumentIdCounter++);

        // Do we know that after loading the document, its initial view is the "current" view?
        SfxLokHelper::setDocumentIdOfView(pDocument->mnDocumentId);
        if (pLib->mpCallback)
        {
            int nState = doc_getSignatureState(pDocument);
@@ -3081,7 +3087,9 @@
    {
        // tile painting always needs a SfxViewShell::Current(), but actually
        // it does not really matter which one - all of them should paint the
        // same thing.
        // same thing. It's important to get a view for the correct document,
        // though.
        // doc_getViewsCount() returns the count of views for the document in the current view.
        int viewCount = doc_getViewsCount(pThis);
        if (viewCount == 0)
            return;
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index 3d71ac1..12bda7b 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -364,6 +364,8 @@
public:
    virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) const = 0;
    virtual ViewShellId GetViewShellId() const = 0;
    virtual void SetDocId(ViewShellDocId nId) = 0;
    virtual ViewShellDocId GetDocId() const = 0;
    /// Wrapper around SfxLokHelper::notifyOtherViews().
    virtual void NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload) = 0;
    /// Wrapper around SfxLokHelper::notifyOtherView().
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 05a94c4..3c3cfc3 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -52,8 +52,12 @@
    static int getView(SfxViewShell* pViewShell = nullptr);
    /// Get the number of views of the current object shell.
    static std::size_t getViewsCount();
    /// Get viewIds of all existing views.
    /// Get viewIds of views of the current object shell.
    static bool getViewIds(int* pArray, size_t nSize);
    /// Set the document id of the currently active view
    static void setDocumentIdOfView(int nId);
    /// Get the document id for a view
    static int getDocumentIdOfView(int nViewId);
    /// Get the default language that should be used for views
    static LanguageTag getDefaultLanguage();
    /// Set language of the given view.
@@ -69,7 +73,7 @@
    /// Iterate over any view shell, except pThisViewShell, passing it to the f function.
    template<typename ViewShellType, typename FunctionType>
    static void forEachOtherView(ViewShellType* pThisViewShell, FunctionType f);
    /// Invoke the LOK callback of all views except pThisView, with a payload of rKey-rPayload.
    /// Invoke the LOK callback of all other views showing the same document as pThisView, with a payload of rKey-rPayload.
    static void notifyOtherViews(SfxViewShell* pThisView, int nType, const OString& rKey, const OString& rPayload);
    /// Same as notifyOtherViews(), but works on a selected "other" view, not on all of them.
    static void notifyOtherView(SfxViewShell* pThisView, SfxViewShell const* pOtherView, int nType, const OString& rKey, const OString& rPayload);
@@ -82,7 +86,7 @@
                             const std::vector<vcl::LOKPayloadItem>& rPayload = std::vector<vcl::LOKPayloadItem>());
    /// Emits a LOK_CALLBACK_DOCUMENT_SIZE_CHANGED - if @bInvalidateAll - first invalidates all parts
    static void notifyDocumentSizeChanged(SfxViewShell const* pThisView, const OString& rPayload, vcl::ITiledRenderable* pDoc, bool bInvalidateAll = true);
    /// Emits a LOK_CALLBACK_DOCUMENT_SIZE_CHANGED for all views - if @bInvalidateAll - first invalidates all parts
    /// Emits a LOK_CALLBACK_DOCUMENT_SIZE_CHANGED for all views of the same document - if @bInvalidateAll - first invalidates all parts
    static void notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable* pDoc, bool bInvalidateAll = true);
    /// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed.
    static void notifyInvalidation(SfxViewShell const* pThisView, const OString& rPayload);
@@ -117,7 +121,7 @@
    while (pViewShell)
    {
        auto pOtherViewShell = dynamic_cast<ViewShellType*>(pViewShell);
        if (pOtherViewShell != nullptr && pOtherViewShell != pThisViewShell)
        if (pOtherViewShell != nullptr && pOtherViewShell != pThisViewShell && pOtherViewShell->GetDocId() == pThisViewShell->GetDocId())
        {
            f(pOtherViewShell);
        }
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index ce2297e..e17de5c 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -339,6 +339,8 @@
    virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
    /// See OutlinerViewShell::GetViewShellId().
    ViewShellId GetViewShellId() const override;
    void SetDocId(ViewShellDocId nId) override;
    ViewShellDocId GetDocId() const override;
    /// See OutlinerViewShell::NotifyOtherViews().
    void NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload) override;
    /// See OutlinerViewShell::NotifyOtherView().
diff --git a/include/svl/undo.hxx b/include/svl/undo.hxx
index 8de6231..2757967 100644
--- a/include/svl/undo.hxx
+++ b/include/svl/undo.hxx
@@ -28,6 +28,8 @@
#include <vector>

typedef o3tl::strong_int<sal_Int32, struct ViewShellIdTag> ViewShellId;
typedef o3tl::strong_int<int, struct ViewShellDocIdTag> ViewShellDocId;

typedef struct _xmlTextWriter* xmlTextWriterPtr;

class SVL_DLLPUBLIC SfxRepeatTarget
diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx
index 6247132..d1e1456 100644
--- a/sc/source/ui/docshell/dbdocfun.cxx
+++ b/sc/source/ui/docshell/dbdocfun.cxx
@@ -628,7 +628,8 @@

    ScDocument& rDoc = rDocShell.GetDocument();

    if (ScTabViewShell::isAnyEditViewInRange(/*bColumns*/ false, rQueryParam.nRow1, rQueryParam.nRow2))
    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    if (pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, /*bColumns*/ false, rQueryParam.nRow1, rQueryParam.nRow2))
    {
        return false;
    }
@@ -941,7 +942,6 @@
                                        pOld, bDoSize, pAdvSource ) );
    }

    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    if ( pViewSh )
    {
        // could there be horizontal autofilter ?
diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx
index 54c0119..e634c926 100644
--- a/sc/source/ui/docshell/docsh4.cxx
+++ b/sc/source/ui/docshell/docsh4.cxx
@@ -2516,10 +2516,13 @@
    boost::property_tree::write_json(aStream, aTree);
    std::string aPayload = aStream.str();

    ScViewData* pViewData = GetViewData();
    SfxViewShell* pThisViewShell = ( pViewData ? pViewData->GetViewShell() : nullptr );
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload.c_str());
        if (pThisViewShell == nullptr || pViewShell->GetDocId() == pThisViewShell->GetDocId())
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload.c_str());
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}
diff --git a/sc/source/ui/docshell/olinefun.cxx b/sc/source/ui/docshell/olinefun.cxx
index c3da9c9..8b99085 100644
--- a/sc/source/ui/docshell/olinefun.cxx
+++ b/sc/source/ui/docshell/olinefun.cxx
@@ -315,6 +315,7 @@
                                    bool bRecord, bool bPaint )
{
    ScDocument& rDoc = rDocShell.GetDocument();
    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();

    if (bRecord && !rDoc.IsUndoEnabled())
        bRecord = false;
@@ -362,7 +363,7 @@
        sal_uInt16 nThisLevel = aIter.LastLevel();
        bool bShow = (nThisLevel < nLevel);

        if (!bShow && ScTabViewShell::isAnyEditViewInRange(bColumns, nThisStart, nThisEnd))
        if (!bShow && pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, bColumns, nThisStart, nThisEnd))
            continue;

        if (bShow)                                          // enable
@@ -410,7 +411,6 @@
    rDoc.SetDrawPageSize(nTab);
    rDoc.UpdatePageBreaks( nTab );

    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    if ( pViewSh )
        pViewSh->OnLOKShowHideColRow(bColumns, nStart - 1);

@@ -733,8 +733,8 @@
    SCCOLROW nStart = pEntry->GetStart();
    SCCOLROW nEnd   = pEntry->GetEnd();


    if (ScTabViewShell::isAnyEditViewInRange(bColumns, nStart, nEnd))
    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    if (pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, bColumns, nStart, nEnd))
        return false;

    // TODO undo can mess things up when another view is editing a cell in the range of group entry
@@ -775,7 +775,6 @@
    rDoc.InvalidatePageBreaks(nTab);
    rDoc.UpdatePageBreaks( nTab );

    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    if ( pViewSh )
        pViewSh->OnLOKShowHideColRow(bColumns, nStart - 1);

diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx
index 7975a92..ee7b6e1 100644
--- a/sc/source/ui/inc/tabvwsh.hxx
+++ b/sc/source/ui/inc/tabvwsh.hxx
@@ -388,9 +388,8 @@
    /// See SfxViewShell::NotifyCursor().
    void NotifyCursor(SfxViewShell* pViewShell) const override;
    /// Emits a LOK_CALLBACK_INVALIDATE_HEADER for all views whose current tab is equal to nCurrentTabIndex
    static void notifyAllViewsHeaderInvalidation(HeaderType eHeaderType, SCTAB nCurrentTabIndex);
    static void notifyAllViewsHeaderInvalidation(bool Columns, SCTAB nCurrentTabIndex);
    static bool isAnyEditViewInRange(bool bColumns, SCCOLROW nStart, SCCOLROW nEnd);
    static void notifyAllViewsHeaderInvalidation(SfxViewShell* pForViewShell, HeaderType eHeaderType, SCTAB nCurrentTabIndex);
    static bool isAnyEditViewInRange(SfxViewShell* pForViewShell, bool bColumns, SCCOLROW nStart, SCCOLROW nEnd);
    css::uno::Reference<css::drawing::XShapes> getSelectedXShapes();
    static  css::uno::Reference<css::datatransfer::XTransferable2> GetClipData(vcl::Window* pWin);

diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index b9145c2..cf0669c 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -274,10 +274,10 @@
        if (comphelper::LibreOfficeKit::isActive())
        {
            if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT)
                ScTabViewShell::notifyAllViewsHeaderInvalidation(COLUMN_HEADER,  pViewShell->GetViewData().GetTabNo());
                ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER,  pViewShell->GetViewData().GetTabNo());

            if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN)
                ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER,  pViewShell->GetViewData().GetTabNo());
                ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, pViewShell->GetViewData().GetTabNo());
        }
    }
}
@@ -535,10 +535,10 @@
        if (comphelper::LibreOfficeKit::isActive())
        {
            if (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft)
                ScTabViewShell::notifyAllViewsHeaderInvalidation(COLUMN_HEADER,  pViewShell->GetViewData().GetTabNo());
                ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, pViewShell->GetViewData().GetTabNo());

            if (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp)
                ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER,  pViewShell->GetViewData().GetTabNo());
                ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, pViewShell->GetViewData().GetTabNo());
        }

    }
diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx
index 3739085..d83f194 100644
--- a/sc/source/ui/undo/undodat.cxx
+++ b/sc/source/ui/undo/undodat.cxx
@@ -179,7 +179,7 @@

    pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);

    ScTabViewShell::notifyAllViewsHeaderInvalidation( bColumns, nTab );
    ScTabViewShell::notifyAllViewsHeaderInvalidation( pViewShell, bColumns ? COLUMN_HEADER : ROW_HEADER, nTab );

    EndUndo();
}
@@ -449,7 +449,7 @@

    pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);

    ScTabViewShell::notifyAllViewsHeaderInvalidation(BOTH_HEADERS, nTab);
    ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, BOTH_HEADERS, nTab);

    EndUndo();
}
@@ -733,13 +733,13 @@

void ScUndoQuery::Undo()
{
    if (ScTabViewShell::isAnyEditViewInRange(/*bColumns*/ false, aQueryParam.nRow1, aQueryParam.nRow2))
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
    if (ScTabViewShell::isAnyEditViewInRange(pViewShell, /*bColumns*/ false, aQueryParam.nRow1, aQueryParam.nRow2))
        return;

    BeginUndo();

    ScDocument& rDoc = pDocShell->GetDocument();
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();

    bool bCopy = !aQueryParam.bInplace;
    SCCOL nDestEndCol = 0;
@@ -814,7 +814,7 @@

    // invalidate cache positions and update cursor and selection
    pViewShell->OnLOKShowHideColRow(/*bColumns*/ false, aQueryParam.nRow1 - 1);
    ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER, nTab);
    ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);

    //  Paint

diff --git a/sc/source/ui/view/dbfunc3.cxx b/sc/source/ui/view/dbfunc3.cxx
index d7faee1..24e660b 100644
--- a/sc/source/ui/view/dbfunc3.cxx
+++ b/sc/source/ui/view/dbfunc3.cxx
@@ -93,7 +93,7 @@
        ScOutlineDocFunc aFunc(*pDocSh);
        aFunc.MakeOutline( aRange, bColumns, bRecord, false );

        ScTabViewShell::notifyAllViewsHeaderInvalidation(bColumns, GetViewData().GetTabNo());
        ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns ? COLUMN_HEADER : ROW_HEADER, GetViewData().GetTabNo());
    }
    else
        ErrorMessage(STR_NOMULTISELECT);
@@ -110,7 +110,7 @@
        ScOutlineDocFunc aFunc(*pDocSh);
        aFunc.RemoveOutline( aRange, bColumns, bRecord, false );

        ScTabViewShell::notifyAllViewsHeaderInvalidation(bColumns, GetViewData().GetTabNo());
        ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns ? COLUMN_HEADER : ROW_HEADER, GetViewData().GetTabNo());
    }
    else
        ErrorMessage(STR_NOMULTISELECT);
@@ -2239,11 +2239,12 @@
        return;

    SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
    SfxViewShell* pThisViewShell = GetViewData().GetViewShell();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        if (pTabViewShell && pTabViewShell->GetDocId() == pThisViewShell->GetDocId())
        {
            if (bColumns)
                pTabViewShell->GetViewData().GetLOKWidthHelper(nCurrentTabIndex)->invalidateByIndex(nStart);
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index f6422cf..ce9df4f 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -828,7 +828,7 @@
            // Something went terribly wrong!
            return;

        if (ScTabViewShell::isAnyEditViewInRange(/*bColumns*/ false, aParam.nRow1, aParam.nRow2))
        if (ScTabViewShell::isAnyEditViewInRange(pViewData->GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2))
            return;

        pEntry->bDoQuery = true;
@@ -5704,6 +5704,9 @@
{
    ScTabViewShell* pViewShell = pViewData->GetViewShell();

    if (pViewShell->GetDocId() != pForShell->GetDocId())
        return;

    OString aCursor("EMPTY");
    if (mpOOCursors) // cf. getCellCursor above
    {
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index b0cac06..fbb78fe 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -334,7 +334,7 @@

    while (pViewShell)
    {
        if (pViewShell != pThisViewShell)
        if (pViewShell != pThisViewShell && pViewShell->GetDocId() == pThisViewShell->GetDocId())
        {
            ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
            if (pOtherViewShell)
@@ -953,7 +953,7 @@

        while (pViewShell)
        {
            if (pViewShell != pThisViewShell)
            if (pViewShell != pThisViewShell && pViewShell->GetDocId() == pThisViewShell->GetDocId())
            {
                ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
                if (pTabViewShell)
diff --git a/sc/source/ui/view/tabview4.cxx b/sc/source/ui/view/tabview4.cxx
index cb88d45..910d097 100644
--- a/sc/source/ui/view/tabview4.cxx
+++ b/sc/source/ui/view/tabview4.cxx
@@ -391,7 +391,7 @@

void ScTabView::UpdateScrollBars( HeaderType eHeaderType )
{
    ScTabViewShell::notifyAllViewsHeaderInvalidation(eHeaderType, GetViewData().GetTabNo());
    ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), eHeaderType, GetViewData().GetTabNo());

    long        nDiff;
    bool        bTop =   ( aViewData.GetVSplitMode() != SC_SPLIT_NONE );
diff --git a/sc/source/ui/view/tabview5.cxx b/sc/source/ui/view/tabview5.cxx
index dfd5ecc..55eeb35 100644
--- a/sc/source/ui/view/tabview5.cxx
+++ b/sc/source/ui/view/tabview5.cxx
@@ -672,11 +672,12 @@
    aInvalidRect.AdjustTop( -nBorderSize );
    aInvalidRect.AdjustBottom( nBorderSize );

    SfxViewShell* pCurrentViewShell = SfxViewShell::Current();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        if (pTabViewShell && pViewShell->GetDocId() == pCurrentViewShell->GetDocId())
        {
            for (auto& pWin: pTabViewShell->pGridWin)
            {
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
index e57caf3..a07e05d 100644
--- a/sc/source/ui/view/tabvwsh4.cxx
+++ b/sc/source/ui/view/tabvwsh4.cxx
@@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
@@ -126,6 +126,11 @@
                    SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
                    while ( pSh!=nullptr && pOldHdl!=nullptr)
                    {
                        // Hmm, what if pSh is a shell for a different document? But as this code
                        // does not seem to be LibreOfficeKit-specific, probably that doesn't
                        // happen, because having multiple documents open simultaneously has of
                        // course not been a problem at all in traditional desktop LibreOffice.
                        // (Unlike in a LibreOfficeKit-based process where it has been a problem.)
                        if (static_cast<ScTabViewShell*>(pSh)->GetInputHandler() == pOldHdl)
                        {
                            pOldHdl->ResetDelayTimer();
@@ -1712,8 +1717,12 @@
        // have we already one view ?
        if (pViewShell)
        {
            // this view is not yet visible at this stage, so we look for not visible views, too
            SfxViewShell* pViewShell2 = SfxViewShell::GetNext(*pViewShell, /*only visible shells*/ false);
            // this view is not yet visible at this stage, so we look for not visible views, too, for this same document
            SfxViewShell* pViewShell2 = pViewShell;
            do
            {
                pViewShell2 = SfxViewShell::GetNext(*pViewShell2, /*only visible shells*/ false);
            } while (pViewShell2 && pViewShell2->GetDocId() != pViewShell->GetDocId());
            // if the second view is not this one, it means that there is
            // already more than one active view and so the formula mode
            // has already been disabled
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
index afb406b..432bbb6 100644
--- a/sc/source/ui/view/tabvwshc.cxx
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -495,7 +495,7 @@
    return xTransferable;
}

void ScTabViewShell::notifyAllViewsHeaderInvalidation(HeaderType eHeaderType, SCTAB nCurrentTabIndex)
void ScTabViewShell::notifyAllViewsHeaderInvalidation(SfxViewShell* pForViewShell, HeaderType eHeaderType, SCTAB nCurrentTabIndex)
{
    if (comphelper::LibreOfficeKit::isActive())
    {
@@ -518,7 +518,7 @@
        while (pViewShell)
        {
            ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
            if (pTabViewShell && (nCurrentTabIndex == -1 || pTabViewShell->getPart() == nCurrentTabIndex))
            if (pTabViewShell && pViewShell->GetDocId() == pForViewShell->GetDocId() && (nCurrentTabIndex == -1 || pTabViewShell->getPart() == nCurrentTabIndex))
            {
                pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, aPayload.getStr());
            }
@@ -527,13 +527,7 @@
    }
}

void ScTabViewShell::notifyAllViewsHeaderInvalidation(bool bColumns, SCTAB nCurrentTabIndex)
{
    HeaderType eHeaderType = bColumns ? COLUMN_HEADER : ROW_HEADER;
    ScTabViewShell::notifyAllViewsHeaderInvalidation(eHeaderType, nCurrentTabIndex);
}

bool ScTabViewShell::isAnyEditViewInRange(bool bColumns, SCCOLROW nStart, SCCOLROW nEnd)
bool ScTabViewShell::isAnyEditViewInRange(SfxViewShell* pForViewShell, bool bColumns, SCCOLROW nStart, SCCOLROW nEnd)
{
    if (comphelper::LibreOfficeKit::isActive())
    {
@@ -541,7 +535,7 @@
        while (pViewShell)
        {
            ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
            if (pTabViewShell)
            if (pTabViewShell && pTabViewShell->GetDocId() == pForViewShell->GetDocId())
            {
                ScInputHandler* pInputHandler = pTabViewShell->GetInputHandler();
                if (pInputHandler && pInputHandler->GetActiveView())
diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx
index 09e5b87..3a3bb3e 100644
--- a/sc/source/ui/view/viewfun2.cxx
+++ b/sc/source/ui/view/viewfun2.cxx
@@ -175,7 +175,7 @@
        pDocSh->UpdateOle(&GetViewData());

    if (comphelper::LibreOfficeKit::isActive())
        ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER, GetViewData().GetTabNo());
        ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());

    return bAnyChanged;
}
@@ -224,7 +224,7 @@
                                            PaintPartFlags::Grid | PaintPartFlags::Left );

    if (comphelper::LibreOfficeKit::isActive())
        ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER, GetViewData().GetTabNo());
        ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());

    return bChanged;
}
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index af50904..a189868 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -1468,11 +1468,12 @@
        return;

    SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
    SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
        {
            pTabViewShell->GetViewData().GetLOKWidthHelper(nCurrentTabIndex)->invalidateByIndex(nStartCol);

@@ -1523,11 +1524,12 @@
        return;

    SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
    SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
        {
            pTabViewShell->GetViewData().GetLOKHeightHelper(nCurrentTabIndex)->invalidateByIndex(nStartRow);

@@ -1578,11 +1580,12 @@
        return;

    SCTAB nCurTab = GetViewData().GetTabNo();
    SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
        if (pTabViewShell)
        if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
        {
            if (bWidth)
                pTabViewShell->GetViewData().GetLOKWidthHelper(nCurTab)->invalidateByIndex(nStart);
@@ -1623,10 +1626,10 @@
            if (comphelper::LibreOfficeKit::isActive())
            {
                if (bInsertCols)
                    ScTabViewShell::notifyAllViewsHeaderInvalidation(COLUMN_HEADER, GetViewData().GetTabNo());
                    ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER, GetViewData().GetTabNo());

                if (bInsertRows)
                    ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER, GetViewData().GetTabNo());
                    ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
            }
        }
        OUString aStartAddress =  aRange.aStart.GetColRowString();
@@ -1701,10 +1704,10 @@
        if (comphelper::LibreOfficeKit::isActive())
        {
            if (eCmd == DelCellCmd::Cols)
                ScTabViewShell::notifyAllViewsHeaderInvalidation(COLUMN_HEADER, GetViewData().GetTabNo());
                ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER, GetViewData().GetTabNo());

            if (eCmd == DelCellCmd::Rows)
                ScTabViewShell::notifyAllViewsHeaderInvalidation(ROW_HEADER, GetViewData().GetTabNo());
                ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
        }
    }
    else
diff --git a/sd/source/ui/sidebar/SlideBackground.cxx b/sd/source/ui/sidebar/SlideBackground.cxx
index cb3a5ff..df3a3be 100644
--- a/sd/source/ui/sidebar/SlideBackground.cxx
+++ b/sd/source/ui/sidebar/SlideBackground.cxx
@@ -1083,10 +1083,14 @@
    if (comphelper::LibreOfficeKit::isActive())
    {
        SfxViewShell* pViewShell = SfxViewShell::GetFirst();
        if (pViewShell)
        while (pViewShell)
        {
            SdXImpressDocument* pDoc = comphelper::getUnoTunnelImplementation<SdXImpressDocument>(pViewShell->GetCurrentDocument());
            SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
            if (pViewShell->GetDocId() == mrBase.GetDocId())
            {
                SdXImpressDocument* pDoc = comphelper::getUnoTunnelImplementation<SdXImpressDocument>(pViewShell->GetCurrentDocument());
                SfxLokHelper::notifyDocumentSizeChangedAllViews(pDoc);
            }
            pViewShell = SfxViewShell::GetNext(*pViewShell);
        }
    }
}
diff --git a/sfx2/source/view/lokcharthelper.cxx b/sfx2/source/view/lokcharthelper.cxx
index cd62c93..4d85245 100644
--- a/sfx2/source/view/lokcharthelper.cxx
+++ b/sfx2/source/view/lokcharthelper.cxx
@@ -177,7 +177,7 @@
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        if (pViewShell->getPart() == nPartForCurView)
        if (pViewShell->GetDocId() == pCurView->GetDocId() && pViewShell->getPart() == nPartForCurView)
        {
            LokChartHelper aChartHelper(pViewShell);
            if (aChartHelper.Hit(aPos))
@@ -260,7 +260,7 @@
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        if (pViewShell->getPart() == nPartForCurView)
        if (pCurView && pViewShell->GetDocId() == pCurView->GetDocId() && pViewShell->getPart() == nPartForCurView)
        {
            LokChartHelper aChartHelper(pViewShell);
            aChartHelper.PaintTile(rDevice, aTileRect);
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 2b1791d..d8f36c2 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -76,11 +76,17 @@
    SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst();
    if (!pViewFrame)
        return -1;
    SfxViewShell* pPrevViewShell = SfxViewShell::Current();
    ViewShellDocId nId;
    if (pPrevViewShell)
        nId = pPrevViewShell->GetDocId();
    SfxRequest aRequest(pViewFrame, SID_NEWWINDOW);
    pViewFrame->ExecView_Impl(aRequest);
    SfxViewShell* pViewShell = SfxViewShell::Current();
    if (!pViewShell)
        return -1;
    if (pPrevViewShell)
        pViewShell->SetDocId(nId);
    return static_cast<sal_Int32>(pViewShell->GetViewShellId());
}

@@ -154,7 +160,20 @@
std::size_t SfxLokHelper::getViewsCount()
{
    SfxApplication* pApp = SfxApplication::Get();
    return !pApp ? 0 : pApp->GetViewShells_Impl().size();
    if (!pApp)
        return 0;

    const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
    const ViewShellDocId nCurrentDocId = pCurrentViewShell ? pCurrentViewShell->GetDocId() : ViewShellDocId(-1);
    std::size_t n = 0;
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        if (pViewShell->GetDocId() == nCurrentDocId)
            n++;
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
    return n;
}

bool SfxLokHelper::getViewIds(int* pArray, size_t nSize)
@@ -163,18 +182,45 @@
    if (!pApp)
        return false;

    SfxViewShellArr_Impl& rViewArr = pApp->GetViewShells_Impl();
    if (rViewArr.size() > nSize)
        return false;

    for (std::size_t i = 0; i < rViewArr.size(); ++i)
    const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
    const ViewShellDocId nCurrentDocId = pCurrentViewShell ? pCurrentViewShell->GetDocId() : ViewShellDocId(-1);
    std::size_t n = 0;
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        SfxViewShell* pViewShell = rViewArr[i];
        pArray[i] = static_cast<sal_Int32>(pViewShell->GetViewShellId());
        if (n == nSize)
            return false;
        if (pViewShell->GetDocId() == nCurrentDocId)
        {
            pArray[n] = static_cast<sal_Int32>(pViewShell->GetViewShellId());
            n++;
        }
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
    return true;
}

void SfxLokHelper::setDocumentIdOfView(int nId)
{
    SfxViewShell* pViewShell = SfxViewShell::Current();
    assert(pViewShell);
    if (!pViewShell)
        return;
    pViewShell->SetDocId(ViewShellDocId(nId));
}

int SfxLokHelper::getDocumentIdOfView(int nViewId)
{
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        if (pViewShell->GetViewShellId() == ViewShellId(nViewId))
            return static_cast<int>(pViewShell->GetDocId());
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
    return -1;
}

LanguageTag SfxLokHelper::getDefaultLanguage()
{
    return g_defaultLanguageTag;
@@ -259,13 +305,13 @@

void SfxLokHelper::notifyOtherViews(SfxViewShell* pThisView, int nType, const OString& rKey, const OString& rPayload)
{
    if (SfxLokHelper::getViewsCount() <= 1 || DisableCallbacks::disabled())
    if (DisableCallbacks::disabled())
        return;

    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        if (pViewShell != pThisView)
        if (pViewShell != pThisView && pViewShell->GetDocId() == pThisView-> GetDocId())
            notifyOtherView(pThisView, pViewShell, nType, rKey, rPayload);

        pViewShell = SfxViewShell::GetNext(*pViewShell);
@@ -379,10 +425,13 @@
    if (!comphelper::LibreOfficeKit::isActive() || DisableCallbacks::disabled())
        return;

    // FIXME: Do we know whether it is the views for the document that is in the "current" view that has changed?
    const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        SfxLokHelper::notifyDocumentSizeChanged(pViewShell, "", pDoc, bInvalidateAll);
        if (pViewShell->GetDocId() == pCurrentViewShell-> GetDocId())
            SfxLokHelper::notifyDocumentSizeChanged(pViewShell, "", pDoc, bInvalidateAll);
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}
@@ -414,10 +463,12 @@
        return;

    const auto payload = rPayload.getStr();
    const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        pViewShell->libreOfficeKitViewCallback(nType, payload);
        if (pViewShell->GetDocId() == pCurrentViewShell->GetDocId())
            pViewShell->libreOfficeKitViewCallback(nType, payload);
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}
diff --git a/sfx2/source/view/viewimp.hxx b/sfx2/source/view/viewimp.hxx
index bb4cea0..c1ee641 100644
--- a/sfx2/source/view/viewimp.hxx
+++ b/sfx2/source/view/viewimp.hxx
@@ -54,6 +54,7 @@
    bool m_bTiledSearching;
    static sal_uInt32 m_nLastViewShellId;
    const ViewShellId m_nViewShellId;
    ViewShellDocId m_nDocId;

    explicit SfxViewShell_Impl(SfxViewShellFlags const nFlags);
    ~SfxViewShell_Impl();
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index ae468e4..603ecc5 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -225,7 +225,9 @@
,   m_pLibreOfficeKitViewData(nullptr)
,   m_bTiledSearching(false)
,   m_nViewShellId(SfxViewShell_Impl::m_nLastViewShellId++)
{}
,   m_nDocId(-1)
{
}

SfxViewShell_Impl::~SfxViewShell_Impl()
{
@@ -1100,7 +1102,6 @@

SfxViewShell::~SfxViewShell()
{

    // Remove from list
    const SfxViewShell *pThis = this;
    SfxViewShellArr_Impl &rViewArr = SfxGetpApp()->GetViewShells_Impl();
@@ -1451,7 +1452,8 @@
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        pViewShell->NotifyCursor(this);
        if (pViewShell->GetDocId() == GetDocId())
            pViewShell->NotifyCursor(this);
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}
@@ -1541,6 +1543,17 @@
    return pImpl->m_nViewShellId;
}

void SfxViewShell::SetDocId(ViewShellDocId nId)
{
    assert(static_cast<int>(pImpl->m_nDocId) == -1);
    pImpl->m_nDocId = nId;
}

ViewShellDocId SfxViewShell::GetDocId() const
{
    return pImpl->m_nDocId;
}

void SfxViewShell::NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload)
{
    SfxLokHelper::notifyOtherViews(this, nType, rKey, rPayload);
diff --git a/starmath/source/smmod.cxx b/starmath/source/smmod.cxx
index 788f5f5..9404692 100644
--- a/starmath/source/smmod.cxx
+++ b/starmath/source/smmod.cxx
@@ -150,6 +150,9 @@
        SfxViewShell* pViewShell = SfxViewShell::GetFirst();
        while (pViewShell)
        {
            // FIXME: What if pViewShell is for a different document,
            // but OTOH Math is presumably never used through
            // LibreOfficeKit, so maybe an irrelevant concern?
            if (dynamic_cast<const SmViewShell *>(pViewShell) != nullptr)
                pViewShell->GetWindow()->Invalidate();
            pViewShell = SfxViewShell::GetNext(*pViewShell);
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 552f92e..4a8b979 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -411,7 +411,8 @@
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
    while (pViewShell)
    {
        pViewShell->libreOfficeKitViewCallback(nType == RedlineNotification::Modify ? LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED : LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED, aPayload.c_str());
        if (pView && pView->GetDocId() == pViewShell->GetDocId())
            pViewShell->libreOfficeKitViewCallback(nType == RedlineNotification::Modify ? LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED : LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED, aPayload.c_str());
        pViewShell = SfxViewShell::GetNext(*pViewShell);
    }
}
diff --git a/sw/source/core/text/txtcache.cxx b/sw/source/core/text/txtcache.cxx
index 17eedcc1..2c8866c 100644
--- a/sw/source/core/text/txtcache.cxx
+++ b/sw/source/core/text/txtcache.cxx
@@ -170,6 +170,8 @@
         pView != nullptr;
         pView = SfxViewShell::GetNext(*pView, true, checkSfxViewShell<SwView>))
    {
        // Apparently we are not interested here what document pView is for, but only in the
        // total number of shells in the process?
        ++nVisibleShells;
    }