Blame SOURCES/0050-lokdocview-Restructure-this-GObject-class.patch

f325b2
From 90cd5fdf14031c259ddc4f9ecf9ada7c37fcf421 Mon Sep 17 00:00:00 2001
f325b2
From: Pranav Kant <pranavk@gnome.org>
f325b2
Date: Thu, 11 Jun 2015 22:00:11 +0530
f325b2
Subject: [PATCH 050/398] lokdocview: Restructure this GObject class
f325b2
f325b2
This is a big messy commit restructuring the whole class to follow most
f325b2
common practices followed by standard GObject classes, so that it can
f325b2
keep gobject-introspection happy; hence, allowing this widget to be used
f325b2
from other languages.
f325b2
f325b2
(cherry picked from commit 3061e486f9f9313c15cba6782edfaee96fe4f83d)
f325b2
f325b2
Change-Id: I10c34dad402d1ec586958b2db21ff44412c36cea
f325b2
---
f325b2
 include/LibreOfficeKit/LibreOfficeKitGtk.h         |   17 +-
f325b2
 .../qa/gtktiledviewer/gtktiledviewer.cxx           |    4 +-
f325b2
 libreofficekit/source/gtk/lokdocview.cxx           | 1856 +++++++++++---------
f325b2
 3 files changed, 1041 insertions(+), 836 deletions(-)
f325b2
f325b2
diff --git a/include/LibreOfficeKit/LibreOfficeKitGtk.h b/include/LibreOfficeKit/LibreOfficeKitGtk.h
f325b2
index bdd2e9ab90e3..7048dbefc0a1 100644
f325b2
--- a/include/LibreOfficeKit/LibreOfficeKitGtk.h
f325b2
+++ b/include/LibreOfficeKit/LibreOfficeKitGtk.h
f325b2
@@ -25,23 +25,19 @@ G_BEGIN_DECLS
f325b2
 #define LOK_IS_DOC_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  LOK_TYPE_DOC_VIEW))
f325b2
 #define LOK_DOC_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  LOK_TYPE_DOC_VIEW, LOKDocViewClass))
f325b2
 
f325b2
-
f325b2
-typedef struct _LOKDocView       LOKDocView;
f325b2
-typedef struct _LOKDocViewClass  LOKDocViewClass;
f325b2
+typedef struct _LOKDocView        LOKDocView;
f325b2
+typedef struct _LOKDocViewClass   LOKDocViewClass;
f325b2
+typedef struct _LOKDocViewPrivate LOKDocViewPrivate;
f325b2
 
f325b2
 struct _LOKDocView
f325b2
 {
f325b2
     GtkDrawingArea aDrawingArea;
f325b2
-    struct LOKDocView_Impl* m_pImpl;
f325b2
+    LOKDocViewPrivate* priv;
f325b2
 };
f325b2
 
f325b2
 struct _LOKDocViewClass
f325b2
 {
f325b2
     GtkDrawingAreaClass parent_class;
f325b2
-    void (* edit_changed)  (LOKDocView* pView, gboolean was_edit);
f325b2
-    void (* command_changed) (LOKDocView* pView, char* new_state);
f325b2
-    void (* search_not_found) (LOKDocView* pView, char* new_state);
f325b2
-    void (* part_changed) (LOKDocView* pView, int new_part);
f325b2
 };
f325b2
 
f325b2
 GType                          lok_doc_view_get_type               (void) G_GNUC_CONST;
f325b2
@@ -78,9 +74,8 @@ void                           lok_doc_view_post_command           (LOKDocView*
f325b2
                                                                     const char* pArguments);
f325b2
 
f325b2
 /// Posts a keyboard event to LibreOfficeKit.
f325b2
-void                           lok_doc_view_post_key               (GtkWidget* pWidget,
f325b2
-                                                                    GdkEventKey* pEvent,
f325b2
-                                                                    gpointer pData);
f325b2
+void                           lok_doc_view_post_key               (LOKDocView* pDocView,
f325b2
+                                                                    GdkEvent* pEvent);
f325b2
 
f325b2
 float                          lok_doc_view_pixel_to_twip          (LOKDocView* pDocView,
f325b2
                                                                     float fInput);
f325b2
diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
f325b2
index 580d5f66f683..8b006797c226 100644
f325b2
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
f325b2
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
f325b2
@@ -145,12 +145,12 @@ static void getVisibleAreaTwips(GdkRectangle* pArea)
f325b2
 
f325b2
 
f325b2
 /// Handles the key-press-event of the window.
f325b2
-static gboolean signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointer pData)
f325b2
+static gboolean signalKey(GtkWidget* /*pWidget*/, GdkEvent* pEvent, gpointer/* pData*/)
f325b2
 {
f325b2
     LOKDocView* pLOKDocView = LOK_DOC_VIEW(pDocView);
f325b2
     if (!gtk_widget_get_visible(pFindbar) && bool(lok_doc_view_get_edit(pLOKDocView)))
f325b2
         {
f325b2
-            lok_doc_view_post_key(pWidget, pEvent, pData);
f325b2
+            lok_doc_view_post_key(pLOKDocView, pEvent);
f325b2
             return TRUE;
f325b2
         }
f325b2
     return FALSE;
f325b2
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
f325b2
index b00556620288..7031be9b6536 100644
f325b2
--- a/libreofficekit/source/gtk/lokdocview.cxx
f325b2
+++ b/libreofficekit/source/gtk/lokdocview.cxx
f325b2
@@ -36,26 +36,30 @@
f325b2
 // Number of handles around a graphic selection.
f325b2
 #define GRAPHIC_HANDLE_COUNT 8
f325b2
 
f325b2
-/// Holds data used by LOKDocView only.
f325b2
-struct LOKDocView_Impl
f325b2
+struct _LOKDocViewPrivate
f325b2
 {
f325b2
-    LOKDocView* m_pDocView;
f325b2
-    TileBuffer m_aTileBuffer;
f325b2
-
f325b2
-    float m_fZoom;
f325b2
-
f325b2
+    gchar* m_aLOPath;
f325b2
+    gchar* m_aDocPath;
f325b2
+    guint m_nLoadProgress;
f325b2
+    gboolean m_bIsLoading;
f325b2
+    gboolean m_bCanZoomIn;
f325b2
+    gboolean m_bCanZoomOut;
f325b2
     LibreOfficeKit* m_pOffice;
f325b2
     LibreOfficeKitDocument* m_pDocument;
f325b2
-    long m_nDocumentWidthTwips;
f325b2
-    long m_nDocumentHeightTwips;
f325b2
+
f325b2
+    TileBuffer m_aTileBuffer;
f325b2
+
f325b2
+    gfloat m_fZoom;
f325b2
+    glong m_nDocumentWidthTwips;
f325b2
+    glong m_nDocumentHeightTwips;
f325b2
     /// View or edit mode.
f325b2
-    bool m_bEdit;
f325b2
+    gboolean m_bEdit;
f325b2
     /// Position and size of the visible cursor.
f325b2
     GdkRectangle m_aVisibleCursor;
f325b2
     /// Cursor overlay is visible or hidden (for blinking).
f325b2
-    bool m_bCursorOverlayVisible;
f325b2
+    gboolean m_bCursorOverlayVisible;
f325b2
     /// Cursor is visible or hidden (e.g. for graphic selection).
f325b2
-    bool m_bCursorVisible;
f325b2
+    gboolean m_bCursorVisible;
f325b2
     /// Time of the last button press.
f325b2
     guint32 m_nLastButtonPressTime;
f325b2
     /// Time of the last button release.
f325b2
@@ -67,7 +71,7 @@ struct LOKDocView_Impl
f325b2
     /// Position and size of the selection end.
f325b2
     GdkRectangle m_aTextSelectionEnd;
f325b2
     GdkRectangle m_aGraphicSelection;
f325b2
-    bool m_bInDragGraphicSelection;
f325b2
+    gboolean m_bInDragGraphicSelection;
f325b2
 
f325b2
     /// @name Start/middle/end handle.
f325b2
     ///@{
f325b2
@@ -76,19 +80,19 @@ struct LOKDocView_Impl
f325b2
     /// Rectangle of the text selection start handle, to know if the user clicked on it or not
f325b2
     GdkRectangle m_aHandleStartRect;
f325b2
     /// If we are in the middle of a drag of the text selection end handle.
f325b2
-    bool m_bInDragStartHandle;
f325b2
+    gboolean m_bInDragStartHandle;
f325b2
     /// Bitmap of the text selection middle handle.
f325b2
     cairo_surface_t* m_pHandleMiddle;
f325b2
     /// Rectangle of the text selection middle handle, to know if the user clicked on it or not
f325b2
     GdkRectangle m_aHandleMiddleRect;
f325b2
     /// If we are in the middle of a drag of the text selection middle handle.
f325b2
-    bool m_bInDragMiddleHandle;
f325b2
+    gboolean m_bInDragMiddleHandle;
f325b2
     /// Bitmap of the text selection end handle.
f325b2
     cairo_surface_t* m_pHandleEnd;
f325b2
     /// Rectangle of the text selection end handle, to know if the user clicked on it or not
f325b2
     GdkRectangle m_aHandleEndRect;
f325b2
     /// If we are in the middle of a drag of the text selection end handle.
f325b2
-    bool m_bInDragEndHandle;
f325b2
+    gboolean m_bInDragEndHandle;
f325b2
     ///@}
f325b2
 
f325b2
     /// @name Graphic handles.
f325b2
@@ -98,103 +102,38 @@ struct LOKDocView_Impl
f325b2
     /// Rectangle of a graphic selection handle, to know if the user clicked on it or not.
f325b2
     GdkRectangle m_aGraphicHandleRects[8];
f325b2
     /// If we are in the middle of a drag of a graphic selection handle.
f325b2
-    bool m_bInDragGraphicHandles[8];
f325b2
+    gboolean m_bInDragGraphicHandles[8];
f325b2
     ///@}
f325b2
-
f325b2
-    /// Callback data, allocated in lok_doc_view_callback_worker(), released in lok_doc_view_callback().
f325b2
-    struct CallbackData
f325b2
-    {
f325b2
-        int m_nType;
f325b2
-        std::string m_aPayload;
f325b2
-        LOKDocView* m_pDocView;
f325b2
-
f325b2
-        CallbackData(int nType, const std::string& rPayload, LOKDocView* pDocView);
f325b2
-    };
f325b2
-
f325b2
-
f325b2
-    LOKDocView_Impl(LOKDocView* pDocView);
f325b2
-    ~LOKDocView_Impl();
f325b2
-    /// Connected to the destroy signal of LOKDocView, deletes its LOKDocView_Impl.
f325b2
-    static void destroy(LOKDocView* pDocView, gpointer pData);
f325b2
-    /// Connected to the draw of the GtkDrawingArea
f325b2
-    static gboolean renderDocument(GtkWidget *widget, cairo_t *cr, gpointer user_data);
f325b2
-    /// Implementation of draw event handler, invoked by renderDocument().
f325b2
-    gboolean renderDocumentImpl(cairo_t* cr);
f325b2
-    /// Receives a key press or release event.
f325b2
-    void signalKey(GdkEventKey* pEvent);
f325b2
-    /*
f325b2
-     * The user drags the handle, which is below the cursor, but wants to move the
f325b2
-     * cursor accordingly.
f325b2
-     *
f325b2
-     * @param pHandle the rectangle of the handle
f325b2
-     * @param pEvent the motion event
f325b2
-     * @param pPoint the computed point (output parameter)
f325b2
-     */
f325b2
-    static void getDragPoint(GdkRectangle* pHandle, GdkEventButton* pEvent, GdkPoint* pPoint);
f325b2
-    /// Receives a button press event.
f325b2
-    static gboolean signalButton(GtkWidget* pEventBox, GdkEventButton* pEvent, LOKDocView* pDocView);
f325b2
-    /// Implementation of button press event handler, invoked by signalButton().
f325b2
-    gboolean signalButtonImpl(GdkEventButton* pEvent);
f325b2
-    /// Receives a motion event.
f325b2
-    static gboolean signalMotion(GtkWidget* pEventBox, GdkEventButton* pEvent, LOKDocView* pDocView);
f325b2
-    /// Implementation of motion event handler, invoked by signalMotion().
f325b2
-    gboolean signalMotionImpl(GdkEventButton* pEvent);
f325b2
-    /// Receives an expose event.
f325b2
-    static gboolean renderOverlay(GtkWidget* pWidget, cairo_t* cr, gpointer userdata);
f325b2
-    /// Implementation of expose event handler (renders cursor and selection overlay), invoked by renderOverlay().
f325b2
-    gboolean renderOverlayImpl(cairo_t *cr);
f325b2
-    /// Is rRectangle empty?
f325b2
-    static bool isEmptyRectangle(const GdkRectangle& rRectangle);
f325b2
-    /*
f325b2
-     * Renders pHandle below an rCursor rectangle on pCairo.
f325b2
-     * @param rRectangle output parameter, the rectangle that contains the rendered handle.
f325b2
-     */
f325b2
-    void renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor, cairo_surface_t* pHandle, GdkRectangle& rRectangle);
f325b2
-    /// Renders pHandle around an rSelection rectangle on pCairo.
f325b2
-    void renderGraphicHandle(cairo_t* pCairo, const GdkRectangle& rSelection, cairo_surface_t* pHandle);
f325b2
-    /// Takes care of the blinking cursor.
f325b2
-    static gboolean handleTimeout(gpointer pData);
f325b2
-    /// Implementation of the timeout handler, invoked by handleTimeout().
f325b2
-    gboolean handleTimeoutImpl();
f325b2
-    /// Returns the GdkRectangle of a x,y,width,height string.
f325b2
-    GdkRectangle payloadToRectangle(const char* pPayload);
f325b2
-    /// Returns the GdkRectangles of a x1,y1,w1,h1;x2,y2,w2,h2;... string.
f325b2
-    std::vector<GdkRectangle> payloadToRectangles(const char* pPayload);
f325b2
-    /// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
f325b2
-    static const char* callbackTypeToString(int nType);
f325b2
-    /// Invoked on the main thread if callbackWorker() requests so.
f325b2
-    static gboolean callback(gpointer pData);
f325b2
-    /// Invoked on the main thread if globalCallbackWorker() requests so.
f325b2
-    static gboolean globalCallback(gpointer pData);
f325b2
-    /// Implementation of the callback handler, invoked by callback();
f325b2
-    gboolean callbackImpl(CallbackData* pCallbackData);
f325b2
-    /// Our LOK callback, runs on the LO thread.
f325b2
-    static void callbackWorker(int nType, const char* pPayload, void* pData);
f325b2
-    /// Implementation of the callback worder handler, invoked by callbackWorker().
f325b2
-    void callbackWorkerImpl(int nType, const char* pPayload);
f325b2
-    /// Our global LOK callback, runs on the LO thread.
f325b2
-    static void globalCallbackWorker(int nType, const char* pPayload, void* pData);
f325b2
-    /// Implementation of the global callback worder handler, invoked by globalCallbackWorker().
f325b2
-    void globalCallbackWorkerImpl(int nType, const char* pPayload);
f325b2
-    /// Command state (various buttons like bold are toggled or not) is changed.
f325b2
-    void commandChanged(const std::string& rPayload);
f325b2
-    /// Search did not find any matches.
f325b2
-    void searchNotFound(const std::string& rPayload);
f325b2
-    /// LOK decided to change parts, need to update UI.
f325b2
-    void setPart(const std::string& rPayload);
f325b2
-    /// Sets the tiles enclosed by rRectangle as invalid in m_aTileBuffer
f325b2
-    void setTilesInvalid(const GdkRectangle& rRectangle);
f325b2
 };
f325b2
 
f325b2
 enum
f325b2
 {
f325b2
+    LOAD_CHANGED,
f325b2
+    LOAD_FAILED,
f325b2
     EDIT_CHANGED,
f325b2
     COMMAND_CHANGED,
f325b2
     SEARCH_NOT_FOUND,
f325b2
     PART_CHANGED,
f325b2
+    HYPERLINK_CLICKED,
f325b2
+
f325b2
     LAST_SIGNAL
f325b2
 };
f325b2
 
