[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - 19 commits - android/source desktop/source editeng/source include/editeng include/LibreOfficeKit include/sfx2 libreofficekit/Package_selectionhandles.mk libreofficekit/qa libreofficekit/source sc/qa sc/source sd/qa sd/source sfx2/source svx/source sw/inc sw/qa sw/source vcl/headless vcl/source

Miklos Vajna vmiklos at collabora.co.uk
Thu Jul 21 09:26:26 UTC 2016


 desktop/source/lib/init.cxx                         |    5 
 dev/null                                            |binary
 editeng/source/editeng/editeng.cxx                  |    2 
 editeng/source/editeng/editview.cxx                 |    8 
 editeng/source/outliner/outlvw.cxx                  |    8 
 include/LibreOfficeKit/LibreOfficeKitEnums.h        |   32 ++
 include/editeng/editview.hxx                        |    4 
 include/editeng/outliner.hxx                        |    4 
 include/sfx2/viewsh.hxx                             |    2 
 libreofficekit/Package_selectionhandles.mk          |    1 
 libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx |    2 
 libreofficekit/source/gtk/lokdocview.cxx            |  217 +++++++++++++++-----
 sc/qa/unit/tiledrendering/tiledrendering.cxx        |   53 ++++
 sc/source/ui/inc/tabvwsh.hxx                        |    2 
 sc/source/ui/unoobj/docuno.cxx                      |    4 
 sc/source/ui/view/gridwin.cxx                       |    2 
 sc/source/ui/view/tabvwsh4.cxx                      |    8 
 sc/source/ui/view/tabvwshc.cxx                      |    5 
 sd/qa/unit/tiledrendering/data/shape.odp            |binary
 sd/qa/unit/tiledrendering/tiledrendering.cxx        |  157 ++++++++++++++
 sd/source/ui/func/futext.cxx                        |    4 
 sd/source/ui/inc/ViewShellBase.hxx                  |    2 
 sd/source/ui/unoidl/unomodel.cxx                    |    3 
 sd/source/ui/view/ViewShellBase.cxx                 |   20 +
 sfx2/source/view/classificationcontroller.cxx       |    4 
 sfx2/source/view/lokhelper.cxx                      |   19 -
 sfx2/source/view/viewsh.cxx                         |    7 
 svx/source/svdraw/svdedxv.cxx                       |    2 
 svx/source/svdraw/svdmrkv.cxx                       |   10 
 sw/inc/view.hxx                                     |    2 
 sw/qa/extras/tiledrendering/tiledrendering.cxx      |   96 ++++++++
 sw/source/core/crsr/crsrsh.cxx                      |    9 
 sw/source/uibase/uiview/view.cxx                    |    7 
 sw/source/uibase/uiview/viewprt.cxx                 |   12 +
 sw/source/uibase/uno/unotxdoc.cxx                   |   19 -
 vcl/headless/svpframe.cxx                           |    9 
 vcl/source/outdev/outdev.cxx                        |    1 
 vcl/source/window/toolbox2.cxx                      |    6 
 38 files changed, 635 insertions(+), 113 deletions(-)

New commits:
commit 6399df1eebb3eee96640d91002ab84a85fe558e1
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Jul 20 11:33:10 2016 +0200

    sd lok: decouple vcl window focus from cursor visibility
    
    The problem was the the blinking cursor was hidden when another vcl
    window got its focus, so it wasn't possible to edit two shape text in
    parallel in two windows.
    
    The code path is like this:
    
    - show cursor, cursor is created: SdrObjEditView::SdrBeginTextEdit() ->
      OutlinerView::ShowCursor()
    - show cursor, focus case: sd::FuText::Activate() ->
      OutlinerView::ShowCursor()
    - hide cursor, cursor is deleted: SdrObjEditView::SdrEndTextEdit() ->
      OutlinerView::HideCursor()
    - hide cursor, focus case: sd::FuText::Deactivate() ->
      OutlinerView::HideCursor()
    
    So add a new optional bool parameter that allows not emitting the
    LOK_CALLBACK_CURSOR_VISIBLE callback in the focus change case.
    
    Also, if we're at it, make sure that painting emits no show/cursor LOK
    callbacks.
    
    Change-Id: I1068a1b1f5cd76fd09b5a79066834bfb0daebc77
    Reviewed-on: https://gerrit.libreoffice.org/27335
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 6ea8084487411feea049f57712979fba4ad2fbce)

diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index f984d06..bf2746c 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -1435,7 +1435,7 @@ void EditEngine::SetUpdateMode( bool bUpdate )
 {
     pImpEditEngine->SetUpdateMode( bUpdate );
     if ( pImpEditEngine->pActiveView )
-        pImpEditEngine->pActiveView->ShowCursor( false, false );
+        pImpEditEngine->pActiveView->ShowCursor( false, false, /*bActivate=*/true );
 }
 
 bool EditEngine::GetUpdateMode() const
diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index 66b0425..7ace1b8 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -392,7 +392,7 @@ void EditView::Command( const CommandEvent& rCEvt )
     pImpEditView->Command( rCEvt );
 }
 
-void EditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
+void EditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor, bool bActivate )
 {
     if ( pImpEditView->pEditEngine->HasView( this ) )
     {
@@ -401,18 +401,18 @@ void EditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
             bGotoCursor = false;
         pImpEditView->ShowCursor( bGotoCursor, bForceVisCursor );
 
-        if (comphelper::LibreOfficeKit::isActive())
+        if (comphelper::LibreOfficeKit::isActive() && !bActivate)
         {
             pImpEditView->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, OString::boolean(true).getStr());
         }
     }
 }
 
-void EditView::HideCursor()
+void EditView::HideCursor(bool bDeactivate)
 {
     pImpEditView->GetCursor()->Hide();
 
-    if (comphelper::LibreOfficeKit::isActive())
+    if (comphelper::LibreOfficeKit::isActive() && !bDeactivate)
     {
         pImpEditView->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, OString::boolean(false).getStr());
     }
diff --git a/editeng/source/outliner/outlvw.cxx b/editeng/source/outliner/outlvw.cxx
index 12e6f91..a6fed49 100644
--- a/editeng/source/outliner/outlvw.cxx
+++ b/editeng/source/outliner/outlvw.cxx
@@ -1234,14 +1234,14 @@ bool OutlinerView::HasSelection() const
     return pEditView->HasSelection();
 }
 
-void OutlinerView::ShowCursor( bool bGotoCursor )
+void OutlinerView::ShowCursor( bool bGotoCursor, bool bActivate )
 {
-    pEditView->ShowCursor( bGotoCursor );
+    pEditView->ShowCursor( bGotoCursor, /*bForceVisCursor=*/true, bActivate );
 }
 
-void OutlinerView::HideCursor()
+void OutlinerView::HideCursor(bool bDeactivate)
 {
-    pEditView->HideCursor();
+    pEditView->HideCursor(bDeactivate);
 }
 
 void OutlinerView::SetWindow( vcl::Window* pWin )
diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index d4e88b2..818f503 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -111,8 +111,8 @@ public:
     void            Invalidate();
     Pair            Scroll( long nHorzScroll, long nVertScroll, ScrollRangeCheck nRangeCheck = ScrollRangeCheck::NoNegative );
 
-    void            ShowCursor( bool bGotoCursor = true, bool bForceVisCursor = true );
-    void            HideCursor();
+    void            ShowCursor( bool bGotoCursor = true, bool bForceVisCursor = true, bool bActivate = false );
+    void            HideCursor( bool bDeactivate = false );
 
     void            SetSelectionMode( EESelectionMode eMode );
 
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index d467ef5..99b79fe 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -231,8 +231,8 @@ public:
     void        ReleaseMouse();
     bool        MouseMove( const MouseEvent& );
 
-    void        ShowCursor( bool bGotoCursor = true );
-    void        HideCursor();
+    void        ShowCursor( bool bGotoCursor = true, bool bActivate = false );
+    void        HideCursor( bool bDeactivate = false );
 
     Outliner*   GetOutliner() const { return pOwner; }
 
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index acff325..e26c033 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -65,6 +65,7 @@ public:
     void testResizeTableColumn();
     void testViewCursors();
     void testViewCursorParts();
+    void testCursorViews();
 
     CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -86,6 +87,7 @@ public:
     CPPUNIT_TEST(testResizeTableColumn);
     CPPUNIT_TEST(testViewCursors);
     CPPUNIT_TEST(testViewCursorParts);
+    CPPUNIT_TEST(testCursorViews);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -818,11 +820,13 @@ public:
     bool m_bGraphicViewSelectionInvalidated;
     /// Our current part, to be able to decide if a view cursor/selection is relevant for us.
     int m_nPart;
+    bool m_bCursorVisibleChanged;
 
     ViewCallback()
         : m_bGraphicSelectionInvalidated(false),
           m_bGraphicViewSelectionInvalidated(false),
-          m_nPart(0)
+          m_nPart(0),
+          m_bCursorVisibleChanged(false)
     {
     }
 
@@ -850,6 +854,11 @@ public:
                 m_bGraphicViewSelectionInvalidated = true;
         }
         break;
+        case LOK_CALLBACK_CURSOR_VISIBLE:
+        {
+            m_bCursorVisibleChanged = true;
+        }
+        break;
         }
     }
 };
@@ -925,6 +934,35 @@ void SdTiledRenderingTest::testViewCursorParts()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SdTiledRenderingTest::testCursorViews()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    // Create the first view.
+    SdXImpressDocument* pXImpressDocument = createDoc("shape.odp");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+
+    // Begin text edit on the only object on the slide.
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    SdPage* pActualPage = pViewShell->GetActualPage();
+    SdrObject* pObject = pActualPage->GetObj(0);
+    SdrView* pView = pViewShell->GetView();
+    pView->MarkObj(pObject, pView->GetSdrPageView());
+    pView->SdrBeginTextEdit(pObject);
+
+    // Make sure that cursor state is not changed just because we create a second view.
+    aView1.m_bCursorVisibleChanged = false;
+    SfxLokHelper::createView();
+    pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT(!aView1.m_bCursorVisibleChanged);
+
+    mxComponent->dispose();
+    mxComponent.clear();
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/source/ui/func/futext.cxx b/sd/source/ui/func/futext.cxx
index cb0e848..f1bea72 100644
--- a/sd/source/ui/func/futext.cxx
+++ b/sd/source/ui/func/futext.cxx
@@ -977,7 +977,7 @@ void FuText::Activate()
     OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
 
     if (pOLV)
-        pOLV->ShowCursor();
+        pOLV->ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true);
 
     FuConstruct::Activate();
 
@@ -990,7 +990,7 @@ void FuText::Deactivate()
     OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
 
     if (pOLV)
-        pOLV->HideCursor();
+        pOLV->HideCursor(/*bDeactivate=*/true);
 
     mpView->SetHitTolerancePixel( HITPIX );
 
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 7fe6dd3..ac38317 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -385,7 +385,7 @@ void SdrObjEditView::ImpPaintOutlinerView(OutlinerView& rOutlView, const Rectang
         }
     }
 
-    rOutlView.ShowCursor();
+    rOutlView.ShowCursor(/*bGotoCursor=*/true, /*bActivate=*/true);
 }
 
 void SdrObjEditView::ImpInvalidateOutlinerView(OutlinerView& rOutlView) const
