LCOV - code coverage report
Current view: top level - libreofficekit/source/gtk - lokdocview.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 592 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 55 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include <sal/types.h>
      11             : #include <math.h>
      12             : #include <string.h>
      13             : #include <vector>
      14             : #include <string>
      15             : 
      16             : #include <gdk/gdkkeysyms.h>
      17             : 
      18             : #include <com/sun/star/awt/Key.hpp>
      19             : #define LOK_USE_UNSTABLE_API
      20             : #include <LibreOfficeKit/LibreOfficeKit.h>
      21             : #include <LibreOfficeKit/LibreOfficeKitEnums.h>
      22             : #include <LibreOfficeKit/LibreOfficeKitGtk.h>
      23             : #include <rsc/rsc-vcl-shared-types.hxx>
      24             : 
      25             : #include "tilebuffer.hxx"
      26             : 
      27             : #if !GLIB_CHECK_VERSION(2,32,0)
      28             : #define G_SOURCE_REMOVE FALSE
      29             : #define G_SOURCE_CONTINUE TRUE
      30             : #endif
      31             : #if !GLIB_CHECK_VERSION(2,40,0)
      32             : #define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
      33             : #endif
      34             : 
      35             : // Cursor bitmaps from the Android app.
      36             : #define CURSOR_HANDLE_DIR "android/source/res/drawable/"
      37             : // Number of handles around a graphic selection.
      38             : #define GRAPHIC_HANDLE_COUNT 8
      39             : 
      40             : /// Holds data used by LOKDocView only.
      41             : struct LOKDocView_Impl
      42             : {
      43             :     LOKDocView* m_pDocView;
      44             :     GtkWidget *m_pDrawingArea;
      45             :     TileBuffer m_aTileBuffer;
      46             : 
      47             :     float m_fZoom;
      48             : 
      49             :     LibreOfficeKit* m_pOffice;
      50             :     LibreOfficeKitDocument* m_pDocument;
      51             :     long m_nDocumentWidthTwips;
      52             :     long m_nDocumentHeightTwips;
      53             :     /// View or edit mode.
      54             :     bool m_bEdit;
      55             :     /// Position and size of the visible cursor.
      56             :     GdkRectangle m_aVisibleCursor;
      57             :     /// Cursor overlay is visible or hidden (for blinking).
      58             :     bool m_bCursorOverlayVisible;
      59             :     /// Cursor is visible or hidden (e.g. for graphic selection).
      60             :     bool m_bCursorVisible;
      61             :     /// Time of the last button press.
      62             :     guint32 m_nLastButtonPressTime;
      63             :     /// Time of the last button release.
      64             :     guint32 m_nLastButtonReleaseTime;
      65             :     /// Rectangles of the current text selection.
      66             :     std::vector<GdkRectangle> m_aTextSelectionRectangles;
      67             :     /// Position and size of the selection start (as if there would be a cursor caret there).
      68             :     GdkRectangle m_aTextSelectionStart;
      69             :     /// Position and size of the selection end.
      70             :     GdkRectangle m_aTextSelectionEnd;
      71             :     GdkRectangle m_aGraphicSelection;
      72             :     bool m_bInDragGraphicSelection;
      73             : 
      74             :     /// @name Start/middle/end handle.
      75             :     ///@{
      76             :     /// Bitmap of the text selection start handle.
      77             :     cairo_surface_t* m_pHandleStart;
      78             :     /// Rectangle of the text selection start handle, to know if the user clicked on it or not
      79             :     GdkRectangle m_aHandleStartRect;
      80             :     /// If we are in the middle of a drag of the text selection end handle.
      81             :     bool m_bInDragStartHandle;
      82             :     /// Bitmap of the text selection middle handle.
      83             :     cairo_surface_t* m_pHandleMiddle;
      84             :     /// Rectangle of the text selection middle handle, to know if the user clicked on it or not
      85             :     GdkRectangle m_aHandleMiddleRect;
      86             :     /// If we are in the middle of a drag of the text selection middle handle.
      87             :     bool m_bInDragMiddleHandle;
      88             :     /// Bitmap of the text selection end handle.
      89             :     cairo_surface_t* m_pHandleEnd;
      90             :     /// Rectangle of the text selection end handle, to know if the user clicked on it or not
      91             :     GdkRectangle m_aHandleEndRect;
      92             :     /// If we are in the middle of a drag of the text selection end handle.
      93             :     bool m_bInDragEndHandle;
      94             :     ///@}
      95             : 
      96             :     /// @name Graphic handles.
      97             :     ///@{
      98             :     /// Bitmap of a graphic selection handle.
      99             :     cairo_surface_t* m_pGraphicHandle;
     100             :     /// Rectangle of a graphic selection handle, to know if the user clicked on it or not.
     101             :     GdkRectangle m_aGraphicHandleRects[8];
     102             :     /// If we are in the middle of a drag of a graphic selection handle.
     103             :     bool m_bInDragGraphicHandles[8];
     104             :     ///@}
     105             : 
     106             :     /// Callback data, allocated in lok_doc_view_callback_worker(), released in lok_doc_view_callback().
     107           0 :     struct CallbackData
     108             :     {
     109             :         int m_nType;
     110             :         std::string m_aPayload;
     111             :         LOKDocView* m_pDocView;
     112             : 
     113             :         CallbackData(int nType, const std::string& rPayload, LOKDocView* pDocView);
     114             :     };
     115             : 
     116             : 
     117             :     LOKDocView_Impl(LOKDocView* pDocView);
     118             :     ~LOKDocView_Impl();
     119             :     /// Connected to the destroy signal of LOKDocView, deletes its LOKDocView_Impl.
     120             :     static void destroy(LOKDocView* pDocView, gpointer pData);
     121             :     /// Connected to the expose-event of the GtkDrawingArea
     122             :     static void on_exposed(GtkWidget *widget, GdkEvent *event, gpointer user_data);
     123             :     /// Receives a key press or release event.
     124             :     void signalKey(GdkEventKey* pEvent);
     125             :     /**
     126             :      * The user drags the handle, which is below the cursor, but wants to move the
     127             :      * cursor accordingly.
     128             :      *
     129             :      * @param pHandle the rectangle of the handle
     130             :      * @param pEvent the motion event
     131             :      * @param pPoint the computed point (output parameter)
     132             :      */
     133             :     static void getDragPoint(GdkRectangle* pHandle, GdkEventButton* pEvent, GdkPoint* pPoint);
     134             :     /// Receives a button press event.
     135             :     static gboolean signalButton(GtkWidget* pEventBox, GdkEventButton* pEvent, LOKDocView* pDocView);
     136             :     /// Implementation of button press event handler, invoked by signalButton().
     137             :     gboolean signalButtonImpl(GdkEventButton* pEvent);
     138             :     /// Receives a motion event.
     139             :     static gboolean signalMotion(GtkWidget* pEventBox, GdkEventButton* pEvent, LOKDocView* pDocView);
     140             :     /// Implementation of motion event handler, invoked by signalMotion().
     141             :     gboolean signalMotionImpl(GdkEventButton* pEvent);
     142             :     /// Receives an expose event.
     143             :     static gboolean renderOverlay(GtkWidget* pWidget, GdkEventExpose* pEvent, LOKDocView* pDocView);
     144             :     /// Implementation of expose event handler (renders cursor and selection overlay), invoked by renderOverlay().
     145             :     gboolean renderOverlayImpl(GtkWidget* pEventBox);
     146             :     /// Is rRectangle empty?
     147             :     static bool isEmptyRectangle(const GdkRectangle& rRectangle);
     148             :     /**
     149             :      * Renders pHandle below an rCursor rectangle on pCairo.
     150             :      * @param rRectangle output parameter, the rectangle that contains the rendered handle.
     151             :      */
     152             :     void renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor, cairo_surface_t* pHandle, GdkRectangle& rRectangle);
     153             :     /// Renders pHandle around an rSelection rectangle on pCairo.
     154             :     void renderGraphicHandle(cairo_t* pCairo, const GdkRectangle& rSelection, cairo_surface_t* pHandle);
     155             :     /// Takes care of the blinking cursor.
     156             :     static gboolean handleTimeout(gpointer pData);
     157             :     /// Implementation of the timeout handler, invoked by handleTimeout().
     158             :     gboolean handleTimeoutImpl();
     159             :     /**
     160             :      * Renders the document to a number of visible tiles.
     161             :      *
     162             :      * This method is invoked only manually, not when some Gtk signal is
     163             :      * emitted.
     164             :      *
     165             :      * @param pPartial if 0, then the full visible document is rendered, otherwise only
     166             :      * the tiles that intersect with pPartial.
     167             :      */
     168             :     void renderDocument(GdkRectangle* pPartial);
     169             :     /// Returns the GdkRectangle of a x,y,width,height string.
     170             :     GdkRectangle payloadToRectangle(const char* pPayload);
     171             :     /// Returns the GdkRectangles of a x1,y1,w1,h1;x2,y2,w2,h2;... string.
     172             :     std::vector<GdkRectangle> payloadToRectangles(const char* pPayload);
     173             :     /// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
     174             :     static const char* callbackTypeToString(int nType);
     175             :     /// Invoked on the main thread if callbackWorker() requests so.
     176             :     static gboolean callback(gpointer pData);
     177             :     /// Invoked on the main thread if globalCallbackWorker() requests so.
     178             :     static gboolean globalCallback(gpointer pData);
     179             :     /// Implementation of the callback handler, invoked by callback();
     180             :     gboolean callbackImpl(CallbackData* pCallbackData);
     181             :     /// Our LOK callback, runs on the LO thread.
     182             :     static void callbackWorker(int nType, const char* pPayload, void* pData);
     183             :     /// Implementation of the callback worder handler, invoked by callbackWorker().
     184             :     void callbackWorkerImpl(int nType, const char* pPayload);
     185             :     /// Our global LOK callback, runs on the LO thread.
     186             :     static void globalCallbackWorker(int nType, const char* pPayload, void* pData);
     187             :     /// Implementation of the global callback worder handler, invoked by globalCallbackWorker().
     188             :     void globalCallbackWorkerImpl(int nType, const char* pPayload);
     189             :     /// Command state (various buttons like bold are toggled or not) is changed.
     190             :     void commandChanged(const std::string& rPayload);
     191             :     /// Search did not find any matches.
     192             :     void searchNotFound(const std::string& rPayload);
     193             :     /// LOK decided to change parts, need to update UI.
     194             :     void setPart(const std::string& rPayload);
     195             :     /// Sets the tiles enclosed by rRectangle as invalid in m_aTileBuffer
     196             :     void setTilesInvalid(const GdkRectangle& rRectangle);
     197             : };
     198             : 
     199             : enum
     200             : {
     201             :     EDIT_CHANGED,
     202             :     COMMAND_CHANGED,
     203             :     SEARCH_NOT_FOUND,
     204             :     PART_CHANGED,
     205             :     LAST_SIGNAL
     206             : };
     207             : 
     208             : 
     209             : static guint doc_view_signals[LAST_SIGNAL] = { 0 };
     210             : 
     211             : SAL_DLLPUBLIC_EXPORT GType lok_doc_view_get_type();
     212             : #ifdef __GNUC__
     213             : #pragma GCC diagnostic push
     214             : #pragma GCC diagnostic ignored "-Wunused-function"
     215             : #endif
     216           0 : G_DEFINE_TYPE(LOKDocView, lok_doc_view, GTK_TYPE_SCROLLED_WINDOW)
     217             : #ifdef __GNUC__
     218             : #pragma GCC diagnostic pop
     219             : #endif
     220             : 
     221             : namespace {
     222             : 
     223             : /// Sets rWidth and rHeight from a "width, height" string.
     224           0 : void payloadToSize(const char* pPayload, long& rWidth, long& rHeight)
     225             : {
     226           0 :     rWidth = rHeight = 0;
     227           0 :     gchar** ppCoordinates = g_strsplit(pPayload, ", ", 2);
     228           0 :     gchar** ppCoordinate = ppCoordinates;
     229           0 :     if (!*ppCoordinate)
     230           0 :         return;
     231           0 :     rWidth = atoi(*ppCoordinate);
     232           0 :     ++ppCoordinate;
     233           0 :     if (!*ppCoordinate)
     234           0 :         return;
     235           0 :     rHeight = atoi(*ppCoordinate);
     236           0 :     g_strfreev(ppCoordinates);
     237             : }
     238             : 
     239             : }
     240             : 
     241             : 
     242             : 
     243             : namespace {
     244             : 
     245             : /// Implementation of the global callback handler, invoked by globalCallback();
     246           0 : gboolean globalCallbackImpl(LOKDocView_Impl::CallbackData* pCallback)
     247             : {
     248           0 :     switch (pCallback->m_nType)
     249             :     {
     250             :     case LOK_CALLBACK_STATUS_INDICATOR_START:
     251             :     {
     252             :     }
     253           0 :     break;
     254             :     case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
     255             :     {
     256             :     }
     257           0 :     break;
     258             :     case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
     259             :     {
     260             :     }
     261           0 :     break;
     262             :     default:
     263           0 :         g_assert(false);
     264             :         break;
     265             :     }
     266           0 :     delete pCallback;
     267             : 
     268           0 :     return G_SOURCE_REMOVE;
     269             : }
     270             : 
     271             : }
     272             : 
     273           0 : LOKDocView_Impl::CallbackData::CallbackData(int nType, const std::string& rPayload, LOKDocView* pDocView)
     274             :     : m_nType(nType),
     275             :     m_aPayload(rPayload),
     276           0 :     m_pDocView(pDocView)
     277             : {
     278           0 : }
     279             : 
     280           0 : LOKDocView_Impl::LOKDocView_Impl(LOKDocView* pDocView)
     281             :     : m_pDocView(pDocView),
     282           0 :       m_pDrawingArea(gtk_drawing_area_new()),
     283             :       m_aTileBuffer(TileBuffer(0,0)),
     284             :       m_fZoom(1),
     285             :       m_pOffice(0),
     286             :       m_pDocument(0),
     287             :       m_nDocumentWidthTwips(0),
     288             :       m_nDocumentHeightTwips(0),
     289             :       m_bEdit(false),
     290             :       m_aVisibleCursor({0, 0, 0, 0}),
     291             :       m_bCursorOverlayVisible(false),
     292             :       m_bCursorVisible(true),
     293             :       m_nLastButtonPressTime(0),
     294             :       m_nLastButtonReleaseTime(0),
     295             :       m_aTextSelectionStart({0, 0, 0, 0}),
     296             :       m_aTextSelectionEnd({0, 0, 0, 0}),
     297             :       m_aGraphicSelection({0, 0, 0, 0}),
     298             :       m_bInDragGraphicSelection(false),
     299             : 
     300             :       // Start/middle/end handle.
     301             :       m_pHandleStart(0),
     302             :       m_aHandleStartRect({0, 0, 0, 0}),
     303             :       m_bInDragStartHandle(false),
     304             :       m_pHandleMiddle(0),
     305             :       m_aHandleMiddleRect({0, 0, 0, 0}),
     306             :       m_bInDragMiddleHandle(false),
     307             :       m_pHandleEnd(0),
     308             :       m_aHandleEndRect({0, 0, 0, 0}),
     309             :       m_bInDragEndHandle(false),
     310             : 
     311           0 :       m_pGraphicHandle(0)
     312             : {
     313           0 :     memset(&m_aGraphicHandleRects, 0, sizeof(m_aGraphicHandleRects));
     314           0 :     memset(&m_bInDragGraphicHandles, 0, sizeof(m_bInDragGraphicHandles));
     315           0 : }
     316             : 
     317           0 : LOKDocView_Impl::~LOKDocView_Impl()
     318             : {
     319           0 :     if (m_pDocument)
     320           0 :         m_pDocument->pClass->destroy(m_pDocument);
     321           0 :     m_pDocument = 0;
     322           0 : }
     323             : 
     324           0 : void LOKDocView_Impl::destroy(LOKDocView* pDocView, gpointer /*pData*/)
     325             : {
     326             :     // We specifically need to destroy the document when closing in order to ensure
     327             :     // that lock files etc. are cleaned up.
     328           0 :     delete pDocView->m_pImpl;
     329           0 : }
     330             : 
     331           0 : void LOKDocView_Impl::on_exposed(GtkWidget* /*widget*/, GdkEvent* /*event*/, gpointer userdata)
     332             : {
     333           0 :     LOKDocView *pDocView = LOK_DOC_VIEW (userdata);
     334           0 :     pDocView->m_pImpl->renderDocument(0);
     335           0 : }
     336             : 
     337           0 : void LOKDocView_Impl::signalKey(GdkEventKey* pEvent)
     338             : {
     339           0 :     int nCharCode = 0;
     340           0 :     int nKeyCode = 0;
     341             : 
     342           0 :     if (!m_bEdit)
     343             :     {
     344           0 :         g_info("signalKey: not in edit mode, ignore");
     345           0 :         return;
     346             :     }
     347             : 
     348           0 :     switch (pEvent->keyval)
     349             :     {
     350             :     case GDK_BackSpace:
     351           0 :         nKeyCode = com::sun::star::awt::Key::BACKSPACE;
     352           0 :         break;
     353             :     case GDK_Return:
     354           0 :         nKeyCode = com::sun::star::awt::Key::RETURN;
     355           0 :         break;
     356             :     case GDK_Escape:
     357           0 :         nKeyCode = com::sun::star::awt::Key::ESCAPE;
     358           0 :         break;
     359             :     case GDK_Tab:
     360           0 :         nKeyCode = com::sun::star::awt::Key::TAB;
     361           0 :         break;
     362             :     case GDK_Down:
     363           0 :         nKeyCode = com::sun::star::awt::Key::DOWN;
     364           0 :         break;
     365             :     case GDK_Up:
     366           0 :         nKeyCode = com::sun::star::awt::Key::UP;
     367           0 :         break;
     368             :     case GDK_Left:
     369           0 :         nKeyCode = com::sun::star::awt::Key::LEFT;
     370           0 :         break;
     371             :     case GDK_Right:
     372           0 :         nKeyCode = com::sun::star::awt::Key::RIGHT;
     373           0 :         break;
     374             :     default:
     375           0 :         if (pEvent->keyval >= GDK_F1 && pEvent->keyval <= GDK_F26)
     376           0 :             nKeyCode = com::sun::star::awt::Key::F1 + (pEvent->keyval - GDK_F1);
     377             :         else
     378           0 :             nCharCode = gdk_keyval_to_unicode(pEvent->keyval);
     379             :     }
     380             : 
     381             :     // rsc is not public API, but should be good enough for debugging purposes.
     382             :     // If this is needed for real, then probably a new param of type
     383             :     // css::awt::KeyModifier is needed in postKeyEvent().
     384           0 :     if (pEvent->state & GDK_SHIFT_MASK)
     385           0 :         nKeyCode |= KEY_SHIFT;
     386             : 
     387           0 :     if (pEvent->type == GDK_KEY_RELEASE)
     388           0 :         m_pDocument->pClass->postKeyEvent(m_pDocument, LOK_KEYEVENT_KEYUP, nCharCode, nKeyCode);
     389             :     else
     390           0 :         m_pDocument->pClass->postKeyEvent(m_pDocument, LOK_KEYEVENT_KEYINPUT, nCharCode, nKeyCode);
     391             : }
     392             : 
     393           0 : gboolean LOKDocView_Impl::signalButton(GtkWidget* /*pEventBox*/, GdkEventButton* pEvent, LOKDocView* pDocView)
     394             : {
     395           0 :     return pDocView->m_pImpl->signalButtonImpl(pEvent);
     396             : }
     397             : 
     398             : /// Receives a button press event.
     399           0 : gboolean LOKDocView_Impl::signalButtonImpl(GdkEventButton* pEvent)
     400             : {
     401           0 :     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));
     402             : 
     403           0 :     if (pEvent->type == GDK_BUTTON_RELEASE)
     404             :     {
     405           0 :         if (m_bInDragStartHandle)
     406             :         {
     407           0 :             g_info("LOKDocView_Impl::signalButton: end of drag start handle");
     408           0 :             m_bInDragStartHandle = false;
     409           0 :             return FALSE;
     410             :         }
     411           0 :         else if (m_bInDragMiddleHandle)
     412             :         {
     413           0 :             g_info("LOKDocView_Impl::signalButton: end of drag middle handle");
     414           0 :             m_bInDragMiddleHandle = false;
     415           0 :             return FALSE;
     416             :         }
     417           0 :         else if (m_bInDragEndHandle)
     418             :         {
     419           0 :             g_info("LOKDocView_Impl::signalButton: end of drag end handle");
     420           0 :             m_bInDragEndHandle = false;
     421           0 :             return FALSE;
     422             :         }
     423             : 
     424           0 :         for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
     425             :         {
     426           0 :             if (m_bInDragGraphicHandles[i])
     427             :             {
     428           0 :                 g_info("LOKDocView_Impl::signalButton: end of drag graphic handle #%d", i);
     429           0 :                 m_bInDragGraphicHandles[i] = false;
     430           0 :                 m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
     431           0 :                 return FALSE;
     432             :             }
     433             :         }
     434             : 
     435           0 :         if (m_bInDragGraphicSelection)
     436             :         {
     437           0 :             g_info("LOKDocView_Impl::signalButton: end of drag graphic selection");
     438           0 :             m_bInDragGraphicSelection = false;
     439           0 :             m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_END, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
     440           0 :             return FALSE;
     441             :         }
     442             :     }
     443             : 
     444           0 :     if (m_bEdit)
     445             :     {
     446             :         GdkRectangle aClick;
     447           0 :         aClick.x = pEvent->x;
     448           0 :         aClick.y = pEvent->y;
     449           0 :         aClick.width = 1;
     450           0 :         aClick.height = 1;
     451           0 :         if (pEvent->type == GDK_BUTTON_PRESS)
     452             :         {
     453           0 :             if (gdk_rectangle_intersect(&aClick, &m_aHandleStartRect, NULL))
     454             :             {
     455           0 :                 g_info("LOKDocView_Impl::signalButton: start of drag start handle");
     456           0 :                 m_bInDragStartHandle = true;
     457           0 :                 return FALSE;
     458             :             }
     459           0 :             else if (gdk_rectangle_intersect(&aClick, &m_aHandleMiddleRect, NULL))
     460             :             {
     461           0 :                 g_info("LOKDocView_Impl::signalButton: start of drag middle handle");
     462           0 :                 m_bInDragMiddleHandle = true;
     463           0 :                 return FALSE;
     464             :             }
     465           0 :             else if (gdk_rectangle_intersect(&aClick, &m_aHandleEndRect, NULL))
     466             :             {
     467           0 :                 g_info("LOKDocView_Impl::signalButton: start of drag end handle");
     468           0 :                 m_bInDragEndHandle = true;
     469           0 :                 return FALSE;
     470             :             }
     471             : 
     472           0 :             for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
     473             :             {
     474           0 :                 if (gdk_rectangle_intersect(&aClick, &m_aGraphicHandleRects[i], NULL))
     475             :                 {
     476           0 :                     g_info("LOKDocView_Impl::signalButton: start of drag graphic handle #%d", i);
     477           0 :                     m_bInDragGraphicHandles[i] = true;
     478             :                     m_pDocument->pClass->setGraphicSelection(m_pDocument,
     479             :                                                              LOK_SETGRAPHICSELECTION_START,
     480           0 :                                                              pixelToTwip(m_aGraphicHandleRects[i].x + m_aGraphicHandleRects[i].width / 2, m_fZoom),
     481           0 :                                                              pixelToTwip(m_aGraphicHandleRects[i].y + m_aGraphicHandleRects[i].height / 2, m_fZoom));
     482           0 :                     return FALSE;
     483             :                 }
     484             :             }
     485             :         }
     486             :     }
     487             : 
     488           0 :     if (!m_bEdit)
     489           0 :         lok_doc_view_set_edit(m_pDocView, TRUE);
     490             : 
     491           0 :     switch (pEvent->type)
     492             :     {
     493             :     case GDK_BUTTON_PRESS:
     494             :     {
     495           0 :         int nCount = 1;
     496           0 :         if ((pEvent->time - m_nLastButtonPressTime) < 250)
     497           0 :             nCount++;
     498           0 :         m_nLastButtonPressTime = pEvent->time;
     499           0 :         m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), nCount);
     500           0 :         break;
     501             :     }
     502             :     case GDK_BUTTON_RELEASE:
     503             :     {
     504           0 :         int nCount = 1;
     505           0 :         if ((pEvent->time - m_nLastButtonReleaseTime) < 250)
     506           0 :             nCount++;
     507           0 :         m_nLastButtonReleaseTime = pEvent->time;
     508           0 :         m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), nCount);
     509           0 :         break;
     510             :     }
     511             :     default:
     512           0 :         break;
     513             :     }
     514           0 :     return FALSE;
     515             : }
     516             : 
     517           0 : void LOKDocView_Impl::getDragPoint(GdkRectangle* pHandle, GdkEventButton* pEvent, GdkPoint* pPoint)
     518             : {
     519             :     GdkPoint aCursor, aHandle;
     520             : 
     521             :     // Center of the cursor rectangle: we know that it's above the handle.
     522           0 :     aCursor.x = pHandle->x + pHandle->width / 2;
     523           0 :     aCursor.y = pHandle->y - pHandle->height / 2;
     524             :     // Center of the handle rectangle.
     525           0 :     aHandle.x = pHandle->x + pHandle->width / 2;
     526           0 :     aHandle.y = pHandle->y + pHandle->height / 2;
     527             :     // Our target is the original cursor position + the dragged offset.
     528           0 :     pPoint->x = aCursor.x + (pEvent->x - aHandle.x);
     529           0 :     pPoint->y = aCursor.y + (pEvent->y - aHandle.y);
     530           0 : }
     531             : 
     532           0 : gboolean LOKDocView_Impl::signalMotion(GtkWidget* /*pEventBox*/, GdkEventButton* pEvent, LOKDocView* pDocView)
     533             : {
     534           0 :     return pDocView->m_pImpl->signalMotionImpl(pEvent);
     535             : }
     536             : 
     537           0 : gboolean LOKDocView_Impl::signalMotionImpl(GdkEventButton* pEvent)
     538             : {
     539             :     GdkPoint aPoint;
     540             : 
     541           0 :     if (m_bInDragMiddleHandle)
     542             :     {
     543           0 :         g_info("lcl_signalMotion: dragging the middle handle");
     544           0 :         LOKDocView_Impl::getDragPoint(&m_aHandleMiddleRect, pEvent, &aPoint);
     545           0 :         m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_RESET, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
     546           0 :         return FALSE;
     547             :     }
     548           0 :     if (m_bInDragStartHandle)
     549             :     {
     550           0 :         g_info("lcl_signalMotion: dragging the start handle");
     551           0 :         LOKDocView_Impl::getDragPoint(&m_aHandleStartRect, pEvent, &aPoint);
     552           0 :         m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_START, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
     553           0 :         return FALSE;
     554             :     }
     555           0 :     if (m_bInDragEndHandle)
     556             :     {
     557           0 :         g_info("lcl_signalMotion: dragging the end handle");
     558           0 :         LOKDocView_Impl::getDragPoint(&m_aHandleEndRect, pEvent, &aPoint);
     559           0 :         m_pDocument->pClass->setTextSelection(m_pDocument, LOK_SETTEXTSELECTION_END, pixelToTwip(aPoint.x, m_fZoom), pixelToTwip(aPoint.y, m_fZoom));
     560           0 :         return FALSE;
     561             :     }
     562           0 :     for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
     563             :     {
     564           0 :         if (m_bInDragGraphicHandles[i])
     565             :         {
     566           0 :             g_info("lcl_signalMotion: dragging the graphic handle #%d", i);
     567           0 :             return FALSE;
     568             :         }
     569             :     }
     570           0 :     if (m_bInDragGraphicSelection)
     571             :     {
     572           0 :         g_info("lcl_signalMotion: dragging the graphic selection");
     573           0 :         return FALSE;
     574             :     }
     575             : 
     576             :     GdkRectangle aMotionInTwipsInTwips;
     577           0 :     aMotionInTwipsInTwips.x = pixelToTwip(pEvent->x, m_fZoom);
     578           0 :     aMotionInTwipsInTwips.y = pixelToTwip(pEvent->y, m_fZoom);
     579           0 :     aMotionInTwipsInTwips.width = 1;
     580           0 :     aMotionInTwipsInTwips.height = 1;
     581           0 :     if (gdk_rectangle_intersect(&aMotionInTwipsInTwips, &m_aGraphicSelection, 0))
     582             :     {
     583           0 :         g_info("lcl_signalMotion: start of drag graphic selection");
     584           0 :         m_bInDragGraphicSelection = true;
     585           0 :         m_pDocument->pClass->setGraphicSelection(m_pDocument, LOK_SETGRAPHICSELECTION_START, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom));
     586           0 :         return FALSE;
     587             :     }
     588             : 
     589             :     // Otherwise a mouse move, as on the desktop.
     590           0 :     m_pDocument->pClass->postMouseEvent(m_pDocument, LOK_MOUSEEVENT_MOUSEMOVE, pixelToTwip(pEvent->x, m_fZoom), pixelToTwip(pEvent->y, m_fZoom), 1);
     591             : 
     592           0 :     return FALSE;
     593             : }
     594             : 
     595           0 : gboolean LOKDocView_Impl::renderOverlay(GtkWidget* pEventBox, GdkEventExpose* /*pEvent*/, LOKDocView* pDocView)
     596             : {
     597           0 :     return pDocView->m_pImpl->renderOverlayImpl(pEventBox);
     598             : }
     599             : 
     600           0 : gboolean LOKDocView_Impl::renderOverlayImpl(GtkWidget* pWidget)
     601             : {
     602             : #if GTK_CHECK_VERSION(2,14,0) // we need gtk_widget_get_window()
     603           0 :     cairo_t* pCairo = gdk_cairo_create(gtk_widget_get_window(pWidget));
     604             : 
     605           0 :     if (m_bEdit && m_bCursorVisible && m_bCursorOverlayVisible && !isEmptyRectangle(m_aVisibleCursor))
     606             :     {
     607           0 :         if (m_aVisibleCursor.width < 30)
     608             :             // Set a minimal width if it would be 0.
     609           0 :             m_aVisibleCursor.width = 30;
     610             : 
     611           0 :         cairo_set_source_rgb(pCairo, 0, 0, 0);
     612             :         cairo_rectangle(pCairo,
     613           0 :                         twipToPixel(m_aVisibleCursor.x, m_fZoom),
     614           0 :                         twipToPixel(m_aVisibleCursor.y, m_fZoom),
     615           0 :                         twipToPixel(m_aVisibleCursor.width, m_fZoom),
     616           0 :                         twipToPixel(m_aVisibleCursor.height, m_fZoom));
     617           0 :         cairo_fill(pCairo);
     618             :     }
     619             : 
     620           0 :     if (m_bEdit && m_bCursorVisible && !isEmptyRectangle(m_aVisibleCursor) && m_aTextSelectionRectangles.empty())
     621             :     {
     622             :         // Have a cursor, but no selection: we need the middle handle.
     623           0 :         if (!m_pHandleMiddle)
     624           0 :             m_pHandleMiddle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_middle.png");
     625           0 :         renderHandle(pCairo, m_aVisibleCursor, m_pHandleMiddle, m_aHandleMiddleRect);
     626             :     }
     627             : 
     628           0 :     if (!m_aTextSelectionRectangles.empty())
     629             :     {
     630           0 :         for (GdkRectangle& rRectangle : m_aTextSelectionRectangles)
     631             :         {
     632             :             // Blue with 75% transparency.
     633           0 :             cairo_set_source_rgba(pCairo, ((double)0x43)/255, ((double)0xac)/255, ((double)0xe8)/255, 0.25);
     634             :             cairo_rectangle(pCairo,
     635           0 :                             twipToPixel(rRectangle.x, m_fZoom),
     636           0 :                             twipToPixel(rRectangle.y, m_fZoom),
     637           0 :                             twipToPixel(rRectangle.width, m_fZoom),
     638           0 :                             twipToPixel(rRectangle.height, m_fZoom));
     639           0 :             cairo_fill(pCairo);
     640             :         }
     641             : 
     642             :         // Handles
     643           0 :         if (!isEmptyRectangle(m_aTextSelectionStart))
     644             :         {
     645             :             // Have a start position: we need a start handle.
     646           0 :             if (!m_pHandleStart)
     647           0 :                 m_pHandleStart = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_start.png");
     648           0 :             renderHandle(pCairo, m_aTextSelectionStart, m_pHandleStart, m_aHandleStartRect);
     649             :         }
     650           0 :         if (!isEmptyRectangle(m_aTextSelectionEnd))
     651             :         {
     652             :             // Have a start position: we need an end handle.
     653           0 :             if (!m_pHandleEnd)
     654           0 :                 m_pHandleEnd = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_end.png");
     655           0 :             renderHandle(pCairo, m_aTextSelectionEnd, m_pHandleEnd, m_aHandleEndRect);
     656             :         }
     657             :     }
     658             : 
     659           0 :     if (!isEmptyRectangle(m_aGraphicSelection))
     660             :     {
     661           0 :         if (!m_pGraphicHandle)
     662           0 :             m_pGraphicHandle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_graphic.png");
     663           0 :         renderGraphicHandle(pCairo, m_aGraphicSelection, m_pGraphicHandle);
     664             :     }
     665             : 
     666           0 :     cairo_destroy(pCairo);
     667             : #endif
     668           0 :     return FALSE;
     669             : }
     670             : 
     671           0 : bool LOKDocView_Impl::isEmptyRectangle(const GdkRectangle& rRectangle)
     672             : {
     673           0 :     return rRectangle.x == 0 && rRectangle.y == 0 && rRectangle.width == 0 && rRectangle.height == 0;
     674             : }
     675             : 
     676           0 : void LOKDocView_Impl::setTilesInvalid(const GdkRectangle& rRectangle)
     677             : {
     678             :     GdkRectangle aRectanglePixels;
     679             :     GdkPoint aStart, aEnd;
     680             : 
     681           0 :     aRectanglePixels.x = twipToPixel(rRectangle.x, m_fZoom);
     682           0 :     aRectanglePixels.y = twipToPixel(rRectangle.y, m_fZoom);
     683           0 :     aRectanglePixels.width = twipToPixel(rRectangle.width, m_fZoom);
     684           0 :     aRectanglePixels.height = twipToPixel(rRectangle.height, m_fZoom);
     685             : 
     686           0 :     aStart.x = aRectanglePixels.y / nTileSizePixels;
     687           0 :     aStart.y = aRectanglePixels.x / nTileSizePixels;
     688           0 :     aEnd.x = (aRectanglePixels.y + aRectanglePixels.height + nTileSizePixels) / nTileSizePixels;
     689           0 :     aEnd.y = (aRectanglePixels.x + aRectanglePixels.width + nTileSizePixels) / nTileSizePixels;
     690             : 
     691           0 :     for (int i = aStart.x; i < aEnd.x; i++)
     692           0 :         for (int j = aStart.y; j < aEnd.y; j++)
     693           0 :             m_aTileBuffer.setInvalid(i, j);
     694           0 : }
     695             : 
     696           0 : void LOKDocView_Impl::renderHandle(cairo_t* pCairo, const GdkRectangle& rCursor, cairo_surface_t* pHandle, GdkRectangle& rRectangle)
     697             : {
     698             :     GdkPoint aCursorBottom;
     699             :     int nHandleWidth, nHandleHeight;
     700             :     double fHandleScale;
     701             : 
     702           0 :     nHandleWidth = cairo_image_surface_get_width(pHandle);
     703           0 :     nHandleHeight = cairo_image_surface_get_height(pHandle);
     704             :     // We want to scale down the handle, so that its height is the same as the cursor caret.
     705           0 :     fHandleScale = twipToPixel(rCursor.height, m_fZoom) / nHandleHeight;
     706             :     // We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
     707           0 :     aCursorBottom.x = twipToPixel(rCursor.x, m_fZoom) + twipToPixel(rCursor.width, m_fZoom) / 2 - (nHandleWidth * fHandleScale) / 2;
     708           0 :     aCursorBottom.y = twipToPixel(rCursor.y, m_fZoom) + twipToPixel(rCursor.height, m_fZoom);
     709           0 :     cairo_save(pCairo);
     710           0 :     cairo_translate(pCairo, aCursorBottom.x, aCursorBottom.y);
     711           0 :     cairo_scale(pCairo, fHandleScale, fHandleScale);
     712           0 :     cairo_set_source_surface(pCairo, pHandle, 0, 0);
     713           0 :     cairo_paint(pCairo);
     714           0 :     cairo_restore(pCairo);
     715             : 
     716           0 :     rRectangle.x = aCursorBottom.x;
     717           0 :     rRectangle.y = aCursorBottom.y;
     718           0 :     rRectangle.width = nHandleWidth * fHandleScale;
     719           0 :     rRectangle.height = nHandleHeight * fHandleScale;
     720           0 : }
     721             : 
     722             : /// Renders pHandle around an rSelection rectangle on pCairo.
     723           0 : void LOKDocView_Impl::renderGraphicHandle(cairo_t* pCairo, const GdkRectangle& rSelection, cairo_surface_t* pHandle)
     724             : {
     725             :     int nHandleWidth, nHandleHeight;
     726             :     GdkRectangle aSelection;
     727             : 
     728           0 :     nHandleWidth = cairo_image_surface_get_width(pHandle);
     729           0 :     nHandleHeight = cairo_image_surface_get_height(pHandle);
     730             : 
     731           0 :     aSelection.x = twipToPixel(rSelection.x, m_fZoom);
     732           0 :     aSelection.y = twipToPixel(rSelection.y, m_fZoom);
     733           0 :     aSelection.width = twipToPixel(rSelection.width, m_fZoom);
     734           0 :     aSelection.height = twipToPixel(rSelection.height, m_fZoom);
     735             : 
     736           0 :     for (int i = 0; i < GRAPHIC_HANDLE_COUNT; ++i)
     737             :     {
     738           0 :         int x = aSelection.x, y = aSelection.y;
     739           0 :         cairo_save(pCairo);
     740             : 
     741           0 :         switch (i)
     742             :         {
     743             :         case 0: // top-left
     744           0 :             break;
     745             :         case 1: // top-middle
     746           0 :             x += aSelection.width / 2;
     747           0 :             break;
     748             :         case 2: // top-right
     749           0 :             x += aSelection.width;
     750           0 :             break;
     751             :         case 3: // middle-left
     752           0 :             y += aSelection.height / 2;
     753           0 :             break;
     754             :         case 4: // middle-right
     755           0 :             x += aSelection.width;
     756           0 :             y += aSelection.height / 2;
     757           0 :             break;
     758             :         case 5: // bottom-left
     759           0 :             y += aSelection.height;
     760           0 :             break;
     761             :         case 6: // bottom-middle
     762           0 :             x += aSelection.width / 2;
     763           0 :             y += aSelection.height;
     764           0 :             break;
     765             :         case 7: // bottom-right
     766           0 :             x += aSelection.width;
     767           0 :             y += aSelection.height;
     768           0 :             break;
     769             :         }
     770             : 
     771             :         // Center the handle.
     772           0 :         x -= nHandleWidth / 2;
     773           0 :         y -= nHandleHeight / 2;
     774             : 
     775           0 :         m_aGraphicHandleRects[i].x = x;
     776           0 :         m_aGraphicHandleRects[i].y = y;
     777           0 :         m_aGraphicHandleRects[i].width = nHandleWidth;
     778           0 :         m_aGraphicHandleRects[i].height = nHandleHeight;
     779             : 
     780           0 :         cairo_translate(pCairo, x, y);
     781           0 :         cairo_set_source_surface(pCairo, pHandle, 0, 0);
     782           0 :         cairo_paint(pCairo);
     783           0 :         cairo_restore(pCairo);
     784             :     }
     785           0 : }
     786             : 
     787           0 : gboolean LOKDocView_Impl::handleTimeout(gpointer pData)
     788             : {
     789           0 :     LOKDocView* pDocView = static_cast<LOKDocView*>(pData);
     790           0 :     return pDocView->m_pImpl->handleTimeoutImpl();
     791             : }
     792             : 
     793           0 : gboolean LOKDocView_Impl::handleTimeoutImpl()
     794             : {
     795           0 :     if (m_bEdit)
     796             :     {
     797           0 :         if (m_bCursorOverlayVisible)
     798           0 :             m_bCursorOverlayVisible = false;
     799             :         else
     800           0 :             m_bCursorOverlayVisible = true;
     801           0 :         gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
     802             :     }
     803             : 
     804           0 :     return G_SOURCE_CONTINUE;
     805             : }
     806             : 
     807           0 : void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
     808             : {
     809             :     GdkRectangle visibleArea;
     810           0 :     lok_doc_view_get_visarea (m_pDocView, &visibleArea);
     811             : 
     812           0 :     long nDocumentWidthPixels = twipToPixel(m_nDocumentWidthTwips, m_fZoom);
     813           0 :     long nDocumentHeightPixels = twipToPixel(m_nDocumentHeightTwips, m_fZoom);
     814             :     // Total number of rows / columns in this document.
     815           0 :     guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
     816           0 :     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
     817             : 
     818           0 :     cairo_t *pcairo = gdk_cairo_create(m_pDrawingArea->window);
     819             : 
     820             :     // Render the tiles.
     821           0 :     for (guint nRow = 0; nRow < nRows; ++nRow)
     822             :     {
     823           0 :         for (guint nColumn = 0; nColumn < nColumns; ++nColumn)
     824             :         {
     825             :             GdkRectangle aTileRectangleTwips, aTileRectanglePixels;
     826           0 :             bool bPaint = true;
     827             : 
     828             :             // Determine size of the tile: the rightmost/bottommost tiles may
     829             :             // be smaller, and we need the size to decide if we need to repaint.
     830           0 :             if (nColumn == nColumns - 1)
     831           0 :                 aTileRectanglePixels.width = nDocumentWidthPixels - nColumn * nTileSizePixels;
     832             :             else
     833           0 :                 aTileRectanglePixels.width = nTileSizePixels;
     834           0 :             if (nRow == nRows - 1)
     835           0 :                 aTileRectanglePixels.height = nDocumentHeightPixels - nRow * nTileSizePixels;
     836             :             else
     837           0 :                 aTileRectanglePixels.height = nTileSizePixels;
     838             : 
     839             :             // Determine size and position of the tile in document coordinates,
     840             :             // so we can decide if we can skip painting for partial rendering.
     841           0 :             aTileRectangleTwips.x = pixelToTwip(nTileSizePixels, m_fZoom) * nColumn;
     842           0 :             aTileRectangleTwips.y = pixelToTwip(nTileSizePixels, m_fZoom) * nRow;
     843           0 :             aTileRectangleTwips.width = pixelToTwip(aTileRectanglePixels.width, m_fZoom);
     844           0 :             aTileRectangleTwips.height = pixelToTwip(aTileRectanglePixels.height, m_fZoom);
     845           0 :             if (pPartial && !gdk_rectangle_intersect(pPartial, &aTileRectangleTwips, 0))
     846           0 :                 bPaint = false;
     847             : 
     848           0 :             if (!gdk_rectangle_intersect(&visibleArea, &aTileRectangleTwips, 0))
     849           0 :                 bPaint = false;
     850             : 
     851           0 :             if (bPaint)
     852             :             {
     853             :                 //g_info("tile_buffer_get_tile (%d, %d)", nRow, nColumn);
     854             : 
     855           0 :                 Tile& currentTile = m_aTileBuffer.getTile(nRow, nColumn, m_fZoom);
     856           0 :                 GdkPixbuf* pPixBuf = currentTile.getBuffer();
     857             : 
     858             :                 gdk_cairo_set_source_pixbuf (pcairo, pPixBuf,
     859           0 :                                              twipToPixel(aTileRectangleTwips.x, m_fZoom),
     860           0 :                                              twipToPixel(aTileRectangleTwips.y, m_fZoom));
     861           0 :                 cairo_paint(pcairo);
     862             :             }
     863             :         }
     864             :     }
     865             : 
     866           0 :     cairo_destroy(pcairo);
     867           0 : }
     868             : 
     869             : 
     870           0 : GdkRectangle LOKDocView_Impl::payloadToRectangle(const char* pPayload)
     871             : {
     872             :     GdkRectangle aRet;
     873             : 
     874           0 :     aRet.width = aRet.height = aRet.x = aRet.y = 0;
     875           0 :     gchar** ppCoordinates = g_strsplit(pPayload, ", ", 4);
     876           0 :     gchar** ppCoordinate = ppCoordinates;
     877           0 :     if (!*ppCoordinate)
     878           0 :         return aRet;
     879           0 :     aRet.x = atoi(*ppCoordinate);
     880           0 :     if (aRet.x < 0)
     881           0 :         aRet.x = 0;
     882           0 :     ++ppCoordinate;
     883           0 :     if (!*ppCoordinate)
     884           0 :         return aRet;
     885           0 :     aRet.y = atoi(*ppCoordinate);
     886           0 :     if (aRet.y < 0)
     887           0 :         aRet.y = 0;
     888           0 :     ++ppCoordinate;
     889           0 :     if (!*ppCoordinate)
     890           0 :         return aRet;
     891           0 :     aRet.width = atoi(*ppCoordinate);
     892           0 :     if (aRet.x + aRet.width > m_nDocumentWidthTwips)
     893           0 :         aRet.width = m_nDocumentWidthTwips - aRet.x;
     894           0 :     ++ppCoordinate;
     895           0 :     if (!*ppCoordinate)
     896           0 :         return aRet;
     897           0 :     aRet.height = atoi(*ppCoordinate);
     898           0 :     if (aRet.y + aRet.height > m_nDocumentHeightTwips)
     899           0 :         aRet.height = m_nDocumentHeightTwips - aRet.y;
     900           0 :     g_strfreev(ppCoordinates);
     901           0 :     return aRet;
     902             : }
     903             : 
     904           0 : std::vector<GdkRectangle> LOKDocView_Impl::payloadToRectangles(const char* pPayload)
     905             : {
     906           0 :     std::vector<GdkRectangle> aRet;
     907             : 
     908           0 :     gchar** ppRectangles = g_strsplit(pPayload, "; ", 0);
     909           0 :     for (gchar** ppRectangle = ppRectangles; *ppRectangle; ++ppRectangle)
     910           0 :         aRet.push_back(payloadToRectangle(*ppRectangle));
     911           0 :     g_strfreev(ppRectangles);
     912             : 
     913           0 :     return aRet;
     914             : }
     915             : 
     916             : /// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
     917           0 : const char* LOKDocView_Impl::callbackTypeToString(int nType)
     918             : {
     919           0 :     switch (nType)
     920             :     {
     921             :     case LOK_CALLBACK_INVALIDATE_TILES:
     922           0 :         return "LOK_CALLBACK_INVALIDATE_TILES";
     923             :     case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
     924           0 :         return "LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR";
     925             :     case LOK_CALLBACK_TEXT_SELECTION:
     926           0 :         return "LOK_CALLBACK_TEXT_SELECTION";
     927             :     case LOK_CALLBACK_TEXT_SELECTION_START:
     928           0 :         return "LOK_CALLBACK_TEXT_SELECTION_START";
     929             :     case LOK_CALLBACK_TEXT_SELECTION_END:
     930           0 :         return "LOK_CALLBACK_TEXT_SELECTION_END";
     931             :     case LOK_CALLBACK_CURSOR_VISIBLE:
     932           0 :         return "LOK_CALLBACK_CURSOR_VISIBLE";
     933             :     case LOK_CALLBACK_GRAPHIC_SELECTION:
     934           0 :         return "LOK_CALLBACK_GRAPHIC_SELECTION";
     935             :     case LOK_CALLBACK_HYPERLINK_CLICKED:
     936           0 :         return "LOK_CALLBACK_HYPERLINK_CLICKED";
     937             :     case LOK_CALLBACK_STATE_CHANGED:
     938           0 :         return "LOK_CALLBACK_STATE_CHANGED";
     939             :     case LOK_CALLBACK_STATUS_INDICATOR_START:
     940           0 :         return "LOK_CALLBACK_STATUS_INDICATOR_START";
     941             :     case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
     942           0 :         return "LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE";
     943             :     case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
     944           0 :         return "LOK_CALLBACK_STATUS_INDICATOR_FINISH";
     945             :     case LOK_CALLBACK_SEARCH_NOT_FOUND:
     946           0 :         return "LOK_CALLBACK_SEARCH_NOT_FOUND";
     947             :     case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
     948           0 :         return "LOK_CALLBACK_DOCUMENT_SIZE_CHANGED";
     949             :     case LOK_CALLBACK_SET_PART:
     950           0 :         return "LOK_CALLBACK_SET_PART";
     951             :     }
     952           0 :     return 0;
     953             : }
     954             : 
     955           0 : gboolean LOKDocView_Impl::callback(gpointer pData)
     956             : {
     957           0 :     LOKDocView_Impl::CallbackData* pCallback = static_cast<LOKDocView_Impl::CallbackData*>(pData);
     958           0 :     return pCallback->m_pDocView->m_pImpl->callbackImpl(pCallback);
     959             : }
     960             : 
     961           0 : gboolean LOKDocView_Impl::globalCallback(gpointer pData)
     962             : {
     963           0 :     LOKDocView_Impl::CallbackData* pCallback = static_cast<LOKDocView_Impl::CallbackData*>(pData);
     964           0 :     return globalCallbackImpl(pCallback);
     965             : }
     966             : 
     967           0 : gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
     968             : {
     969           0 :     switch (pCallback->m_nType)
     970             :     {
     971             :     case LOK_CALLBACK_INVALIDATE_TILES:
     972             :     {
     973           0 :         if (pCallback->m_aPayload != "EMPTY")
     974             :         {
     975           0 :             GdkRectangle aRectangle = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
     976           0 :             setTilesInvalid(aRectangle);
     977             :         }
     978             :         else
     979           0 :             m_aTileBuffer.resetAllTiles();
     980             : 
     981           0 :         gtk_widget_queue_draw(m_pDrawingArea);
     982             :     }
     983           0 :     break;
     984             :     case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
     985             :     {
     986           0 :         m_aVisibleCursor = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
     987           0 :         m_bCursorOverlayVisible = true;
     988           0 :         gtk_widget_queue_draw(m_pDrawingArea);
     989             :     }
     990           0 :     break;
     991             :     case LOK_CALLBACK_TEXT_SELECTION:
     992             :     {
     993           0 :         m_aTextSelectionRectangles = LOKDocView_Impl::payloadToRectangles(pCallback->m_aPayload.c_str());
     994             : 
     995             :         // In case the selection is empty, then we get no LOK_CALLBACK_TEXT_SELECTION_START/END events.
     996           0 :         if (m_aTextSelectionRectangles.empty())
     997             :         {
     998           0 :             memset(&m_aTextSelectionStart, 0, sizeof(m_aTextSelectionStart));
     999           0 :             memset(&m_aHandleStartRect, 0, sizeof(m_aHandleStartRect));
    1000           0 :             memset(&m_aTextSelectionEnd, 0, sizeof(m_aTextSelectionEnd));
    1001           0 :             memset(&m_aHandleEndRect, 0, sizeof(m_aHandleEndRect));
    1002             :         }
    1003             :         else
    1004           0 :             memset(&m_aHandleMiddleRect, 0, sizeof(m_aHandleMiddleRect));
    1005             :     }
    1006           0 :     break;
    1007             :     case LOK_CALLBACK_TEXT_SELECTION_START:
    1008             :     {
    1009           0 :         m_aTextSelectionStart = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
    1010             :     }
    1011           0 :     break;
    1012             :     case LOK_CALLBACK_TEXT_SELECTION_END:
    1013             :     {
    1014           0 :         m_aTextSelectionEnd = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
    1015             :     }
    1016           0 :     break;
    1017             :     case LOK_CALLBACK_CURSOR_VISIBLE:
    1018             :     {
    1019           0 :         m_bCursorVisible = pCallback->m_aPayload == "true";
    1020             :     }
    1021           0 :     break;
    1022             :     case LOK_CALLBACK_GRAPHIC_SELECTION:
    1023             :     {
    1024           0 :         if (pCallback->m_aPayload != "EMPTY")
    1025           0 :             m_aGraphicSelection = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
    1026             :         else
    1027           0 :             memset(&m_aGraphicSelection, 0, sizeof(m_aGraphicSelection));
    1028           0 :         gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
    1029             :     }
    1030           0 :     break;
    1031             :     case LOK_CALLBACK_HYPERLINK_CLICKED:
    1032             :     {
    1033           0 :         GError* pError = NULL;
    1034             : #if GTK_CHECK_VERSION(2,14,0)
    1035           0 :         gtk_show_uri(NULL, pCallback->m_aPayload.c_str(), GDK_CURRENT_TIME, &pError);
    1036             : #endif
    1037             :     }
    1038           0 :     break;
    1039             :     case LOK_CALLBACK_STATE_CHANGED:
    1040             :     {
    1041           0 :         commandChanged(pCallback->m_aPayload);
    1042             :     }
    1043           0 :     break;
    1044             :     case LOK_CALLBACK_SEARCH_NOT_FOUND:
    1045             :     {
    1046           0 :         searchNotFound(pCallback->m_aPayload);
    1047             :     }
    1048           0 :     break;
    1049             :     case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
    1050             :     {
    1051           0 :         payloadToSize(pCallback->m_aPayload.c_str(), m_nDocumentWidthTwips, m_nDocumentHeightTwips);
    1052             :         gtk_widget_set_size_request(m_pDrawingArea,
    1053           0 :                                     twipToPixel(m_nDocumentWidthTwips, m_fZoom),
    1054           0 :                                     twipToPixel(m_nDocumentHeightTwips, m_fZoom));
    1055             :     }
    1056           0 :     break;
    1057             :     case LOK_CALLBACK_SET_PART:
    1058             :     {
    1059           0 :         setPart(pCallback->m_aPayload);
    1060             :     }
    1061           0 :     break;
    1062             :     default:
    1063           0 :         g_assert(false);
    1064             :         break;
    1065             :     }
    1066           0 :     delete pCallback;
    1067             : 
    1068           0 :     return G_SOURCE_REMOVE;
    1069             : }
    1070             : 
    1071           0 : void LOKDocView_Impl::callbackWorker(int nType, const char* pPayload, void* pData)
    1072             : {
    1073           0 :     LOKDocView* pDocView = static_cast<LOKDocView*>(pData);
    1074           0 :     pDocView->m_pImpl->callbackWorkerImpl(nType, pPayload);
    1075           0 : }
    1076             : 
    1077           0 : void LOKDocView_Impl::globalCallbackWorker(int nType, const char* pPayload, void* pData)
    1078             : {
    1079           0 :     LOKDocView* pDocView = static_cast<LOKDocView*>(pData);
    1080           0 :     pDocView->m_pImpl->globalCallbackWorkerImpl(nType, pPayload);
    1081           0 : }
    1082             : 
    1083           0 : void LOKDocView_Impl::callbackWorkerImpl(int nType, const char* pPayload)
    1084             : {
    1085           0 :     LOKDocView_Impl::CallbackData* pCallback = new LOKDocView_Impl::CallbackData(nType, pPayload ? pPayload : "(nil)", m_pDocView);
    1086           0 :     g_info("lok_doc_view_callback_worker: %s, '%s'", LOKDocView_Impl::callbackTypeToString(nType), pPayload);
    1087             : #if GTK_CHECK_VERSION(2,12,0)
    1088           0 :     gdk_threads_add_idle(LOKDocView_Impl::callback, pCallback);
    1089             : #endif
    1090           0 : }
    1091             : 
    1092           0 : void LOKDocView_Impl::globalCallbackWorkerImpl(int nType, const char* pPayload)
    1093             : {
    1094           0 :     LOKDocView_Impl::CallbackData* pCallback = new LOKDocView_Impl::CallbackData(nType, pPayload ? pPayload : "(nil)", m_pDocView);
    1095           0 :     g_info("LOKDocView_Impl::globalCallbackWorkerImpl: %s, '%s'", LOKDocView_Impl::callbackTypeToString(nType), pPayload);
    1096             : #if GTK_CHECK_VERSION(2,12,0)
    1097           0 :     gdk_threads_add_idle(LOKDocView_Impl::globalCallback, pCallback);
    1098             : #endif
    1099           0 : }
    1100             : 
    1101             : 
    1102             : 
    1103           0 : void LOKDocView_Impl::commandChanged(const std::string& rString)
    1104             : {
    1105           0 :     g_signal_emit(m_pDocView, doc_view_signals[COMMAND_CHANGED], 0, rString.c_str());
    1106           0 : }
    1107             : 
    1108           0 : void LOKDocView_Impl::searchNotFound(const std::string& rString)
    1109             : {
    1110           0 :     g_signal_emit(m_pDocView, doc_view_signals[SEARCH_NOT_FOUND], 0, rString.c_str());
    1111           0 : }
    1112             : 
    1113           0 : void LOKDocView_Impl::setPart(const std::string& rString)
    1114             : {
    1115           0 :     g_signal_emit(m_pDocView, doc_view_signals[PART_CHANGED], 0, std::stoi(rString));
    1116           0 :     renderDocument(0);
    1117           0 : }
    1118             : 
    1119           0 : static void lok_doc_view_class_init (LOKDocViewClass* pClass)
    1120             : {
    1121           0 :     GObjectClass *gobject_class = G_OBJECT_CLASS(pClass);
    1122           0 :     pClass->edit_changed = NULL;
    1123             :     doc_view_signals[EDIT_CHANGED] =
    1124             :         g_signal_new("edit-changed",
    1125             :                      G_TYPE_FROM_CLASS (gobject_class),
    1126             :                      G_SIGNAL_RUN_FIRST,
    1127             :                      G_STRUCT_OFFSET (LOKDocViewClass, edit_changed),
    1128             :                      NULL, NULL,
    1129             :                      g_cclosure_marshal_VOID__BOOLEAN,
    1130             :                      G_TYPE_NONE, 1,
    1131           0 :                      G_TYPE_BOOLEAN);
    1132           0 :     pClass->command_changed = NULL;
    1133             :     doc_view_signals[COMMAND_CHANGED] =
    1134             :         g_signal_new("command-changed",
    1135             :                      G_TYPE_FROM_CLASS(gobject_class),
    1136             :                      G_SIGNAL_RUN_FIRST,
    1137             :                      G_STRUCT_OFFSET(LOKDocViewClass, command_changed),
    1138             :                      NULL, NULL,
    1139             :                      g_cclosure_marshal_VOID__STRING,
    1140             :                      G_TYPE_NONE, 1,
    1141           0 :                      G_TYPE_STRING);
    1142           0 :     pClass->search_not_found = 0;
    1143             :     doc_view_signals[SEARCH_NOT_FOUND] =
    1144             :         g_signal_new("search-not-found",
    1145             :                      G_TYPE_FROM_CLASS(gobject_class),
    1146             :                      G_SIGNAL_RUN_FIRST,
    1147             :                      G_STRUCT_OFFSET(LOKDocViewClass, search_not_found),
    1148             :                      NULL, NULL,
    1149             :                      g_cclosure_marshal_VOID__STRING,
    1150             :                      G_TYPE_NONE, 1,
    1151           0 :                      G_TYPE_STRING);
    1152           0 :     pClass->part_changed = 0;
    1153             :     doc_view_signals[PART_CHANGED] =
    1154             :         g_signal_new("part-changed",
    1155             :                      G_TYPE_FROM_CLASS(gobject_class),
    1156             :                      G_SIGNAL_RUN_FIRST,
    1157             :                      G_STRUCT_OFFSET(LOKDocViewClass, part_changed),
    1158             :                      NULL, NULL,
    1159             :                      g_cclosure_marshal_VOID__INT,
    1160             :                      G_TYPE_NONE, 1,
    1161           0 :                      G_TYPE_INT);
    1162           0 : }
    1163             : 
    1164           0 : static void lok_doc_view_init (LOKDocView* pDocView)
    1165             : {
    1166             :     // Gtk ScrolledWindow is apparently not fully initialised yet, we specifically
    1167             :     // have to set the [hv]adjustment to prevent GTK assertions from firing, see
    1168             :     // https://bugzilla.gnome.org/show_bug.cgi?id=438114 for more info.
    1169           0 :     gtk_scrolled_window_set_hadjustment( GTK_SCROLLED_WINDOW( pDocView ), NULL );
    1170           0 :     gtk_scrolled_window_set_vadjustment( GTK_SCROLLED_WINDOW( pDocView ), NULL );
    1171             : 
    1172           0 :     pDocView->m_pImpl = new LOKDocView_Impl(pDocView);
    1173           0 :     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(pDocView),
    1174           0 :                                            pDocView->m_pImpl->m_pDrawingArea );
    1175             : 
    1176           0 :     g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
    1177             :                      "expose-event",
    1178           0 :                      G_CALLBACK(LOKDocView_Impl::on_exposed), pDocView);
    1179           0 :     g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
    1180             :                      "expose-event",
    1181           0 :                      G_CALLBACK(LOKDocView_Impl::renderOverlay), pDocView);
    1182             :     gtk_widget_add_events(pDocView->m_pImpl->m_pDrawingArea,
    1183             :                            GDK_BUTTON_PRESS_MASK
    1184             :                           |GDK_BUTTON_RELEASE_MASK
    1185           0 :                           |GDK_BUTTON_MOTION_MASK);
    1186             : 
    1187           0 :     g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
    1188             :                      "button-press-event",
    1189           0 :                      G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
    1190           0 :     g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
    1191             :                      "button-release-event",
    1192           0 :                      G_CALLBACK(LOKDocView_Impl::signalButton), pDocView);
    1193           0 :     g_signal_connect(G_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
    1194             :                      "motion-notify-event",
    1195           0 :                      G_CALLBACK(LOKDocView_Impl::signalMotion), pDocView);
    1196             : 
    1197           0 :     g_signal_connect(G_OBJECT(pDocView), "destroy", G_CALLBACK(LOKDocView_Impl::destroy), 0);
    1198           0 : }
    1199             : 
    1200           0 : SAL_DLLPUBLIC_EXPORT GtkWidget* lok_doc_view_new( LibreOfficeKit* pOffice )
    1201             : {
    1202           0 :     LOKDocView* pDocView = LOK_DOC_VIEW(gtk_type_new(lok_doc_view_get_type()));
    1203           0 :     pDocView->m_pImpl->m_pOffice = pOffice;
    1204           0 :     return GTK_WIDGET( pDocView );
    1205             : }
    1206             : 
    1207           0 : SAL_DLLPUBLIC_EXPORT gboolean lok_doc_view_open_document( LOKDocView* pDocView, char* pPath )
    1208             : {
    1209           0 :     if ( pDocView->m_pImpl->m_pDocument )
    1210             :     {
    1211           0 :         pDocView->m_pImpl->m_pDocument->pClass->destroy( pDocView->m_pImpl->m_pDocument );
    1212           0 :         pDocView->m_pImpl->m_pDocument = 0;
    1213             :     }
    1214             : 
    1215           0 :     pDocView->m_pImpl->m_pOffice->pClass->registerCallback(pDocView->m_pImpl->m_pOffice, &LOKDocView_Impl::globalCallbackWorker, pDocView);
    1216             :     pDocView->m_pImpl->m_pDocument = pDocView->m_pImpl->m_pOffice->pClass->documentLoad( pDocView->m_pImpl->m_pOffice,
    1217           0 :                                                                    pPath );
    1218           0 :     if ( !pDocView->m_pImpl->m_pDocument )
    1219             :     {
    1220             :         // FIXME: should have a GError parameter and populate it.
    1221           0 :         char *pError = pDocView->m_pImpl->m_pOffice->pClass->getError( pDocView->m_pImpl->m_pOffice );
    1222           0 :         fprintf( stderr, "Error opening document '%s'\n", pError );
    1223           0 :         return FALSE;
    1224             :     }
    1225             :     else
    1226             :     {
    1227           0 :         pDocView->m_pImpl->m_pDocument->pClass->initializeForRendering(pDocView->m_pImpl->m_pDocument);
    1228           0 :         pDocView->m_pImpl->m_pDocument->pClass->registerCallback(pDocView->m_pImpl->m_pDocument, &LOKDocView_Impl::callbackWorker, pDocView);
    1229           0 :         pDocView->m_pImpl->m_pDocument->pClass->getDocumentSize(pDocView->m_pImpl->m_pDocument, &pDocView->m_pImpl->m_nDocumentWidthTwips, &pDocView->m_pImpl->m_nDocumentHeightTwips);
    1230           0 :         g_timeout_add(600, &LOKDocView_Impl::handleTimeout, pDocView);
    1231             : 
    1232           0 :         float zoom = pDocView->m_pImpl->m_fZoom;
    1233           0 :         long nDocumentWidthTwips = pDocView->m_pImpl->m_nDocumentWidthTwips;
    1234           0 :         long nDocumentHeightTwips = pDocView->m_pImpl->m_nDocumentHeightTwips;
    1235           0 :         long nDocumentWidthPixels = twipToPixel(nDocumentWidthTwips, zoom);
    1236           0 :         long nDocumentHeightPixels = twipToPixel(nDocumentHeightTwips, zoom);
    1237             :         // Total number of columns in this document.
    1238           0 :         guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
    1239             : 
    1240             : 
    1241           0 :         pDocView->m_pImpl->m_aTileBuffer = TileBuffer(pDocView->m_pImpl->m_pDocument,
    1242           0 :                                                       nColumns);
    1243             :         gtk_widget_set_size_request(pDocView->m_pImpl->m_pDrawingArea,
    1244             :                                     nDocumentWidthPixels,
    1245           0 :                                     nDocumentHeightPixels);
    1246           0 :         pDocView->m_pImpl->renderDocument(0);
    1247             :     }
    1248             : 
    1249           0 :     return TRUE;
    1250             : }
    1251             : 
    1252           0 : SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument* lok_doc_view_get_document(LOKDocView* pDocView)
    1253             : {
    1254           0 :     return pDocView->m_pImpl->m_pDocument;
    1255             : }
    1256             : 
    1257           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_zoom ( LOKDocView* pDocView, float fZoom )
    1258             : {
    1259           0 :     pDocView->m_pImpl->m_fZoom = fZoom;
    1260           0 :     long nDocumentWidthPixels = twipToPixel(pDocView->m_pImpl->m_nDocumentWidthTwips, fZoom);
    1261           0 :     long nDocumentHeightPixels = twipToPixel(pDocView->m_pImpl->m_nDocumentHeightTwips, fZoom);
    1262             :     // Total number of columns in this document.
    1263           0 :     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
    1264             : 
    1265           0 :     pDocView->m_pImpl->m_aTileBuffer = TileBuffer(pDocView->m_pImpl->m_pDocument,
    1266           0 :                                                   nColumns);
    1267             :     gtk_widget_set_size_request(pDocView->m_pImpl->m_pDrawingArea,
    1268             :                                 nDocumentWidthPixels,
    1269           0 :                                 nDocumentHeightPixels);
    1270             : 
    1271           0 :     if ( pDocView->m_pImpl->m_pDocument )
    1272           0 :         pDocView->m_pImpl->renderDocument(0);
    1273           0 : }
    1274             : 
    1275           0 : SAL_DLLPUBLIC_EXPORT float lok_doc_view_get_zoom ( LOKDocView* pDocView )
    1276             : {
    1277           0 :     return pDocView->m_pImpl->m_fZoom;
    1278             : }
    1279             : 
    1280           0 : SAL_DLLPUBLIC_EXPORT int lok_doc_view_get_parts( LOKDocView* pDocView )
    1281             : {
    1282           0 :     return pDocView->m_pImpl->m_pDocument->pClass->getParts( pDocView->m_pImpl->m_pDocument );
    1283             : }
    1284             : 
    1285           0 : SAL_DLLPUBLIC_EXPORT int lok_doc_view_get_part( LOKDocView* pDocView )
    1286             : {
    1287           0 :     return pDocView->m_pImpl->m_pDocument->pClass->getPart( pDocView->m_pImpl->m_pDocument );
    1288             : }
    1289             : 
    1290           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_part( LOKDocView* pDocView, int nPart)
    1291             : {
    1292           0 :     pDocView->m_pImpl->m_pDocument->pClass->setPart( pDocView->m_pImpl->m_pDocument, nPart );
    1293           0 : }
    1294             : 
    1295           0 : SAL_DLLPUBLIC_EXPORT char* lok_doc_view_get_part_name( LOKDocView* pDocView, int nPart )
    1296             : {
    1297           0 :     return pDocView->m_pImpl->m_pDocument->pClass->getPartName( pDocView->m_pImpl->m_pDocument, nPart );
    1298             : }
    1299             : 
    1300           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_partmode( LOKDocView* pDocView,
    1301             :                                                     int nPartMode )
    1302             : {
    1303           0 :     pDocView->m_pImpl->m_pDocument->pClass->setPartMode( pDocView->m_pImpl->m_pDocument, nPartMode );
    1304           0 :     pDocView->m_pImpl->renderDocument(0);
    1305           0 : }
    1306             : 
    1307           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_set_edit( LOKDocView* pDocView,
    1308             :                                                 gboolean bEdit )
    1309             : {
    1310           0 :     gboolean bWasEdit = pDocView->m_pImpl->m_bEdit;
    1311             : 
    1312           0 :     if (!pDocView->m_pImpl->m_bEdit && bEdit)
    1313           0 :         g_info("lok_doc_view_set_edit: entering edit mode");
    1314           0 :     else if (pDocView->m_pImpl->m_bEdit && !bEdit)
    1315             :     {
    1316           0 :         g_info("lok_doc_view_set_edit: leaving edit mode");
    1317           0 :         pDocView->m_pImpl->m_pDocument->pClass->resetSelection(pDocView->m_pImpl->m_pDocument);
    1318             :     }
    1319           0 :     pDocView->m_pImpl->m_bEdit = bEdit;
    1320           0 :     g_signal_emit(pDocView, doc_view_signals[EDIT_CHANGED], 0, bWasEdit);
    1321           0 :     gtk_widget_queue_draw(GTK_WIDGET(pDocView->m_pImpl->m_pDrawingArea));
    1322           0 : }
    1323             : 
    1324           0 : SAL_DLLPUBLIC_EXPORT gboolean lok_doc_view_get_edit(LOKDocView* pDocView)
    1325             : {
    1326           0 :     return pDocView->m_pImpl->m_bEdit;
    1327             : }
    1328             : 
    1329           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_post_command(LOKDocView* pDocView, const char* pCommand, const char* pArguments)
    1330             : {
    1331           0 :     pDocView->m_pImpl->m_pDocument->pClass->postUnoCommand(pDocView->m_pImpl->m_pDocument, pCommand, pArguments);
    1332           0 : }
    1333             : 
    1334           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_post_key(GtkWidget* /*pWidget*/, GdkEventKey* pEvent, gpointer pData)
    1335             : {
    1336           0 :     LOKDocView* pDocView = static_cast<LOKDocView *>(pData);
    1337           0 :     pDocView->m_pImpl->signalKey(pEvent);
    1338           0 : }
    1339             : 
    1340           0 : SAL_DLLPUBLIC_EXPORT void lok_doc_view_get_visarea(LOKDocView* pThis, GdkRectangle* pArea)
    1341             : {
    1342             : #if GTK_CHECK_VERSION(2,14,0) // we need gtk_adjustment_get_page_size()
    1343           0 :     float zoom = pThis->m_pImpl->m_fZoom;
    1344           0 :     GtkAdjustment* pHAdjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(pThis));
    1345           0 :     pArea->x = pixelToTwip(gtk_adjustment_get_value(pHAdjustment),zoom);
    1346           0 :     pArea->width = pixelToTwip(gtk_adjustment_get_page_size(pHAdjustment), zoom);
    1347           0 :     GtkAdjustment* pVAdjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(pThis));
    1348           0 :     pArea->y = pixelToTwip(gtk_adjustment_get_value(pVAdjustment), zoom);
    1349           0 :     pArea->height = pixelToTwip(gtk_adjustment_get_page_size(pVAdjustment), zoom);
    1350             : #endif
    1351           0 : }
    1352             : 
    1353             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11