f325b2
+enum
f325b2
+{
f325b2
+    PROP_0,
f325b2
+
f325b2
+    PROP_LO_PATH,
f325b2
+    PROP_DOC_PATH,
f325b2
+    PROP_EDITABLE,
f325b2
+    PROP_LOAD_PROGRESS,
f325b2
+    PROP_ZOOM,
f325b2
+    PROP_IS_LOADING,
f325b2
+    PROP_DOC_WIDTH,
f325b2
+    PROP_DOC_HEIGHT,
f325b2
+    PROP_CAN_ZOOM_IN,
f325b2
+    PROP_CAN_ZOOM_OUT
f325b2
+};
f325b2
 
f325b2
 static guint doc_view_signals[LAST_SIGNAL] = { 0 };
f325b2
 
f325b2
@@ -203,15 +142,26 @@ SAL_DLLPUBLIC_EXPORT GType lok_doc_view_get_type();
f325b2
 #pragma GCC diagnostic push
f325b2
 #pragma GCC diagnostic ignored "-Wunused-function"
f325b2
 #endif
f325b2
-G_DEFINE_TYPE(LOKDocView, lok_doc_view, GTK_TYPE_DRAWING_AREA)
f325b2
+G_DEFINE_TYPE_WITH_PRIVATE (LOKDocView, lok_doc_view, GTK_TYPE_DRAWING_AREA)
f325b2
 #ifdef __GNUC__
f325b2
 #pragma GCC diagnostic pop
f325b2
 #endif
f325b2
 
f325b2
-namespace {
f325b2
 
f325b2
-/// Sets rWidth and rHeight from a "width, height" string.
f325b2
-void payloadToSize(const char* pPayload, long& rWidth, long& rHeight)
f325b2
+struct CallbackData
f325b2
+{
f325b2
+    int m_nType;
f325b2
+    std::string m_aPayload;
f325b2
+    LOKDocView* m_pDocView;
f325b2
+
f325b2
+    CallbackData(int nType, const std::string& rPayload, LOKDocView* pDocView)
f325b2
+        : m_nType(nType),
f325b2
+          m_aPayload(rPayload),
f325b2
+          m_pDocView(pDocView) {}
f325b2
+};
f325b2
+
f325b2
+static void
f325b2
+payloadToSize(const char* pPayload, long& rWidth, long& rHeight)
f325b2
 {
f325b2
     rWidth = rHeight = 0;
f325b2
     gchar** ppCoordinates = g_strsplit(pPayload, ", ", 2);
f325b2
@@ -226,177 +176,70 @@ void payloadToSize(const char* pPayload, long& rWidth, long& rHeight)
f325b2
     g_strfreev(ppCoordinates);
f325b2
 }
f325b2
 
f325b2
-}
f325b2
-
f325b2
-
f325b2
-
f325b2
-namespace {
f325b2
-
f325b2
-/// Implementation of the global callback handler, invoked by globalCallback();
f325b2
-gboolean globalCallbackImpl(LOKDocView_Impl::CallbackData* pCallback)
f325b2
+/// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
f325b2
+static const char*
f325b2
+callbackTypeToString (int nType)
f325b2
 {
f325b2
-    switch (pCallback->m_nType)
f325b2
+    switch (nType)
f325b2
     {
f325b2
+    case LOK_CALLBACK_INVALIDATE_TILES:
f325b2
+        return "LOK_CALLBACK_INVALIDATE_TILES";
f325b2
+    case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
f325b2
+        return "LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR";
f325b2
+    case LOK_CALLBACK_TEXT_SELECTION:
f325b2
+        return "LOK_CALLBACK_TEXT_SELECTION";
f325b2
+    case LOK_CALLBACK_TEXT_SELECTION_START:
f325b2
+        return "LOK_CALLBACK_TEXT_SELECTION_START";
f325b2
+    case LOK_CALLBACK_TEXT_SELECTION_END:
f325b2
+        return "LOK_CALLBACK_TEXT_SELECTION_END";
f325b2
+    case LOK_CALLBACK_CURSOR_VISIBLE:
f325b2
+        return "LOK_CALLBACK_CURSOR_VISIBLE";
f325b2
+    case LOK_CALLBACK_GRAPHIC_SELECTION:
f325b2
+        return "LOK_CALLBACK_GRAPHIC_SELECTION";
f325b2
+    case LOK_CALLBACK_HYPERLINK_CLICKED:
f325b2
+        return "LOK_CALLBACK_HYPERLINK_CLICKED";
f325b2
+    case LOK_CALLBACK_STATE_CHANGED:
f325b2
+        return "LOK_CALLBACK_STATE_CHANGED";
f325b2
     case LOK_CALLBACK_STATUS_INDICATOR_START:
f325b2
-    {
f325b2
-    }
f325b2
-    break;
f325b2
+        return "LOK_CALLBACK_STATUS_INDICATOR_START";
f325b2
     case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
f325b2
-    {
f325b2
-    }
f325b2
-    break;
f325b2
+        return "LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE";
f325b2
     case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
f325b2
-    {
f325b2
-    }
f325b2
-    break;
f325b2
-    default:
f325b2
-        g_assert(false);
f325b2
-        break;
f325b2
+        return "LOK_CALLBACK_STATUS_INDICATOR_FINISH";
f325b2
+    case LOK_CALLBACK_SEARCH_NOT_FOUND:
f325b2
+        return "LOK_CALLBACK_SEARCH_NOT_FOUND";
f325b2
+    case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
f325b2
+        return "LOK_CALLBACK_DOCUMENT_SIZE_CHANGED";
f325b2
+    case LOK_CALLBACK_SET_PART:
f325b2
+        return "LOK_CALLBACK_SET_PART";
f325b2
     }
f325b2
-    delete pCallback;
f325b2
-
f325b2
-    return G_SOURCE_REMOVE;
f325b2
-}
f325b2
-
f325b2
-}
f325b2
-
f325b2
-LOKDocView_Impl::CallbackData::CallbackData(int nType, const std::string& rPayload, LOKDocView* pDocView)
f325b2
-    : m_nType(nType),
f325b2
-    m_aPayload(rPayload),
f325b2
-    m_pDocView(pDocView)
f325b2
-{
f325b2
-}
f325b2
-
f325b2
-LOKDocView_Impl::LOKDocView_Impl(LOKDocView* pDocView)
f325b2
-    : m_pDocView(pDocView),
f325b2
-      m_aTileBuffer(TileBuffer(0,0)),
f325b2
-      m_fZoom(1),
f325b2
-      m_pOffice(0),
f325b2
-      m_pDocument(0),
f325b2
-      m_nDocumentWidthTwips(0),
f325b2
-      m_nDocumentHeightTwips(0),
f325b2
-      m_bEdit(false),
f325b2
-      m_aVisibleCursor({0, 0, 0, 0}),
f325b2
-      m_bCursorOverlayVisible(false),
f325b2
-      m_bCursorVisible(true),
f325b2
-      m_nLastButtonPressTime(0),
f325b2
-      m_nLastButtonReleaseTime(0),
f325b2
-      m_aTextSelectionStart({0, 0, 0, 0}),
f325b2
-      m_aTextSelectionEnd({0, 0, 0, 0}),
f325b2
-      m_aGraphicSelection({0, 0, 0, 0}),
f325b2
-      m_bInDragGraphicSelection(false),
f325b2
-
f325b2
-      // Start/middle/end handle.
f325b2
-      m_pHandleStart(0),
f325b2
-      m_aHandleStartRect({0, 0, 0, 0}),
f325b2
-      m_bInDragStartHandle(false),
f325b2
-      m_pHandleMiddle(0),
f325b2
-      m_aHandleMiddleRect({0, 0, 0, 0}),
f325b2
-      m_bInDragMiddleHandle(false),
f325b2
-      m_pHandleEnd(0),
f325b2
-      m_aHandleEndRect({0, 0, 0, 0}),
f325b2
-      m_bInDragEndHandle(false),
f325b2
-
f325b2
-      m_pGraphicHandle(0)
f325b2
-{
f325b2
-    memset(&m_aGraphicHandleRects, 0, sizeof(m_aGraphicHandleRects));
f325b2
-    memset(&m_bInDragGraphicHandles, 0, sizeof(m_bInDragGraphicHandles));
f325b2
-}
f325b2
-
f325b2
-LOKDocView_Impl::~LOKDocView_Impl()
f325b2
-{
f325b2
-    if (m_pDocument)
f325b2
-        m_pDocument->pClass->destroy(m_pDocument);
f325b2
-    if (m_pOffice)
f325b2
-        m_pOffice->pClass->destroy(m_pOffice);
f325b2
-    m_pDocument = 0;
f325b2
-    m_pOffice = 0;
f325b2
-}
f325b2
-
f325b2
-void LOKDocView_Impl::destroy(LOKDocView* pDocView, gpointer /*pData*/)
f325b2
-{
f325b2
-    // We specifically need to destroy the document when closing in order to ensure
f325b2
-    // that lock files etc. are cleaned up.
f325b2
-    delete pDocView->m_pImpl;
f325b2
-}
f325b2
-
f325b2
-gboolean LOKDocView_Impl::renderDocument(GtkWidget* /*widget*/, cairo_t *cr, gpointer userdata)
f325b2
-{
f325b2
-    LOKDocView *pDocView = LOK_DOC_VIEW (userdata);
f325b2
-    return pDocView->m_pImpl->renderDocumentImpl(cr);
f325b2
+    return 0;
f325b2
 }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::renderDocumentImpl(cairo_t *pCairo)
f325b2
+static bool
f325b2
+isEmptyRectangle(const GdkRectangle& rRectangle)
f325b2
 {
f325b2
-    long nDocumentWidthPixels = twipToPixel(m_nDocumentWidthTwips, m_fZoom);
f325b2
-    long nDocumentHeightPixels = twipToPixel(m_nDocumentHeightTwips, m_fZoom);
f325b2
-    // Total number of rows / columns in this document.
f325b2
-    guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
f325b2
-    guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
-    GdkRectangle aVisibleArea;
f325b2
-
f325b2
-    gdk_cairo_get_clip_rectangle (pCairo, &aVisibleArea);
f325b2
-
f325b2
-    aVisibleArea.x = pixelToTwip (aVisibleArea.x, m_fZoom);
f325b2
-    aVisibleArea.y = pixelToTwip (aVisibleArea.y, m_fZoom);
f325b2
-    aVisibleArea.width = pixelToTwip (aVisibleArea.width, m_fZoom);
f325b2
-    aVisibleArea.height = pixelToTwip (aVisibleArea.height, m_fZoom);
f325b2
-
f325b2
-    // Render the tiles.
f325b2
-    for (guint nRow = 0; nRow < nRows; ++nRow)
f325b2
-    {
f325b2
-        for (guint nColumn = 0; nColumn < nColumns; ++nColumn)
f325b2
-        {
f325b2
-            GdkRectangle aTileRectangleTwips, aTileRectanglePixels;
f325b2
-            bool bPaint = true;
f325b2
-
f325b2
-            // Determine size of the tile: the rightmost/bottommost tiles may
f325b2
-            // be smaller, and we need the size to decide if we need to repaint.
f325b2
-            if (nColumn == nColumns - 1)
f325b2
-                aTileRectanglePixels.width = nDocumentWidthPixels - nColumn * nTileSizePixels;
f325b2
-            else
f325b2
-                aTileRectanglePixels.width = nTileSizePixels;
f325b2
-            if (nRow == nRows - 1)
f325b2
-                aTileRectanglePixels.height = nDocumentHeightPixels - nRow * nTileSizePixels;
f325b2
-            else
f325b2
-                aTileRectanglePixels.height = nTileSizePixels;
f325b2
-
f325b2
-            // Determine size and position of the tile in document coordinates,
f325b2
-            // so we can decide if we can skip painting for partial rendering.
f325b2
-            aTileRectangleTwips.x = pixelToTwip(nTileSizePixels, m_fZoom) * nColumn;
f325b2
-            aTileRectangleTwips.y = pixelToTwip(nTileSizePixels, m_fZoom) * nRow;
f325b2
-            aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width, m_fZoom);
f325b2
-            aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height, m_fZoom);
f325b2
-
f325b2
-            if (!gdk_rectangle_intersect(&aVisibleArea, &aTileRectangleTwips, 0))
f325b2
-                bPaint = false;
f325b2
-
f325b2
-            if (bPaint)
f325b2
-            {
f325b2
-                Tile& currentTile = m_aTileBuffer.getTile(nRow, nColumn, m_fZoom);
f325b2
-                GdkPixbuf* pPixBuf = currentTile.getBuffer();
f325b2
-                gdk_cairo_set_source_pixbuf (pCairo, pPixBuf,
f325b2
-                                             twipToPixel(aTileRectangleTwips.x, m_fZoom),
f325b2
-                                             twipToPixel(aTileRectangleTwips.y, m_fZoom));
f325b2
-                cairo_paint(pCairo);
f325b2
-            }
f325b2
-        }
f325b2
-    }
f325b2
-    return FALSE;
f325b2
+    return rRectangle.x == 0 && rRectangle.y == 0 && rRectangle.width == 0 && rRectangle.height == 0;
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::signalKey(GdkEventKey* pEvent)
f325b2
+static void
f325b2
+signalKey (LOKDocView* pDocView, const GdkEvent* pEvent)
f325b2
 {
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
     int nCharCode = 0;
f325b2
     int nKeyCode = 0;
f325b2
+    guint keyval;
f325b2
+    GdkModifierType state;
f325b2
+    gdk_event_get_keyval (pEvent, &keyval);
f325b2
+    gdk_event_get_state (pEvent, &state);
f325b2
 
f325b2
-    if (!m_bEdit)
f325b2
+    if (!priv->m_bEdit)
f325b2
     {
f325b2
         g_info("signalKey: not in edit mode, ignore");
f325b2
         return;
f325b2
     }
f325b2
 
f325b2
-    switch (pEvent->keyval)
f325b2
+    switch (keyval)
f325b2
     {
f325b2
     case GDK_KEY_BackSpace:
f325b2
         nKeyCode = com::sun::star::awt::Key::BACKSPACE;
f325b2
@@ -423,325 +266,300 @@ void LOKDocView_Impl::signalKey(GdkEventKey* pEvent)
f325b2
         nKeyCode = com::sun::star::awt::Key::RIGHT;
f325b2
         break;
f325b2
     default:
f325b2
-        if (pEvent->keyval >= GDK_KEY_F1 && pEvent->keyval <= GDK_KEY_F26)
f325b2
-            nKeyCode = com::sun::star::awt::Key::F1 + (pEvent->keyval - GDK_KEY_F1);
f325b2
+        if (keyval >= GDK_KEY_F1 && keyval <= GDK_KEY_F26)
f325b2
+            nKeyCode = com::sun::star::awt::Key::F1 + (keyval - GDK_KEY_F1);
f325b2
         else
f325b2
-            nCharCode = gdk_keyval_to_unicode(pEvent->keyval);
f325b2
+            nCharCode = gdk_keyval_to_unicode(keyval);
f325b2
     }
f325b2
 
f325b2
     // rsc is not public API, but should be good enough for debugging purposes.
f325b2
     // If this is needed for real, then probably a new param of type
f325b2
     // css::awt::KeyModifier is needed in postKeyEvent().
f325b2
-    if (pEvent->state & GDK_SHIFT_MASK)
f325b2
+    if (state & GDK_SHIFT_MASK)
f325b2
         nKeyCode |= KEY_SHIFT;
f325b2
 
f325b2
     if (pEvent->type == GDK_KEY_RELEASE)
f325b2
-        m_pDocument->pClass->postKeyEvent(m_pDocument, LOK_KEYEVENT_KEYUP, nCharCode, nKeyCode);
f325b2
+        priv->m_pDocument->pClass->postKeyEvent(priv->m_pDocument, LOK_KEYEVENT_KEYUP, nCharCode, nKeyCode);
f325b2
     else
f325b2
-        m_pDocument->pClass->postKeyEvent(m_pDocument, LOK_KEYEVENT_KEYINPUT, nCharCode, nKeyCode);
f325b2
-}
f325b2
-
f325b2
-gboolean LOKDocView_Impl::signalButton(GtkWidget* /*pEventBox*/, GdkEventButton* pEvent, LOKDocView* pDocView)
f325b2
-{
f325b2
-    return pDocView->m_pImpl->signalButtonImpl(pEvent);
f325b2
+        priv->m_pDocument->pClass->postKeyEvent(priv->m_pDocument, LOK_KEYEVENT_KEYINPUT, nCharCode, nKeyCode);
f325b2
 }