commit 044b9fdd6890b4fd34324d44fabb675daa8ff356
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 19 15:57:29 2016 +0200

    lokdocview: still allow view selections/cursors from other Writer views
    
    Writer pages are exposed as parts, but it still makes sense showing
    selections/cursors from other parts in that case.
    
    Change-Id: Ic76d93291bde2d959c149cf2ef5eba7ed33a45e8
    Reviewed-on: https://gerrit.libreoffice.org/27321
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 3c425926d48e513937ad727a56ab7744ca379e63)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 09ba343..6386d26 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -172,9 +172,12 @@ struct LOKDocViewPrivateImpl
     /// View ID, returned by createView() or 0 by default.
     int m_nViewId;
 
-    /// Part ID, returned by getPart().
+    /// Cached part ID, returned by getPart().
     int m_nPartId;
 
+    /// Cached document type, returned by getDocumentType().
+    LibreOfficeKitDocumentType m_eDocumentType;
+
     /**
      * Contains a freshly set zoom level: logic size of a tile.
      * It gets reset back to 0 when LOK was informed about this zoom change.
@@ -1586,7 +1589,8 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
             if (itVisibility != priv->m_aViewCursorVisibilities.end() && !itVisibility->second)
                 continue;
 
-            if (rPair.second.m_nPart != priv->m_nPartId)
+            // Show view cursors when in Writer or when the part matches.
+            if (rPair.second.m_nPart != priv->m_nPartId && priv->m_eDocumentType != LOK_DOCTYPE_TEXT)
                 continue;
 
             GdkRectangle& rCursor = rPair.second.m_aRectangle;
@@ -1662,7 +1666,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     // Selections of other views.
     for (auto& rPair : priv->m_aTextViewSelectionRectangles)
     {
-        if (rPair.second.m_nPart != priv->m_nPartId)
+        if (rPair.second.m_nPart != priv->m_nPartId && priv->m_eDocumentType != LOK_DOCTYPE_TEXT)
             continue;
 
         for (GdkRectangle& rRectangle : rPair.second.m_aRectangles)
@@ -1689,7 +1693,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     for (auto& rPair : priv->m_aGraphicViewSelections)
     {
         const ViewRectangle& rRectangle = rPair.second;
-        if (rRectangle.m_nPart != priv->m_nPartId)
+        if (rRectangle.m_nPart != priv->m_nPartId && priv->m_eDocumentType != LOK_DOCTYPE_TEXT)
             continue;
 
         const GdkRGBA& rDark = getDarkColor(rPair.first);
@@ -2046,6 +2050,7 @@ openDocumentInThread (gpointer data)
 
     priv->m_pOffice->pClass->registerCallback(priv->m_pOffice, globalCallbackWorker, pDocView);
     priv->m_pDocument = priv->m_pOffice->pClass->documentLoad( priv->m_pOffice, priv->m_aDocPath );
+    priv->m_eDocumentType = static_cast<LibreOfficeKitDocumentType>(priv->m_pDocument->pClass->getDocumentType(priv->m_pDocument));
     if ( !priv->m_pDocument )
     {
         char *pError = priv->m_pOffice->pClass->getError( priv->m_pOffice );
@@ -2319,6 +2324,7 @@ static void lok_doc_view_set_property (GObject* object, guint propId, const GVal
         break;
     case PROP_DOC_POINTER:
         priv->m_pDocument = static_cast<LibreOfficeKitDocument*>(g_value_get_pointer(value));
+        priv->m_eDocumentType = static_cast<LibreOfficeKitDocumentType>(priv->m_pDocument->pClass->getDocumentType(priv->m_pDocument));
         break;
     case PROP_EDITABLE:
         lok_doc_view_set_edit (pDocView, g_value_get_boolean (value));
commit 541ab755005d37c31f3b93fdaba2d537a956b2d6
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 19 14:35:56 2016 +0200

    sc lok: notify other views about selection changes of multiple cells
    
    A single cell is handled by the cell cursor, which was already handled.
    This one takes care of the situation when multiple cells are selected.
    
    Change-Id: I11b3045e4884ad9629655e2c05c16af83d21e7b2
    Reviewed-on: https://gerrit.libreoffice.org/27318
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 495cfa27c173741caa233575438c18746272b4aa)

diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index f82afb9..5857dab 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -14,6 +14,7 @@
 
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/DispatchHelper.hpp>
 #include <comphelper/dispatchcommand.hxx>
 #include <comphelper/processfactory.hxx>
 #include <comphelper/propertysequence.hxx>
@@ -53,6 +54,7 @@ public:
     void testPartHash();
     void testDocumentSize();
     void testViewCursors();
+    void testTextViewSelection();
 
     CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
     CPPUNIT_TEST(testRowColumnSelections);
@@ -60,6 +62,7 @@ public:
     CPPUNIT_TEST(testPartHash);
     CPPUNIT_TEST(testDocumentSize);
     CPPUNIT_TEST(testViewCursors);
+    CPPUNIT_TEST(testTextViewSelection);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -335,10 +338,12 @@ class ViewCallback
 public:
     bool m_bOwnCursorInvalidated;
     bool m_bViewCursorInvalidated;
+    bool m_bTextViewSelectionInvalidated;
 
     ViewCallback()
         : m_bOwnCursorInvalidated(false),
-          m_bViewCursorInvalidated(false)
+          m_bViewCursorInvalidated(false),
+          m_bTextViewSelectionInvalidated(false)
     {
     }
 
@@ -361,6 +366,11 @@ public:
             m_bViewCursorInvalidated = true;
         }
         break;
+        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+        {
+            m_bTextViewSelectionInvalidated = true;
+        }
+        break;
         }
     }
 };
@@ -387,6 +397,45 @@ void ScTiledRenderingTest::testViewCursors()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void lcl_dispatchCommand(const uno::Reference<lang::XComponent>& xComponent, const OUString& rCommand)
+{
+    uno::Reference<frame::XController> xController = uno::Reference<frame::XModel>(xComponent, uno::UNO_QUERY)->getCurrentController();
+    CPPUNIT_ASSERT(xController.is());
+    uno::Reference<frame::XDispatchProvider> xFrame(xController->getFrame(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT(xFrame.is());
+
+    uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+    uno::Reference<frame::XDispatchHelper> xDispatchHelper(frame::DispatchHelper::create(xContext));
+    CPPUNIT_ASSERT(xDispatchHelper.is());
+
+    xDispatchHelper->executeDispatch(xFrame, rCommand, OUString(), 0, {});
+}
+
+void ScTiledRenderingTest::testTextViewSelection()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    // Create two views, and leave the second one current.
+    ScModelObj* pModelObj = createDoc("select-row-cols.ods");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    SfxLokHelper::createView();
+    ViewCallback aView2;
+    pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // Create a selection on two cells in the second view, that's a text selection in LOK terms.
+    aView1.m_bTextViewSelectionInvalidated = false;
+    lcl_dispatchCommand(mxComponent, ".uno:GoRightSel");
+    Scheduler::ProcessEventsToIdle();
+    // Make sure the first view got its notification.
+    CPPUNIT_ASSERT(aView1.m_bTextViewSelectionInvalidated);
+
+    mxComponent->dispose();
+    mxComponent.clear();
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(ScTiledRenderingTest);
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index 47c21c6..06f2774 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -70,6 +70,7 @@
 #if HAVE_FEATURE_OPENCL
 #include <opencl/platforminfo.hxx>
 #endif
+#include <sfx2/lokhelper.hxx>
 
 #include "cellsuno.hxx"
 #include <columnspanset.hxx>
@@ -860,6 +861,7 @@ void ScModelObj::resetSelection()
 
     // and hide the cell and text selection
     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "");
+    SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
 }
 
 void ScModelObj::setClipboard(const uno::Reference<datatransfer::clipboard::XClipboard>& xClipboard)
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 4e6d9c6..18dbaad 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -6017,6 +6017,7 @@ static void updateLibreOfficeKitSelection(ScViewData* pViewData, const std::vect
     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_START, aStart.toString().getStr());
     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_END, aEnd.toString().getStr());
     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aSelection.getStr());
+    SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", aSelection.getStr());
 }
 
 void ScGridWindow::UpdateCursorOverlay()
@@ -6263,6 +6264,7 @@ void ScGridWindow::UpdateSelectionOverlay()
     {
         ScTabViewShell* pViewShell = pViewData->GetViewShell();
         pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "EMPTY");
+        SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "EMPTY");
     }
 
     if ( aOldMode != aDrawMode )
commit 338b100cbf034e2aab0c8d1af5bbcba21a73407b
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 19 11:14:52 2016 +0200

    lokdocview: handle part number in view selections/cursors
    
    This way we show view selections/cursors from other views only in case
    the part number matches. Anything else looks buggy in Calc/Impress.
    
    Change-Id: If3ecbfc4b05350606730319b1a570afc15fd9d0a
    Reviewed-on: https://gerrit.libreoffice.org/27315
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 1ba00c2173938ed2ea2f25074e866ea51370d727)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 43016dd..09ba343 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -48,6 +48,32 @@
 /// This is expected to be locked during setView(), doSomethingElse() LOK calls.
 std::mutex g_aLOKMutex;
 
+/// Same as a GdkRectangle, but also tracks in which part the rectangle is.
+struct ViewRectangle
+{
+    int m_nPart;
+    GdkRectangle m_aRectangle;
+
+    ViewRectangle(int nPart = 0, const GdkRectangle& rRectangle = GdkRectangle())
+        : m_nPart(nPart),
+        m_aRectangle(rRectangle)
+    {
+    }
+};
+
+/// Same as a list of GdkRectangles, but also tracks in which part the rectangle is.
+struct ViewRectangles
+{
+    int m_nPart;
+    std::vector<GdkRectangle> m_aRectangles;
+
+    ViewRectangles(int nPart = 0, const std::vector<GdkRectangle>& rRectangles = std::vector<GdkRectangle>())
+        : m_nPart(nPart),
+        m_aRectangles(rRectangles)
+    {
+    }
+};
+
 /// Private struct used by this GObject type
 struct LOKDocViewPrivateImpl
 {
@@ -78,7 +104,7 @@ struct LOKDocViewPrivateImpl
     GdkRectangle m_aVisibleCursor;
     /// Position and size of the view cursors. The current view can only see
     /// them, can't modify them. Key is the view id.
-    std::map<int, GdkRectangle> m_aViewCursors;
+    std::map<int, ViewRectangle> m_aViewCursors;
     /// Cursor overlay is visible or hidden (for blinking).
     gboolean m_bCursorOverlayVisible;
     /// Cursor is visible or hidden (e.g. for graphic selection).
@@ -98,7 +124,7 @@ struct LOKDocViewPrivateImpl
     std::vector<GdkRectangle> m_aTextSelectionRectangles;
     /// Rectangles of view selections. The current view can only see
     /// them, can't modify them. Key is the view id.
-    std::map<int, std::vector<GdkRectangle>> m_aTextViewSelectionRectangles;
+    std::map<int, ViewRectangles> m_aTextViewSelectionRectangles;
     /// Position and size of the selection start (as if there would be a cursor caret there).
     GdkRectangle m_aTextSelectionStart;
     /// Position and size of the selection end.
@@ -106,11 +132,11 @@ struct LOKDocViewPrivateImpl
     GdkRectangle m_aGraphicSelection;
     /// Position and size of the graphic view selections. The current view can only
     /// see them, can't modify them. Key is the view id.
-    std::map<int, GdkRectangle> m_aGraphicViewSelections;
+    std::map<int, ViewRectangle> m_aGraphicViewSelections;
     GdkRectangle m_aCellCursor;
     /// Position and size of the cell view cursors. The current view can only
     /// see them, can't modify them. Key is the view id.
-    std::map<int, GdkRectangle> m_aCellViewCursors;
+    std::map<int, ViewRectangle> m_aCellViewCursors;
     gboolean m_bInDragGraphicSelection;
 
     /// @name Start/middle/end handle.
@@ -146,6 +172,9 @@ struct LOKDocViewPrivateImpl
     /// View ID, returned by createView() or 0 by default.
     int m_nViewId;
 
+    /// Part ID, returned by getPart().
+    int m_nPartId;
+
     /**
      * Contains a freshly set zoom level: logic size of a tile.
      * It gets reset back to 0 when LOK was informed about this zoom change.
@@ -197,6 +226,7 @@ struct LOKDocViewPrivateImpl
         m_aHandleEndRect({0, 0, 0, 0}),
         m_bInDragEndHandle(false),
         m_nViewId(0),
+        m_nPartId(0),
         m_nTileSizeTwips(0),
         m_aVisibleArea({0, 0, 0, 0}),
         m_bVisibleAreaSet(false),
@@ -840,7 +870,9 @@ static void reportError(LOKDocView* /*pDocView*/, const std::string& rString)
 static void
 setPart(LOKDocView* pDocView, const std::string& rString)
 {
-    g_signal_emit(pDocView, doc_view_signals[PART_CHANGED], 0, std::stoi(rString));
+    LOKDocViewPrivate& priv = getPrivate(pDocView);
+    priv->m_nPartId = std::stoi(rString);
+    g_signal_emit(pDocView, doc_view_signals[PART_CHANGED], 0, priv->m_nPartId);
 }
 
 static void
