[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - 8 commits - editeng/source include/editeng include/LibreOfficeKit include/sfx2 include/vcl libreofficekit/source sc/inc sc/source sd/source sfx2/source sw/inc sw/qa sw/source

Miklos Vajna vmiklos at collabora.co.uk
Wed Jul 20 16:00:15 UTC 2016


 editeng/source/editeng/editview.cxx            |    5 -
 editeng/source/editeng/impedit.cxx             |   12 --
 editeng/source/editeng/impedit.hxx             |    8 -
 editeng/source/outliner/outlvw.cxx             |    9 -
 include/LibreOfficeKit/LibreOfficeKitEnums.h   |   16 +++
 include/editeng/editview.hxx                   |    2 
 include/editeng/outliner.hxx                   |   13 --
 include/sfx2/lokhelper.hxx                     |    6 +
 include/vcl/ITiledRenderable.hxx               |    9 -
 libreofficekit/source/gtk/lokdocview.cxx       |  114 ++++++++++++++++++++++++-
 sc/inc/docuno.hxx                              |    3 
 sc/source/ui/unoobj/docuno.cxx                 |    4 
 sd/source/ui/inc/unomodel.hxx                  |    2 
 sd/source/ui/unoidl/unomodel.cxx               |    4 
 sfx2/source/view/lokhelper.cxx                 |   27 +++++
 sfx2/source/view/viewsh.cxx                    |    9 +
 sw/inc/PostItMgr.hxx                           |    2 
 sw/inc/unotxdoc.hxx                            |    2 
 sw/qa/extras/tiledrendering/tiledrendering.cxx |   97 +++++++++++++++++++++
 sw/source/core/crsr/viscrs.cxx                 |   23 -----
 sw/source/uibase/docvw/PostItMgr.cxx           |   12 --
 sw/source/uibase/uno/unotxdoc.cxx              |    4 
 22 files changed, 269 insertions(+), 114 deletions(-)

New commits:
commit 2996f4c670d1a32a646dd1a552036ea1f18e5113
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Jun 22 08:01:04 2016 +0200

    Remove no longer needed ImpEditView::mpLibreOfficeKitSearchable
    
    All clients has been ported to use
    ImpEditView::mpLibreOfficeKitViewCallable instead.
    
    Change-Id: I3a2513ac5900f801a2e7aec79807f4e333dfba3d
    Reviewed-on: https://gerrit.libreoffice.org/26561
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 03e83de83bcc640cf359fe7997edcdadb5067b36)

diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index a41e889..66b0425 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -588,11 +588,6 @@ Color EditView::GetBackgroundColor() const
     return pImpEditView->GetBackgroundColor();
 }
 
-void EditView::registerLibreOfficeKitCallback(OutlinerSearchable *pSearchable)
-{
-    pImpEditView->registerLibreOfficeKitCallback(pSearchable);
-}
-
 void EditView::registerLibreOfficeKitViewCallback(OutlinerViewCallable *pCallable)
 {
     pImpEditView->registerLibreOfficeKitViewCallback(pCallable);
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index 64b4ed4..b54c6d8 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -79,7 +79,6 @@ ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindo
     pOutWin             = pWindow;
     pPointer            = nullptr;
     pBackgroundColor    = nullptr;
-    mpLibreOfficeKitSearchable = nullptr;
     mpLibreOfficeKitViewCallable = nullptr;
     nScrollDiffX        = 0;
     nExtraCursorFlags   = 0;
@@ -118,17 +117,6 @@ void ImpEditView::SetBackgroundColor( const Color& rColor )
     pBackgroundColor = new Color( rColor );
 }
 
-void ImpEditView::registerLibreOfficeKitCallback(OutlinerSearchable* pSearchable)
-{
-    mpLibreOfficeKitSearchable = pSearchable;
-}
-
-void ImpEditView::libreOfficeKitCallback(int nType, const char* pPayload) const
-{
-    if (mpLibreOfficeKitSearchable)
-        mpLibreOfficeKitSearchable->libreOfficeKitCallback(nType, pPayload);
-}
-
 void ImpEditView::registerLibreOfficeKitViewCallback(OutlinerViewCallable* pCallable)
 {
     mpLibreOfficeKitViewCallable = pCallable;
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index fde2a6e..fe9895b 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -222,8 +222,6 @@ private:
     EditView*           pEditView;
     vcl::Cursor*        pCursor;
     Color*              pBackgroundColor;
-    /// Model callback.
-    OutlinerSearchable* mpLibreOfficeKitSearchable;
     /// Per-view callback.
     OutlinerViewCallable* mpLibreOfficeKitViewCallable;
     EditEngine*         pEditEngine;
@@ -370,11 +368,7 @@ public:
     const Color&    GetBackgroundColor() const {
                         return ( pBackgroundColor ? *pBackgroundColor : pOutWin->GetBackground().GetColor() ); }
 
-    /// @see vcl::ITiledRenderable::registerCallback().
-    void registerLibreOfficeKitCallback(OutlinerSearchable* pSearchable);
-    /// Invokes the registered model callback, if there are any.
-    void libreOfficeKitCallback(int nType, const char* pPayload) const;
-    /// @see vcl::ITiledRenderable::registerCallback().
+    /// @see SfxViewShell::registerLibreOfficeKitViewCallback().
     void registerLibreOfficeKitViewCallback(OutlinerViewCallable* pCallable);
     /// Invokes the registered view callback, if there are any.
     void libreOfficeKitViewCallback(int nType, const char* pPayload) const;
diff --git a/editeng/source/outliner/outlvw.cxx b/editeng/source/outliner/outlvw.cxx
index 1266830..12e6f91 100644
--- a/editeng/source/outliner/outlvw.cxx
+++ b/editeng/source/outliner/outlvw.cxx
@@ -1426,11 +1426,6 @@ void OutlinerView::SetBackgroundColor( const Color& rColor )
     pEditView->SetBackgroundColor( rColor );
 }
 