f325b2
 
f325b2
-/// Receives a button press event.
f325b2
-gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
f325b2
+static gboolean
f325b2
+handleTimeout (gpointer pData)
f325b2
 {
f325b2
-    g_info("LOKDocView_Impl::signalButton: %d, %d (in twips: %d, %d)", (int)pEvent->x, (int)pEvent->y, (int)pixelToTwip(pEvent->x, m_fZoom), (int)pixelToTwip(pEvent->y, m_fZoom));
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (pData);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
 
f325b2
-    if (pEvent->type == GDK_BUTTON_RELEASE)
f325b2
+    if (priv->m_bEdit)
f325b2
     {
f325b2
-        if (m_bInDragStartHandle)
f325b2
-        {
f325b2
-            g_info("LOKDocView_Impl::signalButton: end of drag start handle");
f325b2
-            m_bInDragStartHandle = false;
f325b2
-            return FALSE;
f325b2
-        }
f325b2
-        else if (m_bInDragMiddleHandle)
f325b2
-        {
f325b2
-            g_info("LOKDocView_Impl::signalButton: end of drag middle handle");
f325b2
-            m_bInDragMiddleHandle = false;
f325b2
-            return FALSE;
f325b2
-        }
f325b2
-        else if (m_bInDragEndHandle)
f325b2
-        {
f325b2
-            g_info("LOKDocView_Impl::signalButton: end of drag end handle");
f325b2
-            m_bInDragEndHandle = false;
f325b2
-            return FALSE;
f325b2
-        }
f325b2
+        if (priv->m_bCursorOverlayVisible)
f325b2
+            priv->m_bCursorOverlayVisible = false;
f325b2
+        else
f325b2
+            priv->m_bCursorOverlayVisible = true;
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
f325b2
+    }
f325b2
 
f325b2
-        for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
-        {
f325b2
-            if (m_bInDragGraphicHandles[i])
f325b2
-            {
f325b2
-                g_info("LOKDocView_Impl::signalButton: end of drag graphic handle #%d", i);
f325b2
-                m_bInDragGraphicHandles[i] = false;
f325b2
-                m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
f325b2
-                return FALSE;
f325b2
-            }
f325b2
-        }
f325b2
+    return G_SOURCE_CONTINUE;
f325b2
+}
f325b2
 
f325b2
-        if (m_bInDragGraphicSelection)
f325b2
-        {
f325b2
-            g_info("LOKDocView_Impl::signalButton: end of drag graphic selection");
f325b2
-            m_bInDragGraphicSelection = false;
f325b2
-            m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
f325b2
-            return FALSE;
f325b2
-        }
f325b2
-    }
f325b2
+static void
f325b2
+commandChanged(LOKDocView* pDocView, const std::string& rString)
f325b2
+{
f325b2
+    g_signal_emit(pDocView, doc_view_signals[COMMAND_CHANGED], 0, rString.c_str());
f325b2
+}
f325b2
 
f325b2
-    if (m_bEdit)
f325b2
-    {
f325b2
-        GdkRectangle aClick;
f325b2
-        aClick.x = pEvent->x;
f325b2
-        aClick.y = pEvent->y;
f325b2
-        aClick.width = 1;
f325b2
-        aClick.height = 1;
f325b2
-        if (pEvent->type == GDK_BUTTON_PRESS)
f325b2
-        {
f325b2
-            if (gdk_rectangle_intersect(&aClick, &m_aHandleStartRect, NULL))
f325b2
-            {
f325b2
-                g_info("LOKDocView_Impl::signalButton: start of drag start handle");
f325b2
-                m_bInDragStartHandle = true;
f325b2
-                return FALSE;
f325b2
-            }
f325b2
-            else if (gdk_rectangle_intersect(&aClick, &m_aHandleMiddleRect, NULL))
f325b2
-            {
f325b2
-                g_info("LOKDocView_Impl::signalButton: start of drag middle handle");
f325b2
-                m_bInDragMiddleHandle = true;
f325b2
-                return FALSE;
f325b2
-            }
f325b2
-            else if (gdk_rectangle_intersect(&aClick, &m_aHandleEndRect, NULL))
f325b2
-            {
f325b2
-                g_info("LOKDocView_Impl::signalButton: start of drag end handle");
f325b2
-                m_bInDragEndHandle = true;
f325b2
-                return FALSE;
f325b2
-            }
f325b2
+static void
f325b2
+searchNotFound(LOKDocView* pDocView, const std::string& rString)
f325b2
+{
f325b2
+    g_signal_emit(pDocView, doc_view_signals[SEARCH_NOT_FOUND], 0, rString.c_str());
f325b2
+}
f325b2
 
f325b2
-            for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
-            {
f325b2
-                if (gdk_rectangle_intersect(&aClick, &m_aGraphicHandleRects[i], NULL))
f325b2
-                {
f325b2
-                    g_info("LOKDocView_Impl::signalButton: start of drag graphic handle #%d", i);
f325b2
-                    m_bInDragGraphicHandles[i] = true;
f325b2
-                    m_pDocument->pClass->setGraphicSelection(m_pDocument,
f325b2
-                                                             LOK_SETGRAPHICSELECTION_START,
f325b2
-                                                             pixelToTwip(m_aGraphicHandleRects[i].x + m_aGraphicHandleRects[i].width / 2, m_fZoom),
f325b2
-                                                             pixelToTwip(m_aGraphicHandleRects[i].y + m_aGraphicHandleRects[i].height / 2, m_fZoom));
f325b2
-                    return FALSE;
f325b2
-                }
f325b2
-            }
f325b2
-        }
f325b2
-    }
f325b2
+static void
f325b2
+setPart(LOKDocView* pDocView, const std::string& rString)
f325b2
+{
f325b2
+    g_signal_emit(pDocView, doc_view_signals[PART_CHANGED], 0, std::stoi(rString));
f325b2
+}
f325b2
 
f325b2
-    if (!m_bEdit)
f325b2
-        lok_doc_view_set_edit(m_pDocView, TRUE);
f325b2
+/// Implementation of the global callback handler, invoked by globalCallback();
f325b2
+static gboolean
f325b2
+globalCallback (gpointer pData)
f325b2
+{
f325b2
+    CallbackData* pCallback = static_cast<CallbackData*>(pData);
f325b2
 
f325b2
-    switch (pEvent->type)
f325b2
+    switch (pCallback->m_nType)
f325b2
     {
f325b2
-    case GDK_BUTTON_PRESS:
f325b2
+    case LOK_CALLBACK_STATUS_INDICATOR_START:
f325b2
     {
f325b2
-        int nCount = 1;
f325b2
-        if ((pEvent->time - m_nLastButtonPressTime) < 250)
f325b2
-            nCount++;
f325b2
-        m_nLastButtonPressTime = pEvent->time;
f325b2
-        m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), nCount);
f325b2
-        break;
f325b2
     }
f325b2
-    case GDK_BUTTON_RELEASE:
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
f325b2
     {
f325b2
-        int nCount = 1;
f325b2
-        if ((pEvent->time - m_nLastButtonReleaseTime) < 250)
f325b2
-            nCount++;
f325b2
-        m_nLastButtonReleaseTime = pEvent->time;
f325b2
-        m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), nCount);
f325b2
-        break;
f325b2
     }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
f325b2
+    {
f325b2
+    }
f325b2
+    break;
f325b2
     default:
f325b2
+        g_assert(false);
f325b2
         break;
f325b2
     }
f325b2
-    return FALSE;
f325b2
+    delete pCallback;
f325b2
+
f325b2
+    return G_SOURCE_REMOVE;
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::getDragPoint(GdkRectangle* pHandle, GdkEventButton* pEvent, GdkPoint* pPoint)
f325b2
+static void
f325b2
+globalCallbackWorker(int nType, const char* pPayload, void* pData)
f325b2
 {
f325b2
-    GdkPoint aCursor, aHandle;
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (pData);
f325b2
 
f325b2
-    // Center of the cursor rectangle: we know that it's above the handle.
f325b2
-    aCursor.x = pHandle->x + pHandle->width / 2;
f325b2
-    aCursor.y = pHandle->y - pHandle->height / 2;
f325b2
-    // Center of the handle rectangle.
f325b2
-    aHandle.x = pHandle->x + pHandle->width / 2;
f325b2
-    aHandle.y = pHandle->y + pHandle->height / 2;
f325b2
-    // Our target is the original cursor position + the dragged offset.
f325b2
-    pPoint->x = aCursor.x + (pEvent->x - aHandle.x);
f325b2
-    pPoint->y = aCursor.y + (pEvent->y - aHandle.y);
f325b2
+    CallbackData* pCallback = new CallbackData(nType, pPayload ? pPayload : "(nil)", pDocView);
f325b2
+    g_info("LOKDocView_Impl::globalCallbackWorkerImpl: %s, '%s'", callbackTypeToString(nType), pPayload);
f325b2
+    gdk_threads_add_idle(globalCallback, pCallback);
f325b2
 }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::signalMotion(GtkWidget* /*pEventBox*/, GdkEventButton* pEvent, LOKDocView* pDocView)
f325b2
+static GdkRectangle
f325b2
+payloadToRectangle (LOKDocView* pDocView, const char* pPayload)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->signalMotionImpl(pEvent);
f325b2
-}
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
+    GdkRectangle aRet;
f325b2
+    gchar** ppCoordinates = g_strsplit(pPayload, ", ", 4);
f325b2
+    gchar** ppCoordinate = ppCoordinates;
f325b2
 
f325b2
-gboolean LOKDocView_Impl::signalMotionImpl(GdkEventButton* pEvent)
f325b2
-{
f325b2
-    GdkPoint aPoint;
f325b2
+    aRet.width = aRet.height = aRet.x = aRet.y = 0;
f325b2
 
f325b2
-    if (m_bInDragMiddleHandle)
f325b2
-    {
f325b2
-        g_info("lcl_signalMotion: dragging the middle handle");
f325b2
-        LOKDocView_Impl::getDragPoint(&m_aHandleMiddleRect, pEvent, &aPoint);
f325b2
-        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_RESET, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
f325b2
-        return FALSE;
f325b2
-    }
f325b2
-    if (m_bInDragStartHandle)
f325b2
-    {
f325b2
-        g_info("lcl_signalMotion: dragging the start handle");
f325b2
-        LOKDocView_Impl::getDragPoint(&m_aHandleStartRect, pEvent, &aPoint);
f325b2
-        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_START, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
f325b2
-        return FALSE;
f325b2
-    }
f325b2
-    if (m_bInDragEndHandle)
f325b2
-    {
f325b2
-        g_info("lcl_signalMotion: dragging the end handle");
f325b2
-        LOKDocView_Impl::getDragPoint(&m_aHandleEndRect, pEvent, &aPoint);
f325b2
-        m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
f325b2
-        return FALSE;
f325b2
-    }
f325b2
-    for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
-    {
f325b2
-        if (m_bInDragGraphicHandles[i])
f325b2
-        {
f325b2
-            g_info("lcl_signalMotion: dragging the graphic handle #%d", i);
f325b2
-            return FALSE;
f325b2
-        }
f325b2
-    }
f325b2
-    if (m_bInDragGraphicSelection)
f325b2
-    {
f325b2
-        g_info("lcl_signalMotion: dragging the graphic selection");
f325b2
-        return FALSE;
f325b2
-    }
f325b2
+    if (!*ppCoordinate)
f325b2
+        return aRet;
f325b2
+    aRet.x = atoi(*ppCoordinate);
f325b2
+    if (aRet.x < 0)
f325b2
+        aRet.x = 0;
f325b2
+    ++ppCoordinate;
f325b2
+    if (!*ppCoordinate)
f325b2
+        return aRet;
f325b2
+    aRet.y = atoi(*ppCoordinate);
f325b2
+    if (aRet.y < 0)
f325b2
+        aRet.y = 0;
f325b2
+    ++ppCoordinate;
f325b2
+    if (!*ppCoordinate)
f325b2
+        return aRet;
f325b2
+    aRet.width = atoi(*ppCoordinate);
f325b2
+    if (aRet.x + aRet.width > priv->m_nDocumentWidthTwips)
f325b2
+        aRet.width = priv->m_nDocumentWidthTwips - aRet.x;
f325b2
+    ++ppCoordinate;
f325b2
+    if (!*ppCoordinate)
f325b2
+        return aRet;
f325b2
+    aRet.height = atoi(*ppCoordinate);
f325b2
+    if (aRet.y + aRet.height > priv->m_nDocumentHeightTwips)
f325b2
+        aRet.height = priv->m_nDocumentHeightTwips - aRet.y;
f325b2
+    g_strfreev(ppCoordinates);
f325b2
 
f325b2
-    GdkRectangle aMotionInTwipsInTwips;
f325b2
-    aMotionInTwipsInTwips.x = pixelToTwip(pEvent->x, m_fZoom);
f325b2
-    aMotionInTwipsInTwips.y = pixelToTwip(pEvent->y, m_fZoom);
f325b2
-    aMotionInTwipsInTwips.width = 1;
f325b2
-    aMotionInTwipsInTwips.height = 1;
f325b2
-    if (gdk_rectangle_intersect(&aMotionInTwipsInTwips, &m_aGraphicSelection, 0))
f325b2
-    {
f325b2
-        g_info("lcl_signalMotion: start of drag graphic selection");
f325b2
-        m_bInDragGraphicSelection = true;
f325b2
-        m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_START, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
f325b2
-        return FALSE;
f325b2
-    }
f325b2
+    return aRet;
f325b2
+}
f325b2
 
f325b2
-    // Otherwise a mouse move, as on the desktop.
f325b2
-    m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEMOVE, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), 1);
f325b2
+static const std::vector<GdkRectangle>
f325b2
+payloadToRectangles(LOKDocView* pDocView, const char* pPayload)
f325b2
+{
f325b2
+    std::vector<GdkRectangle> aRet;
f325b2
 
f325b2
-    return FALSE;
f325b2
+    gchar** ppRectangles = g_strsplit(pPayload, "; ", 0);
f325b2
+    for (gchar** ppRectangle = ppRectangles; *ppRectangle; ++ppRectangle)
f325b2
+        aRet.push_back(payloadToRectangle(pDocView, *ppRectangle));
f325b2
+    g_strfreev(ppRectangles);
f325b2
+
f325b2
+    return aRet;
f325b2
 }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::renderOverlay(GtkWidget* /*widget*/, cairo_t *cr, gpointer userdata)
f325b2
+
f325b2
+static void
f325b2
+setTilesInvalid (LOKDocView* pDocView, const GdkRectangle& rRectangle)
f325b2
 {
f325b2
-    LOKDocView *pDocView = LOK_DOC_VIEW (userdata);
f325b2
-    return pDocView->m_pImpl->renderOverlayImpl(cr);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
+    GdkRectangle aRectanglePixels;
f325b2
+    GdkPoint aStart, aEnd;
f325b2
+
f325b2
+    aRectanglePixels.x = twipToPixel(rRectangle.x, priv->m_fZoom);
f325b2
+    aRectanglePixels.y = twipToPixel(rRectangle.y, priv->m_fZoom);
f325b2
+    aRectanglePixels.width = twipToPixel(rRectangle.width, priv->m_fZoom);
f325b2
+    aRectanglePixels.height = twipToPixel(rRectangle.height, priv->m_fZoom);
f325b2
+
f325b2
+    aStart.x = aRectanglePixels.y / nTileSizePixels;
f325b2
+    aStart.y = aRectanglePixels.x / nTileSizePixels;
f325b2
+    aEnd.x = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
f325b2
+    aEnd.y = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
f325b2
+
f325b2
+    for (int i = aStart.x; i < aEnd.x; i++)
f325b2
+        for (int j = aStart.y; j < aEnd.y; j++)
f325b2
+            priv->m_aTileBuffer.setInvalid(i, j);
f325b2
 }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::renderOverlayImpl(cairo_t *pCairo)