@@ -1127,9 +1159,10 @@ callback (gpointer pData)
         boost::property_tree::ptree aTree;
         boost::property_tree::read_json(aStream, aTree);
         int nViewId = aTree.get<int>("viewId");
+        int nPart = aTree.get<int>("part");
         const std::string& rRectangle = aTree.get<std::string>("selection");
         if (rRectangle != "EMPTY")
-            priv->m_aGraphicViewSelections[nViewId] = payloadToRectangle(pDocView, rRectangle.c_str());
+            priv->m_aGraphicViewSelections[nViewId] = ViewRectangle(nPart, payloadToRectangle(pDocView, rRectangle.c_str()));
         else
         {
             auto it = priv->m_aGraphicViewSelections.find(nViewId);
@@ -1214,8 +1247,9 @@ callback (gpointer pData)
         boost::property_tree::ptree aTree;
         boost::property_tree::read_json(aStream, aTree);
         int nViewId = aTree.get<int>("viewId");
+        int nPart = aTree.get<int>("part");
         const std::string& rRectangle = aTree.get<std::string>("rectangle");
-        priv->m_aViewCursors[nViewId] = payloadToRectangle(pDocView, rRectangle.c_str());
+        priv->m_aViewCursors[nViewId] = ViewRectangle(nPart, payloadToRectangle(pDocView, rRectangle.c_str()));
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
         break;
     }
@@ -1225,8 +1259,9 @@ callback (gpointer pData)
         boost::property_tree::ptree aTree;
         boost::property_tree::read_json(aStream, aTree);
         int nViewId = aTree.get<int>("viewId");
+        int nPart = aTree.get<int>("part");
         const std::string& rSelection = aTree.get<std::string>("selection");
-        priv->m_aTextViewSelectionRectangles[nViewId] = payloadToRectangles(pDocView, rSelection.c_str());
+        priv->m_aTextViewSelectionRectangles[nViewId] = ViewRectangles(nPart, payloadToRectangles(pDocView, rSelection.c_str()));
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
         break;
     }
@@ -1248,9 +1283,10 @@ callback (gpointer pData)
         boost::property_tree::ptree aTree;
         boost::property_tree::read_json(aStream, aTree);
         int nViewId = aTree.get<int>("viewId");
+        int nPart = aTree.get<int>("part");
         const std::string& rRectangle = aTree.get<std::string>("rectangle");
         if (rRectangle != "EMPTY")
-            priv->m_aCellViewCursors[nViewId] = payloadToRectangle(pDocView, rRectangle.c_str());
+            priv->m_aCellViewCursors[nViewId] = ViewRectangle(nPart, payloadToRectangle(pDocView, rRectangle.c_str()));
         else
         {
             auto it = priv->m_aCellViewCursors.find(nViewId);
@@ -1550,7 +1586,10 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
             if (itVisibility != priv->m_aViewCursorVisibilities.end() && !itVisibility->second)
                 continue;
 
-            GdkRectangle& rCursor = rPair.second;
+            if (rPair.second.m_nPart != priv->m_nPartId)
+                continue;
+
+            GdkRectangle& rCursor = rPair.second.m_aRectangle;
             if (rCursor.width < 30)
                 // Set a minimal width if it would be 0.
                 rCursor.width = 30;
@@ -1621,9 +1660,12 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     }
 
     // Selections of other views.
-    for (std::pair<const int, std::vector<GdkRectangle>>& rPair : priv->m_aTextViewSelectionRectangles)
+    for (auto& rPair : priv->m_aTextViewSelectionRectangles)
     {
-        for (GdkRectangle& rRectangle : rPair.second)
+        if (rPair.second.m_nPart != priv->m_nPartId)
+            continue;
+
+        for (GdkRectangle& rRectangle : rPair.second.m_aRectangles)
         {
             const GdkRGBA& rDark = getDarkColor(rPair.first);
             // 75% transparency.
@@ -1644,10 +1686,14 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     }
 
     // Graphic selections of other views.
-    for (std::pair<const int, GdkRectangle>& rPair : priv->m_aGraphicViewSelections)
+    for (auto& rPair : priv->m_aGraphicViewSelections)
     {
+        const ViewRectangle& rRectangle = rPair.second;
+        if (rRectangle.m_nPart != priv->m_nPartId)
+            continue;
+
         const GdkRGBA& rDark = getDarkColor(rPair.first);
-        renderGraphicHandle(pDocView, pCairo, rPair.second, rDark);
+        renderGraphicHandle(pDocView, pCairo, rRectangle.m_aRectangle, rDark);
     }
 
     // Draw the cell cursor.
@@ -1659,10 +1705,6 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
                         twipToPixel(priv->m_aCellCursor.y, priv->m_fZoom),
                         twipToPixel(priv->m_aCellCursor.width, priv->m_fZoom),
                         twipToPixel(priv->m_aCellCursor.height, priv->m_fZoom));
-                        // priv->m_aCellCursor.x - 1,
-                        // priv->m_aCellCursor.y - 1,
-                        // priv->m_aCellCursor.width + 2,
-                        // priv->m_aCellCursor.height + 2);
         cairo_set_line_width(pCairo, 2.0);
         cairo_stroke(pCairo);
     }
@@ -1670,15 +1712,17 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     // Cell view cursors: they are colored.
     for (auto& rPair : priv->m_aCellViewCursors)
     {
-        GdkRectangle& rCursor = rPair.second;
+        const ViewRectangle& rCursor = rPair.second;
+        if (rCursor.m_nPart != priv->m_nPartId)
+            continue;
 
         const GdkRGBA& rDark = getDarkColor(rPair.first);
         cairo_set_source_rgb(pCairo, rDark.red, rDark.green, rDark.blue);
         cairo_rectangle(pCairo,
-                        twipToPixel(rCursor.x, priv->m_fZoom),
-                        twipToPixel(rCursor.y, priv->m_fZoom),
-                        twipToPixel(rCursor.width, priv->m_fZoom),
-                        twipToPixel(rCursor.height, priv->m_fZoom));
+                        twipToPixel(rCursor.m_aRectangle.x, priv->m_fZoom),
+                        twipToPixel(rCursor.m_aRectangle.y, priv->m_fZoom),
+                        twipToPixel(rCursor.m_aRectangle.width, priv->m_fZoom),
+                        twipToPixel(rCursor.m_aRectangle.height, priv->m_fZoom));
         cairo_set_line_width(pCairo, 2.0);
         cairo_stroke(pCairo);
     }
@@ -3104,6 +3148,7 @@ lok_doc_view_set_part (LOKDocView* pDocView, int nPart)
         g_clear_error(&error);
     }
     g_object_unref(task);
+    priv->m_nPartId = nPart;
 }
 
 SAL_DLLPUBLIC_EXPORT gchar*
commit fc4bb1254ef77d29368535c9a810875c8db15b77
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 19 10:02:08 2016 +0200

    sfx2 lok: expose part number in SfxLokHelper::notifyOtherViews()
    
    This way a client can decide if the view cursor it gets is relevant (the
    views show the same part) or not.
    
    Change-Id: I7b274b28f0c4f0509df5071831acf50512eff640
    Reviewed-on: https://gerrit.libreoffice.org/27311
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 299b9377469473abd8f58ba7f1054794491bdc56)

diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index d489d55..afee970 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -331,6 +331,8 @@ public:
     void setTiledSearching(bool bTiledSearching);
     /// Are we doing tiled searching?
     bool isTiledSearching() const;
+    /// See lok::Document::getPart().
+    virtual int getPart() const;
 };
 
 
diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx
index ec6f226..6a2ae9b 100644
--- a/sc/source/ui/inc/tabvwsh.hxx
+++ b/sc/source/ui/inc/tabvwsh.hxx
@@ -385,6 +385,8 @@ public:
     // #i123629#
     bool    GetForceFocusOnCurCell() const { return bForceFocusOnCurCell; }
     void SetForceFocusOnCurCell(bool bFlag) { bForceFocusOnCurCell=bFlag; }
+    /// See SfxViewShell::getPart().
+    int getPart() const override;
 };
 
 #endif
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index b38031f..47c21c6 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -512,7 +512,7 @@ int ScModelObj::getParts()
 int ScModelObj::getPart()
 {
     ScViewData* pViewData = ScDocShell::GetViewData();
-    return pViewData->GetTabNo();
+    return pViewData->GetViewShell()->getPart();
 }
 
 OUString ScModelObj::getPartName( int nPart )
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
index bfe6d8e..9cdc11e 100644
--- a/sc/source/ui/view/tabvwshc.cxx
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -536,4 +536,9 @@ VclPtr<SfxModelessDialog> ScTabViewShell::CreateRefDialog(
     return pResult;
 }
 
+int ScTabViewShell::getPart() const
+{
+    return GetViewData().GetTabNo();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/tiledrendering/data/shape.odp b/sd/qa/unit/tiledrendering/data/shape.odp
index f734761..b1ffa54 100644
Binary files a/sd/qa/unit/tiledrendering/data/shape.odp and b/sd/qa/unit/tiledrendering/data/shape.odp differ
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 316936f..acff325 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -64,6 +64,7 @@ public:
     void testResizeTable();
     void testResizeTableColumn();
     void testViewCursors();
+    void testViewCursorParts();
 
     CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -84,6 +85,7 @@ public:
     CPPUNIT_TEST(testResizeTable);
     CPPUNIT_TEST(testResizeTableColumn);
     CPPUNIT_TEST(testViewCursors);
+    CPPUNIT_TEST(testViewCursorParts);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -814,10 +816,13 @@ class ViewCallback
 public:
     bool m_bGraphicSelectionInvalidated;
     bool m_bGraphicViewSelectionInvalidated;
+    /// Our current part, to be able to decide if a view cursor/selection is relevant for us.
+    int m_nPart;
 
     ViewCallback()
         : m_bGraphicSelectionInvalidated(false),
-          m_bGraphicViewSelectionInvalidated(false)
+          m_bGraphicViewSelectionInvalidated(false),
+          m_nPart(0)
     {
     }
 
@@ -826,7 +831,7 @@ public:
         static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
     }
 