-void OutlinerView::registerLibreOfficeKitCallback(OutlinerSearchable* pSearchable)
-{
-    pEditView->registerLibreOfficeKitCallback(pSearchable);
-}
-
 void OutlinerView::registerLibreOfficeKitViewCallback(OutlinerViewCallable* pCallable)
 {
     pEditView->registerLibreOfficeKitViewCallback(pCallable);
@@ -1461,10 +1456,6 @@ Selection OutlinerView::GetSurroundingTextSelection() const
     return pEditView->GetSurroundingTextSelection();
 }
 
-OutlinerSearchable::~OutlinerSearchable()
-{
-}
-
 // ===== some code for thesaurus sub menu within context menu
 
 
diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index 80b22f5..d4e88b2 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -183,8 +183,6 @@ public:
     void            SetBackgroundColor( const Color& rColor );
     Color           GetBackgroundColor() const;
 
-    /// Register a LOK model callback.
-    void registerLibreOfficeKitCallback(OutlinerSearchable *pSearchable);
     /// Register a LOK view callback.
     void registerLibreOfficeKitViewCallback(OutlinerViewCallable *pCallable);
 
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index 9ef1b93..d467ef5 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -274,8 +274,6 @@ public:
     void        SetBackgroundColor( const Color& rColor );
     Color       GetBackgroundColor();
 
-    /// Registers a LOK model callback.
-    void registerLibreOfficeKitCallback(OutlinerSearchable* pSearchable);
     /// Registers a LOK view callback.
     void registerLibreOfficeKitViewCallback(OutlinerViewCallable* pCallable);
 
@@ -379,16 +377,7 @@ public:
     void        SetEndCutPasteLinkHdl(const Link<LinkParamNone*,void> &rLink) { aEndCutPasteLink = rLink; }
 };
 
-/// Interface class to not depend on SdrModel in editeng.
-class EDITENG_DLLPUBLIC OutlinerSearchable
-{
-public:
-    virtual ~OutlinerSearchable();
-
-    virtual void libreOfficeKitCallback(int nType, const char* pPayload) const = 0;
-};
-
-/// Interface class to not depend on SfxViewShell in editeng, meant to replace OutlinerSearchable at the end.
+/// Interface class to not depend on SfxViewShell in editeng.
 class SAL_NO_VTABLE SAL_DLLPUBLIC_RTTI OutlinerViewCallable
 {
 public:
diff --git a/sw/inc/PostItMgr.hxx b/sw/inc/PostItMgr.hxx
index 8f9a220..33f0953 100644
--- a/sw/inc/PostItMgr.hxx
+++ b/sw/inc/PostItMgr.hxx
@@ -290,8 +290,6 @@ class SwPostItMgr: public SfxListener
 
         void DrawNotesForPage(OutputDevice *pOutDev, sal_uInt32 nPage);
         void PaintTile(OutputDevice& rRenderContext, const Rectangle& rRect);
-        /// Informs already created annotations about a newly registered LOK callback.
-        void registerLibreOfficeKitCallback(OutlinerSearchable* pSearchable);
 };
 
 #endif
diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx
index b0ddb3b..ceb8703 100644
--- a/sw/source/uibase/docvw/PostItMgr.cxx
+++ b/sw/source/uibase/docvw/PostItMgr.cxx
@@ -881,18 +881,6 @@ void SwPostItMgr::PaintTile(OutputDevice& rRenderContext, const Rectangle& /*rRe
     }
 }
 
-void SwPostItMgr::registerLibreOfficeKitCallback(OutlinerSearchable* pSearchable)
-{
-    for (SwSidebarItem* pItem : mvPostItFields)
-    {
-        SwSidebarWin* pPostIt = pItem->pPostIt;
-        if (!pPostIt)
-            continue;
-
-        pPostIt->GetOutlinerView()->registerLibreOfficeKitCallback(pSearchable);
-    }
-}
-
 void SwPostItMgr::Scroll(const long lScroll,const unsigned long aPage)
 {
     OSL_ENSURE((lScroll % GetScrollSize() )==0,"SwPostItMgr::Scroll: scrolling by wrong value");
commit 3e9dad4e65aed149a2590d6ec05c407eb99d4c6b
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Wed Jun 22 08:02:46 2016 +0200

    lokdocview: ensure setView() + doSomethingElse is atomic
    
    Otherwise it's possible that a keystroke is sent in for a different view,
    when that other view reacts to an invalidation (invoking paintTile())
    caused by a previous keystroke.
    
    I.e. open two views, place the cursor at different positions, type fast,
    and some of the characters appeared at the incorrect view.
    
    Change-Id: Ie5e471f1b9c2d69adaa87111fba74d4abe184ef8
    Reviewed-on: https://gerrit.libreoffice.org/26562
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 380a646b957052f96b3f9440d20dc63fc72e1d46)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 60e22fc..6e2a343 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -15,6 +15,7 @@
 #include <string>
 #include <sstream>
 #include <iostream>
+#include <mutex>
 #include <boost/property_tree/json_parser.hpp>
 
 #include <com/sun/star/awt/Key.hpp>
@@ -44,6 +45,9 @@
 // Minimum Zoom allowed
 #define MIN_ZOOM 0.25f
 
+/// This is expected to be locked during setView(), doSomethingElse() LOK calls.
+std::mutex g_aLOKMutex;
+
 /// Private struct used by this GObject type
 struct LOKDocViewPrivateImpl
 {
@@ -581,6 +585,7 @@ postKeyEventInThread(gpointer data)
     LOKDocViewPrivate& priv = getPrivate(pDocView);
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
 
+    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());
@@ -836,6 +841,7 @@ static gboolean postDocumentLoad(gpointer pData)
     LOKDocView* pLOKDocView = static_cast<LOKDocView*>(pData);
     LOKDocViewPrivate& priv = getPrivate(pLOKDocView);
 
+    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());
@@ -845,6 +851,7 @@ static gboolean postDocumentLoad(gpointer pData)
     priv->m_pDocument->pClass->registerCallback(priv->m_pDocument, callbackWorker, pLOKDocView);
     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);
 
     float zoom = priv->m_fZoom;
@@ -1727,6 +1734,7 @@ lok_doc_view_signal_motion (GtkWidget* pWidget, GdkEventMotion* pEvent)
     GdkPoint aPoint;
     GError* error = nullptr;
 
+    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());
@@ -1752,6 +1760,7 @@ lok_doc_view_signal_motion (GtkWidget* pWidget, GdkEventMotion* pEvent)
         priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
         return FALSE;
     }
+    aGuard.unlock();
     for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
     {
         if (priv->m_bInDragGraphicHandles[i])
@@ -1826,6 +1835,7 @@ setGraphicSelectionInThread(gpointer data)
     LOKDocViewPrivate& priv = getPrivate(pDocView);
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
 
+    std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
     std::stringstream ss;
     ss << "lok::Document::setView(" << priv->m_nViewId << ")";
     g_info("%s", ss.str().c_str());
@@ -1849,6 +1859,7 @@ setClientZoomInThread(gpointer data)
     LOKDocViewPrivate& priv = getPrivate(pDocView);
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
 
+    std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
     priv->m_pDocument->pClass->setClientZoom(priv->m_pDocument,
                                              pLOEvent->m_nTilePixelWidth,
                                              pLOEvent->m_nTilePixelHeight,
@@ -1864,6 +1875,7 @@ postMouseEventInThread(gpointer data)
     LOKDocViewPrivate& priv = getPrivate(pDocView);
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
 
+    std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
     std::stringstream ss;
     ss << "lok::Document::setView(" << priv->m_nViewId << ")";
     g_info("%s", ss.str().c_str());
@@ -1892,6 +1904,7 @@ openDocumentInThread (gpointer data)
     LOKDocView* pDocView = LOK_DOC_VIEW(g_task_get_source_object(task));
     LOKDocViewPrivate& priv = getPrivate(pDocView);
 
+    std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
     if ( priv->m_pDocument )
     {
         priv->m_pDocument->pClass->destroy( priv->m_pDocument );
@@ -1921,11 +1934,13 @@ setPartInThread(gpointer data)
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
     int nPart = pLOEvent->m_nPart;
 
+    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->setPart( priv->m_pDocument, nPart );
+    aGuard.unlock();
 
     lok_doc_view_reset_view(pDocView);
 }
@@ -1939,6 +1954,7 @@ setPartmodeInThread(gpointer data)
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
     int nPartMode = pLOEvent->m_nPartMode;
 
+    std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
     std::stringstream ss;
     ss << "lok::Document::setView(" << priv->m_nViewId << ")";
     g_info("%s", ss.str().c_str());
@@ -1961,6 +1977,7 @@ setEditInThread(gpointer data)
     else if (priv->m_bEdit && !bEdit)
     {
         g_info("lok_doc_view_set_edit: leaving edit mode");
+        std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
         std::stringstream ss;
         ss << "lok::Document::setView(" << priv->m_nViewId << ")";
         g_info("%s", ss.str().c_str());
@@ -1980,6 +1997,7 @@ postCommandInThread (gpointer data)
     LOEvent* pLOEvent = static_cast<LOEvent*>(g_task_get_task_data(task));
     LOKDocViewPrivate& priv = getPrivate(pDocView);
 
+    std::lock_guard<std::mutex> aGuard(g_aLOKMutex);
     std::stringstream ss;
     ss << "lok::Document::setView(" << priv->m_nViewId << ")";
     g_info("%s", ss.str().c_str());
@@ -2030,6 +2048,7 @@ paintTileInThread (gpointer data)
     aTileRectangle.x = pixelToTwip(nTileSizePixels, pLOEvent->m_fPaintTileZoom) * pLOEvent->m_nPaintTileY;
     aTileRectangle.y = pixelToTwip(nTileSizePixels, pLOEvent->m_fPaintTileZoom) * pLOEvent->m_nPaintTileX;
 
+    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());
@@ -2049,6 +2068,7 @@ paintTileInThread (gpointer data)
                                          aTileRectangle.x, aTileRectangle.y,
                                          pixelToTwip(nTileSizePixels, pLOEvent->m_fPaintTileZoom),
                                          pixelToTwip(nTileSizePixels, pLOEvent->m_fPaintTileZoom));
+    aGuard.unlock();
 
     g_timer_elapsed(aTimer, &nElapsedMs);
     ss << " rendered in " << (nElapsedMs / 1000.) << " milliseconds";
@@ -2929,6 +2949,7 @@ lok_doc_view_get_parts (LOKDocView* pDocView)
     if (!priv->m_pDocument)
         return -1;
 
+    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());
@@ -2943,6 +2964,7 @@ lok_doc_view_get_part (LOKDocView* pDocView)
     if (!priv->m_pDocument)
         return -1;
 
+    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());
@@ -2986,6 +3008,7 @@ lok_doc_view_get_part_name (LOKDocView* pDocView, int nPart)
     if (!priv->m_pDocument)
         return nullptr;
 
+    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());
commit 16382e0c6779305a7460b4182612e4e59561ef6b
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jun 21 14:28:08 2016 +0200

    sw: add LOK_CALLBACK_TEXT_VIEW_SELECTION testcase
    
    Fails with 9f66db9c474f71f43d7a3667230241fd4fa4183f (sw lok: add
    LOK_CALLBACK_TEXT_VIEW_SELECTION, 2016-06-21) reverted.
    
    Change-Id: Ide21167ce2dc4287b1860b5f03a6975dc9edd4c6
    Reviewed-on: https://gerrit.libreoffice.org/26550
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 45182f36ef263d6fd94cc79bb242fbfb5a471c22)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 4d3bae2..60e22fc 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -1033,7 +1033,6 @@ callback (gpointer pData)
                       priv->m_aVisibleCursor.y,
                       priv->m_aVisibleCursor.width,
                       priv->m_aVisibleCursor.height);
-        std::cerr << "debug, LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: i am " << priv->m_nViewId << ", i got " << pCallback->m_aPayload << " for myself" << std::endl;
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
     }
     break;
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 5034537..6998023 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -226,7 +226,7 @@ void SwTiledRenderingTest::testSetTextSelection()
     SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
     // Move the cursor into the second word.
     pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 5, /*bBasicCall=*/false);