f325b2
+static gboolean
f325b2
+callback (gpointer pData)
f325b2
 {
f325b2
-    if (m_bEdit && m_bCursorVisible && m_bCursorOverlayVisible && !isEmptyRectangle(m_aVisibleCursor))
f325b2
-    {
f325b2
-        if (m_aVisibleCursor.width < 30)
f325b2
-            // Set a minimal width if it would be 0.
f325b2
-            m_aVisibleCursor.width = 30;
f325b2
+    CallbackData* pCallback = static_cast<CallbackData*>(pData);
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (pCallback->m_pDocView);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
 
f325b2
-        cairo_set_source_rgb(pCairo, 0, 0, 0);
f325b2
-        cairo_rectangle(pCairo,
f325b2
-                        twipToPixel(m_aVisibleCursor.x, m_fZoom),
f325b2
-                        twipToPixel(m_aVisibleCursor.y, m_fZoom),
f325b2
-                        twipToPixel(m_aVisibleCursor.width, m_fZoom),
f325b2
-                        twipToPixel(m_aVisibleCursor.height, m_fZoom));
f325b2
-        cairo_fill(pCairo);
f325b2
-    }
f325b2
-
f325b2
-    if (m_bEdit && m_bCursorVisible && !isEmptyRectangle(m_aVisibleCursor) && m_aTextSelectionRectangles.empty())
f325b2
+    switch (pCallback->m_nType)
f325b2
     {
f325b2
-        // Have a cursor, but no selection: we need the middle handle.
f325b2
-        if (!m_pHandleMiddle)
f325b2
-            m_pHandleMiddle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_middle.png");
f325b2
-        renderHandle(pCairo, m_aVisibleCursor, m_pHandleMiddle, m_aHandleMiddleRect);
f325b2
-    }
f325b2
-
f325b2
-    if (!m_aTextSelectionRectangles.empty())
f325b2
+    case LOK_CALLBACK_INVALIDATE_TILES:
f325b2
     {
f325b2
-        for (GdkRectangle& rRectangle : m_aTextSelectionRectangles)
f325b2
+        if (pCallback->m_aPayload != "EMPTY")
f325b2
         {
f325b2
-            // Blue with 75% transparency.
f325b2
-            cairo_set_source_rgba(pCairo, ((double)0x43)/255, ((double)0xac)/255, ((double)0xe8)/255, 0.25);
f325b2
-            cairo_rectangle(pCairo,
f325b2
-                            twipToPixel(rRectangle.x, m_fZoom),
f325b2
-                            twipToPixel(rRectangle.y, m_fZoom),
f325b2
-                            twipToPixel(rRectangle.width, m_fZoom),
f325b2
-                            twipToPixel(rRectangle.height, m_fZoom));
f325b2
-            cairo_fill(pCairo);
f325b2
+            GdkRectangle aRectangle = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
f325b2
+            setTilesInvalid(pDocView, aRectangle);
f325b2
         }
f325b2
+        else
f325b2
+            priv->m_aTileBuffer.resetAllTiles();
f325b2
 
f325b2
-        // Handles
f325b2
-        if (!isEmptyRectangle(m_aTextSelectionStart))
f325b2
-        {
f325b2
-            // Have a start position: we need a start handle.
f325b2
-            if (!m_pHandleStart)
f325b2
-                m_pHandleStart = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_start.png");
f325b2
-            renderHandle(pCairo, m_aTextSelectionStart, m_pHandleStart, m_aHandleStartRect);
f325b2
-        }
f325b2
-        if (!isEmptyRectangle(m_aTextSelectionEnd))
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
f325b2
+    {
f325b2
+        priv->m_aVisibleCursor = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
f325b2
+        priv->m_bCursorOverlayVisible = true;
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_TEXT_SELECTION:
f325b2
+    {
f325b2
+        priv->m_aTextSelectionRectangles = payloadToRectangles(pDocView, pCallback->m_aPayload.c_str());
f325b2
+        // In case the selection is empty, then we get no LOK_CALLBACK_TEXT_SELECTION_START/END events.
f325b2
+        if (priv->m_aTextSelectionRectangles.empty())
f325b2
         {
f325b2
-            // Have a start position: we need an end handle.
f325b2
-            if (!m_pHandleEnd)
f325b2
-                m_pHandleEnd = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_end.png");
f325b2
-            renderHandle(pCairo, m_aTextSelectionEnd, m_pHandleEnd, m_aHandleEndRect);
f325b2
+            memset(&priv->m_aTextSelectionStart, 0, sizeof(priv->m_aTextSelectionStart));
f325b2
+            memset(&priv->m_aHandleStartRect, 0, sizeof(priv->m_aHandleStartRect));
f325b2
+            memset(&priv->m_aTextSelectionEnd, 0, sizeof(priv->m_aTextSelectionEnd));
f325b2
+            memset(&priv->m_aHandleEndRect, 0, sizeof(priv->m_aHandleEndRect));
f325b2
         }
f325b2
+        else
f325b2
+            memset(&priv->m_aHandleMiddleRect, 0, sizeof(priv->m_aHandleMiddleRect));
f325b2
     }
f325b2
-
f325b2
-    if (!isEmptyRectangle(m_aGraphicSelection))
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_TEXT_SELECTION_START:
f325b2
     {
f325b2
-        if (!m_pGraphicHandle)
f325b2
-            m_pGraphicHandle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_graphic.png");
f325b2
-        renderGraphicHandle(pCairo, m_aGraphicSelection, m_pGraphicHandle);
f325b2
+        priv->m_aTextSelectionStart = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
f325b2
     }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_TEXT_SELECTION_END:
f325b2
+    {
f325b2
+        priv->m_aTextSelectionEnd = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_CURSOR_VISIBLE:
f325b2
+    {
f325b2
+        priv->m_bCursorVisible = pCallback->m_aPayload == "true";
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_GRAPHIC_SELECTION:
f325b2
+    {
f325b2
+        if (pCallback->m_aPayload != "EMPTY")
f325b2
+            priv->m_aGraphicSelection = payloadToRectangle(pDocView, pCallback->m_aPayload.c_str());
f325b2
+        else
f325b2
+            memset(&priv->m_aGraphicSelection, 0, sizeof(priv->m_aGraphicSelection));
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView));
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_HYPERLINK_CLICKED:
f325b2
+    {
f325b2
+        GError* pError = NULL;
f325b2
+        gtk_show_uri(NULL, pCallback->m_aPayload.c_str(), GDK_CURRENT_TIME, &pError);
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_STATE_CHANGED:
f325b2
+    {
f325b2
+        commandChanged(pDocView, pCallback->m_aPayload);
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_SEARCH_NOT_FOUND:
f325b2
+    {
f325b2
+        searchNotFound(pDocView, pCallback->m_aPayload);
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
f325b2
+    {
f325b2
+        g_info ("%d %d", priv->m_nDocumentWidthTwips, priv->m_nDocumentHeightTwips);
f325b2
+        g_info ("startin");
f325b2
+        payloadToSize(pCallback->m_aPayload.c_str(), priv->m_nDocumentWidthTwips, priv->m_nDocumentHeightTwips);
f325b2
+        g_info ("%d %d", priv->m_nDocumentWidthTwips, priv->m_nDocumentHeightTwips);
f325b2
+        gtk_widget_set_size_request(GTK_WIDGET(pDocView),
f325b2
+                                    twipToPixel(priv->m_nDocumentWidthTwips, priv->m_fZoom),
f325b2
+                                    twipToPixel(priv->m_nDocumentHeightTwips, priv->m_fZoom));
f325b2
+    }
f325b2
+    break;
f325b2
+    case LOK_CALLBACK_SET_PART:
f325b2
+    {
f325b2
+        setPart(pDocView, pCallback->m_aPayload);
f325b2
+    }
f325b2
+    break;
f325b2
+    default:
f325b2
+        g_assert(false);
f325b2
+        break;
f325b2
+    }
f325b2
+    delete pCallback;
f325b2
 
f325b2
-    return FALSE;
f325b2
-}
f325b2
-
f325b2
-bool LOKDocView_Impl::isEmptyRectangle(const GdkRectangle& rRectangle)
f325b2
-{
f325b2
-    return rRectangle.x == 0 && rRectangle.y == 0 && rRectangle.width == 0 && rRectangle.height == 0;
f325b2
+    return G_SOURCE_REMOVE;
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::setTilesInvalid(const GdkRectangle& rRectangle)
f325b2
+static void
f325b2
+callbackWorker (int nType, const char* pPayload, void* pData)
f325b2
 {
f325b2
-    GdkRectangle aRectanglePixels;
f325b2
-    GdkPoint aStart, aEnd;
f325b2
-
f325b2
-    aRectanglePixels.x = twipToPixel(rRectangle.x, m_fZoom);
f325b2
-    aRectanglePixels.y = twipToPixel(rRectangle.y, m_fZoom);
f325b2
-    aRectanglePixels.width = twipToPixel(rRectangle.width, m_fZoom);
f325b2
-    aRectanglePixels.height = twipToPixel(rRectangle.height, m_fZoom);
f325b2
-
f325b2
-    aStart.x = aRectanglePixels.y / nTileSizePixels;
f325b2
-    aStart.y = aRectanglePixels.x / nTileSizePixels;
f325b2
-    aEnd.x = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
f325b2
-    aEnd.y = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (pData);
f325b2
 
f325b2
-    for (int i = aStart.x; i < aEnd.x; i++)
f325b2
-        for (int j = aStart.y; j < aEnd.y; j++)
f325b2
-            m_aTileBuffer.setInvalid(i, j);
f325b2
+    CallbackData* pCallback = new CallbackData(nType, pPayload ? pPayload : "(nil)", pDocView);
f325b2
+    g_info("lok_doc_view_callbackWorker: %s, '%s'", callbackTypeToString(nType), pPayload);
f325b2
+    gdk_threads_add_idle(callback, pCallback);
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor, cairo_surface_t* pHandle, GdkRectangle& rRectangle)
f325b2
+static void
f325b2
+renderHandle(LOKDocView* pDocView,
f325b2
+             cairo_t* pCairo,
f325b2
+             const GdkRectangle& rCursor,
f325b2
+             cairo_surface_t* pHandle,
f325b2
+             GdkRectangle& rRectangle)
f325b2
 {
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
     GdkPoint aCursorBottom;
f325b2
     int nHandleWidth, nHandleHeight;
f325b2
     double fHandleScale;
f325b2
@@ -749,16 +567,17 @@ void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor,
f325b2
     nHandleWidth = cairo_image_surface_get_width(pHandle);
f325b2
     nHandleHeight = cairo_image_surface_get_height(pHandle);
f325b2
     // We want to scale down the handle, so that its height is the same as the cursor caret.
f325b2
-    fHandleScale = twipToPixel(rCursor.height, m_fZoom) / nHandleHeight;
f325b2
+    fHandleScale = twipToPixel(rCursor.height, priv->m_fZoom) / nHandleHeight;
f325b2
     // We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
f325b2
-    aCursorBottom.x = twipToPixel(rCursor.x, m_fZoom) + twipToPixel(rCursor.width, m_fZoom) / 2 - (nHandleWidth * fHandleScale) / 2;
f325b2
-    aCursorBottom.y = twipToPixel(rCursor.y, m_fZoom) + twipToPixel(rCursor.height, m_fZoom);
f325b2
-    cairo_save(pCairo);
f325b2
+    aCursorBottom.x = twipToPixel(rCursor.x, priv->m_fZoom) + twipToPixel(rCursor.width, priv->m_fZoom) / 2 - (nHandleWidth * fHandleScale) / 2;
f325b2
+    aCursorBottom.y = twipToPixel(rCursor.y, priv->m_fZoom) + twipToPixel(rCursor.height, priv->m_fZoom);
f325b2
+
f325b2
+    cairo_save (pCairo);
f325b2
     cairo_translate(pCairo, aCursorBottom.x, aCursorBottom.y);
f325b2
     cairo_scale(pCairo, fHandleScale, fHandleScale);
f325b2
     cairo_set_source_surface(pCairo, pHandle, 0, 0);
f325b2
     cairo_paint(pCairo);
f325b2
-    cairo_restore(pCairo);
f325b2
+    cairo_restore (pCairo);
f325b2
 
f325b2
     rRectangle.x = aCursorBottom.x;
f325b2
     rRectangle.y = aCursorBottom.y;
f325b2
@@ -767,23 +586,27 @@ void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor,
f325b2
 }
f325b2
 
f325b2
 /// Renders pHandle around an rSelection rectangle on pCairo.
f325b2
-void LOKDocView_Impl::renderGraphicHandle(cairo_t* pCairo, const GdkRectangle& rSelection, cairo_surface_t* pHandle)
f325b2
+static void
f325b2
+renderGraphicHandle(LOKDocView* pDocView,
f325b2
+                    cairo_t* pCairo,
f325b2
+                    const GdkRectangle& rSelection,
f325b2
+                    cairo_surface_t* pHandle)
f325b2
 {
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
     int nHandleWidth, nHandleHeight;
f325b2
     GdkRectangle aSelection;
f325b2
 
f325b2
     nHandleWidth = cairo_image_surface_get_width(pHandle);
f325b2
     nHandleHeight = cairo_image_surface_get_height(pHandle);
f325b2
 
f325b2
-    aSelection.x = twipToPixel(rSelection.x, m_fZoom);
f325b2
-    aSelection.y = twipToPixel(rSelection.y, m_fZoom);
f325b2
-    aSelection.width = twipToPixel(rSelection.width, m_fZoom);
f325b2
-    aSelection.height = twipToPixel(rSelection.height, m_fZoom);
f325b2
+    aSelection.x = twipToPixel(rSelection.x, priv->m_fZoom);
f325b2
+    aSelection.y = twipToPixel(rSelection.y, priv->m_fZoom);
f325b2
+    aSelection.width = twipToPixel(rSelection.width, priv->m_fZoom);
f325b2
+    aSelection.height = twipToPixel(rSelection.height, priv->m_fZoom);
f325b2
 
f325b2
     for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
     {
f325b2
         int x = aSelection.x, y = aSelection.y;
f325b2
-        cairo_save(pCairo);
f325b2
 
f325b2
         switch (i)
f325b2
         {
f325b2
@@ -819,364 +642,722 @@ void LOKDocView_Impl::renderGraphicHandle(cairo_t* pCairo, const GdkRectangle& r
f325b2
         x -= nHandleWidth / 2;
f325b2
         y -= nHandleHeight / 2;
f325b2
 
f325b2
-        m_aGraphicHandleRects[i].x = x;
f325b2
-        m_aGraphicHandleRects[i].y = y;
f325b2
-        m_aGraphicHandleRects[i].width = nHandleWidth;
f325b2
-        m_aGraphicHandleRects[i].height = nHandleHeight;
f325b2
+        priv->m_aGraphicHandleRects[i].x = x;
f325b2
+        priv->m_aGraphicHandleRects[i].y = y;
f325b2
+        priv->m_aGraphicHandleRects[i].width = nHandleWidth;
f325b2
+        priv->m_aGraphicHandleRects[i].height = nHandleHeight;
f325b2
 
f325b2
+        cairo_save (pCairo);
f325b2
         cairo_translate(pCairo, x, y);
f325b2
         cairo_set_source_surface(pCairo, pHandle, 0, 0);
f325b2
         cairo_paint(pCairo);
f325b2
-        cairo_restore(pCairo);
f325b2
+        cairo_restore (pCairo);
f325b2
     }
f325b2
 }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::handleTimeout(gpointer pData)
f325b2
-{
f325b2
-    LOKDocView* pDocView = static_cast<LOKDocView*>(pData);
f325b2
-    return pDocView->m_pImpl->handleTimeoutImpl();
f325b2
-}
f325b2
 
f325b2
-gboolean LOKDocView_Impl::handleTimeoutImpl()
f325b2
+static gboolean
f325b2
+renderDocument(LOKDocView* pDocView, cairo_t* pCairo)
f325b2
 {
f325b2
-    if (m_bEdit)
f325b2
+    LOKDocViewPrivate *priv = pDocView->priv;
f325b2
+    GdkRectangle aVisibleArea;
f325b2
+    long nDocumentWidthPixels = twipToPixel(priv->m_nDocumentWidthTwips, priv->m_fZoom);
f325b2
+    long nDocumentHeightPixels = twipToPixel(priv->m_nDocumentHeightTwips, priv->m_fZoom);
f325b2
+    // Total number of rows / columns in this document.
f325b2
+    guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
f325b2
+    guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
+
f325b2
+    gdk_cairo_get_clip_rectangle (pCairo, &aVisibleArea);
f325b2
+    aVisibleArea.x = pixelToTwip (aVisibleArea.x, priv->m_fZoom);
f325b2
+    aVisibleArea.y = pixelToTwip (aVisibleArea.y, priv->m_fZoom);
f325b2
+    aVisibleArea.width = pixelToTwip (aVisibleArea.width, priv->m_fZoom);
f325b2
+    aVisibleArea.height = pixelToTwip (aVisibleArea.height, priv->m_fZoom);
f325b2
+
f325b2
+    // Render the tiles.
f325b2
+    for (guint nRow = 0; nRow < nRows; ++nRow)
f325b2
     {
f325b2
-        if (m_bCursorOverlayVisible)
f325b2
-            m_bCursorOverlayVisible = false;
f325b2
-        else
f325b2
-            m_bCursorOverlayVisible = true;
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pDocView));
f325b2
-    }
f325b2
+        for (guint nColumn = 0; nColumn < nColumns; ++nColumn)
f325b2
+        {
f325b2
+            GdkRectangle aTileRectangleTwips, aTileRectanglePixels;
f325b2
+            bool bPaint = true;
f325b2
 
f325b2
-    return G_SOURCE_CONTINUE;
f325b2
-}
f325b2
+            // Determine size of the tile: the rightmost/bottommost tiles may
f325b2
+            // be smaller, and we need the size to decide if we need to repaint.
f325b2
+            if (nColumn == nColumns - 1)
f325b2
+                aTileRectanglePixels.width = nDocumentWidthPixels - nColumn * nTileSizePixels;
f325b2
+            else
f325b2
+                aTileRectanglePixels.width = nTileSizePixels;
f325b2
+            if (nRow == nRows - 1)
f325b2
+                aTileRectanglePixels.height = nDocumentHeightPixels - nRow * nTileSizePixels;
f325b2
+            else
f325b2
+                aTileRectanglePixels.height = nTileSizePixels;
f325b2
 
f325b2
-GdkRectangle LOKDocView_Impl::payloadToRectangle(const char* pPayload)
f325b2
-{
f325b2
-    GdkRectangle aRet;
f325b2
+            // Determine size and position of the tile in document coordinates,
f325b2
+            // so we can decide if we can skip painting for partial rendering.
f325b2
+            aTileRectangleTwips.x = pixelToTwip(nTileSizePixels, priv->m_fZoom) * nColumn;
f325b2
+            aTileRectangleTwips.y = pixelToTwip(nTileSizePixels, priv->m_fZoom) * nRow;
f325b2
+            aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width, priv->m_fZoom);
f325b2
+            aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height, priv->m_fZoom);
f325b2
 
f325b2
-    aRet.width = aRet.height = aRet.x = aRet.y = 0;
f325b2
-    gchar** ppCoordinates = g_strsplit(pPayload, ", ", 4);
f325b2
-    gchar** ppCoordinate = ppCoordinates;
f325b2
-    if (!*ppCoordinate)
f325b2
-        return aRet;
f325b2
-    aRet.x = atoi(*ppCoordinate);
f325b2
-    if (aRet.x < 0)
f325b2
-        aRet.x = 0;
f325b2
-    ++ppCoordinate;
f325b2
-    if (!*ppCoordinate)
f325b2
-        return aRet;
f325b2
-    aRet.y = atoi(*ppCoordinate);
f325b2
-    if (aRet.y < 0)
f325b2
-        aRet.y = 0;
f325b2
-    ++ppCoordinate;
f325b2
-    if (!*ppCoordinate)
f325b2
-        return aRet;
f325b2
-    aRet.width = atoi(*ppCoordinate);
f325b2
-    if (aRet.x + aRet.width > m_nDocumentWidthTwips)
f325b2
-        aRet.width = m_nDocumentWidthTwips - aRet.x;
f325b2
-    ++ppCoordinate;
f325b2
-    if (!*ppCoordinate)
f325b2
-        return aRet;
f325b2
-    aRet.height = atoi(*ppCoordinate);
f325b2
-    if (aRet.y + aRet.height > m_nDocumentHeightTwips)
f325b2
-        aRet.height = m_nDocumentHeightTwips - aRet.y;
f325b2
-    g_strfreev(ppCoordinates);
f325b2
-    return aRet;
f325b2
+            if (!gdk_rectangle_intersect(&aVisibleArea, &aTileRectangleTwips, 0))
f325b2
+                bPaint = false;
f325b2
+
f325b2
+            if (bPaint)
f325b2
+            {
f325b2
+                Tile& currentTile = priv->m_aTileBuffer.getTile(nRow, nColumn, priv->m_fZoom);
f325b2
+                GdkPixbuf* pPixBuf = currentTile.getBuffer();
f325b2
+                gdk_cairo_set_source_pixbuf (pCairo, pPixBuf,
f325b2
+                                             twipToPixel(aTileRectangleTwips.x, priv->m_fZoom),
f325b2
+                                             twipToPixel(aTileRectangleTwips.y, priv->m_fZoom));
f325b2
+                cairo_paint(pCairo);
f325b2
+            }
f325b2
+        }
f325b2
+    }
f325b2
+
f325b2
+    return FALSE;
f325b2
 }
f325b2
 
f325b2
-std::vector<GdkRectangle> LOKDocView_Impl::payloadToRectangles(const char* pPayload)
f325b2
+static gboolean
f325b2
+renderOverlay(LOKDocView* pDocView, cairo_t* pCairo)
f325b2
 {
f325b2
-    std::vector<GdkRectangle> aRet;
f325b2
+    LOKDocViewPrivate *priv = pDocView->priv;
f325b2
 
f325b2
-    gchar** ppRectangles = g_strsplit(pPayload, "; ", 0);
f325b2
-    for (gchar** ppRectangle = ppRectangles; *ppRectangle; ++ppRectangle)
f325b2
-        aRet.push_back(payloadToRectangle(*ppRectangle));
f325b2
-    g_strfreev(ppRectangles);
f325b2
+    if (priv->m_bEdit && priv->m_bCursorVisible && priv->m_bCursorOverlayVisible && !isEmptyRectangle(priv->m_aVisibleCursor))
f325b2
+    {
f325b2
+        if (priv->m_aVisibleCursor.width < 30)
f325b2
+            // Set a minimal width if it would be 0.
f325b2
+            priv->m_aVisibleCursor.width = 30;
f325b2
 
f325b2
-    return aRet;
f325b2
-}
f325b2
+        cairo_set_source_rgb(pCairo, 0, 0, 0);
f325b2
+        cairo_rectangle(pCairo,
f325b2
+                        twipToPixel(priv->m_aVisibleCursor.x, priv->m_fZoom),
f325b2
+                        twipToPixel(priv->m_aVisibleCursor.y, priv->m_fZoom),
f325b2
+                        twipToPixel(priv->m_aVisibleCursor.width, priv->m_fZoom),
f325b2
+                        twipToPixel(priv->m_aVisibleCursor.height, priv->m_fZoom));
f325b2
+        cairo_fill(pCairo);
f325b2
+    }
f325b2
 
f325b2
-/// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
f325b2
-const char* LOKDocView_Impl::callbackTypeToString(int nType)
f325b2
-{
f325b2
-    switch (nType)
f325b2
+    if (priv->m_bEdit && priv->m_bCursorVisible && !isEmptyRectangle(priv->m_aVisibleCursor) && priv->m_aTextSelectionRectangles.empty())
f325b2
     {
f325b2
-    case LOK_CALLBACK_INVALIDATE_TILES:
f325b2
-        return "LOK_CALLBACK_INVALIDATE_TILES";
f325b2
-    case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
f325b2
-        return "LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR";
f325b2
-    case LOK_CALLBACK_TEXT_SELECTION:
f325b2
-        return "LOK_CALLBACK_TEXT_SELECTION";
f325b2
-    case LOK_CALLBACK_TEXT_SELECTION_START:
f325b2
-        return "LOK_CALLBACK_TEXT_SELECTION_START";
f325b2
-    case LOK_CALLBACK_TEXT_SELECTION_END:
f325b2
-        return "LOK_CALLBACK_TEXT_SELECTION_END";
f325b2
-    case LOK_CALLBACK_CURSOR_VISIBLE:
f325b2
-        return "LOK_CALLBACK_CURSOR_VISIBLE";
f325b2
-    case LOK_CALLBACK_GRAPHIC_SELECTION:
f325b2
-        return "LOK_CALLBACK_GRAPHIC_SELECTION";
f325b2
-    case LOK_CALLBACK_HYPERLINK_CLICKED:
f325b2
-        return "LOK_CALLBACK_HYPERLINK_CLICKED";
f325b2
-    case LOK_CALLBACK_STATE_CHANGED:
f325b2
-        return "LOK_CALLBACK_STATE_CHANGED";
f325b2
-    case LOK_CALLBACK_STATUS_INDICATOR_START:
f325b2
-        return "LOK_CALLBACK_STATUS_INDICATOR_START";
f325b2
-    case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
f325b2
-        return "LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE";
f325b2
-    case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
f325b2
-        return "LOK_CALLBACK_STATUS_INDICATOR_FINISH";
f325b2
-    case LOK_CALLBACK_SEARCH_NOT_FOUND:
f325b2
-        return "LOK_CALLBACK_SEARCH_NOT_FOUND";
f325b2
-    case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
f325b2
-        return "LOK_CALLBACK_DOCUMENT_SIZE_CHANGED";
f325b2
-    case LOK_CALLBACK_SET_PART:
f325b2
-        return "LOK_CALLBACK_SET_PART";
f325b2
+        // Have a cursor, but no selection: we need the middle handle.
f325b2
+        gchar* handleMiddlePath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_middle.png", NULL);
f325b2
+        if (!priv->m_pHandleMiddle)
f325b2
+            priv->m_pHandleMiddle = cairo_image_surface_create_from_png(handleMiddlePath);
f325b2
+        g_free (handleMiddlePath);
f325b2
+        renderHandle(pDocView, pCairo, priv->m_aVisibleCursor, priv->m_pHandleMiddle, priv->m_aHandleMiddleRect);
f325b2
+    }
f325b2
+
f325b2
+    if (!priv->m_aTextSelectionRectangles.empty())
f325b2
+    {
f325b2
+        for (GdkRectangle& rRectangle : priv->m_aTextSelectionRectangles)
f325b2
+        {
f325b2
+            // Blue with 75% transparency.
f325b2
+            cairo_set_source_rgba(pCairo, ((double)0x43)/255, ((double)0xac)/255, ((double)0xe8)/255, 0.25);
f325b2
+            cairo_rectangle(pCairo,
f325b2
+                            twipToPixel(rRectangle.x, priv->m_fZoom),
f325b2
+                            twipToPixel(rRectangle.y, priv->m_fZoom),
f325b2
+                            twipToPixel(rRectangle.width, priv->m_fZoom),
f325b2
+                            twipToPixel(rRectangle.height, priv->m_fZoom));
f325b2
+            cairo_fill(pCairo);
f325b2
+        }
f325b2
+
f325b2
+        // Handles
f325b2
+        if (!isEmptyRectangle(priv->m_aTextSelectionStart))
f325b2
+        {
f325b2
+            // Have a start position: we need a start handle.
f325b2
+            gchar* handleStartPath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_start.png", NULL);
f325b2
+            if (!priv->m_pHandleStart)
f325b2
+                priv->m_pHandleStart = cairo_image_surface_create_from_png(handleStartPath);
f325b2
+            renderHandle(pDocView, pCairo, priv->m_aTextSelectionStart, priv->m_pHandleStart, priv->m_aHandleStartRect);
f325b2
+            g_free (handleStartPath);
f325b2
+        }
f325b2
+        if (!isEmptyRectangle(priv->m_aTextSelectionEnd))
f325b2
+        {
f325b2
+            // Have a start position: we need an end handle.
f325b2
+            gchar* handleEndPath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_end.png", NULL);
f325b2
+            if (!priv->m_pHandleEnd)
f325b2
+                priv->m_pHandleEnd = cairo_image_surface_create_from_png(handleEndPath);
f325b2
+            renderHandle(pDocView, pCairo, priv->m_aTextSelectionEnd, priv->m_pHandleEnd, priv->m_aHandleEndRect);
f325b2
+            g_free (handleEndPath);
f325b2
+        }
f325b2
     }
f325b2
-    return 0;
f325b2
-}
f325b2
 
f325b2
-gboolean LOKDocView_Impl::callback(gpointer pData)
f325b2
-{
f325b2
-    LOKDocView_Impl::CallbackData* pCallback = static_cast<LOKDocView_Impl::CallbackData*>(pData);
f325b2
-    return pCallback->m_pDocView->m_pImpl->callbackImpl(pCallback);
f325b2
-}
f325b2
+    if (!isEmptyRectangle(priv->m_aGraphicSelection))
f325b2
+    {
f325b2
+        gchar* handleGraphicPath = g_strconcat (priv->m_aLOPath, "/../..", CURSOR_HANDLE_DIR, "handle_graphic.png", NULL);
f325b2
+        if (!priv->m_pGraphicHandle)
f325b2
+            priv->m_pGraphicHandle = cairo_image_surface_create_from_png(handleGraphicPath);
f325b2
+        renderGraphicHandle(pDocView, pCairo, priv->m_aGraphicSelection, priv->m_pGraphicHandle);
f325b2
+        g_free (handleGraphicPath);
f325b2
+    }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::globalCallback(gpointer pData)
f325b2
-{
f325b2
-    LOKDocView_Impl::CallbackData* pCallback = static_cast<LOKDocView_Impl::CallbackData*>(pData);
f325b2
-    return globalCallbackImpl(pCallback);
f325b2
+    return FALSE;
f325b2
 }
f325b2
 
f325b2
-gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
f325b2
+static gboolean
f325b2
+lok_doc_view_signal_button(GtkWidget* pWidget, GdkEventButton* pEvent)
f325b2
 {
f325b2
-    switch (pCallback->m_nType)
f325b2
-    {
f325b2
-    case LOK_CALLBACK_INVALIDATE_TILES:
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (pWidget);
f325b2
+    LOKDocViewPrivate *priv = pDocView->priv;
f325b2
+
f325b2
+    g_info("LOKDocView_Impl::signalButton: %d, %d (in twips: %d, %d)",
f325b2
+           (int)pEvent->x, (int)pEvent->y,
f325b2
+           (int)pixelToTwip(pEvent->x, priv->m_fZoom),
f325b2
+           (int)pixelToTwip(pEvent->y, priv->m_fZoom));
f325b2
+
f325b2
+    if (pEvent->type == GDK_BUTTON_RELEASE)
f325b2
     {
f325b2
-        if (pCallback->m_aPayload != "EMPTY")
f325b2
+        if (priv->m_bInDragStartHandle)
f325b2
         {
f325b2
-            GdkRectangle aRectangle = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
-            setTilesInvalid(aRectangle);
f325b2
+            g_info("LOKDocView_Impl::signalButton: end of drag start handle");
f325b2
+            priv->m_bInDragStartHandle = false;
f325b2
+            return FALSE;
f325b2
+        }
f325b2
+        else if (priv->m_bInDragMiddleHandle)
f325b2
+        {
f325b2
+            g_info("LOKDocView_Impl::signalButton: end of drag middle handle");
f325b2
+            priv->m_bInDragMiddleHandle = false;
f325b2
+            return FALSE;
f325b2
+        }
f325b2
+        else if (priv->m_bInDragEndHandle)
f325b2
+        {
f325b2
+            g_info("LOKDocView_Impl::signalButton: end of drag end handle");
f325b2
+            priv->m_bInDragEndHandle = false;
f325b2
+            return FALSE;
f325b2
         }
f325b2
-        else
f325b2
-            m_aTileBuffer.resetAllTiles();
f325b2
 
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pDocView));
f325b2
-    }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
f325b2
-    {
f325b2
-        m_aVisibleCursor = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
-        m_bCursorOverlayVisible = true;
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pDocView));
f325b2
-    }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_TEXT_SELECTION:
f325b2
-    {
f325b2
-        m_aTextSelectionRectangles = LOKDocView_Impl::payloadToRectangles(pCallback->m_aPayload.c_str());
f325b2
+        for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
+        {
f325b2
+            if (priv->m_bInDragGraphicHandles[i])
f325b2
+            {
f325b2
+                g_info("LOKDocView_Impl::signalButton: end of drag graphic handle #%d", i);
f325b2
+                priv->m_bInDragGraphicHandles[i] = false;
f325b2
+                priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom));
f325b2
+                return FALSE;
f325b2
+            }
f325b2
+        }
f325b2
 