-    void callbackImpl(int nType, const char* /*pPayload*/)
+    void callbackImpl(int nType, const char* pPayload)
     {
         switch (nType)
         {
@@ -837,7 +842,12 @@ public:
         break;
         case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
         {
-            m_bGraphicViewSelectionInvalidated = true;
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            if (aTree.get_child("part").get_value<int>() == m_nPart)
+                // Ignore callbacks which are for a different part.
+                m_bGraphicViewSelectionInvalidated = true;
         }
         break;
         }
@@ -874,6 +884,47 @@ void SdTiledRenderingTest::testViewCursors()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SdTiledRenderingTest::testViewCursorParts()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    // Create two views.
+    SdXImpressDocument* pXImpressDocument = createDoc("shape.odp");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    SfxLokHelper::createView();
+    pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    ViewCallback aView2;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // Select the shape in the second view.
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    SdPage* pActualPage = pViewShell->GetActualPage();
+    SdrObject* pObject = pActualPage->GetObj(0);
+    SdrView* pView = pViewShell->GetView();
+    pView->MarkObj(pObject, pView->GetSdrPageView());
+    Scheduler::ProcessEventsToIdle();
+    // First view notices that there was a selection change in the other view.
+    CPPUNIT_ASSERT(aView1.m_bGraphicViewSelectionInvalidated);
+    pView->UnmarkAllObj(pView->GetSdrPageView());
+
+    // Now switch to the second part in the second view.
+    pXImpressDocument->setPart(1);
+    aView2.m_nPart = 1;
+    aView1.m_bGraphicViewSelectionInvalidated = false;
+    pActualPage = pViewShell->GetActualPage();
+    pObject = pActualPage->GetObj(0);
+    pView->MarkObj(pObject, pView->GetSdrPageView());
+    Scheduler::ProcessEventsToIdle();
+    // First view ignores view selection, as it would be for part 1, and it's in part 0.
+    // This failed when the "part" was always 0 in the callback.
+    CPPUNIT_ASSERT(!aView1.m_bGraphicViewSelectionInvalidated);
+
+    mxComponent->dispose();
+    mxComponent.clear();
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/source/ui/inc/ViewShellBase.hxx b/sd/source/ui/inc/ViewShellBase.hxx
index 5e4aec3..22489f1 100644
--- a/sd/source/ui/inc/ViewShellBase.hxx
+++ b/sd/source/ui/inc/ViewShellBase.hxx
@@ -220,6 +220,8 @@ public:
     /** returns the ui descriptive name for the given uno slot. The result is taken from the configuration
         and not cached, so do not use it excessive (f.e. in status updates) */
     OUString RetrieveLabelFromCommand( const OUString& aCmdURL ) const;
+    /// See SfxViewShell::getPart().
+    int getPart() const override;
 
 protected:
 
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 8cf5983..4d00606 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2312,8 +2312,7 @@ int SdXImpressDocument::getPart()
     if (!pViewSh)
         return 0;
 
-    // curPageId seems to start at 1
-    return pViewSh->GetCurPageId() - 1;
+    return pViewSh->GetViewShellBase().getPart();
 }
 
 OUString SdXImpressDocument::getPartName( int nPart )
diff --git a/sd/source/ui/view/ViewShellBase.cxx b/sd/source/ui/view/ViewShellBase.cxx
index b90fa2a..5f4ba54 100644
--- a/sd/source/ui/view/ViewShellBase.cxx
+++ b/sd/source/ui/view/ViewShellBase.cxx
@@ -1032,6 +1032,19 @@ OUString ViewShellBase::RetrieveLabelFromCommand( const OUString& aCmdURL ) cons
     return ImplRetrieveLabelFromCommand( xFrame, aCmdURL );
 }
 
+int ViewShellBase::getPart() const
+{
+    ViewShell* pViewShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
+
+    if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pViewShell))
+    {
+        // curPageId seems to start at 1
+        return pDrawViewShell->GetCurPageId() - 1;
+    }
+
+    return 0;
+}
+
 //===== ViewShellBase::Implementation =========================================
 
 ViewShellBase::Implementation::Implementation (ViewShellBase& rBase)
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index d027bad..09d78cf 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -108,6 +108,8 @@ void SfxLokHelper::notifyOtherViews(SfxViewShell* pThisView, int nType, const OS
             boost::property_tree::ptree aTree;
             aTree.put("viewId", SfxLokHelper::getView(pThisView));
             aTree.put(rKey.getStr(), rPayload.getStr());
+            aTree.put("part", pThisView->getPart());
+            aTree.put(rKey.getStr(), rPayload.getStr());
             std::stringstream aStream;
             boost::property_tree::write_json(aStream, aTree);
             OString aPayload = aStream.str().c_str();
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index a68e8c0..92d3f1a 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -1643,6 +1643,11 @@ bool SfxViewShell::isTiledSearching() const
     return pImp->m_bTiledSearching;
 }
 
+int SfxViewShell::getPart() const
+{
+    return 0;
+}
+
 bool SfxViewShell::KeyInput( const KeyEvent &rKeyEvent )
 
 /*  [Description]
diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx
index 328460f..f422ced 100644
--- a/sw/inc/view.hxx
+++ b/sw/inc/view.hxx
@@ -649,6 +649,8 @@ public:
     SAL_DLLPRIVATE virtual VclPtr<SfxTabPage> CreatePrintOptionsPage( vcl::Window* pParent,
                                                     const SfxItemSet& rSet) override;
     static SvxSearchItem* GetSearchItem() { return m_pSrchItem; }
+    /// See SfxViewShell::getPart().
+    int getPart() const override;
 };
 
 inline long SwView::GetXScroll() const
diff --git a/sw/source/uibase/uiview/viewprt.cxx b/sw/source/uibase/uiview/viewprt.cxx
index 6a91527..8d12214 100644
--- a/sw/source/uibase/uiview/viewprt.cxx
+++ b/sw/source/uibase/uiview/viewprt.cxx
@@ -246,6 +246,18 @@ void SwView::ExecutePrint(SfxRequest& rReq)
     }
 }
 
+int SwView::getPart() const
+{
+    if (!m_pWrtShell)
+        return 0;
+
+    sal_uInt16 nPage, nLogPage;
+    OUString sDisplay;
+    m_pWrtShell->GetPageNumber(-1, m_pWrtShell->IsCursorVisible(), nPage, nLogPage, sDisplay);
+
+    return nPage - 1;
+}
+
 // Create page printer/additions for SwView and SwPagePreview
 
 VclPtr<SfxTabPage> CreatePrintOptionsPage( vcl::Window *pParent,
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 396e79d..a37764a 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3203,15 +3203,11 @@ int SwXTextDocument::getPart()
 {
     SolarMutexGuard aGuard;
 
-    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
-    if (!pWrtShell)
+    SwView* pView = pDocShell->GetView();
+    if (!pView)
         return 0;
 
-    sal_uInt16 nPage, nLogPage;
-    OUString sDisplay;
-    pWrtShell->GetPageNumber(-1, pWrtShell->IsCursorVisible(), nPage, nLogPage, sDisplay);
-
-    return nPage - 1;
+    return pView->getPart();
 }
 
 OUString SwXTextDocument::getPartName(int nPart)
commit ff11e4ff92036006851458cc5d935ff946618ae8
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Jul 18 09:10:19 2016 +0200

    CppunitTest_sw_tiledrendering: blind stack-use-after-return fix
    
    Change-Id: I23c0324979939955f94408a452020e9776358967
    (cherry picked from commit 58b592a59122144d6c5446f200dd2f48108c8909)

diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index ad1c36c..e0554a8 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -657,6 +657,8 @@ void SwTiledRenderingTest::testMissingInvalidation()
     Scheduler::ProcessEventsToIdle();
     CPPUNIT_ASSERT(aView1.m_bTilesInvalidated);
     CPPUNIT_ASSERT(aView2.m_bTilesInvalidated);
+    mxComponent->dispose();
+    mxComponent.clear();
 
     comphelper::LibreOfficeKit::setActive(false);
 }
@@ -698,6 +700,8 @@ void SwTiledRenderingTest::testViewCursors()
     CPPUNIT_ASSERT(aView1.m_bViewSelectionSet);
     CPPUNIT_ASSERT(aView2.m_bOwnSelectionSet);
     CPPUNIT_ASSERT(!aView2.m_bViewSelectionSet);
+    mxComponent->dispose();
+    mxComponent.clear();
 
     comphelper::LibreOfficeKit::setActive(false);
 }
commit 37e215f708a872b9a232247217648c2c4872d550
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 15 17:26:34 2016 +0200

    lok::Document::destroyView: clean up view cursors/selections
    
    (cherry picked from commit bc9b4fd4c83af3532204237157821d4884c42d8e)
    
    Conflicts:
    	sd/source/ui/view/ViewShellBase.cxx
    	sw/source/uibase/uiview/view.cxx
    
    Change-Id: Icd3f96a922e7d1aec0d52e90df87ec45790c9807

diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
index 5a6413e..9d91dec 100644
--- a/sc/source/ui/view/tabvwsh4.cxx
+++ b/sc/source/ui/view/tabvwsh4.cxx
@@ -97,6 +97,8 @@
 #include <com/sun/star/chart2/XCoordinateSystem.hpp>
 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
 #include <com/sun/star/chart2/XChartType.hpp>
+#include <sfx2/lokhelper.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 extern SfxViewShell* pScActiveViewShell;            // global.cxx
 
@@ -1717,6 +1719,12 @@ ScTabViewShell::ScTabViewShell( SfxViewFrame* pViewFrame,
 
 ScTabViewShell::~ScTabViewShell()
 {
+    // Notify other LOK views that we are going away.
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");
+
     ScDocShell* pDocSh = GetViewData().GetDocShell();
     EndListening(*pDocSh);
     EndListening(*GetViewFrame());
diff --git a/sd/source/ui/view/ViewShellBase.cxx b/sd/source/ui/view/ViewShellBase.cxx
index 7b57e9e..b90fa2a 100644
--- a/sd/source/ui/view/ViewShellBase.cxx
+++ b/sd/source/ui/view/ViewShellBase.cxx
@@ -84,6 +84,8 @@
 #include <vcl/settings.hxx>
 
 #include <tools/diagnose_ex.h>
+#include <sfx2/lokhelper.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 #include "fubullet.hxx"
 
@@ -268,6 +270,11 @@ ViewShellBase::ViewShellBase (
 */
 ViewShellBase::~ViewShellBase()
 {
+    // Notify other LOK views that we are going away.
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
+
     rtl::Reference<SlideShow> xSlideShow(SlideShow::GetSlideShow(*this));
     if (xSlideShow.is() && xSlideShow->dependsOn(this))
         SlideShow::Stop(*this);
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 6ab106d..ad1c36c 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -55,6 +55,7 @@ public:
     void testViewCursors();
     void testMissingInvalidation();
     void testViewCursorVisibility();
+    void testViewCursorCleanup();
 
     CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -76,6 +77,7 @@ public:
     CPPUNIT_TEST(testViewCursors);
     CPPUNIT_TEST(testMissingInvalidation);
     CPPUNIT_TEST(testViewCursorVisibility);
+    CPPUNIT_TEST(testViewCursorCleanup);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -557,6 +559,7 @@ public:
     bool m_bViewSelectionSet;
     bool m_bTilesInvalidated;
     bool m_bViewCursorVisible;
+    bool m_bGraphicViewSelection;
 
     ViewCallback()
         : m_bOwnCursorInvalidated(false),
@@ -564,7 +567,8 @@ public:
           m_bOwnSelectionSet(false),
           m_bViewSelectionSet(false),
           m_bTilesInvalidated(false),
-          m_bViewCursorVisible(false)
+          m_bViewCursorVisible(false),
+          m_bGraphicViewSelection(false)
     {
     }
 
@@ -607,6 +611,14 @@ public:
             m_bViewCursorVisible = OString("true") == pPayload;
         }
         break;