-    // Create a selection by on the word.
+    // Create a selection on the word.
     pWrtShell->SelWrd();
     SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
     // Did we indeed manage to select the second word?
@@ -549,10 +549,14 @@ class ViewCallback
 public:
     bool m_bOwnCursorInvalidated;
     bool m_bViewCursorInvalidated;
+    bool m_bOwnSelectionSet;
+    bool m_bViewSelectionSet;
 
     ViewCallback()
         : m_bOwnCursorInvalidated(false),
-          m_bViewCursorInvalidated(false)
+          m_bViewCursorInvalidated(false),
+          m_bOwnSelectionSet(false),
+          m_bViewSelectionSet(false)
     {
     }
 
@@ -575,6 +579,16 @@ public:
             m_bViewCursorInvalidated = true;
         }
         break;
+        case LOK_CALLBACK_TEXT_SELECTION:
+        {
+            m_bOwnSelectionSet = true;
+        }
+        break;
+        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+        {
+            m_bViewSelectionSet = true;
+        }
+        break;
         }
     }
 };
@@ -583,7 +597,7 @@ void SwTiledRenderingTest::testViewCursors()
 {
     comphelper::LibreOfficeKit::setActive();
 
-    createDoc("dummy.fodt");
+    SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
     ViewCallback aView1;
     SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
     SfxLokHelper::createView();
@@ -596,6 +610,27 @@ void SwTiledRenderingTest::testViewCursors()
     // it changed.
     CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
 
+    // Make sure that aView1 gets a view-only selection notification, while
+    // aView2 gets a real selection notification.
+    aView1.m_bOwnSelectionSet = false;
+    aView1.m_bViewSelectionSet = false;
+    aView2.m_bOwnSelectionSet = false;
+    aView2.m_bViewSelectionSet = false;
+    SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+    // Move the cursor into the second word.
+    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 5, /*bBasicCall=*/false);
+    // Create a selection on the word.
+    pWrtShell->SelWrd();
+    SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
+    // Did we indeed manage to select the second word?
+    CPPUNIT_ASSERT_EQUAL(OUString("bbb"), pShellCursor->GetText());
+    CPPUNIT_ASSERT(!aView1.m_bOwnSelectionSet);
+    // This failed, aView1 did not get notification about selection changes in
+    // aView2.
+    CPPUNIT_ASSERT(aView1.m_bViewSelectionSet);
+    CPPUNIT_ASSERT(aView2.m_bOwnSelectionSet);
+    CPPUNIT_ASSERT(!aView2.m_bViewSelectionSet);
+
     comphelper::LibreOfficeKit::setActive(false);
 }
 
commit da9595dca88ca207b1ac9c2f236230202aaa9500
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jun 21 11:30:04 2016 +0200

    lokdocview: handle LOK_CALLBACK_TEXT_VIEW_SELECTION
    
    It's similar to the normal selection, but it's colored and has no
    handles.
    
    Change-Id: Ibd9594b4834ff4f9b1cfd85912ed5cee3c8b8c71
    Reviewed-on: https://gerrit.libreoffice.org/26543
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 6b9053d371fc8b8543faf7add5fb6d61aab26605)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 9289d44..4d3bae2 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -89,6 +89,9 @@ struct LOKDocViewPrivateImpl
     guint32 m_nKeyModifier;
     /// Rectangles of the current text selection.
     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<std::uintptr_t, std::vector<GdkRectangle>> 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.