f325b2
-        // In case the selection is empty, then we get no LOK_CALLBACK_TEXT_SELECTION_START/END events.
f325b2
-        if (m_aTextSelectionRectangles.empty())
f325b2
+        if (priv->m_bInDragGraphicSelection)
f325b2
         {
f325b2
-            memset(&m_aTextSelectionStart, 0, sizeof(m_aTextSelectionStart));
f325b2
-            memset(&m_aHandleStartRect, 0, sizeof(m_aHandleStartRect));
f325b2
-            memset(&m_aTextSelectionEnd, 0, sizeof(m_aTextSelectionEnd));
f325b2
-            memset(&m_aHandleEndRect, 0, sizeof(m_aHandleEndRect));
f325b2
+            g_info("LOKDocView_Impl::signalButton: end of drag graphic selection");
f325b2
+            priv->m_bInDragGraphicSelection = false;
f325b2
+            priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom));
f325b2
+            return FALSE;
f325b2
         }
f325b2
-        else
f325b2
-            memset(&m_aHandleMiddleRect, 0, sizeof(m_aHandleMiddleRect));
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_TEXT_SELECTION_START:
f325b2
+
f325b2
+    if (priv->m_bEdit)
f325b2
     {
f325b2
-        m_aTextSelectionStart = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
+        GdkRectangle aClick;
f325b2
+        aClick.x = pEvent->x;
f325b2
+        aClick.y = pEvent->y;
f325b2
+        aClick.width = 1;
f325b2
+        aClick.height = 1;
f325b2
+        if (pEvent->type == GDK_BUTTON_PRESS)
f325b2
+        {
f325b2
+            if (gdk_rectangle_intersect(&aClick, &priv->m_aHandleStartRect, NULL))
f325b2
+            {
f325b2
+                g_info("LOKDocView_Impl::signalButton: start of drag start handle");
f325b2
+                priv->m_bInDragStartHandle = true;
f325b2
+                return FALSE;
f325b2
+            }
f325b2
+            else if (gdk_rectangle_intersect(&aClick, &priv->m_aHandleMiddleRect, NULL))
f325b2
+            {
f325b2
+                g_info("LOKDocView_Impl::signalButton: start of drag middle handle");
f325b2
+                priv->m_bInDragMiddleHandle = true;
f325b2
+                return FALSE;
f325b2
+            }
f325b2
+            else if (gdk_rectangle_intersect(&aClick, &priv->m_aHandleEndRect, NULL))
f325b2
+            {
f325b2
+                g_info("LOKDocView_Impl::signalButton: start of drag end handle");
f325b2
+                priv->m_bInDragEndHandle = true;
f325b2
+                return FALSE;
f325b2
+            }
f325b2
+
f325b2
+            for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
+            {
f325b2
+                if (gdk_rectangle_intersect(&aClick, &priv->m_aGraphicHandleRects[i], NULL))
f325b2
+                {
f325b2
+                    g_info("LOKDocView_Impl::signalButton: start of drag graphic handle #%d", i);
f325b2
+                    priv->m_bInDragGraphicHandles[i] = true;
f325b2
+                    priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument,
f325b2
+                                                             LOK_SETGRAPHICSELECTION_START,
f325b2
+                                                             pixelToTwip(priv->m_aGraphicHandleRects[i].x + priv->m_aGraphicHandleRects[i].width / 2, priv->m_fZoom),
f325b2
+                                                             pixelToTwip(priv->m_aGraphicHandleRects[i].y + priv->m_aGraphicHandleRects[i].height / 2, priv->m_fZoom));
f325b2
+                    return FALSE;
f325b2
+                }
f325b2
+            }
f325b2
+        }
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_TEXT_SELECTION_END:
f325b2
+
f325b2
+    if (!priv->m_bEdit)
f325b2
+        lok_doc_view_set_edit(pDocView, TRUE);
f325b2
+
f325b2
+    switch (pEvent->type)
f325b2
     {
f325b2
-        m_aTextSelectionEnd = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
-    }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_CURSOR_VISIBLE:
f325b2
+    case GDK_BUTTON_PRESS:
f325b2
     {
f325b2
-        m_bCursorVisible = pCallback->m_aPayload == "true";
f325b2
+        int nCount = 1;
f325b2
+        if ((pEvent->time - priv->m_nLastButtonPressTime) < 250)
f325b2
+            nCount++;
f325b2
+        priv->m_nLastButtonPressTime = pEvent->time;
f325b2
+        priv->m_pDocument->pClass->postMouseEvent(priv->m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom), nCount);
f325b2
+        break;
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_GRAPHIC_SELECTION:
f325b2
+    case GDK_BUTTON_RELEASE:
f325b2
     {
f325b2
-        if (pCallback->m_aPayload != "EMPTY")
f325b2
-            m_aGraphicSelection = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
-        else
f325b2
-            memset(&m_aGraphicSelection, 0, sizeof(m_aGraphicSelection));
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pDocView));
f325b2
+        int nCount = 1;
f325b2
+        if ((pEvent->time - priv->m_nLastButtonReleaseTime) < 250)
f325b2
+            nCount++;
f325b2
+        priv->m_nLastButtonReleaseTime = pEvent->time;
f325b2
+        priv->m_pDocument->pClass->postMouseEvent(priv->m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom), nCount);
f325b2
+        break;
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_HYPERLINK_CLICKED:
f325b2
+    default:
f325b2
+        break;
f325b2
+    }
f325b2
+    return FALSE;
f325b2
+}
f325b2
+
f325b2
+static void
f325b2
+getDragPoint(GdkRectangle* pHandle,
f325b2
+             GdkEventMotion* pEvent,
f325b2
+             GdkPoint* pPoint)
f325b2
+{
f325b2
+    GdkPoint aCursor, aHandle;
f325b2
+
f325b2
+    // Center of the cursor rectangle: we know that it's above the handle.
f325b2
+    aCursor.x = pHandle->x + pHandle->width / 2;
f325b2
+    aCursor.y = pHandle->y - pHandle->height / 2;
f325b2
+    // Center of the handle rectangle.
f325b2
+    aHandle.x = pHandle->x + pHandle->width / 2;
f325b2
+    aHandle.y = pHandle->y + pHandle->height / 2;
f325b2
+    // Our target is the original cursor position + the dragged offset.
f325b2
+    pPoint->x = aCursor.x + (pEvent->x - aHandle.x);
f325b2
+    pPoint->y = aCursor.y + (pEvent->y - aHandle.y);
f325b2
+}
f325b2
+
f325b2
+static gboolean
f325b2
+lok_doc_view_signal_motion (GtkWidget* pWidget, GdkEventMotion* pEvent)
f325b2
+{
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (pWidget);
f325b2
+    LOKDocViewPrivate *priv = pDocView->priv;
f325b2
+    GdkPoint aPoint;
f325b2
+
f325b2
+    if (priv->m_bInDragMiddleHandle)
f325b2
     {
f325b2
-        GError* pError = NULL;
f325b2
-        gtk_show_uri(NULL, pCallback->m_aPayload.c_str(), GDK_CURRENT_TIME, &pError);
f325b2
+        g_info("lcl_signalMotion: dragging the middle handle");
f325b2
+        getDragPoint(&priv->m_aHandleMiddleRect, pEvent, &aPoint);
f325b2
+        priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_RESET, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
f325b2
+        return FALSE;
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_STATE_CHANGED:
f325b2
+    if (priv->m_bInDragStartHandle)
f325b2
     {
f325b2
-        commandChanged(pCallback->m_aPayload);
f325b2
+        g_info("lcl_signalMotion: dragging the start handle");
f325b2
+        getDragPoint(&priv->m_aHandleStartRect, pEvent, &aPoint);
f325b2
+        priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_START, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
f325b2
+        return FALSE;
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_SEARCH_NOT_FOUND:
f325b2
+    if (priv->m_bInDragEndHandle)
f325b2
     {
f325b2
-        searchNotFound(pCallback->m_aPayload);
f325b2
+        g_info("lcl_signalMotion: dragging the end handle");
f325b2
+        getDragPoint(&priv->m_aHandleEndRect, pEvent, &aPoint);
f325b2
+        priv->m_pDocument->pClass->setTextSelection(priv->m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x, priv->m_fZoom), pixelToTwip(aPoint.y, priv->m_fZoom));
f325b2
+        return FALSE;
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
f325b2
+    for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
f325b2
     {
f325b2
-        payloadToSize(pCallback->m_aPayload.c_str(), m_nDocumentWidthTwips, m_nDocumentHeightTwips);
f325b2
-        gtk_widget_set_size_request(GTK_WIDGET(m_pDocView),
f325b2
-                                    twipToPixel(m_nDocumentWidthTwips, m_fZoom),
f325b2
-                                    twipToPixel(m_nDocumentHeightTwips, m_fZoom));
f325b2
+        if (priv->m_bInDragGraphicHandles[i])
f325b2
+        {
f325b2
+            g_info("lcl_signalMotion: dragging the graphic handle #%d", i);
f325b2
+            return FALSE;
f325b2
+        }
f325b2
     }
f325b2
-    break;
f325b2
-    case LOK_CALLBACK_SET_PART:
f325b2
+    if (priv->m_bInDragGraphicSelection)
f325b2
     {
f325b2
-        setPart(pCallback->m_aPayload);
f325b2
+        g_info("lcl_signalMotion: dragging the graphic selection");
f325b2
+        return FALSE;
f325b2
     }
f325b2
-    break;
f325b2
-    default:
f325b2
-        g_assert(false);
f325b2
-        break;
f325b2
+
f325b2
+    GdkRectangle aMotionInTwipsInTwips;
f325b2
+    aMotionInTwipsInTwips.x = pixelToTwip(pEvent->x, priv->m_fZoom);
f325b2
+    aMotionInTwipsInTwips.y = pixelToTwip(pEvent->y, priv->m_fZoom);
f325b2
+    aMotionInTwipsInTwips.width = 1;
f325b2
+    aMotionInTwipsInTwips.height = 1;
f325b2
+    if (gdk_rectangle_intersect(&aMotionInTwipsInTwips, &priv->m_aGraphicSelection, 0))
f325b2
+    {
f325b2
+        g_info("lcl_signalMotion: start of drag graphic selection");
f325b2
+        priv->m_bInDragGraphicSelection = true;
f325b2
+        priv->m_pDocument->pClass->setGraphicSelection(priv->m_pDocument, LOK_SETGRAPHICSELECTION_START, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom));
f325b2
+        return FALSE;
f325b2
     }
f325b2
-    delete pCallback;
f325b2
 
f325b2
-    return G_SOURCE_REMOVE;
f325b2
-}
f325b2
+    // Otherwise a mouse move, as on the desktop.
f325b2
+    priv->m_pDocument->pClass->postMouseEvent(priv->m_pDocument, LOK_MOUSEEVENT_MOUSEMOVE, pixelToTwip(pEvent->x, priv->m_fZoom), pixelToTwip(pEvent->y, priv->m_fZoom), 1);
f325b2
 
f325b2
-void LOKDocView_Impl::callbackWorker(int nType, const char* pPayload, void* pData)
f325b2
-{
f325b2
-    LOKDocView* pDocView = static_cast<LOKDocView*>(pData);
f325b2
-    pDocView->m_pImpl->callbackWorkerImpl(nType, pPayload);
f325b2
+    return FALSE;
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::globalCallbackWorker(int nType, const char* pPayload, void* pData)
f325b2
+static void lok_doc_view_init (LOKDocView* pDocView)
f325b2
 {
f325b2
-    LOKDocView* pDocView = static_cast<LOKDocView*>(pData);
f325b2
-    pDocView->m_pImpl->globalCallbackWorkerImpl(nType, pPayload);
f325b2
+    pDocView->priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
f325b2
+    pDocView->priv->m_bCursorVisible = true;
f325b2
+
f325b2
+    gtk_widget_add_events(GTK_WIDGET(pDocView),
f325b2
+                          GDK_BUTTON_PRESS_MASK
f325b2
+                          |GDK_BUTTON_RELEASE_MASK
f325b2
+                          |GDK_BUTTON_MOTION_MASK
f325b2
+                          |GDK_KEY_PRESS_MASK
f325b2
+                          |GDK_KEY_RELEASE_MASK);
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::callbackWorkerImpl(int nType, const char* pPayload)
f325b2
+static void lok_doc_view_set_property (GObject* object, guint propId, const GValue *value, GParamSpec *pspec)
f325b2
 {
f325b2
-    LOKDocView_Impl::CallbackData* pCallback = new LOKDocView_Impl::CallbackData(nType, pPayload ? pPayload : "(nil)", m_pDocView);
f325b2
-    g_info("lok_doc_view_callback_worker: %s, '%s'", LOKDocView_Impl::callbackTypeToString(nType), pPayload);
f325b2
-    gdk_threads_add_idle(LOKDocView_Impl::callback, pCallback);
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (object);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
+
f325b2
+    switch (propId)
f325b2
+    {
f325b2
+    case PROP_LO_PATH:
f325b2
+        priv->m_aLOPath = g_value_dup_string (value);
f325b2
+        break;
f325b2
+    case PROP_DOC_PATH:
f325b2
+        priv->m_aDocPath = g_value_dup_string (value);
f325b2
+        break;
f325b2
+    case PROP_EDITABLE:
f325b2
+        lok_doc_view_set_edit (pDocView, g_value_get_boolean (value));
f325b2
+        break;
f325b2
+    case PROP_ZOOM:
f325b2
+        lok_doc_view_set_zoom (pDocView, g_value_get_float (value));
f325b2
+        break;
f325b2
+    case PROP_DOC_WIDTH:
f325b2
+        priv->m_nDocumentWidthTwips = g_value_get_long (value);
f325b2
+        break;
f325b2
+    case PROP_DOC_HEIGHT:
f325b2
+        priv->m_nDocumentHeightTwips = g_value_get_long (value);
f325b2
+        break;
f325b2
+    default:
f325b2
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propId, pspec);
f325b2
+    }
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::globalCallbackWorkerImpl(int nType, const char* pPayload)
f325b2
+static void lok_doc_view_get_property (GObject* object, guint propId, GValue *value, GParamSpec *pspec)
f325b2
 {
f325b2
-    LOKDocView_Impl::CallbackData* pCallback = new LOKDocView_Impl::CallbackData(nType, pPayload ? pPayload : "(nil)", m_pDocView);
f325b2
-    g_info("LOKDocView_Impl::globalCallbackWorkerImpl: %s, '%s'", LOKDocView_Impl::callbackTypeToString(nType), pPayload);
f325b2
-    gdk_threads_add_idle(LOKDocView_Impl::globalCallback, pCallback);
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (object);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
+
f325b2
+    switch (propId)
f325b2
+    {
f325b2
+    case PROP_LO_PATH:
f325b2
+        g_value_set_string (value, priv->m_aLOPath);
f325b2
+        break;
f325b2
+    case PROP_DOC_PATH:
f325b2
+        g_value_set_string (value, priv->m_aDocPath);
f325b2
+        break;
f325b2
+    case PROP_EDITABLE:
f325b2
+        g_value_set_boolean (value, priv->m_bEdit);
f325b2
+        break;
f325b2
+    case PROP_LOAD_PROGRESS:
f325b2
+        g_value_set_uint (value, priv->m_nLoadProgress);
f325b2
+        break;
f325b2
+    case PROP_ZOOM:
f325b2
+        g_value_set_float (value, priv->m_fZoom);
f325b2
+        break;
f325b2
+    case PROP_IS_LOADING:
f325b2
+        g_value_set_boolean (value, priv->m_bIsLoading);
f325b2
+        break;
f325b2
+    case PROP_DOC_WIDTH:
f325b2
+        g_value_set_long (value, priv->m_nDocumentWidthTwips);
f325b2
+        break;
f325b2
+    case PROP_DOC_HEIGHT:
f325b2
+        g_value_set_long (value, priv->m_nDocumentHeightTwips);
f325b2
+        break;
f325b2
+    case PROP_CAN_ZOOM_IN:
f325b2
+        g_value_set_boolean (value, priv->m_bCanZoomIn);
f325b2
+        break;
f325b2
+    case PROP_CAN_ZOOM_OUT:
f325b2
+        g_value_set_boolean (value, priv->m_bCanZoomOut);
f325b2
+        break;
f325b2
+    default:
f325b2
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propId, pspec);
f325b2
+    }
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::commandChanged(const std::string& rString)
f325b2
+static gboolean lok_doc_view_draw (GtkWidget* pWidget, cairo_t* pCairo)
f325b2
 {
f325b2
-    g_signal_emit(m_pDocView, doc_view_signals[COMMAND_CHANGED], 0, rString.c_str());
f325b2
+    LOKDocView *pDocView = LOK_DOC_VIEW (pWidget);
f325b2
+
f325b2
+    renderDocument (pDocView, pCairo);
f325b2
+    renderOverlay (pDocView, pCairo);
f325b2
+
f325b2
+    return FALSE;
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::searchNotFound(const std::string& rString)
f325b2
+static void lok_doc_view_finalize (GObject* object)
f325b2
 {
f325b2
-    g_signal_emit(m_pDocView, doc_view_signals[SEARCH_NOT_FOUND], 0, rString.c_str());
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (object);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
+
f325b2
+    if (priv->m_pDocument)
f325b2
+        priv->m_pDocument->pClass->destroy (priv->m_pDocument);
f325b2
+    if (priv->m_pOffice)
f325b2
+        priv->m_pOffice->pClass->destroy (priv->m_pOffice);
f325b2
+
f325b2
+    G_OBJECT_CLASS (lok_doc_view_parent_class)->finalize (object);
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::setPart(const std::string& rString)
f325b2
+static void lok_doc_view_constructed (GObject* object)
f325b2
 {
f325b2
-    g_signal_emit(m_pDocView, doc_view_signals[PART_CHANGED], 0, std::stoi(rString));
f325b2
+    LOKDocView* pDocView = LOK_DOC_VIEW (object);
f325b2
+    LOKDocViewPrivate* priv = pDocView->priv;
f325b2
+
f325b2
+    G_OBJECT_CLASS (lok_doc_view_parent_class)->constructed (object);
f325b2
+
f325b2
+    pDocView->priv->m_pOffice = lok_init (priv->m_aLOPath);
f325b2
 }
f325b2
 
f325b2
 static void lok_doc_view_class_init (LOKDocViewClass* pClass)
f325b2
 {
f325b2
-    GObjectClass *gobject_class = G_OBJECT_CLASS(pClass);
f325b2
-    pClass->edit_changed = NULL;
f325b2
+    GObjectClass *pGObjectClass = G_OBJECT_CLASS(pClass);
f325b2
+    GtkWidgetClass *pWidgetClass = GTK_WIDGET_CLASS(pClass);
f325b2
+
f325b2
+    pGObjectClass->get_property = lok_doc_view_get_property;
f325b2
+    pGObjectClass->set_property = lok_doc_view_set_property;
f325b2
+    pGObjectClass->finalize = lok_doc_view_finalize;
f325b2
+    pGObjectClass->constructed = lok_doc_view_constructed;
f325b2
+
f325b2
+    pWidgetClass->draw = lok_doc_view_draw;
f325b2
+    pWidgetClass->button_press_event = lok_doc_view_signal_button;
f325b2
+    pWidgetClass->button_release_event = lok_doc_view_signal_button;
f325b2
+    pWidgetClass->motion_notify_event = lok_doc_view_signal_motion;
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:lopath:
f325b2
+     *
f325b2
+     * The absolute path of the LibreOffice install.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_LO_PATH,
f325b2
+          g_param_spec_string("lopath",
f325b2
+                              "LO Path",
f325b2
+                              "LibreOffice Install Path",
f325b2
+                              0,
f325b2
+                              static_cast<GParamFlags>(G_PARAM_READWRITE
f325b2
+                                                       | G_PARAM_CONSTRUCT_ONLY)));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:docpath:
f325b2
+     *
f325b2
+     * The path of the document that is currently being viewed.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_DOC_PATH,
f325b2
+          g_param_spec_string("docpath",
f325b2
+                              "Document Path",
f325b2
+                              "The URI of the document to open",
f325b2
+                              0,
f325b2
+                              G_PARAM_READWRITE));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:editable:
f325b2
+     *
f325b2
+     * Whether the document loaded inside of #LOKDocView is editable or not.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_EDITABLE,
f325b2
+          g_param_spec_boolean("editable",
f325b2
+                               "Editable",
f325b2
+                               "Whether the content is in edit mode or not",
f325b2
+                               FALSE,
f325b2
+                               G_PARAM_READWRITE));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:load-progress:
f325b2
+     *
f325b2
+     * The percent completion of the current loading operation of the
f325b2
+     * document. This can be used for progress bars. Note that this is not a
f325b2
+     * very accurate progress indicator, and its value might reset it couple of
f325b2
+     * times to 0 and start again. You should not rely on its numbers.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_LOAD_PROGRESS,
f325b2
+          g_param_spec_int("load-progress",
f325b2
+                           "Estimated Load Progress",
f325b2
+                           "Whether the content is in edit mode or not",
f325b2
+                           0, 100, 0,
f325b2
+                           G_PARAM_READABLE));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:zoom-level:
f325b2
+     *
f325b2
+     * The current zoom level of the document loaded inside #LOKDocView. The
f325b2
+     * default value is 1.0.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_ZOOM,
f325b2
+          g_param_spec_float("zoom-level",
f325b2
+                             "Zoom Level",
f325b2
+                             "The current zoom level of the content",
f325b2
+                             0, 5.0, 1.0,
f325b2
+                             static_cast<GParamFlags>(G_PARAM_READWRITE |
f325b2
+                                                      G_PARAM_CONSTRUCT)));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:is-loading:
f325b2
+     *
f325b2
+     * Whether the requested document is being loaded or not. %TRUE if it is
f325b2
+     * being loaded, otherwise %FALSE.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_IS_LOADING,
f325b2
+          g_param_spec_boolean("is-loading",
f325b2
+                               "Is Loading",
f325b2
+                               "Whether the view is loading a document",
f325b2
+                               FALSE,
f325b2
+                               G_PARAM_READABLE));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:doc-width:
f325b2
+     *
f325b2
+     * The width of the currently loaded document in #LOKDocView in twips.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_DOC_WIDTH,
f325b2
+          g_param_spec_long("doc-width",
f325b2
+                            "Document Width",
f325b2
+                            "Width of the document in twips",
f325b2
+                            0, G_MAXLONG, 0,
f325b2
+                            G_PARAM_READWRITE));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:doc-height:
f325b2
+     *
f325b2
+     * The height of the currently loaded document in #LOKDocView in twips.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_DOC_HEIGHT,
f325b2
+          g_param_spec_long("doc-height",
f325b2
+                            "Document Height",
f325b2
+                            "Height of the document in twips",
f325b2
+                            0, G_MAXLONG, 0,
f325b2
+                            G_PARAM_READWRITE));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:can-zoom-in:
f325b2
+     *
f325b2
+     * It tells whether the view can further be zoomed in or not.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_CAN_ZOOM_IN,
f325b2
+          g_param_spec_boolean("can-zoom-in",
f325b2
+                               "Can Zoom In",
f325b2
+                               "Whether the view can be zoomed in further",
f325b2
+                               TRUE,
f325b2
+                               static_cast<GParamFlags>(G_PARAM_READABLE
f325b2
+                                                       | G_PARAM_STATIC_STRINGS)));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView:can-zoom-out:
f325b2
+     *
f325b2
+     * It tells whether the view can further be zoomed out or not.
f325b2
+     */
f325b2
+    g_object_class_install_property (pGObjectClass,
f325b2
+          PROP_CAN_ZOOM_OUT,
f325b2
+          g_param_spec_boolean("can-zoom-out",
f325b2
+                               "Can Zoom Out",
f325b2
+                               "Whether the view can be zoomed out further",
f325b2
+                               TRUE,
f325b2
+                               static_cast<GParamFlags>(G_PARAM_READABLE
f325b2
+                                                       | G_PARAM_STATIC_STRINGS)));
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView::edit-changed:
f325b2
+     * @pDocView: the #LOKDocView on which the signal is emitted
f325b2
+     * @bEdit: the new edit value of the view
f325b2
+     */
f325b2
     doc_view_signals[EDIT_CHANGED] =