+        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+        {
+            std::stringstream aStream(pPayload);
+            boost::property_tree::ptree aTree;
+            boost::property_tree::read_json(aStream, aTree);
+            m_bGraphicViewSelection = aTree.get_child("selection").get_value<std::string>() != "EMPTY";
+        }
+        break;
         }
     }
 };
@@ -720,6 +732,43 @@ void SwTiledRenderingTest::testViewCursorVisibility()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SwTiledRenderingTest::testViewCursorCleanup()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    // Load a document that has a shape and create two views.
+    SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    int nView2 = SfxLokHelper::createView();
+    pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    ViewCallback aView2;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // Click on the shape in the second view.
+    SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+    SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+    SdrObject* pObject = pPage->GetObj(0);
+    Point aCenter = pObject->GetSnapRect().Center();
+    aView1.m_bGraphicViewSelection = false;
+    pXTextDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, aCenter.getX(), aCenter.getY(), 1);
+    pXTextDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, aCenter.getX(), aCenter.getY(), 1);
+    Scheduler::ProcessEventsToIdle();
+    // Make sure there is a graphic view selection on the first view.
+    CPPUNIT_ASSERT(aView1.m_bGraphicViewSelection);
+
+    // Now destroy the second view.
+    SfxLokHelper::destroyView(nView2);
+    Scheduler::ProcessEventsToIdle();
+    CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), SfxLokHelper::getViews());
+    // Make sure that the graphic view selection on the first view is cleaned up.
+    CPPUNIT_ASSERT(!aView1.m_bGraphicViewSelection);
+    mxComponent->dispose();
+    mxComponent.clear();
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 0f3ff77..e95ac2e 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -112,6 +112,8 @@
 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 
 #include <svl/cjkoptions.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::uno;
@@ -1016,6 +1018,11 @@ SwView::SwView( SfxViewFrame *_pFrame, SfxViewShell* pOldSh )
 
 SwView::~SwView()
 {
+    // Notify other LOK views that we are going away.
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
+    SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
+
     GetViewFrame()->GetWindow().RemoveChildEventListener( LINK( this, SwView, WindowChildEventListener ) );
     delete m_pPostItMgr;
     m_pPostItMgr = nullptr;
commit 3d32a7536fad8e50e6f5210688b8af1a2e6338f2
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 15 17:12:20 2016 +0200

    sfx2 lok: handle when SfxViewFrame::Current() returns nullptr
    
    In these two cases no need to call it and dereference the result
    unconditionally, there are other ways to get the info.
    
    Change-Id: Idb5969e909dc2faed97a5a4ac79dfcc1aec8ddcd
    (cherry picked from commit 85c5a172953ac29d1fcab3f4c2f19fa897074e52)

diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 653dd7f..d027bad 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -38,7 +38,7 @@ int shellToView(SfxViewShell* pViewShell)
 
 int SfxLokHelper::createView()
 {
-    SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+    SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst();
     SfxRequest aRequest(pViewFrame, SID_NEWWINDOW);
     pViewFrame->ExecView_Impl(aRequest);
 
@@ -91,21 +91,8 @@ int SfxLokHelper::getView(SfxViewShell* pViewShell)
 
 std::size_t SfxLokHelper::getViews()
 {
-    std::size_t nRet = 0;
-
-    SfxViewFrame* pViewFrame = SfxViewFrame::Current();
-    if (!pViewFrame)
-        return nRet;
-
-    SfxObjectShell* pObjectShell = pViewFrame->GetObjectShell();
     SfxViewShellArr_Impl& rViewArr = SfxGetpApp()->GetViewShells_Impl();
-    for (SfxViewShell* i : rViewArr)
-    {
-        if (i->GetObjectShell() == pObjectShell)
-            ++nRet;
-    }
-
-    return nRet;
+    return rViewArr.size();
 }
 
 void SfxLokHelper::notifyOtherViews(SfxViewShell* pThisView, int nType, const OString& rKey, const OString& rPayload)
commit 0f42ed98b2ca61917c98a3b5f794a80716e589de
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 15 17:10:47 2016 +0200

    lokdocview: ignore notifications on view shutdown
    
    Callbacks are processed on idle on the main thread, so by the time we
    parse them, possibly the widget is already gone, avoid that problem.
    
    Change-Id: Ie8e16423d1ffe087e0dd21425026f7a5d644c27b
    (cherry picked from commit 8090b53e0e16e9aef95f2f5557985f7c2e7c69f3)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index cce13ed..43016dd 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -2379,6 +2379,15 @@ static void lok_doc_view_finalize (GObject* object)
     LOKDocView* pDocView = LOK_DOC_VIEW (object);
     LOKDocViewPrivate& priv = getPrivate(pDocView);
 
+    // Ignore notifications sent to this view on shutdown.
+    std::unique_lock<std::mutex> aGuard(g_aLOKMutex);
+    std::stringstream ss;
+    ss << "lok::Document::setView(" << priv->m_nViewId << ")";
+    g_info("%s", ss.str().c_str());
+    priv->m_pDocument->pClass->setView(priv->m_pDocument, priv->m_nViewId);
+    priv->m_pDocument->pClass->registerCallback(priv->m_pDocument, nullptr, nullptr);
+    aGuard.unlock();
+
     if (priv->m_pDocument && priv->m_pDocument->pClass->getViews(priv->m_pDocument) > 1)
     {
         priv->m_pDocument->pClass->destroyView(priv->m_pDocument, priv->m_nViewId);
commit 25ec228ab074fe9c5979353a925f5ce71c2721f0
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 15 15:37:51 2016 +0200

    gtktiledviewer: allow testing of destroyView()
    
    By calling it when we're not the last window.
    
    Change-Id: I6fd4763243fc088ccfe015b6c03b6b3f25146fac
    (cherry picked from commit 99f05d9947db2dd0676fafa66106d17e4d8eea6d)

diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
index 7dbe13f..8da591b 100644
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
@@ -1206,7 +1206,7 @@ static GtkWidget* createWindow(TiledWindow& rWindow)
     GtkWidget *pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     gtk_window_set_title(GTK_WINDOW(pWindow), "LibreOfficeKit GTK Tiled Viewer");
     gtk_window_set_default_size(GTK_WINDOW(pWindow), 1280, 720);
-    g_signal_connect(pWindow, "destroy", G_CALLBACK(gtk_main_quit), 0);
+    g_signal_connect(pWindow, "destroy", G_CALLBACK(gtk_widget_destroy), pWindow);
 
     rWindow.m_pVBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
     gtk_container_add(GTK_CONTAINER(pWindow), rWindow.m_pVBox);
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index fe68302..cce13ed 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -155,6 +155,9 @@ struct LOKDocViewPrivateImpl
     GdkRectangle m_aVisibleArea;
     bool m_bVisibleAreaSet;
 
+    /// Event source ID for handleTimeout() of this widget.
+    guint m_nTimeoutId;
+
     LOKDocViewPrivateImpl()
         : m_aLOPath(nullptr),
         m_pUserProfileURL(nullptr),
@@ -196,11 +199,17 @@ struct LOKDocViewPrivateImpl
         m_nViewId(0),
         m_nTileSizeTwips(0),
         m_aVisibleArea({0, 0, 0, 0}),
-        m_bVisibleAreaSet(false)
+        m_bVisibleAreaSet(false),
+        m_nTimeoutId(0)
     {
         memset(&m_aGraphicHandleRects, 0, sizeof(m_aGraphicHandleRects));
         memset(&m_bInDragGraphicHandles, 0, sizeof(m_bInDragGraphicHandles));
     }
+
+    ~LOKDocViewPrivateImpl()
+    {
+        g_source_remove(m_nTimeoutId);
+    }
 };
 
 /// Wrapper around LOKDocViewPrivateImpl, managed by malloc/memset/free.
@@ -863,7 +872,7 @@ static gboolean postDocumentLoad(gpointer pData)
     priv->m_pDocument->pClass->getDocumentSize(priv->m_pDocument, &priv->m_nDocumentWidthTwips, &priv->m_nDocumentHeightTwips);
     priv->m_nParts = priv->m_pDocument->pClass->getParts(priv->m_pDocument);
     aGuard.unlock();
-    g_timeout_add(600, handleTimeout, pLOKDocView);
+    priv->m_nTimeoutId = g_timeout_add(600, handleTimeout, pLOKDocView);
 
     float zoom = priv->m_fZoom;
     long nDocumentWidthTwips = priv->m_nDocumentWidthTwips;
@@ -2370,10 +2379,17 @@ static void lok_doc_view_finalize (GObject* object)
     LOKDocView* pDocView = LOK_DOC_VIEW (object);
     LOKDocViewPrivate& priv = getPrivate(pDocView);
 
-    if (priv->m_pDocument)
-        priv->m_pDocument->pClass->destroy (priv->m_pDocument);
-    if (priv->m_pOffice)
-        priv->m_pOffice->pClass->destroy (priv->m_pOffice);
+    if (priv->m_pDocument && priv->m_pDocument->pClass->getViews(priv->m_pDocument) > 1)
+    {
+        priv->m_pDocument->pClass->destroyView(priv->m_pDocument, priv->m_nViewId);
+    }
+    else
+    {
+        if (priv->m_pDocument)
+            priv->m_pDocument->pClass->destroy (priv->m_pDocument);
+        if (priv->m_pOffice)
+            priv->m_pOffice->pClass->destroy (priv->m_pOffice);
+    }
     delete priv.m_pImpl;
     priv.m_pImpl = nullptr;
 
commit 76a18147044dc29379d50810541182aa12756d80
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 15 12:02:57 2016 +0200

    sw lok: fix shape text editing with multiple views
    
    When changing the active view shell,
    sw::DocumentLayoutManager::GetCurrentViewShell() is not instantly
    updated, only when e.g. the focus changes. This means that calling
    setView() + paintTile() pairs on random views typically did not use the
    matching view shell, but the last one. This has a visible effect when
    editing shape text, as the non-text-edit views had the outdated shape
    text visible, unlike on the desktop.
    
    Fix the problem by using SwDocShell::GetWrtShell() instead.
    
    Change-Id: Ia4b67d0a8931692ed4fc5c5e97cc1a09ef81e647
    (cherry picked from commit 5a3653f87502e40cf00d8f1ed1c0ecf5a979e67d)

diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 8374da9..396e79d 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3105,16 +3105,14 @@ void SwXTextDocument::paintTile( VirtualDevice &rDevice,
                                  int nTilePosX, int nTilePosY,
                                  long nTileWidth, long nTileHeight )
 {
-    SwDoc* pDoc = pDocShell->GetDoc();
-    SwViewShell* pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
+    SwViewShell* pViewShell = pDocShell->GetWrtShell();
     pViewShell->PaintTile(rDevice, nOutputWidth, nOutputHeight,
                           nTilePosX, nTilePosY, nTileWidth, nTileHeight);
 }
 
 Size SwXTextDocument::getDocumentSize()
 {
-    SwDoc* pDoc = pDocShell->GetDoc();
-    SwViewShell* pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
+    SwViewShell* pViewShell = pDocShell->GetWrtShell();
     Size aDocSize = pViewShell->GetDocSize();
 
     return Size(aDocSize.Width()  + 2L * DOCUMENTBORDER,
@@ -3235,8 +3233,7 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
 {
     SolarMutexGuard aGuard;
 
-    SwDoc* pDoc = pDocShell->GetDoc();
-    SwViewShell* pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
+    SwViewShell* pViewShell = pDocShell->GetWrtShell();
 
     bool      bBookMode = false;
     sal_Int16 nColumns = 1;
commit fa5a1490a6d2af662117b60b4e53a783cc66f989
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Jul 14 18:37:04 2016 +0200

    vcl headless: ignore visibility in GetClientSize()
    
    This fixes the missing-invalidation problem outlined in commit
    22023b104cd1e024aecc28a6161bea519a584407 (vcl lok: fix missing paints
    due to zero-sized windows, 2016-07-12) also in Writer, not only in
    Impress. Starting text edit, doing a change, and ending text edit now
    results in the expected invalidations.
    
    Ignoring visibility seems to be a better fix for the missing paints.
    This way the headless case doesn't hit the corner cases of 0x0-sized
    windows. Also, the gtk vclplug's GetClientSize() only returns 0x0 in
    case the underlying window is disposed or it's minimized, but it does
    hand out the size before Show() is called, so now the headless backend
    is in sync with that.
    
    Change-Id: I78698cbfce954c8c593d279ab057a87cfbe87260
    Reviewed-on: https://gerrit.libreoffice.org/27224
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit ac0b3b05ab52d0ac06137cf93d71187c7957ec99)

diff --git a/vcl/headless/svpframe.cxx b/vcl/headless/svpframe.cxx
index 4a48abb..3adf2a3 100644
--- a/vcl/headless/svpframe.cxx
+++ b/vcl/headless/svpframe.cxx
@@ -309,13 +309,8 @@ void SvpSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_u
 
 void SvpSalFrame::GetClientSize( long& rWidth, long& rHeight )
 {
-    if( m_bVisible )
-    {
-        rWidth = maGeometry.nWidth;
-        rHeight = maGeometry.nHeight;
-    }
-    else
-        rWidth = rHeight = 0;
+    rWidth = maGeometry.nWidth;
+    rHeight = maGeometry.nHeight;
 }
 
 void SvpSalFrame::GetWorkArea( Rectangle& rRect )
diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx
index 6f3be20..b7429f6 100644
--- a/vcl/source/outdev/outdev.cxx
+++ b/vcl/source/outdev/outdev.cxx
@@ -107,13 +107,6 @@ OutputDevice::OutputDevice() :
     mnOutOffY                       = 0;
     mnOutWidth                      = 0;
     mnOutHeight                     = 0;
-    if (comphelper::LibreOfficeKit::isActive())
-    {
-        // Device size isn't set later in this case, and with zero size, we
-        // miss paint events.
-        mnOutWidth = 1;
-        mnOutHeight = 1;
-    }
     mnDPIX                          = 0;
     mnDPIY                          = 0;
     mnDPIScaleFactor                = 1;
commit b0ef5ee39d3af9da10bb2ffcccea99e44664abdd
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 12 17:56:46 2016 +0200

    vcl lok: fix missing paints due to zero-sized windows
    
    How to reproduce the problem: open an Impress presentation in
    gtktiledviewer, create two views. Start editing the text of a shape in
    one view -> nothing happens in the other view.
    
    There is no invalidation in the other view, as
    sdr::contact::ViewContact::AddViewObjectContact() is not called for
    either of the views. Editing with a single view only worked as when
    clicking into the shape, the ViewObjectContact is created.
    
    On the desktop, those ViewObjectContacts are created on the first paint
    of the slide, but in the LOK case the vcl::Window instances had a 0x0
    size, so an invalidation didn't result in a paint -> no
    ViewObjectContact was created -> no LOK invalidation was sent.
    
    No testcase, as I didn't manage to write code that actually triggers the
    failure under cppunit with the fix reverted.
    
    Change-Id: If29fcea4258a45f3d6d9aab284445756609fa13c
    Reviewed-on: https://gerrit.libreoffice.org/27159
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 22023b104cd1e024aecc28a6161bea519a584407)

diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx
index b343f50..6f3be20 100644
--- a/vcl/source/outdev/outdev.cxx
+++ b/vcl/source/outdev/outdev.cxx
@@ -32,6 +32,7 @@
 #include <vcl/unowrap.hxx>
 #include <vcl/settings.hxx>
 #include <vcl/sysdata.hxx>
+#include <comphelper/lok.hxx>
 
 #include <vcl/outdevstate.hxx>
 
@@ -106,6 +107,13 @@ OutputDevice::OutputDevice() :
     mnOutOffY                       = 0;
     mnOutWidth                      = 0;
     mnOutHeight                     = 0;
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        // Device size isn't set later in this case, and with zero size, we
+        // miss paint events.
+        mnOutWidth = 1;
+        mnOutHeight = 1;
+    }
     mnDPIX                          = 0;
     mnDPIY                          = 0;
     mnDPIScaleFactor                = 1;
commit 983dc855e1f5a93216308e1c09eb39f1bb7f4abe
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 12 11:29:52 2016 +0200

    lokdocview: log the view id of the callback messages
    
    So that e.g. it's possible to see which invalidation affects which view.
    
    Change-Id: I6b6db2fa07eaecd1315ce8160c3b3b86e9e5a348
    Reviewed-on: https://gerrit.libreoffice.org/27138
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 29089b562ea6d0137cf054d9710b7238e327aa4f)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 2985685..fe68302 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1265,7 +1265,10 @@ static void callbackWorker (int nType, const char* pPayload, void* pData)
     LOKDocView* pDocView = LOK_DOC_VIEW (pData);
 
     CallbackData* pCallback = new CallbackData(nType, pPayload ? pPayload : "(nil)", pDocView);
-    g_info("callbackWorker: %s, '%s'", callbackTypeToString(nType), pPayload);
+    LOKDocViewPrivate& priv = getPrivate(pDocView);
+    std::stringstream ss;
+    ss << "callbackWorker, view #" << priv->m_nViewId << ": " << callbackTypeToString(nType) << ", '" << pPayload << "'";
+    g_info("%s", ss.str().c_str());
     gdk_threads_add_idle(callback, pCallback);
 }
 