@@ -1173,7 +1176,13 @@ callback (gpointer pData)
     }
     case LOK_CALLBACK_TEXT_VIEW_SELECTION:
     {
-        // TODO: Implement me
+        std::stringstream aStream(pCallback->m_aPayload);
+        boost::property_tree::ptree aTree;
+        boost::property_tree::read_json(aStream, aTree);
+        std::uintptr_t nViewId = aTree.get<std::uintptr_t>("viewId");
+        const std::string& rSelection = aTree.get<std::string>("selection");
+        priv->m_aTextViewSelectionRectangles[nViewId] = payloadToRectangles(pDocView, rSelection.c_str());
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
         break;
     }
     default:
@@ -1469,7 +1478,7 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
                 // Set a minimal width if it would be 0.
                 rCursor.width = 30;
 
-            const GdkRGBA& rDark = getDarkColor(priv->m_nViewId);
+            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),
@@ -1534,6 +1543,23 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
         }
     }
 
+    // Selections of other views.
+    for (std::pair<const std::uintptr_t, std::vector<GdkRectangle>>& rPair : priv->m_aTextViewSelectionRectangles)
+    {
+        for (GdkRectangle& rRectangle : rPair.second)
+        {
+            const GdkRGBA& rDark = getDarkColor(rPair.first);
+            // 75% transparency.
+            cairo_set_source_rgba(pCairo, rDark.red, rDark.green, rDark.blue, 0.25);
+            cairo_rectangle(pCairo,
+                            twipToPixel(rRectangle.x, priv->m_fZoom),
+                            twipToPixel(rRectangle.y, priv->m_fZoom),
+                            twipToPixel(rRectangle.width, priv->m_fZoom),
+                            twipToPixel(rRectangle.height, priv->m_fZoom));
+            cairo_fill(pCairo);
+        }
+    }
+
     if (!isEmptyRectangle(priv->m_aGraphicSelection))
     {
         gchar* handleGraphicPath = g_strconcat (priv->m_aLOPath, CURSOR_HANDLE_DIR, "handle_graphic.png", nullptr);
commit c64ac7b2e9898cc56266ea8b32321bdd8558da34
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jun 21 11:29:49 2016 +0200

    sw lok: add LOK_CALLBACK_TEXT_VIEW_SELECTION
    
    So a view can be aware where selections of other views are.
    
    Change-Id: I5026b1ff2b99a4eedfd0bde32a05ceb8e2f424bc
    Reviewed-on: https://gerrit.libreoffice.org/26542
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 9f66db9c474f71f43d7a3667230241fd4fa4183f)

diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 4229e73..4dfb8be 100644
--- a/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -316,7 +316,6 @@ typedef enum
      * The size and/or the position of the view cursor changed. A view cursor
      * is a cursor of an other view, the current view can't change it.
      *
-     * Rectangle format is the same as LOK_CALLBACK_INVALIDATE_TILES.
      * The payload format:
      *
      * {
@@ -329,6 +328,21 @@ typedef enum
      */
     LOK_CALLBACK_INVALIDATE_VIEW_CURSOR,
 
+    /**
+     * The the text 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_TEXT_SELECTION.
+     */
+    LOK_CALLBACK_TEXT_VIEW_SELECTION,
+
 }
 LibreOfficeKitCallbackType;
 
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index ec68ed6..4cfe081 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -13,6 +13,7 @@
 #include <sfx2/dllapi.h>
 #include <cstddef>
 #include <cstdint>
+#include <rtl/string.hxx>
 
 class SfxViewShell;
 
@@ -29,6 +30,9 @@ public:
     static std::uintptr_t getView(SfxViewShell* pViewShell = nullptr);
     /// Get the number of views of the current object shell.
     static std::size_t getViews();
+
+    /// Invoke the LOK callback of all views except pThisView, with a payload of rKey-rPayload.
+    static void notifyOtherViews(SfxViewShell* pThisView, int nType, const OString& rKey, const OString& rPayload);
 };
 
 #endif
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 64a6396..9289d44 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -346,6 +346,8 @@ callbackTypeToString (int nType)
         return "LOK_CALLBACK_CONTEXT_MENU";
     case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
         return "LOK_CALLBACK_INVALIDATE_VIEW_CURSOR";
+    case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+        return "LOK_CALLBACK_TEXT_VIEW_SELECTION";
     }
     return nullptr;
 }
@@ -1169,6 +1171,11 @@ callback (gpointer pData)
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
         break;
     }
+    case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+    {
+        // TODO: Implement me
+        break;
+    }
     default:
         g_assert(false);
         break;
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index c994877..b44392c 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -8,6 +8,9 @@
  */
 
 #include <sfx2/lokhelper.hxx>
+
+#include <boost/property_tree/json_parser.hpp>
+
 #include <sfx2/viewsh.hxx>
 #include <sfx2/request.hxx>
 #include <sfx2/viewfrm.hxx>
@@ -86,4 +89,26 @@ std::size_t SfxLokHelper::getViews()
     return nRet;
 }
 