f325b2
         g_signal_new("edit-changed",
f325b2
-                     G_TYPE_FROM_CLASS (gobject_class),
f325b2
+                     G_TYPE_FROM_CLASS (pGObjectClass),
f325b2
                      G_SIGNAL_RUN_FIRST,
f325b2
-                     G_STRUCT_OFFSET (LOKDocViewClass, edit_changed),
f325b2
+                     0,
f325b2
                      NULL, NULL,
f325b2
                      g_cclosure_marshal_VOID__BOOLEAN,
f325b2
                      G_TYPE_NONE, 1,
f325b2
                      G_TYPE_BOOLEAN);
f325b2
-    pClass->command_changed = NULL;
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView::command-changed:
f325b2
+     * @pDocView: the #LOKDocView on which the signal is emitted
f325b2
+     * @aCommand: the command that was changed
f325b2
+     */
f325b2
     doc_view_signals[COMMAND_CHANGED] =
f325b2
         g_signal_new("command-changed",
f325b2
-                     G_TYPE_FROM_CLASS(gobject_class),
f325b2
+                     G_TYPE_FROM_CLASS(pGObjectClass),
f325b2
                      G_SIGNAL_RUN_FIRST,
f325b2
-                     G_STRUCT_OFFSET(LOKDocViewClass, command_changed),
f325b2
+                     0,
f325b2
                      NULL, NULL,
f325b2
                      g_cclosure_marshal_VOID__STRING,
f325b2
                      G_TYPE_NONE, 1,
f325b2
                      G_TYPE_STRING);
