loleaflet/Makefile                                           |    2 
 loleaflet/README                                             |    3 
 loleaflet/reference.html                                     |   25 ++
 loleaflet/src/control/Parts.js                               |   19 ++
 loleaflet/src/core/Socket.js                                 |    1 
 loleaflet/src/layer/tile/GridLayer.js                        |   28 +++
 loleaflet/src/layer/tile/TileLayer.js                        |   96 ++++++++++-
 loleaflet/src/map/handler/Map.Keyboard.js                    |   70 +++++++-
 loleaflet/src/map/handler/Map.Mouse.js                       |   33 ++-
 loolwsd/LOKitClient.cpp                                      |    6 
 loolwsd/LOOLSession.cpp                                      |   54 +++++-
 loolwsd/LOOLSession.hpp                                      |    6 
 loolwsd/Makefile.am                                          |    4 
 loolwsd/TileCache.cpp                                        |    2 
 loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h      |   29 ++-
 loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h |    4 
 loolwsd/protocol.txt                                         |    7 
 17 files changed, 360 insertions(+), 29 deletions(-)

New commits:
commit 4fa63063d2dc957fd830cb3f27356a83e7fc985c
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Thu Oct 8 16:40:19 2015 +0300

    loleaflet: bump version after tarball

diff --git a/loleaflet/Makefile b/loleaflet/Makefile
index 444fc81..a77191f 100644
--- a/loleaflet/Makefile
+++ b/loleaflet/Makefile
@@ -3,7 +3,7 @@
 # ("micro") part: Between releases odd, even for releases (no other
 # changes inbetween).
 
-VERSION=1.2.6
+VERSION=1.2.7
 
 # Version number of the bundled 'draw' thing
 DRAW_VERSION=0.2.4
commit b433d066ce3f01b5e6ee28d60a4227771efc608c
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Thu Oct 8 16:39:47 2015 +0300

    loleaflet: bump version before tarball

diff --git a/loleaflet/Makefile b/loleaflet/Makefile
index aa96ef8..444fc81 100644
--- a/loleaflet/Makefile
+++ b/loleaflet/Makefile
@@ -3,7 +3,7 @@
 # ("micro") part: Between releases odd, even for releases (no other
 # changes inbetween).
 
-VERSION=1.2.5
+VERSION=1.2.6
 
 # Version number of the bundled 'draw' thing
 DRAW_VERSION=0.2.4
commit 1cf0c7299236734fc07950fac4fe5c2f145ab3de
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Tue Oct 6 17:33:22 2015 +0300

    handle LOK_CALLBACK_SEARCH_RESULT_SELECTION callback

diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index d45f019..057c2d5 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -6823,6 +6823,11 @@ map.addControl(new MyControl());
                <td><code>Number</code></td>
                <td>Number of search results</td>
        </tr>
+       <tr>
+               <td><code><b>results</b></code></td>
+               <td><code><a href="#bounds">Bounds[]</a></code></td>
+               <td>An array of bounds representing the selections of the 
search results in the document.</td>
+       </tr>
 </table>
 
 <h3 id="partpagerectangles-event">PartPageRectangles</h3>