commit 85f84f4a12812d23ee4cac88c3892128548fa718
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jul 12 10:13:22 2016 +0200

    tdf#100600 sfx2 classification: never replace the control with label
    
    Thanks to Caolán McNamara for pointing out where is the condition of the
    replacement in VCL.
    
    Change-Id: I7e1ef4a016a37b25e084c4c6467a42ca557069a4
    Reviewed-on: https://gerrit.libreoffice.org/27133
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 8192da8e4de7a058ef95253f992f4143f83fa0f1)

diff --git a/sfx2/source/view/classificationcontroller.cxx b/sfx2/source/view/classificationcontroller.cxx
index a04287f..7ec52ca 100644
--- a/sfx2/source/view/classificationcontroller.cxx
+++ b/sfx2/source/view/classificationcontroller.cxx
@@ -235,7 +235,9 @@ void ClassificationCategoriesController::removeEntries()
 }
 
 ClassificationControl::ClassificationControl(vcl::Window* pParent)
-    : Window(pParent, WB_DIALOGCONTROL)
+    // WB_NOLABEL means here that the control won't be replaced with a label
+    // when it wouldn't fit the available space.
+    : Window(pParent, WB_DIALOGCONTROL | WB_NOLABEL)
 {
     m_pLabels[SfxClassificationPolicyType::IntellectualProperty] = VclPtr<FixedText>::Create(this, WB_CENTER);
     m_pLabels[SfxClassificationPolicyType::NationalSecurity] = VclPtr<FixedText>::Create(this, WB_CENTER);
diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx
index c3d1173..8b08e94 100644
--- a/vcl/source/window/toolbox2.cxx
+++ b/vcl/source/window/toolbox2.cxx
@@ -215,6 +215,12 @@ Size ImplToolItem::GetSize( bool bHorz, bool bCheckMaxWidth, long maxWidth, cons
             // get size of item window and check if it fits
             // no windows in vertical toolbars (the default is mbShowWindow=false)
             Size aWinSize = mpWindow->GetSizePixel();
+
+            if (mpWindow->GetStyle() & WB_NOLABEL)
+                // Window wants no label? Then don't check width, it'll be just
+                // clipped.
+                bCheckMaxWidth = false;
+
             if ( !bCheckMaxWidth || (aWinSize.Width() <= maxWidth) )
             {
                 aSize.Width()   = aWinSize.Width();
commit 931af50553379d08c61457261cd9dcdda3ecb0ca
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 8 15:13:13 2016 +0200

    sw lok: add LOK_CALLBACK_VIEW_CURSOR_VISIBLE
    
    With this, in case a text cursor is turned into a graphic selection in
    view#0, then view#1 can also hide the text cursor of view#0.
    
    Change-Id: I7de89b8537ef8b0985336793b719d93733604bff
    Reviewed-on: https://gerrit.libreoffice.org/27044
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit af8419fa1d3cea57481e0e53518237eea2d9cdad)

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index ba749c4..deb6cd8 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -482,6 +482,7 @@ CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, Li
     m_states.emplace(LOK_CALLBACK_CELL_VIEW_CURSOR, "NIL");
     m_states.emplace(LOK_CALLBACK_CELL_FORMULA, "NIL");
     m_states.emplace(LOK_CALLBACK_CURSOR_VISIBLE, "NIL");
+    m_states.emplace(LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "NIL");
     m_states.emplace(LOK_CALLBACK_SET_PART, "NIL");
 
     Start();
@@ -525,6 +526,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
             type != LOK_CALLBACK_INVALIDATE_TILES &&
             type != LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR &&
             type != LOK_CALLBACK_CURSOR_VISIBLE &&
+            type != LOK_CALLBACK_VIEW_CURSOR_VISIBLE &&
             type != LOK_CALLBACK_TEXT_SELECTION)
         {
             //SAL_WARN("lokevt", "Skipping while painting [" + std::to_string(type) + "]: [" + payload + "].");
@@ -586,6 +588,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
         case LOK_CALLBACK_CELL_VIEW_CURSOR:
         case LOK_CALLBACK_CELL_FORMULA:
         case LOK_CALLBACK_CURSOR_VISIBLE:
+        case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
         case LOK_CALLBACK_SET_PART:
         case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
             removeAllButLast(type, false);
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index d8e46db..63abda8 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -374,6 +374,22 @@ typedef enum
      */
     LOK_CALLBACK_GRAPHIC_VIEW_SELECTION,
 
+    /**
+     * The blinking text cursor in one of the other views is now visible or
+     * not.
+     *
+     * The payload format:
+     *
+     * {
+     *     "viewId": "..."
+     *     "visible": "..."
+     * }
+     *
+     * - viewId is a value returned earlier by lok::Document::createView()
+     * - visible uses the format of LOK_CALLBACK_CURSOR_VISIBLE.
+     */
+    LOK_CALLBACK_VIEW_CURSOR_VISIBLE,
+
 }
 LibreOfficeKitCallbackType;
 
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 6c7c305..2985685 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -83,6 +83,9 @@ struct LOKDocViewPrivateImpl
     gboolean m_bCursorOverlayVisible;
     /// Cursor is visible or hidden (e.g. for graphic selection).
     gboolean m_bCursorVisible;
+    /// Visibility of view selections. The current view can only see / them,
+    /// can't modify them. Key is the view id.
+    std::map<int, bool> m_aViewCursorVisibilities;
     /// Time of the last button press.
     guint32 m_nLastButtonPressTime;
     /// Time of the last button release.
@@ -324,6 +327,8 @@ callbackTypeToString (int nType)
         return "LOK_CALLBACK_TEXT_SELECTION_END";
     case LOK_CALLBACK_CURSOR_VISIBLE:
         return "LOK_CALLBACK_CURSOR_VISIBLE";
+    case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
+        return "LOK_CALLBACK_VIEW_CURSOR_VISIBLE";
     case LOK_CALLBACK_GRAPHIC_SELECTION:
         return "LOK_CALLBACK_GRAPHIC_SELECTION";
     case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
@@ -1216,6 +1221,18 @@ callback (gpointer pData)
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
         break;
     }