f325b2
-    pClass->search_not_found = 0;
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView::search-not-found:
f325b2
+     * @pDocView: the #LOKDocView on which the signal is emitted
f325b2
+     * @aCommand: the string for which the search was not found.
f325b2
+     */
f325b2
     doc_view_signals[SEARCH_NOT_FOUND] =
f325b2
         g_signal_new("search-not-found",
f325b2
-                     G_TYPE_FROM_CLASS(gobject_class),
f325b2
+                     G_TYPE_FROM_CLASS(pGObjectClass),
f325b2
                      G_SIGNAL_RUN_FIRST,
f325b2
-                     G_STRUCT_OFFSET(LOKDocViewClass, search_not_found),
f325b2
+                     0,
f325b2
                      NULL, NULL,
f325b2
                      g_cclosure_marshal_VOID__STRING,
f325b2
                      G_TYPE_NONE, 1,
f325b2
                      G_TYPE_STRING);
f325b2
-    pClass->part_changed = 0;
f325b2
+
f325b2
+    /**
f325b2
+     * LOKDocView::part-changed:
f325b2
+     * @pDocView: the #LOKDocView on which the signal is emitted
f325b2
+     * @aCommand: the part number which the view changed to
f325b2
+     */
f325b2
     doc_view_signals[PART_CHANGED] =
f325b2
         g_signal_new("part-changed",
f325b2
-                     G_TYPE_FROM_CLASS(gobject_class),
f325b2
+                     G_TYPE_FROM_CLASS(pGObjectClass),
f325b2
                      G_SIGNAL_RUN_FIRST,
f325b2
-                     G_STRUCT_OFFSET(LOKDocViewClass, part_changed),
f325b2
+                     0,
f325b2
                      NULL, NULL,
f325b2
                      g_cclosure_marshal_VOID__INT,
f325b2
                      G_TYPE_NONE, 1,
f325b2
                      G_TYPE_INT);
f325b2
-}
f325b2
 