diff --git a/loleaflet/src/layer/tile/TileLayer.js 
b/loleaflet/src/layer/tile/TileLayer.js
index 5eaab4d..6be61de 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -214,8 +214,8 @@ L.TileLayer = L.GridLayer.extend({
                else if (textMsg.startsWith('searchnotfound:')) {
                        this._onSearchNotFoundMsg(textMsg);
                }
-               else if (textMsg.startsWith('searchresultcount:')) {
-                       this._onSearchResultCount(textMsg);
+               else if (textMsg.startsWith('searchresultselection:')) {
+                       this._onSearchResultSelection(textMsg);
                }
                else if (textMsg.startsWith('setpart:')) {
                        this._onSetPartMsg(textMsg);
@@ -336,11 +336,16 @@ L.TileLayer = L.GridLayer.extend({
                this._map.fire('search', {originalPhrase: originalPhrase, 
count: 0});
        },
 
-       _onSearchResultCount: function (textMsg) {
-               textMsg = textMsg.substring(19);
-               var count = parseInt(textMsg.substring(0, 
textMsg.indexOf(';')));
-               var originalPhrase = textMsg.substring(textMsg.indexOf(';') + 
1);
-               this._map.fire('search', {originalPhrase: originalPhrase, 
count: count});
+       _onSearchResultSelection: function (textMsg) {
+               textMsg = textMsg.substring(23);
+               var obj = JSON.parse(textMsg);
+               var originalPhrase = obj.searchString;
+               var count = obj.searchResultSelection.length;
+               var results = [];
+               for (var i = 0; i < obj.searchResultSelection.length; i++) {
+                       
results.push(this._twipsRectangleToPixelBounds(obj.searchResultSelection[i]));
+               }
+               this._map.fire('search', {originalPhrase: originalPhrase, 
count: count, results: results});
        },
 
        _onStateChangedMsg: function (textMsg) {
diff --git a/loolwsd/LOKitClient.cpp b/loolwsd/LOKitClient.cpp
index 57f0e03..8e3f546 100644
--- a/loolwsd/LOKitClient.cpp
+++ b/loolwsd/LOKitClient.cpp
@@ -58,6 +58,7 @@ extern "C"
             CASE(STATUS_INDICATOR_FINISH);
             CASE(SEARCH_NOT_FOUND);
             CASE(SEARCH_RESULT_COUNT);
+            CASE(SEARCH_RESULT_SELECTION);
             CASE(DOCUMENT_SIZE_CHANGED);
             CASE(SET_PART);
 #undef CASE
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index ef1f1d8..d8b7dd0 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -826,6 +826,9 @@ extern "C"
         case LOK_CALLBACK_SEARCH_NOT_FOUND:
             srv->sendTextFrame("searchnotfound: " + std::string(pPayload));
             break;
+        case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
+            srv->sendTextFrame("searchresultselection: " + 
std::string(pPayload));
+            break;
         case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
             srv->getStatus("", 0);
             srv->getPartPageRectangles("", 0);
commit 68398735302d6866461f52f948a09351d6a2b879
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Tue Oct 6 17:32:39 2015 +0300

    loleaflet: twips rectangle to pixel bounds method

diff --git a/loleaflet/src/layer/tile/GridLayer.js 
b/loleaflet/src/layer/tile/GridLayer.js
index 9c89f7c..0e1fded 100644
--- a/loleaflet/src/layer/tile/GridLayer.js
+++ b/loleaflet/src/layer/tile/GridLayer.js
@@ -758,6 +758,21 @@ L.GridLayer = L.Layer.extend({
                                pixels.y * this._tileHeightTwips / 
this._tileSize);
        },
 
+       _twipsRectangleToPixelBounds: function (strRectangle) {
+               // TODO use this more
+               // strRectangle = x, y, width, height
+               var strTwips = strRectangle.match(/\d+/g);
+               if (!strTwips) {
+                       return null;
+               }
+               var topLeftTwips = new L.Point(parseInt(strTwips[0]), 
parseInt(strTwips[1]));
+               var offset = new L.Point(parseInt(strTwips[2]), 
parseInt(strTwips[3]));
+               var bottomRightTwips = topLeftTwips.add(offset);
+               return new L.Bounds(
+                               this._twipsToPixels(topLeftTwips),
+                               this._twipsToPixels(bottomRightTwips));
+       },
+
        _noTilesToLoad: function () {
                for (var key in this._tiles) {
                        if (!this._tiles[key].loaded) { return false; }
commit be67ec80650293c40135e63eeaf518aacd5c7134
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Mon Oct 5 20:02:35 2015 +0300

    loleaflet: some ctrl+key shortcuts #tdf94608

diff --git a/loleaflet/src/map/handler/Map.Keyboard.js 
b/loleaflet/src/map/handler/Map.Keyboard.js
index 98c722d..93490e4 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -187,10 +187,7 @@ L.Map.Keyboard = L.Handler.extend({
                var alt = e.originalEvent.altKey ? this.keyModifier.alt : 0;
                this.modifier = shift | ctrl | alt;
                if (e.originalEvent.ctrlKey) {
-                       // we prepare for a copy event
-                       docLayer._textArea.value = 'dummy text';
-                       docLayer._textArea.focus();
-                       docLayer._textArea.select();
+                       this._handleCtrlCommand(e);
                        return;
                }
 
@@ -244,6 +241,65 @@ L.Map.Keyboard = L.Handler.extend({
                        }
                }
                L.DomEvent.stopPropagation(e.originalEvent);
+       },
+
+       _handleCtrlCommand: function (e) {
+               if (e.type !== 'keydown') {
+                       e.originalEvent.preventDefault();
+                       return;
+               };
+
+               switch (e.originalEvent.keyCode) {
+                       case 13: // enter
+                               L.Socket.sendMessage('uno 
.uno:InsertPagebreak');
+                               break;
+                       case 37: // left arrow
+                               L.Socket.sendMessage('uno .uno:GoToPrevWord');
+                               break;
+                       case 39: // right arrow
+                               L.Socket.sendMessage('uno .uno:GoToNextWord');
+                               break;
+                       case 65: // a
+                               L.Socket.sendMessage('uno .uno:Selectall');
+                               break;
+                       case 66: // b
+                               L.Socket.sendMessage('uno .uno:Bold');
+                               break;
+                       case 67: // c
+                               // we prepare for a copy event
+                               this._map._docLayer._textArea.value = 'dummy 
text';
+                               this._map._docLayer._textArea.focus();
+                               this._map._docLayer._textArea.select();
+                               break;
+                       case 69: // e
+                               L.Socket.sendMessage('uno .uno:CenterPara');
+                               break;
+                       case 73: // i
+                               L.Socket.sendMessage('uno .uno:Italic');
+                               break;
+                       case 74: // j
+                               L.Socket.sendMessage('uno .uno:JustifyPara');
+                               break;
+                       case 76: // l
+                               L.Socket.sendMessage('uno .uno:LeftPara');
+                               break;
+                       case 82: // r
+                               L.Socket.sendMessage('uno .uno:RightPara');
+                               break;
+                       case 85: // u
+                               L.Socket.sendMessage('uno .uno:Underline');
+                               break;
+                       case 90: // z
+                               L.Socket.sendMessage('uno .uno:Undo');
+                               break;
+                       case 189: // -
+                               L.Socket.sendMessage('uno 
.uno:InsertSoftHyphen');
+                               break;
+               }
+               if (e.originalEvent.keyCode !== 67 && e.originalEvent.keyCode 
!== 86) {
+                       // not copy or paste
+                       e.originalEvent.preventDefault();
+               }
        }
 });
 
commit f68c3907477ffd4829b0216f75db72d872fae60d
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Mon Oct 5 16:44:40 2015 +0300

    search result count callback handler

diff --git a/loleaflet/src/layer/tile/TileLayer.js 
b/loleaflet/src/layer/tile/TileLayer.js
index cfe686a..5eaab4d 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -214,6 +214,9 @@ L.TileLayer = L.GridLayer.extend({
                else if (textMsg.startsWith('searchnotfound:')) {
                        this._onSearchNotFoundMsg(textMsg);
                }
+               else if (textMsg.startsWith('searchresultcount:')) {
+                       this._onSearchResultCount(textMsg);
+               }
                else if (textMsg.startsWith('setpart:')) {
                        this._onSetPartMsg(textMsg);
                }
@@ -333,6 +336,13 @@ L.TileLayer = L.GridLayer.extend({
                this._map.fire('search', {originalPhrase: originalPhrase, 
count: 0});
        },
 
+       _onSearchResultCount: function (textMsg) {
+               textMsg = textMsg.substring(19);
+               var count = parseInt(textMsg.substring(0, 
textMsg.indexOf(';')));
+               var originalPhrase = textMsg.substring(textMsg.indexOf(';') + 
1);
+               this._map.fire('search', {originalPhrase: originalPhrase, 
count: count});
+       },
+
        _onStateChangedMsg: function (textMsg) {
                var unoMsg = textMsg.substr(14).split('=');
                var commandName = '',
diff --git a/loolwsd/LOKitClient.cpp b/loolwsd/LOKitClient.cpp
index 97d42da..57f0e03 100644
--- a/loolwsd/LOKitClient.cpp
+++ b/loolwsd/LOKitClient.cpp
@@ -57,6 +57,7 @@ extern "C"
             CASE(STATUS_INDICATOR_SET_VALUE);
             CASE(STATUS_INDICATOR_FINISH);
             CASE(SEARCH_NOT_FOUND);
+            CASE(SEARCH_RESULT_COUNT);
             CASE(DOCUMENT_SIZE_CHANGED);
             CASE(SET_PART);
 #undef CASE
@@ -117,7 +118,7 @@ protected:
 
             if (tokens[0] == "?" || tokens[0] == "help")
             {
-                std::cout << 
+                std::cout <<
                     "Commands mimic LOOL protocol but we talk directly to 
LOKit:" << std::endl <<
                     "    status" << std::endl <<
                     "        calls LibreOfficeKitDocument::getDocumentType, 
getParts, getPartName, getDocumentSize" << std::endl <<
@@ -152,7 +153,7 @@ protected:
                 int tilePosY(std::stoi(tokens[5]));
                 int tileWidth(std::stoi(tokens[6]));
                 int tileHeight(std::stoi(tokens[7]));
-                
+
                 std::vector<unsigned char> pixmap(canvasWidth*canvasHeight*4);
                 loKitDocument->pClass->setPart(loKitDocument, partNumber);
                 loKitDocument->pClass->paintTile(loKitDocument, pixmap.data(), 
canvasWidth, canvasHeight, tilePosX, tilePosY, tileWidth, tileHeight);
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index a293cde..ef1f1d8 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -808,6 +808,9 @@ extern "C"
         case LOK_CALLBACK_HYPERLINK_CLICKED:
             srv->sendTextFrame("hyperlinkclicked: " + std::string(pPayload));
             break;
+        case LOK_CALLBACK_SEARCH_RESULT_COUNT:
+            srv->sendTextFrame("searchresultcount: " + std::string(pPayload));
+            break;
         case LOK_CALLBACK_STATE_CHANGED:
             srv->sendTextFrame("statechanged: " + std::string(pPayload));
             break;
diff --git a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h 
b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h
index 7038e5f..dc3e0f9 100644
--- a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h
+++ b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h
@@ -155,7 +155,9 @@ typedef enum
      *
      * Payload is a single 0-based integer.
      */
-    LOK_CALLBACK_SET_PART
+    LOK_CALLBACK_SET_PART,
+    /// Number of search results, in case something is found.
+    LOK_CALLBACK_SEARCH_RESULT_COUNT
 }
 LibreOfficeKitCallbackType;
 
commit f3af51450ac43c16594d04a9bbb49391a6a493b9
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Mon Oct 5 15:04:19 2015 +0300

    We now send the mouse button that has been pressed and also they key
    modifiers for actions such as ctrl+click or shift+click

diff --git a/loleaflet/src/layer/tile/TileLayer.js 
b/loleaflet/src/layer/tile/TileLayer.js
index 86d7f2b..cfe686a 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -191,6 +191,9 @@ L.TileLayer = L.GridLayer.extend({
                else if (textMsg.startsWith('graphicselection:')) {
                        this._onGraphicSelectionMsg(textMsg);
                }
+               else if (textMsg.startsWith('hyperlinkclicked:')) {
+                       this._onHyperlinkClickedMsg(textMsg);
+               }
                else if (textMsg.startsWith('invalidatecursor:')) {
                        this._onInvalidateCursorMsg(textMsg);
                }
@@ -280,6 +283,11 @@ L.TileLayer = L.GridLayer.extend({
                this._onUpdateGraphicSelection();
        },
 
+       _onHyperlinkClickedMsg: function (textMsg) {
+               var link = textMsg.substring(18);
+               window.open(link, '_blank');
+       },
+
        _onInvalidateCursorMsg: function (textMsg) {
                var strTwips = textMsg.match(/\d+/g);
                var topLeftTwips = new L.Point(parseInt(strTwips[0]), 
parseInt(strTwips[1]));
@@ -503,9 +511,10 @@ L.TileLayer = L.GridLayer.extend({
                this._onUpdateGraphicSelection();
        },
 
-       _postMouseEvent: function(type, x, y, count) {
+       _postMouseEvent: function(type, x, y, count, buttons, modifier) {
                L.Socket.sendMessage('mouse type=' + type +
-                               ' x=' + x + ' y=' + y + ' count=' + count);
+                               ' x=' + x + ' y=' + y + ' count=' + count +
+                               ' buttons=' + buttons + ' modifier=' + 
modifier);
        },
 
        _postKeyboardEvent: function(type, charcode, keycode) {
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js 
b/loleaflet/src/map/handler/Map.Keyboard.js
index 987d2b4..98c722d 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -115,6 +115,7 @@ L.Map.Keyboard = L.Handler.extend({
                this._map = map;
                this._setPanOffset(map.options.keyboardPanOffset);
                this._setZoomOffset(map.options.keyboardZoomOffset);
+               this.modifier = 0;
        },
 
        addHooks: function () {
@@ -180,6 +181,11 @@ L.Map.Keyboard = L.Handler.extend({
 
        _onKeyDown: function (e) {
                var docLayer = this._map._docLayer;
+               this.modifier = 0;
+               var shift = e.originalEvent.shiftKey ? this.keyModifier.shift : 
0;
+               var ctrl = e.originalEvent.ctrlKey ? this.keyModifier.ctrl : 0;
+               var alt = e.originalEvent.altKey ? this.keyModifier.alt : 0;
+               this.modifier = shift | ctrl | alt;
                if (e.originalEvent.ctrlKey) {
                        // we prepare for a copy event
                        docLayer._textArea.value = 'dummy text';
diff --git a/loleaflet/src/map/handler/Map.Mouse.js 
b/loleaflet/src/map/handler/Map.Mouse.js
index ac731a8..9fd8ba8 100644
--- a/loleaflet/src/map/handler/Map.Mouse.js
+++ b/loleaflet/src/map/handler/Map.Mouse.js
@@ -23,6 +23,18 @@ L.Map.Mouse = L.Handler.extend({
                        this._onMouseEvent, this);
        },
 
+       LOButtons: {
+               left: 1,
+               middle: 2,
+               right: 4
+       },
+
+       JSButtons: {
+               left: 0,
+               middle: 1,
+               right: 2
+       },
+
        _onMouseEvent: function (e) {
                var docLayer = this._map._docLayer;
                if (!docLayer) {
@@ -39,6 +51,12 @@ L.Map.Mouse = L.Handler.extend({
                        }
                }
 
+               var modifier = this._map.keyboard.modifier;
+               var buttons = 0;
+               buttons |= e.originalEvent.button === this.JSButtons.left ? 
this.LOButtons.left : 0;
+               buttons |= e.originalEvent.button === this.JSButtons.middle ? 
this.LOButtons.middle : 0;
+               buttons |= e.originalEvent.button === this.JSButtons.right ? 
this.LOButtons.right : 0;
+
                if (e.type === 'mousedown') {
                        docLayer._resetPreFetching();
                        this._mouseDown = true;
@@ -47,7 +65,8 @@ L.Map.Mouse = L.Handler.extend({
                        }
                        var mousePos = docLayer._latLngToTwips(e.latlng);
                        this._mouseEventsQueue.push(L.bind(function() {
-                               this._postMouseEvent('buttondown', mousePos.x, 
mousePos.y, 1);}, docLayer));
+                               this._postMouseEvent('buttondown', mousePos.x, 
mousePos.y, 1, buttons, modifier);
+                       }, docLayer));
                        this._holdMouseEvent = 
setTimeout(L.bind(this._executeMouseEvents, this), 500);
                }
                else if (e.type === 'mouseup') {
@@ -82,7 +101,7 @@ L.Map.Mouse = L.Handler.extend({
                                                }
                                        }
                                        this._mouseEventsQueue = [];
-                                       docLayer._postMouseEvent('buttonup', 
mousePos.x, mousePos.y, 1);
+                                       docLayer._postMouseEvent('buttonup', 
mousePos.x, mousePos.y, 1, buttons, modifier);
                                        docLayer._textArea.focus();
                                }, this));
                                this._holdMouseEvent = 
setTimeout(L.bind(this._executeMouseEvents, this), timeOut);
@@ -113,7 +132,7 @@ L.Map.Mouse = L.Handler.extend({
                        }
                        if (!this._map.dragging.enabled()) {
                                mousePos = docLayer._latLngToTwips(e.latlng);
-                               docLayer._postMouseEvent('move', mousePos.x, 
mousePos.y, 1);
+                               docLayer._postMouseEvent('move', mousePos.x, 
mousePos.y, 1, buttons, modifier);
                                for (key in docLayer._selectionHandles) {
                                        handle = 
docLayer._selectionHandles[key];
                                        if (handle._icon) {
@@ -124,10 +143,10 @@ L.Map.Mouse = L.Handler.extend({
                }
                else if (e.type === 'dblclick') {
                        mousePos = docLayer._latLngToTwips(e.latlng);
-                       docLayer._postMouseEvent('buttondown', mousePos.x, 
mousePos.y, 1);
-                       docLayer._postMouseEvent('buttondown', mousePos.x, 
mousePos.y, 2);
-                       docLayer._postMouseEvent('buttonup', mousePos.x, 
mousePos.y, 2);
-                       docLayer._postMouseEvent('buttonup', mousePos.x, 
mousePos.y, 1);
+                       docLayer._postMouseEvent('buttondown', mousePos.x, 
mousePos.y, 1, buttons, modifier);
+                       docLayer._postMouseEvent('buttondown', mousePos.x, 
mousePos.y, 2, buttons, modifier);
+                       docLayer._postMouseEvent('buttonup', mousePos.x, 
mousePos.y, 2, 1, buttons, modifier);
+                       docLayer._postMouseEvent('buttonup', mousePos.x, 
mousePos.y, 1, 1, buttons, modifier);
                }
        },
 
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 5f5d12e..a293cde 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -1025,9 +1025,9 @@ bool ChildProcessSession::keyEvent(const char *buffer, 
int length, StringTokeniz
 
 bool ChildProcessSession::mouseEvent(const char *buffer, int length, 
StringTokenizer& tokens)
 {
-    int type, x, y, count;
+    int type, x, y, count, buttons, modifier;
 
-    if (tokens.count() != 5 ||
+    if (tokens.count() != 7 ||
         !getTokenKeyword(tokens[1], "type",
                          {{"buttondown", LOK_MOUSEEVENT_MOUSEBUTTONDOWN},
                           {"buttonup", LOK_MOUSEEVENT_MOUSEBUTTONUP},
@@ -1035,13 +1035,15 @@ bool ChildProcessSession::mouseEvent(const char 
*buffer, int length, StringToken
                          type) ||
         !getTokenInteger(tokens[2], "x", x) ||
         !getTokenInteger(tokens[3], "y", y) ||
-        !getTokenInteger(tokens[4], "count", count))
+        !getTokenInteger(tokens[4], "count", count),
+        !getTokenInteger(tokens[5], "buttons", buttons),
+        !getTokenInteger(tokens[6], "modifier", modifier))
     {
         sendTextFrame("error: cmd=mouse kind=syntax");
         return false;
     }
 
-    _loKitDocument->pClass->postMouseEvent(_loKitDocument, type, x, y, count);
+    _loKitDocument->pClass->postMouseEvent(_loKitDocument, type, x, y, count, 
buttons, modifier);
 
     return true;
 }
diff --git a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h 
b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h
index d83dd49..83dcc98 100644
--- a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h
@@ -137,7 +137,9 @@ struct _LibreOfficeKitDocumentClass
                             int nType,
                             int nX,
                             int nY,
-                            int nCount);
+                            int nCount,
+                            int nButtons,
+                            int nModifier);
 
     /// @see lok::Document::postUnoCommand
     void (*postUnoCommand) (LibreOfficeKitDocument* pThis,
commit d92c8903adb565d8ac4040cdacac4ad7b94d5099
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Wed Sep 30 17:22:00 2015 +0300

    loolwsd: update page sizes when the doc size changes

diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 313e76f..5f5d12e 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -825,6 +825,7 @@ extern "C"
             break;
         case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
             srv->getStatus("", 0);
+            srv->getPartPageRectangles("", 0);
             break;
         case LOK_CALLBACK_SET_PART:
             srv->sendTextFrame("setpart: " + std::string(pPayload));
commit 0557bc170a179393a6e237d0a596f8fdb98eafd2
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Wed Sep 30 17:17:03 2015 +0300

    loolwsd: switch to editing dir when invalidating the cursor

diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 4b00dea..313e76f 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -218,6 +218,9 @@ bool MasterProcessSession::handleInput(const char *buffer, 
int length)
             {
                 peer->_tileCache->saveTextFile(std::string(buffer, length), 
"partpagerectangles.txt");
             }
+            else if (tokens[0] == "invalidatecursor:") {
+                peer->_tileCache->setEditing(true);
+            }
             else if (tokens[0] == "invalidatetiles:")
             {
                 // FIXME temporarily, set the editing on the 1st invalidate, 
TODO extend
diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp
index 76ca730..cbd0278 100644
--- a/loolwsd/TileCache.cpp
+++ b/loolwsd/TileCache.cpp
@@ -172,7 +172,7 @@ void TileCache::setEditing(bool editing)
 
 void TileCache::saveTextFile(const std::string& text, std::string fileName)
 {
-    std::string dirName = cacheDirName(_hasUnsavedChanges);
+    std::string dirName = cacheDirName(_isEditing);
 
     File(dirName).createDirectories();
 
commit 0219c1877a8f6c6276ee8808f7e90264e4f7ec15
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Wed Sep 30 13:43:12 2015 +0300

    loleaflet: goToPage without having a LOK instance
    
    Knowing the page dimension, we can scroll to the desired page
    without requesting sending the 'setpage' command to the server

diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js
index 1ae0825..d710d47 100644
--- a/loleaflet/src/control/Parts.js
+++ b/loleaflet/src/control/Parts.js
@@ -122,7 +122,19 @@ L.Map.include({
                else if (typeof (page) === 'number' && page >= 0 && page < 
docLayer._pages) {
                        docLayer._currentPage = page;
                }
-               L.Socket.sendMessage('setpage page=' + docLayer._currentPage);
+               if (docLayer._permission !== 'edit' && 
docLayer._partPageRectanglesPixels.length > docLayer._currentPage) {
+                       // we can scroll to the desired page without having a 
LOK instance
+                       var pageBounds = 
docLayer._partPageRectanglesPixels[docLayer._currentPage];
+                       var pos = new L.Point(
+                                       pageBounds.min.x + (pageBounds.max.x - 
pageBounds.min.x) / 2,
+                                       pageBounds.min.y);
+                       pos.y -= this.getSize().y / 4; // offset by a quater of 
the viewing area so that the previous page is visible
+                       this.scrollTop(pos.y, {update: true});
+                       this.scrollLeft(pos.x, {update: true});
+               }
+               else {
+                       L.Socket.sendMessage('setpage page=' + 
docLayer._currentPage);
+               }
                this.fire('pagenumberchanged', {
                        currentPage: docLayer._currentPage,
                        pages: docLayer._pages,
commit 771ae08cb682aa163b770ad736ad21d696bee259
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Wed Sep 30 13:17:43 2015 +0300

    loleaflet: partpagerectangles command integration
    
    An event is fired with the page dimensions.
    Also the current page number is updated based on which page contains
    the current view's center

diff --git a/loleaflet/README b/loleaflet/README
index 4a32d13..8cc2739 100644
--- a/loleaflet/README
+++ b/loleaflet/README
@@ -193,6 +193,9 @@ Writer pages:
             + e.docType = document type, should be 'text'
         map.on('invalidatepreview', function (e) {})
             + e.id = the preview's id
+        map.on('partpagerectangles', function (e) {}) where:
+            + e.pixelRectangles = An array of bounds representing each page's 
dimension in pixels on the current zoom level
+            + e.twipsRectangles = An array of bounds representing each page's 
dimension in twips.
 
 Error:
     - events
diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 595dd62..d45f019 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -6825,6 +6825,26 @@ map.addControl(new MyControl());
        </tr>
 </table>
 
+<h3 id="partpagerectangles-event">PartPageRectangles</h3>
+
+<table data-id='events'>
+       <tr>
+               <th class="width100">property</th>
+               <th>type</th>
+               <th>description</th>
+       </tr>
+       <tr>
+               <td><code><b>pixelRectangles</b></code></td>
+        <td><code><a href="#bounds">Bounds[]</a></code></td>
+               <td>An array of bounds representing each page's dimension in 
pixels on the current zoom level.</td>
+       </tr>
+       <tr>
+               <td><code><b>twipsRectangles</b></code></td>
+               <td><code><a href="#bounds">Bounds[]</a></code></td>
+               <td>An array of bounds representing each page's dimension in 
twips.</td>
+       </tr>
+</table>
+
 <h3 id="permission-event">PermissionEvent</h3>
 
 <table data-id='events'>
diff --git a/loleaflet/src/control/Parts.js b/loleaflet/src/control/Parts.js
index 55d4c9b..1ae0825 100644
--- a/loleaflet/src/control/Parts.js
+++ b/loleaflet/src/control/Parts.js
@@ -123,6 +123,11 @@ L.Map.include({
                        docLayer._currentPage = page;
                }
                L.Socket.sendMessage('setpage page=' + docLayer._currentPage);
+               this.fire('pagenumberchanged', {
+                       currentPage: docLayer._currentPage,
+                       pages: docLayer._pages,
+                       docType: docLayer._docType
+               });
        },
 
        getNumberOfPages: function () {
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index ba93c2b..99a8c19 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -52,6 +52,7 @@ L.Socket = {
                }
                this.socket.send(msg);
                this.socket.send('status');
+               this.socket.send('partpagerectangles');
                for (var i = 0; i < this._msgQueue.length; i++) {
                        this.socket.send(this._msgQueue[i].msg);
                        L.Log.log(this._msgQueue[i].msg, 
this._msgQueue[i].coords);
diff --git a/loleaflet/src/layer/tile/GridLayer.js 
b/loleaflet/src/layer/tile/GridLayer.js
index 2922d7e..9c89f7c 100644
--- a/loleaflet/src/layer/tile/GridLayer.js
+++ b/loleaflet/src/layer/tile/GridLayer.js
@@ -444,6 +444,7 @@ L.GridLayer = L.Layer.extend({
        _move: function () {
                this._update();
                this._resetPreFetching(true);
+               this._onCurrentPageUpdate();
        },
 
        _update: function (center, zoom) {
diff --git a/loleaflet/src/layer/tile/TileLayer.js 
b/loleaflet/src/layer/tile/TileLayer.js
index 0bf5474..86d7f2b 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -102,6 +102,7 @@ L.TileLayer = L.GridLayer.extend({
                map.on('drag resize zoomend', this._updateScrollOffset, this);
                map.on('copy', this._onCopy, this);
                map.on('zoomend', this._onUpdateCursor, this);
+               map.on('zoomend', this._onUpdatePartPageRectangles, this);
                map.on('dragstart', this._onDragStart, this);
                map.on('requestloksession', this._onRequestLOKSession, this);
                map.on('error', this._mapOnError, this);
@@ -204,6 +205,9 @@ L.TileLayer = L.GridLayer.extend({
                        msg += 'height=' + this._docHeightTwips;
                        this._onInvalidateTilesMsg(msg);
                }
+               else if (textMsg.startsWith('partpagerectangles:')) {
+                       this._onPartPageRectanglesMsg(textMsg);
+               }
                else if (textMsg.startsWith('searchnotfound:')) {
                        this._onSearchNotFoundMsg(textMsg);
                }
@@ -288,6 +292,34 @@ L.TileLayer = L.GridLayer.extend({
                this._onUpdateCursor();
        },
 
+       _onPartPageRectanglesMsg: function (textMsg) {
+               textMsg = textMsg.substring(19);
+               var pages = textMsg.split(';');
+               this._partPageRectanglesTwips = [];
+               this._partPageRectanglesPixels = [];
+               for (var i = 0; i < pages.length; i++) {
+                       var strTwips = pages[i].match(/\d+/g);
+                       if (!strTwips) {
+                               // probably not a text file
+                               return;
+                       }
+                       var topLeftTwips = new L.Point(parseInt(strTwips[0]), 
parseInt(strTwips[1]));
+                       var offset = new L.Point(parseInt(strTwips[2]), 
parseInt(strTwips[3]));
+                       var bottomRightTwips = topLeftTwips.add(offset);
+                       var pageBoundsTwips = new L.Bounds(topLeftTwips, 
bottomRightTwips);
+                       this._partPageRectanglesTwips.push(pageBoundsTwips);
+                       var pageBoundsPixels = new L.Bounds(
+                                       this._twipsToPixels(topLeftTwips),
+                                       this._twipsToPixels(bottomRightTwips));
+                       this._partPageRectanglesPixels.push(pageBoundsPixels);
+               }
+               this._map.fire('partpagerectangles', {
+                       pixelRectangles: this._partPageRectanglesPixels,
+                       twipsRectangles: this._partPageRectanglesTwips
+               });
+               this._onCurrentPageUpdate();
+       },
+
        _onSearchNotFoundMsg: function (textMsg) {
                var originalPhrase = textMsg.substring(16);
                this._map.fire('search', {originalPhrase: originalPhrase, 
count: 0});
@@ -689,6 +721,42 @@ L.TileLayer = L.GridLayer.extend({
                                this._map.setZoom(Math.min(10, 
this._map.getZoom() + zoomDelta), {animate: false});
                        }
                }
+       },
+
+       _onCurrentPageUpdate: function () {
+               var mapCenter = this._map.project(this._map.getCenter());
+               if (!this._partPageRectanglesPixels || !(this._currentPage >= 
0) ||
+                               
this._partPageRectanglesPixels[this._currentPage].contains(mapCenter)) {
+                       // page number has not changed
+                       return;
+               }
+               for (var i = 0; i < this._partPageRectanglesPixels.length; i++) 
{
+                       if 
(this._partPageRectanglesPixels[i].contains(mapCenter)) {
+                               this._currentPage = i;
+                               this._map.fire('pagenumberchanged', {
+                                       currentPage: this._currentPage,
+                                       pages: this._pages,
+                                       docType: this._docType
+                               });
+                               return;
+                       }
+               }
+       },
+
+       _onUpdatePartPageRectangles: function () {
+               if (this._partPageRectanglesPixels.length > 0) {
+                       this._partPageRectanglesPixels = [];
+                       for (var i = 0; i < 
this._partPageRectanglesTwips.length; i++) {
+                               var pageBounds = new L.Bounds(
+                                               
this._twipsToPixels(this._partPageRectanglesTwips[i].min),
+                                               
this._twipsToPixels(this._partPageRectanglesTwips[i].max));
+                               this._partPageRectanglesPixels.push(pageBounds);
+                       }
+                       this._map.fire('partpagerectangles', {
+                               pixelRectangles: this._partPageRectanglesPixels,
+                               twipsRectangles: this._partPageRectanglesTwips
+                       });
+               }
        }
 });
 
commit 32e89553b8a4a281d721e3a6b1fe7eb3300567ef
Author: Mihai Varga <mihai.va...@collabora.com>
Date:   Wed Sep 30 13:10:48 2015 +0300

    loleaflet: twipsToPixels and back methods

diff --git a/loleaflet/src/layer/tile/GridLayer.js 
b/loleaflet/src/layer/tile/GridLayer.js
index e010aa3..2922d7e 100644
--- a/loleaflet/src/layer/tile/GridLayer.js
+++ b/loleaflet/src/layer/tile/GridLayer.js
@@ -745,6 +745,18 @@ L.GridLayer = L.Layer.extend({
                                Math.round(pixels.y / this._tileSize * 
this._tileHeightTwips));
        },
 
+       _twipsToPixels: function (twips) {
+               return new L.Point(
+                               twips.x / this._tileWidthTwips * this._tileSize,
+                               twips.y / this._tileHeightTwips * 
this._tileSize);
+       },
+
+       _pixelsToTwips: function (pixels) {
+               return new L.Point(
+                               pixels.x * this._tileWidthTwips / 
this._tileSize,
+                               pixels.y * this._tileHeightTwips / 
this._tileSize);
+       },
+
        _noTilesToLoad: function () {
                for (var key in this._tiles) {
                        if (!this._tiles[key].loaded) { return false; }
commit afe2a71692bf4cfaf9f3c3e1c17b9e5b9cb0a979
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Tue Sep 29 12:55:21 2015 +0200

    loolwsd: document partpagerectangles command on both directions

diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt
index 369bb69..88cc062 100644
--- a/loolwsd/protocol.txt
+++ b/loolwsd/protocol.txt
@@ -75,6 +75,9 @@ uno <command>
 
     <command> is a line of text.
 
+partpagerectangles
+
+    Invokes lok::Document::getPartPageRectangles().
 
 server -> client
 ================
@@ -117,6 +120,10 @@ status: type=<typeName> parts=<numberOfParts> 
current=<currentPartNumber> width=
 
 styles: {"styleFamily": ["styles in family"], etc. }
 
+partpagerectangles: <payload>
+
+    Payload format is the same as LOK_CALLBACK_TEXT_SELECTION.
+
 textselectioncontent: <content>
 
     Current selection's content
commit c543d3d740be636caee43de1e72ba248e5503fce
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Tue Sep 29 12:27:45 2015 +0200

    loolwsd: parse the partpagerectangles command and cache the values

diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 233e999..4b00dea 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -214,6 +214,10 @@ bool MasterProcessSession::handleInput(const char *buffer, 
int length)
                 std::string commandName = 
object->get("commandName").toString();
                 peer->_tileCache->saveTextFile(std::string(buffer, length), 
"cmdValues" + commandName + ".txt");
             }
+            else if (tokens[0] == "partpagerectangles:")
+            {
+                peer->_tileCache->saveTextFile(std::string(buffer, length), 
"partpagerectangles.txt");
+            }
             else if (tokens[0] == "invalidatetiles:")
             {
                 // FIXME temporarily, set the editing on the 1st invalidate, 
TODO extend
@@ -283,6 +287,7 @@ bool MasterProcessSession::handleInput(const char *buffer, 
int length)
     }
     else if (tokens[0] != "canceltiles" &&
              tokens[0] != "commandvalues" &&
+             tokens[0] != "partpagerectangles" &&
              tokens[0] != "gettextselection" &&
              tokens[0] != "invalidatetiles" &&
              tokens[0] != "key" &&
@@ -315,6 +320,10 @@ bool MasterProcessSession::handleInput(const char *buffer, 
int length)
     {
         return getCommandValues(buffer, length, tokens);
     }
+    else if (tokens[0] == "partpagerectangles")
+    {
+        return getPartPageRectangles(buffer, length);
+    }
     else if (tokens[0] == "invalidatetiles")
     {
         return invalidateTiles(buffer, length, tokens);
@@ -454,6 +463,21 @@ bool MasterProcessSession::getCommandValues(const char 
*buffer, int length, Stri
     return true;
 }
 
+bool MasterProcessSession::getPartPageRectangles(const char *buffer, int 
length)
+{
+    std::string partPageRectangles = 
_tileCache->getTextFile("partpagerectangles.txt");
+    if (partPageRectangles.size() > 0)
+    {
+        sendTextFrame(partPageRectangles);
+        return true;
+    }
+
+    if (_peer.expired())
+        dispatchChild();
+    forwardToPeer(buffer, length);
+    return true;
+}
+
 void MasterProcessSession::sendTile(const char *buffer, int length, 
StringTokenizer& tokens)
 {
     int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight;
@@ -633,6 +657,10 @@ bool ChildProcessSession::handleInput(const char *buffer, 
int length)
     {
         return getCommandValues(buffer, length, tokens);
     }
+    if (tokens[0] == "partpagerectangles")
+    {
+        return getPartPageRectangles(buffer, length);
+    }
     if (tokens[0] == "load")
     {
         if (_docURL != "")
@@ -895,6 +923,12 @@ bool ChildProcessSession::getCommandValues(const char 
*buffer, int length, Strin
     return true;
 }
 
+bool ChildProcessSession::getPartPageRectangles(const char* /*buffer*/, int 
/*length*/)
+{
+    sendTextFrame("partpagerectangles: " + 
std::string(_loKitDocument->pClass->getPartPageRectangles(_loKitDocument)));
+    return true;
+}
+
 void ChildProcessSession::sendTile(const char *buffer, int length, 
StringTokenizer& tokens)
 {
     int part, width, height, tilePosX, tilePosY, tileWidth, tileHeight;
diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp
index 247012c..13970c6 100644
--- a/loolwsd/LOOLSession.hpp
+++ b/loolwsd/LOOLSession.hpp
@@ -47,6 +47,8 @@ public:
 
     virtual bool getCommandValues(const char *buffer, int length, 
Poco::StringTokenizer& tokens) = 0;
 
+    virtual bool getPartPageRectangles(const char *buffer, int length) = 0;
+
     virtual bool handleInput(const char *buffer, int length) = 0;
 
 protected:
@@ -113,6 +115,8 @@ public:
 
     virtual bool getCommandValues(const char *buffer, int length, 
Poco::StringTokenizer& tokens);
 
+    virtual bool getPartPageRectangles(const char *buffer, int length) 
override;
+
  protected:
     bool invalidateTiles(const char *buffer, int length, 
Poco::StringTokenizer& tokens);
 
@@ -161,6 +165,8 @@ public:
 
     virtual bool getCommandValues(const char *buffer, int length, 
Poco::StringTokenizer& tokens);
 
+    virtual bool getPartPageRectangles(const char *buffer, int length) 
override;
+
     LibreOfficeKitDocument *_loKitDocument;
     std::string _docType;
 
commit d8a4499567712ae5dd9cda99e18ff5124404e05f
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Tue Sep 29 12:27:27 2015 +0200

    loolwsd: update bundled LOK headers

diff --git a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h 
b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h
index 8060f0e..d83dd49 100644
--- a/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/loolwsd/bundled/include/LibreOfficeKit/LibreOfficeKit.h
@@ -54,6 +54,9 @@ struct _LibreOfficeKitClass
     void (*registerCallback) (LibreOfficeKit* pThis,
                               LibreOfficeKitCallback pCallback,
                               void* pData);
+
+    /// @see lok::Office::getFilterTypes().
+    char* (*getFilterTypes) (LibreOfficeKit* pThis);
 #endif
 };
 
@@ -82,6 +85,9 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::getParts().
     int (*getParts) (LibreOfficeKitDocument* pThis);
 
+    /// @see lok::Document::getPartPageRectangles().
+    char* (*getPartPageRectangles) (LibreOfficeKitDocument* pThis);
+
     /// @see lok::Document::getPart().
     int (*getPart) (LibreOfficeKitDocument* pThis);
 
@@ -93,10 +99,7 @@ struct _LibreOfficeKitDocumentClass
     char* (*getPartName) (LibreOfficeKitDocument* pThis,
                           int nPart);
 
-    /** Sets mode of the current part.
-     *
-     * @param nMode - element from the LibreOfficeKitPartMode enum.
-     */
+    /// @see lok::Document::setPartMode().
     void (*setPartMode) (LibreOfficeKitDocument* pThis,
                          int nMode);
 
@@ -118,6 +121,7 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::initializeForRendering().
     void (*initializeForRendering) (LibreOfficeKitDocument* pThis);
 
+    /// @see lok::Document::registerCallback().
     void (*registerCallback) (LibreOfficeKitDocument* pThis,
                               LibreOfficeKitCallback pCallback,
                               void* pData);
@@ -160,8 +164,19 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::resetSelection
     void (*resetSelection) (LibreOfficeKitDocument* pThis);
 
-    /// @see lok::Document:getStyles
+    /// @see lok::Document::getCommandValues().
     char* (*getCommandValues) (LibreOfficeKitDocument* pThis, const char* 
pCommand);
+
+    /// @see lok::Document::createView().
+    int (*createView) (LibreOfficeKitDocument* pThis);
+    /// @see lok::Document::destroyView().
+    void (*destroyView) (LibreOfficeKitDocument* pThis, int nId);
+    /// @see lok::Document::setView().
+    void (*setView) (LibreOfficeKitDocument* pThis, int nId);
+    /// @see lok::Document::getView().
+    int (*getView) (LibreOfficeKitDocument* pThis);
+    /// @see lok::Document::getViews().
+    int (*getViews) (LibreOfficeKitDocument* pThis);
 #endif // LOK_USE_UNSTABLE_API
 };
 
commit fdc739d85732ccec3b176c8cd279517b15dffb5b
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Tue Sep 29 11:15:02 2015 +0200

    loolwsd: implement a 'make tags'

diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index 07b68ca..9e1f143 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -34,3 +34,7 @@ all-local: loolwsd
                sudo chown root loolwsd && sudo chmod u+s loolwsd; \
            fi; \
        fi
+
+tags:
+       ctags --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes \
+               --exclude=jails *
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to