+void SfxLokHelper::notifyOtherViews(SfxViewShell* pThisView, int nType, const OString& rKey, const OString& rPayload)
+{
+    if (SfxLokHelper::getViews() <= 1)
+        return;
+
+    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+    while (pViewShell)
+    {
+        if (pViewShell != pThisView)
+        {
+            boost::property_tree::ptree aTree;
+            aTree.put("viewId", SfxLokHelper::getView(pThisView));
+            aTree.put(rKey.getStr(), rPayload.getStr());
+            std::stringstream aStream;
+            boost::property_tree::write_json(aStream, aTree);
+            OString aPayload = aStream.str().c_str();
+            pViewShell->libreOfficeKitViewCallback(nType, aPayload.getStr());
+        }
+        pViewShell = SfxViewShell::GetNext(*pViewShell);
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 10d7b65..5034537 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -552,7 +552,7 @@ public:
 
     ViewCallback()
         : m_bOwnCursorInvalidated(false),
-        m_bViewCursorInvalidated(false)
+          m_bViewCursorInvalidated(false)
     {
     }
 
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index bb1c363..585a0f4 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -198,26 +198,7 @@ void SwVisibleCursor::_SetPosAndShow()
         Rectangle aSVRect(aRect.Pos().getX(), aRect.Pos().getY(), aRect.Pos().getX() + aRect.SSize().Width(), aRect.Pos().getY() + aRect.SSize().Height());
         OString sRect = aSVRect.toString();
         m_pCursorShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sRect.getStr());
-
-        if (SfxLokHelper::getViews() > 1)
-        {
-            // Notify other views about the invalidated cursor.
-            SfxViewShell* pViewShell = SfxViewShell::GetFirst();
-            while (pViewShell)
-            {
-                if (pViewShell != m_pCursorShell->GetSfxViewShell())
-                {
-                    boost::property_tree::ptree aTree;
-                    aTree.put("viewId", SfxLokHelper::getView(m_pCursorShell->GetSfxViewShell()));
-                    aTree.put("rectangle", sRect.getStr());
-                    std::stringstream aStream;
-                    boost::property_tree::write_json(aStream, aTree);
-                    OString aPayload = aStream.str().c_str();
-                    pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, aPayload.getStr());
-                }
-                pViewShell = SfxViewShell::GetNext(*pViewShell);
-            }
-        }
+        SfxLokHelper::notifyOtherViews(m_pCursorShell->GetSfxViewShell(), LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect);
     }
 
     if ( !m_pCursorShell->IsCursorReadonly()  || m_pCursorShell->GetViewOptions()->IsSelectionInReadonly() )
@@ -416,6 +397,7 @@ void SwSelPaintRects::Show(std::vector<OString>* pSelectionRectangles)
             if (!pSelectionRectangles)
             {
                 GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRect.getStr());
+                SfxLokHelper::notifyOtherViews(GetShell()->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRect);
             }
             else
                 pSelectionRectangles->push_back(sRect);
@@ -625,6 +607,7 @@ void SwShellCursor::Show()
         }
         OString sRect = comphelper::string::join("; ", aRect);
         GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRect.getStr());
+        SfxLokHelper::notifyOtherViews(GetShell()->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRect);
     }
 }
 
commit f31e970376b77d905bc30cbf65d54ceddccb8994
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Jun 21 10:45:37 2016 +0200

    Remove no longer needed vcl::ITiledRenderable::registerCallback()
    
    All clients has been changed to use
    SfxViewShell::registerLibreOfficeKitViewCallback() instead.
    
    Reviewed-on: https://gerrit.libreoffice.org/26540
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit e65b5c19985d725779d8381cc3bd75c441c0ff2e)
    
    Conflicts:
    	include/vcl/ITiledRenderable.hxx
    
    Change-Id: I2538268dc9c4b449f68b5d2b05a72de584c29fd0

diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index 4d9796a..0c90ed3 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -102,15 +102,6 @@ public:
     virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) = 0;
 
     /**
-     * Registers a callback that will be invoked whenever the tiled renderer
-     * wants to notify the client about an event.
-     *
-     * @param pCallBack is the callback function
-     * @param pData is private data of the client that will be sent back when the callback is invoked
-     */
-    virtual void registerCallback(LibreOfficeKitCallback pCallback, void* pData) = 0;
-
-    /**
      * Posts a keyboard event on the document.
      *
      * @see lok::Document::postKeyEvent().
diff --git a/sc/inc/docuno.hxx b/sc/inc/docuno.hxx
index f010b06..617d553 100644
--- a/sc/inc/docuno.hxx
+++ b/sc/inc/docuno.hxx
@@ -381,9 +381,6 @@ public:
     /// @see vcl::ITiledRenderable::initializeForTiledRendering().
     virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
 
-    /// @see vcl::ITiledRenderable::registerCallback().
-    virtual void registerCallback(LibreOfficeKitCallback pCallback, void* pData) override;
-
     /// @see vcl::ITiledRenderable::postKeyEvent().
     virtual void postKeyEvent(int nType, int nCharCode, int nKeyCode) override;
 
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index f15d572..b38031f 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -552,10 +552,6 @@ Size ScModelObj::getDocumentSize()
     return aSize;
 }
 
-void ScModelObj::registerCallback(LibreOfficeKitCallback /*pCallback*/, void* /*pData*/)
-{
-}
-
 void ScModelObj::postKeyEvent(int nType, int nCharCode, int nKeyCode)
 {
     SolarMutexGuard aGuard;
diff --git a/sd/source/ui/inc/unomodel.hxx b/sd/source/ui/inc/unomodel.hxx
index 8f144a2..7ac3f37 100644
--- a/sd/source/ui/inc/unomodel.hxx
+++ b/sd/source/ui/inc/unomodel.hxx
@@ -247,8 +247,6 @@ public:
 
     /// @see vcl::ITiledRenderable::initializeForTiledRendering().
     virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
-    /// @see vcl::ITiledRenderable::registerCallback().
-    virtual void registerCallback(LibreOfficeKitCallback pCallback, void* pData) override;
     /// @see vcl::ITiledRenderable::postKeyEvent().
     virtual void postKeyEvent(int nType, int nCharCode, int nKeyCode) override;
     /// @see vcl::ITiledRenderable::postMouseEvent().
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 47f9bac..8cf5983 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2417,10 +2417,6 @@ void SdXImpressDocument::initializeForTiledRendering(const css::uno::Sequence<cs
     SvtSaveOptions().SetWarnAlienFormat(false);
 }
 
-void SdXImpressDocument::registerCallback(LibreOfficeKitCallback /*pCallback*/, void* /*pData*/)
-{
-}
-
 void SdXImpressDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
 {
     SolarMutexGuard aGuard;
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index cffdb64..8867994 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -417,8 +417,6 @@ public:
     virtual OUString getPartHash(int nPart) override;
     /// @see vcl::ITiledRenderable::initializeForTiledRendering().
     virtual void initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
-    /// @see vcl::ITiledRenderable::registerCallback().
-    virtual void registerCallback(LibreOfficeKitCallback pCallback, void* pData) override;
     /// @see vcl::ITiledRenderable::postKeyEvent().
     virtual void postKeyEvent(int nType, int nCharCode, int nKeyCode) override;
     /// @see vcl::ITiledRenderable::postMouseEvent().
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 695b33c..8374da9 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -3272,10 +3272,6 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
     SvtSaveOptions().SetWarnAlienFormat(false);
 }
 
-void SwXTextDocument::registerCallback(LibreOfficeKitCallback /*pCallback*/, void* /*pData*/)
-{
-}
-
 void SwXTextDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
 {
     SolarMutexGuard aGuard;
commit a27fdd7f9aa0fde0385f4c26a74ea17bdfff5642
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Jun 20 20:33:50 2016 +0200

    sfx2 lok: fix missing view cursors in a new view
    
    When a new view was created, the old views got the position of the new
    view, but not the other way around.
    
    Make sure that the old views notify the new one right after registering
    the callback.
    
    Reviewed-on: https://gerrit.libreoffice.org/26523
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 4d211384f048b689f20e46d4d586f342b110cb5c)
    
    Conflicts:
    	sfx2/source/view/viewsh.cxx
    
    Change-Id: If26edbd57aa939e453d95f4907a0e5722329dd65

diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 43c0189..ec68ed6 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -26,7 +26,7 @@ public:
     /// Set a view shell as current one.
     static void setView(std::uintptr_t nId);
     /// Get the currently active view.
-    static std::uintptr_t getView(SfxViewShell *pViewShell = nullptr);
+    static std::uintptr_t getView(SfxViewShell* pViewShell = nullptr);
     /// Get the number of views of the current object shell.
     static std::size_t getViews();
 };
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index ba42188..c994877 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -60,7 +60,7 @@ void SfxLokHelper::setView(std::uintptr_t nId)
 
 }
 
-std::uintptr_t SfxLokHelper::getView(SfxViewShell *pViewShell)
+std::uintptr_t SfxLokHelper::getView(SfxViewShell* pViewShell)
 {
     if (!pViewShell)
         pViewShell = SfxViewShell::Current();
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index 7d45430..dea4053 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -1602,6 +1602,15 @@ void SfxViewShell::registerLibreOfficeKitViewCallback(LibreOfficeKitCallback pCa
 {
     pImp->m_pLibreOfficeKitViewCallback = pCallback;
     pImp->m_pLibreOfficeKitViewData = pData;
+
+    // Ask other views to send their cursor position to the new view.
+    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+    while (pViewShell)
+    {
+        pViewShell->ShowCursor(false);
+        pViewShell->ShowCursor();
+        pViewShell = SfxViewShell::GetNext(*pViewShell);
+    }
 }
 
 void SfxViewShell::libreOfficeKitViewCallback(int nType, const char* pPayload) const
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 0c49294..10d7b65 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -27,6 +27,7 @@
 #include <ndtxt.hxx>
 #include <wrtsh.hxx>
 #include <sfx2/viewsh.hxx>
+#include <sfx2/lokhelper.hxx>
 
 static const char* DATA_DIRECTORY = "/sw/qa/extras/tiledrendering/data/";
 
@@ -51,6 +52,7 @@ public:
     void testSearchAllNotifications();
     void testPageDownInvalidation();
     void testPartHash();
+    void testViewCursors();
 
     CPPUNIT_TEST_SUITE(SwTiledRenderingTest);
     CPPUNIT_TEST(testRegisterCallback);
@@ -69,6 +71,7 @@ public:
     CPPUNIT_TEST(testSearchAllNotifications);
     CPPUNIT_TEST(testPageDownInvalidation);
     CPPUNIT_TEST(testPartHash);
+    CPPUNIT_TEST(testViewCursors);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -488,6 +491,8 @@ void SwTiledRenderingTest::testSearchAllNotifications()
     SwXTextDocument* pXTextDocument = createDoc("search.odt");
     SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
     pWrtShell->GetSfxViewShell()->registerLibreOfficeKitViewCallback(&SwTiledRenderingTest::callback, this);
+    // Reset notification counter before search.
+    m_nSelectionBeforeSearchResult = 0;
     uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
     {
         {"SearchItem.SearchString", uno::makeAny(OUString("shape"))},
@@ -539,6 +544,61 @@ void SwTiledRenderingTest::testPartHash()
     comphelper::LibreOfficeKit::setActive(false);
 }
 
+class ViewCallback
+{
+public:
+    bool m_bOwnCursorInvalidated;
+    bool m_bViewCursorInvalidated;
+
+    ViewCallback()
+        : m_bOwnCursorInvalidated(false),
+        m_bViewCursorInvalidated(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_INVALIDATE_VISIBLE_CURSOR:
+        {
+            m_bOwnCursorInvalidated = true;
+        }
+        break;
+        case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+        {
+            m_bViewCursorInvalidated = true;
+        }
+        break;
+        }
+    }
+};
+
+void SwTiledRenderingTest::testViewCursors()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    createDoc("dummy.fodt");
+    ViewCallback aView1;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView1);
+    SfxLokHelper::createView();
+    ViewCallback aView2;
+    SfxViewShell::Current()->registerLibreOfficeKitViewCallback(&ViewCallback::callback, &aView2);
+    CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
+    CPPUNIT_ASSERT(aView1.m_bViewCursorInvalidated);
+    CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
+    // This failed: the cursor position of view1 was only known to view2 once
+    // it changed.
+    CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
+
+    comphelper::LibreOfficeKit::setActive(false);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwTiledRenderingTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
commit 5cf23f50bdb5e51a2180c33e298b95a0e5154e2a
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Jun 20 17:14:30 2016 +0200

    lokdocview: handle LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
    
    It's similar to the normal cursor, but it's colored and does not blink.
    
    Change-Id: I6a869a98f46979946f320905426e016fe011cbc6
    Reviewed-on: https://gerrit.libreoffice.org/26522
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit ada901d2c412f8a1b1ae668e883114ccb9c69277)

diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index e72a704..64a6396 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -72,6 +72,9 @@ struct LOKDocViewPrivateImpl
     gint m_nParts;
     /// Position and size of the visible cursor.
     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<std::uintptr_t, GdkRectangle> m_aViewCursors;
     /// Cursor overlay is visible or hidden (for blinking).
     gboolean m_bCursorOverlayVisible;
     /// Cursor is visible or hidden (e.g. for graphic selection).
@@ -1025,6 +1028,7 @@ callback (gpointer pData)
                       priv->m_aVisibleCursor.y,
                       priv->m_aVisibleCursor.width,
                       priv->m_aVisibleCursor.height);
+        std::cerr << "debug, LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: i am " << priv->m_nViewId << ", i got " << pCallback->m_aPayload << " for myself" << std::endl;
         gtk_widget_queue_draw(GTK_WIDGET(pDocView));
     }
     break;
@@ -1156,7 +1160,13 @@ callback (gpointer pData)
     }
     case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
     {
-        // TODO: Implement me
+        std::stringstream aStream(pCallback->m_aPayload);
+        boost::property_tree::ptree aTree;
+        boost::property_tree::read_json(aStream, aTree);
+        std::uintptr_t nViewId = aTree.get<std::uintptr_t>("viewId");
+        const std::string& rRectangle = aTree.get<std::string>("rectangle");
+        priv->m_aViewCursors[nViewId] = payloadToRectangle(pDocView, rRectangle.c_str());
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
         break;
     }
     default:
@@ -1396,6 +1406,32 @@ renderDocument(LOKDocView* pDocView, cairo_t* pCairo)
     return FALSE;
 }
 
+static const GdkRGBA& getDarkColor(std::uintptr_t nViewId)
+{
+    static std::map<std::uintptr_t, GdkRGBA> aColorMap;
+    auto it = aColorMap.find(nViewId);
+    if (it != aColorMap.end())
+        return it->second;
+
+    // Based on tools/colordata.hxx, COL_AUTHOR1_DARK..COL_AUTHOR9_DARK.
+    static std::vector<GdkRGBA> aColors =
+    {
+        {((double)198)/255, ((double)146)/255, ((double)0)/255, 0},
+        {((double)6)/255, ((double)70)/255, ((double)162)/255, 0},
+        {((double)87)/255, ((double)157)/255, ((double)28)/255, 0},
+        {((double)105)/255, ((double)43)/255, ((double)157)/255, 0},
+        {((double)197)/255, ((double)0)/255, ((double)11)/255, 0},
+        {((double)0)/255, ((double)128)/255, ((double)128)/255, 0},
+        {((double)140)/255, ((double)132)/255, ((double)0)/255, 0},
+        {((double)43)/255, ((double)85)/255, ((double)107)/255, 0},
+        {((double)209)/255, ((double)118)/255, ((double)0)/255, 0},
+    };
+    static int nColorCounter = 0;
+    GdkRGBA aColor = aColors[nColorCounter++ % aColors.size()];
+    aColorMap[nViewId] = aColor;
+    return aColorMap[nViewId];
+}
+
 static gboolean
 renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
 {
@@ -1416,6 +1452,27 @@ renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
         cairo_fill(pCairo);
     }
 
+    // View cursors: they do not blink and are colored.
+    if (priv->m_bEdit && !priv->m_aViewCursors.empty())
+    {
+        for (auto& rPair : priv->m_aViewCursors)
+        {
+            GdkRectangle& rCursor = rPair.second;
+            if (rCursor.width < 30)
+                // Set a minimal width if it would be 0.
+                rCursor.width = 30;
+
+            const GdkRGBA& rDark = getDarkColor(priv->m_nViewId);
+            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));
+            cairo_fill(pCairo);
+        }
+    }
+
     if (priv->m_bEdit && priv->m_bCursorVisible && !isEmptyRectangle(priv->m_aVisibleCursor) && priv->m_aTextSelectionRectangles.empty())
     {
         // Have a cursor, but no selection: we need the middle handle.


More information about the Libreoffice-commits mailing list