f325b2
-static void lok_doc_view_init (LOKDocView* pDocView)
f325b2
-{
f325b2
-    pDocView->m_pImpl = new LOKDocView_Impl(pDocView);
f325b2
-
f325b2
-    g_signal_connect(G_OBJECT(pDocView),
f325b2
-                     "draw",
f325b2
-                     G_CALLBACK(LOKDocView_Impl::renderDocument), pDocView);
f325b2
-    g_signal_connect(G_OBJECT(pDocView),
f325b2
-                     "draw",
f325b2
-                     G_CALLBACK(LOKDocView_Impl::renderOverlay), pDocView);
f325b2
-    gtk_widget_add_events(GTK_WIDGET(pDocView),
f325b2
-                           GDK_BUTTON_PRESS_MASK
f325b2
-                          |GDK_BUTTON_RELEASE_MASK
f325b2
-                          |GDK_BUTTON_MOTION_MASK);
f325b2
-
f325b2
-    g_signal_connect(G_OBJECT(pDocView),
f325b2
-                     "button-press-event",
f325b2
-                     G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
f325b2
-    g_signal_connect(G_OBJECT(pDocView),
f325b2
-                     "button-release-event",
f325b2
-                     G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
f325b2
-    g_signal_connect(G_OBJECT(pDocView),
f325b2
-                     "motion-notify-event",
f325b2
-                     G_CALLBACK(LOKDocView_Impl::signalMotion), pDocView);
f325b2
-
f325b2
-    g_signal_connect(G_OBJECT(pDocView), "destroy", G_CALLBACK(LOKDocView_Impl::destroy), 0);
f325b2
+    /**
f325b2
+     * LOKDocView::hyperlinked-clicked:
f325b2
+     * @pDocView: the #LOKDocView on which the signal is emitted
f325b2
+     * @aHyperlink: the URI which the application should handle
f325b2
+     */
f325b2
+    doc_view_signals[PART_CHANGED] =
f325b2
+        g_signal_new("hyperlinked-clicked",
f325b2
+                     G_TYPE_FROM_CLASS(pGObjectClass),
f325b2
+                     G_SIGNAL_RUN_FIRST,
f325b2
+                     0,
f325b2
+                     NULL, NULL,
f325b2
+                     g_cclosure_marshal_VOID__STRING,
f325b2
+                     G_TYPE_NONE, 1,
f325b2
+                     G_TYPE_STRING);
f325b2
 }
f325b2
 
f325b2
+
f325b2
+
f325b2
 /**
f325b2
  * lok_doc_view_new:
f325b2
  * @pPath: LibreOffice install path.
f325b2
  *
f325b2
  * Returns: The #LOKDocView widget instance.
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT GtkWidget* lok_doc_view_new(const char* pPath)
f325b2
+SAL_DLLPUBLIC_EXPORT GtkWidget*
f325b2
+lok_doc_view_new (const char* pPath)
f325b2
 {
f325b2
-    LOKDocView* pDocView = LOK_DOC_VIEW(g_object_new(LOK_TYPE_DOC_VIEW, NULL));
f325b2
-    pDocView->m_pImpl->m_pOffice = lok_init (pPath);
f325b2
-    if (pDocView->m_pImpl->m_pOffice == NULL)
f325b2
-        return NULL;
f325b2
-    return GTK_WIDGET( pDocView );
f325b2
+    return GTK_WIDGET (g_object_new(LOK_TYPE_DOC_VIEW, "lopath", pPath, NULL));
f325b2
 }
f325b2
 
f325b2
 /**
f325b2
@@ -1186,47 +1367,47 @@ SAL_DLLPUBLIC_EXPORT GtkWidget* lok_doc_view_new(const char* pPath)
f325b2
  *
f325b2
  * Returns: %TRUE if the document is loaded succesfully, %FALSE otherwise
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT gboolean lok_doc_view_open_document( LOKDocView* pDocView, char* pPath )
f325b2
+SAL_DLLPUBLIC_EXPORT gboolean
f325b2
+lok_doc_view_open_document (LOKDocView* pDocView, char* pPath)
f325b2
 {
f325b2
-    if ( pDocView->m_pImpl->m_pDocument )
f325b2
+    if ( pDocView->priv->m_pDocument )
f325b2
     {
f325b2
-        pDocView->m_pImpl->m_pDocument->pClass->destroy( pDocView->m_pImpl->m_pDocument );
f325b2
-        pDocView->m_pImpl->m_pDocument = 0;
f325b2
+        pDocView->priv->m_pDocument->pClass->destroy( pDocView->priv->m_pDocument );
f325b2
+        pDocView->priv->m_pDocument = 0;
f325b2
     }
f325b2
 
f325b2
-    pDocView->m_pImpl->m_pOffice->pClass->registerCallback(pDocView->m_pImpl->m_pOffice, &LOKDocView_Impl::globalCallbackWorker, pDocView);
f325b2
-    pDocView->m_pImpl->m_pDocument = pDocView->m_pImpl->m_pOffice->pClass->documentLoad( pDocView->m_pImpl->m_pOffice,
f325b2
+    pDocView->priv->m_pOffice->pClass->registerCallback(pDocView->priv->m_pOffice, globalCallbackWorker, pDocView);
f325b2
+    pDocView->priv->m_pDocument = pDocView->priv->m_pOffice->pClass->documentLoad( pDocView->priv->m_pOffice,
f325b2
                                                                    pPath );
f325b2
-    if ( !pDocView->m_pImpl->m_pDocument )
f325b2
+    if ( !pDocView->priv->m_pDocument )
f325b2
     {
f325b2
         // FIXME: should have a GError parameter and populate it.
f325b2
-        char *pError = pDocView->m_pImpl->m_pOffice->pClass->getError( pDocView->m_pImpl->m_pOffice );
f325b2
+        char *pError = pDocView->priv->m_pOffice->pClass->getError( pDocView->priv->m_pOffice );
f325b2
         fprintf( stderr, "Error opening document '%s'\n", pError );
f325b2
         return FALSE;
f325b2
     }
f325b2
     else
f325b2
     {
f325b2
-        pDocView->m_pImpl->m_pDocument->pClass->initializeForRendering(pDocView->m_pImpl->m_pDocument);
f325b2
-        pDocView->m_pImpl->m_pDocument->pClass->registerCallback(pDocView->m_pImpl->m_pDocument, &LOKDocView_Impl::callbackWorker, pDocView);
f325b2
-        pDocView->m_pImpl->m_pDocument->pClass->getDocumentSize(pDocView->m_pImpl->m_pDocument, &pDocView->m_pImpl->m_nDocumentWidthTwips, &pDocView->m_pImpl->m_nDocumentHeightTwips);
f325b2
-        g_timeout_add(600, &LOKDocView_Impl::handleTimeout, pDocView);
f325b2
-
f325b2
-        float zoom = pDocView->m_pImpl->m_fZoom;
f325b2
-        long nDocumentWidthTwips = pDocView->m_pImpl->m_nDocumentWidthTwips;
f325b2
-        long nDocumentHeightTwips = pDocView->m_pImpl->m_nDocumentHeightTwips;
f325b2
+        pDocView->priv->m_pDocument->pClass->initializeForRendering(pDocView->priv->m_pDocument);
f325b2
+        pDocView->priv->m_pDocument->pClass->registerCallback(pDocView->priv->m_pDocument, callbackWorker, pDocView);
f325b2
+        pDocView->priv->m_pDocument->pClass->getDocumentSize(pDocView->priv->m_pDocument, &pDocView->priv->m_nDocumentWidthTwips, &pDocView->priv->m_nDocumentHeightTwips);
f325b2
+        g_timeout_add(600, handleTimeout, pDocView);
f325b2
+
f325b2
+        float zoom = pDocView->priv->m_fZoom;
f325b2
+        long nDocumentWidthTwips = pDocView->priv->m_nDocumentWidthTwips;
f325b2
+        long nDocumentHeightTwips = pDocView->priv->m_nDocumentHeightTwips;
f325b2
         long nDocumentWidthPixels = twipToPixel(nDocumentWidthTwips, zoom);
f325b2
         long nDocumentHeightPixels = twipToPixel(nDocumentHeightTwips, zoom);
f325b2
         // Total number of columns in this document.
f325b2
         guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
 
f325b2
 
f325b2
-        pDocView->m_pImpl->m_aTileBuffer = TileBuffer(pDocView->m_pImpl->m_pDocument,
f325b2
-                                                      nColumns);
f325b2
+        pDocView->priv->m_aTileBuffer = TileBuffer(pDocView->priv->m_pDocument,
f325b2
+                                                   nColumns);
f325b2
         gtk_widget_set_size_request(GTK_WIDGET(pDocView),
f325b2
                                     nDocumentWidthPixels,
f325b2
                                     nDocumentHeightPixels);
f325b2
     }
f325b2
-
f325b2
     return TRUE;
f325b2
 }
f325b2
 
f325b2
@@ -1236,9 +1417,10 @@ SAL_DLLPUBLIC_EXPORT gboolean lok_doc_view_open_document( LOKDocView* pDocView,
f325b2
  *
f325b2
  * Returns: The #LibreOfficeKitDocument instance the widget is currently showing
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument* lok_doc_view_get_document(LOKDocView* pDocView)
f325b2
+SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument*
f325b2
+lok_doc_view_get_document (LOKDocView* pDocView)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->m_pDocument;
f325b2
+    return pDocView->priv->m_pDocument;
f325b2
 }
f325b2
 
f325b2
 /**
f325b2
@@ -1248,16 +1430,17 @@ SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument* lok_doc_view_get_document(LOKDocVie
f325b2
  *
f325b2
  * Sets the new zoom level for the widget.
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_zoom ( LOKDocView* pDocView, float fZoom )
f325b2
+SAL_DLLPUBLIC_EXPORT void
f325b2
+lok_doc_view_set_zoom (LOKDocView* pDocView, float fZoom)
f325b2
 {
f325b2
-    pDocView->m_pImpl->m_fZoom = fZoom;
f325b2
-    long nDocumentWidthPixels = twipToPixel(pDocView->m_pImpl->m_nDocumentWidthTwips, fZoom);
f325b2
-    long nDocumentHeightPixels = twipToPixel(pDocView->m_pImpl->m_nDocumentHeightTwips, fZoom);
f325b2
+    pDocView->priv->m_fZoom = fZoom;
f325b2
+    long nDocumentWidthPixels = twipToPixel(pDocView->priv->m_nDocumentWidthTwips, fZoom);
f325b2
+    long nDocumentHeightPixels = twipToPixel(pDocView->priv->m_nDocumentHeightTwips, fZoom);
f325b2
     // Total number of columns in this document.
f325b2
     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
 
f325b2
-    pDocView->m_pImpl->m_aTileBuffer = TileBuffer(pDocView->m_pImpl->m_pDocument,
f325b2
-                                                  nColumns);
f325b2
+    pDocView->priv->m_aTileBuffer = TileBuffer(pDocView->priv->m_pDocument,
f325b2
+                                               nColumns);
f325b2
     gtk_widget_set_size_request(GTK_WIDGET(pDocView),
f325b2
                                 nDocumentWidthPixels,
f325b2
                                 nDocumentHeightPixels);
f325b2
@@ -1269,35 +1452,41 @@ SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_zoom ( LOKDocView* pDocView, float fZ
f325b2
  *
f325b2
  * Returns: The current zoom factor value in float for pDocView
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT float lok_doc_view_get_zoom ( LOKDocView* pDocView )
f325b2
+SAL_DLLPUBLIC_EXPORT float
f325b2
+lok_doc_view_get_zoom (LOKDocView* pDocView)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->m_fZoom;
f325b2
+    return pDocView->priv->m_fZoom;
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT int lok_doc_view_get_parts( LOKDocView* pDocView )
f325b2
+SAL_DLLPUBLIC_EXPORT int
f325b2
+lok_doc_view_get_parts (LOKDocView* pDocView)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->m_pDocument->pClass->getParts( pDocView->m_pImpl->m_pDocument );
f325b2
+    return pDocView->priv->m_pDocument->pClass->getParts( pDocView->priv->m_pDocument );
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT int lok_doc_view_get_part( LOKDocView* pDocView )
f325b2
+SAL_DLLPUBLIC_EXPORT int
f325b2
+lok_doc_view_get_part (LOKDocView* pDocView)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->m_pDocument->pClass->getPart( pDocView->m_pImpl->m_pDocument );
f325b2
+    return pDocView->priv->m_pDocument->pClass->getPart( pDocView->priv->m_pDocument );
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_part( LOKDocView* pDocView, int nPart)
f325b2
+SAL_DLLPUBLIC_EXPORT void
f325b2
+lok_doc_view_set_part (LOKDocView* pDocView, int nPart)
f325b2
 {
f325b2
-    pDocView->m_pImpl->m_pDocument->pClass->setPart( pDocView->m_pImpl->m_pDocument, nPart );
f325b2
+    pDocView->priv->m_pDocument->pClass->setPart( pDocView->priv->m_pDocument, nPart );
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT char* lok_doc_view_get_part_name( LOKDocView* pDocView, int nPart )
f325b2
+SAL_DLLPUBLIC_EXPORT char*
f325b2
+lok_doc_view_get_part_name (LOKDocView* pDocView, int nPart)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->m_pDocument->pClass->getPartName( pDocView->m_pImpl->m_pDocument, nPart );
f325b2
+    return pDocView->priv->m_pDocument->pClass->getPartName( pDocView->priv->m_pDocument, nPart );
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_partmode( LOKDocView* pDocView,
f325b2
-                                                    int nPartMode )
f325b2
+SAL_DLLPUBLIC_EXPORT void
f325b2
+lok_doc_view_set_partmode(LOKDocView* pDocView,
f325b2
+                          int nPartMode)
f325b2
 {
f325b2
-    pDocView->m_pImpl->m_pDocument->pClass->setPartMode( pDocView->m_pImpl->m_pDocument, nPartMode );
f325b2
+    pDocView->priv->m_pDocument->pClass->setPartMode( pDocView->priv->m_pDocument, nPartMode );
f325b2
 }
f325b2
 
f325b2
 /**
f325b2
@@ -1307,19 +1496,20 @@ SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_partmode( LOKDocView* pDocView,
f325b2
  *
f325b2
  * Sets the edit-mode for pDocView
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_edit( LOKDocView* pDocView,
f325b2
-                                                gboolean bEdit )
f325b2
+SAL_DLLPUBLIC_EXPORT void
f325b2
+lok_doc_view_set_edit(LOKDocView* pDocView,
f325b2
+                      gboolean bEdit)
f325b2
 {
f325b2
-    gboolean bWasEdit = pDocView->m_pImpl->m_bEdit;
f325b2
+    gboolean bWasEdit = pDocView->priv->m_bEdit;
f325b2
 
f325b2
-    if (!pDocView->m_pImpl->m_bEdit && bEdit)
f325b2
+    if (!pDocView->priv->m_bEdit && bEdit)
f325b2
         g_info("lok_doc_view_set_edit: entering edit mode");
f325b2
-    else if (pDocView->m_pImpl->m_bEdit && !bEdit)
f325b2
+    else if (pDocView->priv->m_bEdit && !bEdit)
f325b2
     {
f325b2
         g_info("lok_doc_view_set_edit: leaving edit mode");
f325b2
-        pDocView->m_pImpl->m_pDocument->pClass->resetSelection(pDocView->m_pImpl->m_pDocument);
f325b2
+        pDocView->priv->m_pDocument->pClass->resetSelection(pDocView->priv->m_pDocument);
f325b2
     }
f325b2
-    pDocView->m_pImpl->m_bEdit = bEdit;
f325b2
+    pDocView->priv->m_bEdit = bEdit;
f325b2
     g_signal_emit(pDocView, doc_view_signals[EDIT_CHANGED], 0, bWasEdit);
f325b2
     gtk_widget_queue_draw(GTK_WIDGET(pDocView));
f325b2
 }
f325b2
@@ -1330,20 +1520,39 @@ SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_edit( LOKDocView* pDocView,
f325b2
  *
f325b2
  * Returns: %TRUE if the given pDocView is in edit mode.
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT gboolean lok_doc_view_get_edit(LOKDocView* pDocView)
f325b2
+SAL_DLLPUBLIC_EXPORT gboolean
f325b2
+lok_doc_view_get_edit (LOKDocView* pDocView)
f325b2
 {
f325b2
-    return pDocView->m_pImpl->m_bEdit;
f325b2
+    return pDocView->priv->m_bEdit;
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT void lok_doc_view_post_command(LOKDocView* pDocView, const char* pCommand, const char* pArguments)
f325b2
+/**
f325b2
+ * lok_doc_view_post_command:
f325b2
+ * @pDocView: the #LOKDocView instance
f325b2
+ * @pCommand: the command to issue to LO core
f325b2
+ * @pArguments: the arguments to the given command
f325b2
+ *
f325b2
+ * This methods forwards your command to LO core.
f325b2
+*/
f325b2
+SAL_DLLPUBLIC_EXPORT void
f325b2
+lok_doc_view_post_command (LOKDocView* pDocView,
f325b2
+                           const char* pCommand,
f325b2
+                           const char* pArguments)
f325b2
 {
f325b2
-    pDocView->m_pImpl->m_pDocument->pClass->postUnoCommand(pDocView->m_pImpl->m_pDocument, pCommand, pArguments);
f325b2
+    pDocView->priv->m_pDocument->pClass->postUnoCommand(pDocView->priv->m_pDocument, pCommand, pArguments);
f325b2
 }
f325b2
 
f325b2
-SAL_DLLPUBLIC_EXPORT void lok_doc_view_post_key(GtkWidget* /*pWidget*/, GdkEventKey* pEvent, gpointer pData)
f325b2
+/**
f325b2
+ * lok_doc_view_post_key:
f325b2
+ * @pDocView: the #LOKDocView instance
f325b2
+ * @pEvent: the #GdkEventKey containing information about the event
f325b2
+ *
f325b2
+ * This methods forwards your key events to the LO core.
f325b2
+*/
f325b2
+SAL_DLLPUBLIC_EXPORT void
f325b2
+lok_doc_view_post_key (LOKDocView* pDocView, GdkEvent* pEvent)
f325b2
 {
f325b2
-    LOKDocView* pDocView = static_cast<LOKDocView *>(pData);
f325b2
-    pDocView->m_pImpl->signalKey(pEvent);
f325b2
+    signalKey(pDocView, pEvent);
f325b2
 }
f325b2
 
f325b2
 /**
f325b2
@@ -1355,9 +1564,10 @@ SAL_DLLPUBLIC_EXPORT void lok_doc_view_post_key(GtkWidget* /*pWidget*/, GdkEvent
f325b2
  *
f325b2
  * Returns: The corresponding value in twips
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT float lok_doc_view_pixel_to_twip(LOKDocView* pDocView, float fInput)
f325b2
+SAL_DLLPUBLIC_EXPORT float
f325b2
+lok_doc_view_pixel_to_twip (LOKDocView* pDocView, float fInput)
f325b2
 {
f325b2
-    return pixelToTwip(fInput, pDocView->m_pImpl->m_fZoom);
f325b2
+    return pixelToTwip(fInput, pDocView->priv->m_fZoom);
f325b2
 }
f325b2
 
f325b2
 /**
f325b2
@@ -1369,10 +1579,10 @@ SAL_DLLPUBLIC_EXPORT float lok_doc_view_pixel_to_twip(LOKDocView* pDocView, floa
f325b2
  *
f325b2
  * Returns: The corresponding value in pixels
f325b2
  */
f325b2
-SAL_DLLPUBLIC_EXPORT float lok_doc_view_twip_to_pixel(LOKDocView* pDocView, float fInput)
f325b2
+SAL_DLLPUBLIC_EXPORT float
f325b2
+lok_doc_view_twip_to_pixel (LOKDocView* pDocView, float fInput)
f325b2
 {
f325b2
-    return twipToPixel(fInput, pDocView->m_pImpl->m_fZoom);
f325b2
+    return twipToPixel(fInput, pDocView->priv->m_fZoom);
f325b2
 }
f325b2
 
f325b2
-
f325b2
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
f325b2
-- 
f325b2
2.12.0
f325b2