+    case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
+    {
+        std::stringstream aStream(pCallback->m_aPayload);
+        boost::property_tree::ptree aTree;
+        boost::property_tree::read_json(aStream, aTree);
+        int nViewId = aTree.get<int>("viewId");
+        const std::string& rVisible = aTree.get<std::string>("visible");
+        priv->m_aViewCursorVisibilities[nViewId] = rVisible == "true";
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
+        break;
+    }
+    break;
     case LOK_CALLBACK_CELL_VIEW_CURSOR:
     {
         std::stringstream aStream(pCallback->m_aPayload);
@@ -1517,6 +1534,10 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     {
         for (auto& rPair : priv->m_aViewCursors)
         {
+            auto itVisibility = priv->m_aViewCursorVisibilities.find(rPair.first);
+            if (itVisibility != priv->m_aViewCursorVisibilities.end() && !itVisibility->second)
+                continue;
+
             GdkRectangle& rCursor = rPair.second;
             if (rCursor.width < 30)
                 // Set a minimal width if it would be 0.
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index e43d0717..6ab106d 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -54,6 +54,7 @@ public:
     void testPartHash();
     void testViewCursors();
     void testMissingInvalidation();
+    void testViewCursorVisibility();
 
     CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -74,6 +75,7 @@ public:
     CPPUNIT_TEST(testPartHash);
     CPPUNIT_TEST(testViewCursors);
     CPPUNIT_TEST(testMissingInvalidation);
+    CPPUNIT_TEST(testViewCursorVisibility);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -554,13 +556,15 @@ public:
     bool m_bOwnSelectionSet;
     bool m_bViewSelectionSet;
     bool m_bTilesInvalidated;
+    bool m_bViewCursorVisible;
 
     ViewCallback()
         : m_bOwnCursorInvalidated(false),
           m_bViewCursorInvalidated(false),
           m_bOwnSelectionSet(false),
           m_bViewSelectionSet(false),
-          m_bTilesInvalidated(false)
+          m_bTilesInvalidated(false),
+          m_bViewCursorVisible(false)
     {
     }
 
@@ -569,7 +573,7 @@ public:
         static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
     }
 
-    void callbackImpl(int nType, const char* /*pPayload*/)
+    void callbackImpl(int nType, const char* pPayload)
     {
         switch (nType)
         {
@@ -598,6 +602,11 @@ public:
             m_bViewSelectionSet = true;
         }
         break;
+        case LOK_CALLBACK_VIEW_CURSOR_VISIBLE:
+        {
+            m_bViewCursorVisible = OString("true") == pPayload;
+        }
+        break;
         }
     }
 };
@@ -681,6 +690,36 @@ void SwTiledRenderingTest::testViewCursors()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+void SwTiledRenderingTest::testViewCursorVisibility()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    // Load a document that has a shape and create two views.
+    SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    SfxLokHelper::createView();
+    pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    ViewCallback aView2;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // Click on the shape in the second view.
+    aView1.m_bViewCursorVisible = true;
+    SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+    SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+    SdrObject* pObject = pPage->GetObj(0);
+    Point aCenter = pObject->GetSnapRect().Center();
+    pXTextDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, aCenter.getX(), aCenter.getY(), 1);
+    pXTextDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, aCenter.getX(), aCenter.getY(), 1);
+    Scheduler::ProcessEventsToIdle();
+    // Make sure the "view/text" cursor of the first view gets a notification.
+    CPPUNIT_ASSERT(!aView1.m_bViewCursorVisible);
+    mxComponent->dispose();
+    mxComponent.clear();
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 6b8755f..4b2bb23 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -64,6 +64,7 @@
 #include <IDocumentLayoutAccess.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <comphelper/string.hxx>
 #include <PostItMgr.hxx>
 
@@ -2146,7 +2147,9 @@ void SwCursorShell::ShowCursor()
 
         if (comphelper::LibreOfficeKit::isActive())
         {
-            GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, OString::boolean(true).getStr());
+            OString aPayload = OString::boolean(m_bSVCursorVis);
+            GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, aPayload.getStr());
+            SfxLokHelper::notifyOtherViews(GetSfxViewShell(), LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", aPayload);
         }
 
         UpdateCursor();
@@ -2165,7 +2168,9 @@ void SwCursorShell::HideCursor()
 
         if (comphelper::LibreOfficeKit::isActive())
         {
-            GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, OString::boolean(false).getStr());
+            OString aPayload = OString::boolean(m_bSVCursorVis);
+            GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE, aPayload.getStr());
+            SfxLokHelper::notifyOtherViews(GetSfxViewShell(), LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", aPayload);
         }
     }
 }
commit 2ca45663bf74e82fe508c2577613627741cf14f6
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 1 18:05:43 2016 +0200

    svx lok: add LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
    
    So a view can be aware where the graphic selections of other views are.
    
    Change-Id: I0cc420cfe4bf3824fbfa1a58da889cac5e9a7b60
    Reviewed-on: https://gerrit.libreoffice.org/26863
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 3ebfc5b95559a9bcb2fc0508b51fd00e8eb20260)

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index e8df4df..ba749c4 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -473,6 +473,7 @@ CallbackFlushHandler::CallbackFlushHandler(LibreOfficeKitDocument* pDocument, Li
     m_states.emplace(LOK_CALLBACK_TEXT_SELECTION_END, "NIL");
     m_states.emplace(LOK_CALLBACK_TEXT_SELECTION, "NIL");
     m_states.emplace(LOK_CALLBACK_GRAPHIC_SELECTION, "NIL");
+    m_states.emplace(LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "NIL");
     m_states.emplace(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, "NIL");
     m_states.emplace(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR , "NIL");
     m_states.emplace(LOK_CALLBACK_STATE_CHANGED, "NIL");
@@ -579,6 +580,7 @@ void CallbackFlushHandler::queue(const int type, const char* data)
         case LOK_CALLBACK_TEXT_SELECTION_END:
         case LOK_CALLBACK_TEXT_SELECTION:
         case LOK_CALLBACK_GRAPHIC_SELECTION:
+        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
         case LOK_CALLBACK_MOUSE_POINTER:
         case LOK_CALLBACK_CELL_CURSOR:
         case LOK_CALLBACK_CELL_VIEW_CURSOR:
diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index c687879..d8e46db 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -358,6 +358,22 @@ typedef enum
      */
     LOK_CALLBACK_CELL_VIEW_CURSOR,
 
+    /**
+     * The size and/or the position of a graphic selection in one of the other
+     * views has changed.
+     *
+     * The payload format:
+     *
+     * {
+     *     "viewId": "..."
+     *     "selection": "..."
+     * }
+     *
+     * - viewId is a value returned earlier by lok::Document::createView()
+     * - selection uses the format of LOK_CALLBACK_INVALIDATE_TILES.
+     */
+    LOK_CALLBACK_GRAPHIC_VIEW_SELECTION,
+
 }
 LibreOfficeKitCallbackType;
 
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index a6fbe78..6c7c305 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -101,9 +101,12 @@ struct LOKDocViewPrivateImpl
     /// Position and size of the selection end.
     GdkRectangle m_aTextSelectionEnd;
     GdkRectangle m_aGraphicSelection;
+    /// Position and size of the graphic view selections. The current view can only
+    /// see them, can't modify them. Key is the view id.
+    std::map<int, GdkRectangle> m_aGraphicViewSelections;
     GdkRectangle m_aCellCursor;
     /// Position and size of the cell view cursors. The current view can only
-    //see / them, can't modify them. Key is the view id.
+    /// see them, can't modify them. Key is the view id.
     std::map<int, GdkRectangle> m_aCellViewCursors;
     gboolean m_bInDragGraphicSelection;
 
@@ -323,6 +326,8 @@ callbackTypeToString (int nType)
         return "LOK_CALLBACK_CURSOR_VISIBLE";
     case LOK_CALLBACK_GRAPHIC_SELECTION:
         return "LOK_CALLBACK_GRAPHIC_SELECTION";
+    case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+        return "LOK_CALLBACK_GRAPHIC_VIEW_SELECTION";
     case LOK_CALLBACK_CELL_CURSOR:
         return "LOK_CALLBACK_CELL_CURSOR";
     case LOK_CALLBACK_HYPERLINK_CLICKED:
@@ -1102,6 +1107,25 @@ callback (gpointer pData)
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
     }
     break;
+    case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+    {
+        std::stringstream aStream(pCallback->m_aPayload);
+        boost::property_tree::ptree aTree;
+        boost::property_tree::read_json(aStream, aTree);
+        int nViewId = aTree.get<int>("viewId");
+        const std::string& rRectangle = aTree.get<std::string>("selection");
+        if (rRectangle != "EMPTY")
+            priv->m_aGraphicViewSelections[nViewId] = payloadToRectangle(pDocView, rRectangle.c_str());
+        else
+        {
+            auto it = priv->m_aGraphicViewSelections.find(nViewId);
+            if (it != priv->m_aGraphicViewSelections.end())
+                priv->m_aGraphicViewSelections.erase(it);
+        }
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
+        break;
+    }
+    break;
     case LOK_CALLBACK_CELL_CURSOR:
     {
         if (pCallback->m_aPayload != "EMPTY")
@@ -1265,7 +1289,8 @@ renderHandle(LOKDocView* pDocView,
 static void
 renderGraphicHandle(LOKDocView* pDocView,
                     cairo_t* pCairo,
-                    const GdkRectangle& rSelection)
+                    const GdkRectangle& rSelection,
+                    const GdkRGBA& rColor)
 {
     LOKDocViewPrivate& priv = getPrivate(pDocView);
     int nHandleWidth = 9, nHandleHeight = 9;
@@ -1319,7 +1344,7 @@ renderGraphicHandle(LOKDocView* pDocView,
         priv->m_aGraphicHandleRects[i].width = nHandleWidth;
         priv->m_aGraphicHandleRects[i].height = nHandleHeight;
 
-        cairo_set_source_rgb(pCairo, 0, 0, 0);
+        cairo_set_source_rgb(pCairo, rColor.red, rColor.green, rColor.blue);
         cairo_rectangle(pCairo, x, y, nHandleWidth, nHandleHeight);
         cairo_fill(pCairo);
     }
@@ -1580,7 +1605,17 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     }
 
     if (!isEmptyRectangle(priv->m_aGraphicSelection))
-        renderGraphicHandle(pDocView, pCairo, priv->m_aGraphicSelection);
+    {
+        GdkRGBA aBlack{0, 0, 0, 0};
+        renderGraphicHandle(pDocView, pCairo, priv->m_aGraphicSelection, aBlack);
+    }
+
+    // Graphic selections of other views.
+    for (std::pair<const int, GdkRectangle>& rPair : priv->m_aGraphicViewSelections)
+    {
+        const GdkRGBA& rDark = getDarkColor(rPair.first);
+        renderGraphicHandle(pDocView, pCairo, rPair.second, rDark);
+    }
 
     // Draw the cell cursor.
     if (!isEmptyRectangle(priv->m_aCellCursor))
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index ab9196c..316936f 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -12,6 +12,7 @@
 #include <test/xmltesttools.hxx>
 #include <boost/property_tree/json_parser.hpp>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sfx2/lokhelper.hxx>
 #include <com/sun/star/frame/Desktop.hpp>
 #include <comphelper/dispatchcommand.hxx>
 #include <comphelper/processfactory.hxx>
@@ -62,6 +63,7 @@ public:
     void testPartHash();
     void testResizeTable();
     void testResizeTableColumn();
+    void testViewCursors();
 
     CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -81,6 +83,7 @@ public:
     CPPUNIT_TEST(testPartHash);
     CPPUNIT_TEST(testResizeTable);
     CPPUNIT_TEST(testResizeTableColumn);
+    CPPUNIT_TEST(testViewCursors);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -806,6 +809,71 @@ void SdTiledRenderingTest::testResizeTableColumn()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+class ViewCallback
+{
+public:
+    bool m_bGraphicSelectionInvalidated;
+    bool m_bGraphicViewSelectionInvalidated;
+
+    ViewCallback()
+        : m_bGraphicSelectionInvalidated(false),
+          m_bGraphicViewSelectionInvalidated(false)
+    {
+    }
+
+    static void callback(int nType, const char* pPayload, void* pData)
+    {
+        static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
+    }
+
+    void callbackImpl(int nType, const char* /*pPayload*/)
+    {
+        switch (nType)
+        {
+        case LOK_CALLBACK_GRAPHIC_SELECTION:
+        {
+            m_bGraphicSelectionInvalidated = true;
+        }
+        break;
+        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
+        {
+            m_bGraphicViewSelectionInvalidated = true;
+        }
+        break;
+        }
+    }
+};
+
+void SdTiledRenderingTest::testViewCursors()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    // Create two views.
+    SdXImpressDocument* pXImpressDocument = createDoc("shape.odp");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    SfxLokHelper::createView();
+    ViewCallback aView2;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+
+    // Select the shape in the second view.
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    SdPage* pActualPage = pViewShell->GetActualPage();
+    SdrObject* pObject = pActualPage->GetObj(0);
+    SdrView* pView = pViewShell->GetView();
+    pView->MarkObj(pObject, pView->GetSdrPageView());
+    Scheduler::ProcessEventsToIdle();
+
+    // First view notices that there was a selection change in the other view.
+    CPPUNIT_ASSERT(aView1.m_bGraphicViewSelectionInvalidated);
+    // Second view notices that there was a selection change in its own view.
+    CPPUNIT_ASSERT(aView2.m_bGraphicSelectionInvalidated);
+    mxComponent->dispose();
+    mxComponent.clear();
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index dea4053..a68e8c0 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -1620,9 +1620,11 @@ void SfxViewShell::libreOfficeKitViewCallback(int nType, const char* pPayload) c
         switch (nType)
         {
         case LOK_CALLBACK_TEXT_SELECTION:
+        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
         case LOK_CALLBACK_TEXT_SELECTION_START:
         case LOK_CALLBACK_TEXT_SELECTION_END:
         case LOK_CALLBACK_GRAPHIC_SELECTION:
+        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
             return;
         }
     }
diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx
index db1b683..df1abb7 100644
--- a/svx/source/svdraw/svdmrkv.cxx
+++ b/svx/source/svdraw/svdmrkv.cxx
@@ -53,6 +53,7 @@
 #include <editeng/editdata.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/viewsh.hxx>
 
 using namespace com::sun::star;
@@ -714,7 +715,10 @@ void SdrMarkView::SetMarkHandles()
                     {
                         // Suppress handles -> empty graphic selection.
                         if(SfxViewShell* pViewShell = SfxViewShell::Current())
+                        {
                             pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, "EMPTY");
+                            SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
+                        }
                     }
                     return;
                 }
@@ -735,7 +739,10 @@ void SdrMarkView::SetMarkHandles()
                 {
                     // The table shape has selected cells, which provide text selection already -> no graphic selection.
                     if(SfxViewShell* pViewShell = SfxViewShell::Current())
+                    {
                         pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, "EMPTY");
+                        SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
+                    }
                     return;
                 }
             }
@@ -768,7 +775,10 @@ void SdrMarkView::SetMarkHandles()
                     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "");
             }
             if(SfxViewShell* pViewShell = SfxViewShell::Current())
+            {
                 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_GRAPHIC_SELECTION, sSelection.getStr());
+                SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", sSelection);
+            }
         }
 
         if (bFrmHdl)
commit 606ad3c7961ced06a9c4278d64a7913090f03abe
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 1 16:51:01 2016 +0200

    lokdocview: replace handle_graphic.png with manual drawing
    
    If we draw a black graphic handle manually, then it's possible to color
    it later, this isn't easy if a bitmap is painted.
    
    Reviewed-on: https://gerrit.libreoffice.org/26860
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit cca44fe22978c6c1c5f3ec500e5ac07becf53745)
    
    Conflicts:
    	scp2/source/ooo/module_libreofficekit.scp
    
    Change-Id: Ib4456fd5155862d52e3ffa79ee49c7bfd16fb742

diff --git a/android/source/res/drawable/handle_graphic.png b/android/source/res/drawable/handle_graphic.png
deleted file mode 100644
index 7317eee..0000000
Binary files a/android/source/res/drawable/handle_graphic.png and /dev/null differ
diff --git a/libreofficekit/Package_selectionhandles.mk b/libreofficekit/Package_selectionhandles.mk
index 5d87805..77c70b4 100644
--- a/libreofficekit/Package_selectionhandles.mk
+++ b/libreofficekit/Package_selectionhandles.mk
@@ -13,7 +13,6 @@ $(eval $(call gb_Package_add_files,libreofficekit_selectionhandles,$(LIBO_SHARE_
 	handle_image_start.png \
 	handle_image_middle.png \
 	handle_image_end.png \
-	handle_graphic.png \
 ))
 
 # vim: set noet sw=4 ts=4:
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index c79e098..a6fbe78 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -131,8 +131,6 @@ struct LOKDocViewPrivateImpl
 
     /// @name Graphic handles.
     ///@{
-    /// Bitmap of a graphic selection handle.
-    cairo_surface_t* m_pGraphicHandle;
     /// Rectangle of a graphic selection handle, to know if the user clicked on it or not.
     GdkRectangle m_aGraphicHandleRects[8];
     /// If we are in the middle of a drag of a graphic selection handle.
@@ -189,7 +187,6 @@ struct LOKDocViewPrivateImpl
         m_pHandleEnd(nullptr),
         m_aHandleEndRect({0, 0, 0, 0}),
         m_bInDragEndHandle(false),
-        m_pGraphicHandle(nullptr),
         m_nViewId(0),
         m_nTileSizeTwips(0),
         m_aVisibleArea({0, 0, 0, 0}),
@@ -1264,20 +1261,16 @@ renderHandle(LOKDocView* pDocView,
     rRectangle.height = nHandleHeight * fHandleScale;
 }
 
-/// Renders pHandle around an rSelection rectangle on pCairo.
+/// Renders handles around an rSelection rectangle on pCairo.
 static void
 renderGraphicHandle(LOKDocView* pDocView,
                     cairo_t* pCairo,
-                    const GdkRectangle& rSelection,
-                    cairo_surface_t* pHandle)
+                    const GdkRectangle& rSelection)
 {
     LOKDocViewPrivate& priv = getPrivate(pDocView);
-    int nHandleWidth, nHandleHeight;
+    int nHandleWidth = 9, nHandleHeight = 9;
     GdkRectangle aSelection;
 
-    nHandleWidth = cairo_image_surface_get_width(pHandle);
-    nHandleHeight = cairo_image_surface_get_height(pHandle);
-
     aSelection.x = twipToPixel(rSelection.x, priv->m_fZoom);
     aSelection.y = twipToPixel(rSelection.y, priv->m_fZoom);
     aSelection.width = twipToPixel(rSelection.width, priv->m_fZoom);
@@ -1326,11 +1319,9 @@ renderGraphicHandle(LOKDocView* pDocView,
         priv->m_aGraphicHandleRects[i].width = nHandleWidth;
         priv->m_aGraphicHandleRects[i].height = nHandleHeight;
 
-        cairo_save (pCairo);
-        cairo_translate(pCairo, x, y);
-        cairo_set_source_surface(pCairo, pHandle, 0, 0);
-        cairo_paint(pCairo);
-        cairo_restore (pCairo);
+        cairo_set_source_rgb(pCairo, 0, 0, 0);
+        cairo_rectangle(pCairo, x, y, nHandleWidth, nHandleHeight);
+        cairo_fill(pCairo);
     }
 }
 
@@ -1589,16 +1580,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
     }
 
     if (!isEmptyRectangle(priv->m_aGraphicSelection))
-    {
-        gchar* handleGraphicPath = g_strconcat (priv->m_aLOPath, CURSOR_HANDLE_DIR, "handle_graphic.png", nullptr);
-        if (!priv->m_pGraphicHandle)
-        {
-            priv->m_pGraphicHandle = cairo_image_surface_create_from_png(handleGraphicPath);
-            assert(cairo_surface_status(priv->m_pGraphicHandle) == CAIRO_STATUS_SUCCESS);
-        }
-        renderGraphicHandle(pDocView, pCairo, priv->m_aGraphicSelection, priv->m_pGraphicHandle);
-        g_free (handleGraphicPath);
-    }
+        renderGraphicHandle(pDocView, pCairo, priv->m_aGraphicSelection);
 
     // Draw the cell cursor.
     if (!isEmptyRectangle(priv->m_aCellCursor))
@@ -3117,8 +3099,6 @@ lok_doc_view_reset_view(LOKDocView* pDocView)
     memset(&priv->m_aHandleEndRect, 0, sizeof(priv->m_aHandleEndRect));
     priv->m_bInDragEndHandle = false;
 
-    cairo_surface_destroy(priv->m_pGraphicHandle);
-    priv->m_pGraphicHandle = nullptr;
     memset(&priv->m_aGraphicHandleRects, 0, sizeof(priv->m_aGraphicHandleRects));
     memset(&priv->m_bInDragGraphicHandles, 0, sizeof(priv->m_bInDragGraphicHandles));
 
commit a3a0692cb2c44dc60ef385710aa5eda1e98cb980
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Jul 1 17:39:42 2016 +0200

    CppunitTest_sc_tiledrendering: clear reference to local var in time
    
    Should fix
    <http://ci.libreoffice.org/job/lo_callgrind_linux/2013/console>.
    
    Change-Id: I4ff4ddafbbb15ee360cb845afe8e8b4dbbf04460
    (cherry picked from commit d77d81604d8604652772e0819e5cf5e472865c65)

diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 46b85e6..f82afb9 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -381,6 +381,8 @@ void ScTiledRenderingTest::testViewCursors()
     Scheduler::ProcessEventsToIdle();
     SfxLokHelper::destroyView(SfxLokHelper::getView());
     CPPUNIT_ASSERT(aView1.m_bViewCursorInvalidated);
+    mxComponent->dispose();
+    mxComponent.clear();
 
     comphelper::LibreOfficeKit::setActive(false);
 }


More information about the Libreoffice-commits mailing list