1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sal/types.h>
18 #include <boost/property_tree/json_parser.hpp>
20 #include <com/sun/star/awt/Key.hpp>
21 #include <LibreOfficeKit/LibreOfficeKit.h>
22 #include <LibreOfficeKit/LibreOfficeKitInit.h>
23 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
24 #include <LibreOfficeKit/LibreOfficeKitGtk.h>
25 #include <rsc/rsc-vcl-shared-types.hxx>
26 #include <vcl/event.hxx>
28 #include "tilebuffer.hxx"
30 #if !GLIB_CHECK_VERSION(2,32,0)
31 #define G_SOURCE_REMOVE FALSE
32 #define G_SOURCE_CONTINUE TRUE
34 #if !GLIB_CHECK_VERSION(2,40,0)
35 #define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
38 // Cursor bitmaps from the installation set.
39 #define CURSOR_HANDLE_DIR "/../share/libreofficekit/"
40 // Number of handles around a graphic selection.
41 #define GRAPHIC_HANDLE_COUNT 8
42 // Maximum Zoom allowed
44 // Minimum Zoom allowed
45 #define MIN_ZOOM 0.25f
47 /// Private struct used by this GObject type
48 struct LOKDocViewPrivateImpl
50 const gchar
* m_aLOPath
;
51 const gchar
* m_pUserProfileURL
;
52 const gchar
* m_aDocPath
;
53 std::string m_aRenderingArguments
;
54 gdouble m_nLoadProgress
;
55 gboolean m_bIsLoading
;
56 gboolean m_bCanZoomIn
;
57 gboolean m_bCanZoomOut
;
58 LibreOfficeKit
* m_pOffice
;
59 LibreOfficeKitDocument
* m_pDocument
;
61 std::unique_ptr
<TileBuffer
> m_pTileBuffer
;
62 GThreadPool
* lokThreadPool
;
65 glong m_nDocumentWidthTwips
;
66 glong m_nDocumentHeightTwips
;
67 /// View or edit mode.
70 guint64 m_nLOKFeatures
;
71 /// Number of parts in currently loaded document
73 /// Position and size of the visible cursor.
74 GdkRectangle m_aVisibleCursor
;
75 /// Cursor overlay is visible or hidden (for blinking).
76 gboolean m_bCursorOverlayVisible
;
77 /// Cursor is visible or hidden (e.g. for graphic selection).
78 gboolean m_bCursorVisible
;
79 /// Time of the last button press.
80 guint32 m_nLastButtonPressTime
;
81 /// Time of the last button release.
82 guint32 m_nLastButtonReleaseTime
;
83 /// Last pressed button (left, right, middle)
84 guint32 m_nLastButtonPressed
;
85 /// Key modifier (ctrl, atl, shift)
86 guint32 m_nKeyModifier
;
87 /// Rectangles of the current text selection.
88 std::vector
<GdkRectangle
> m_aTextSelectionRectangles
;
89 /// Position and size of the selection start (as if there would be a cursor caret there).
90 GdkRectangle m_aTextSelectionStart
;
91 /// Position and size of the selection end.
92 GdkRectangle m_aTextSelectionEnd
;
93 GdkRectangle m_aGraphicSelection
;
94 GdkRectangle m_aCellCursor
;
95 gboolean m_bInDragGraphicSelection
;
97 /// @name Start/middle/end handle.
99 /// Bitmap of the text selection start handle.
100 cairo_surface_t
* m_pHandleStart
;
101 /// Rectangle of the text selection start handle, to know if the user clicked on it or not
102 GdkRectangle m_aHandleStartRect
;
103 /// If we are in the middle of a drag of the text selection end handle.
104 gboolean m_bInDragStartHandle
;
105 /// Bitmap of the text selection middle handle.
106 cairo_surface_t
* m_pHandleMiddle
;
107 /// Rectangle of the text selection middle handle, to know if the user clicked on it or not
108 GdkRectangle m_aHandleMiddleRect
;
109 /// If we are in the middle of a drag of the text selection middle handle.
110 gboolean m_bInDragMiddleHandle
;
111 /// Bitmap of the text selection end handle.
112 cairo_surface_t
* m_pHandleEnd
;
113 /// Rectangle of the text selection end handle, to know if the user clicked on it or not
114 GdkRectangle m_aHandleEndRect
;
115 /// If we are in the middle of a drag of the text selection end handle.
116 gboolean m_bInDragEndHandle
;
119 /// @name Graphic handles.
121 /// Bitmap of a graphic selection handle.
122 cairo_surface_t
* m_pGraphicHandle
;
123 /// Rectangle of a graphic selection handle, to know if the user clicked on it or not.
124 GdkRectangle m_aGraphicHandleRects
[8];
125 /// If we are in the middle of a drag of a graphic selection handle.
126 gboolean m_bInDragGraphicHandles
[8];
129 /// View ID, returned by createView() or 0 by default.
133 * Contains a freshly set zoom level: logic size of a tile.
134 * It gets reset back to 0 when LOK was informed about this zoom change.
136 int m_nTileSizeTwips
;
138 GdkRectangle m_aVisibleArea
;
139 bool m_bVisibleAreaSet
;
141 LOKDocViewPrivateImpl()
142 : m_aLOPath(nullptr),
143 m_pUserProfileURL(nullptr),
150 m_pDocument(nullptr),
151 lokThreadPool(nullptr),
153 m_nDocumentWidthTwips(0),
154 m_nDocumentHeightTwips(0),
158 m_aVisibleCursor({0, 0, 0, 0}),
159 m_bCursorOverlayVisible(false),
160 m_bCursorVisible(true),
161 m_nLastButtonPressTime(0),
162 m_nLastButtonReleaseTime(0),
163 m_nLastButtonPressed(0),
165 m_aTextSelectionStart({0, 0, 0, 0}),
166 m_aTextSelectionEnd({0, 0, 0, 0}),
167 m_aGraphicSelection({0, 0, 0, 0}),
168 m_aCellCursor({0, 0, 0, 0}),
169 m_bInDragGraphicSelection(false),
170 m_pHandleStart(nullptr),
171 m_aHandleStartRect({0, 0, 0, 0}),
172 m_bInDragStartHandle(0),
173 m_pHandleMiddle(nullptr),
174 m_aHandleMiddleRect({0, 0, 0, 0}),
175 m_bInDragMiddleHandle(false),
176 m_pHandleEnd(nullptr),
177 m_aHandleEndRect({0, 0, 0, 0}),
178 m_bInDragEndHandle(false),
179 m_pGraphicHandle(nullptr),
182 m_aVisibleArea({0, 0, 0, 0}),
183 m_bVisibleAreaSet(false)
185 memset(&m_aGraphicHandleRects
, 0, sizeof(m_aGraphicHandleRects
));
186 memset(&m_bInDragGraphicHandles
, 0, sizeof(m_bInDragGraphicHandles
));
190 /// Wrapper around LOKDocViewPrivateImpl, managed by malloc/memset/free.
191 struct _LOKDocViewPrivate
193 LOKDocViewPrivateImpl
* m_pImpl
;
195 LOKDocViewPrivateImpl
* operator->()
226 PROP_USER_PROFILE_URL
,
238 PROP_DOC_PASSWORD_TO_MODIFY
,
243 static guint doc_view_signals
[LAST_SIGNAL
] = { 0 };
244 static GParamSpec
*properties
[PROP_LAST
] = { nullptr };
246 static void lok_doc_view_initable_iface_init (GInitableIface
*iface
);
247 static void callbackWorker (int nType
, const char* pPayload
, void* pData
);
249 SAL_DLLPUBLIC_EXPORT GType
lok_doc_view_get_type();
251 #pragma GCC diagnostic push
252 #pragma GCC diagnostic ignored "-Wunused-function"
254 G_DEFINE_TYPE_WITH_CODE (LOKDocView
, lok_doc_view
, GTK_TYPE_DRAWING_AREA
,
255 G_ADD_PRIVATE (LOKDocView
)
256 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE
, lok_doc_view_initable_iface_init
));
258 #pragma GCC diagnostic pop
261 static LOKDocViewPrivate
& getPrivate(LOKDocView
* pDocView
)
263 LOKDocViewPrivate
* priv
= static_cast<LOKDocViewPrivate
*>(lok_doc_view_get_instance_private(pDocView
));
267 /// Helper struct used to pass the data from soffice thread -> main thread.
271 std::string m_aPayload
;
272 LOKDocView
* m_pDocView
;
274 CallbackData(int nType
, const std::string
& rPayload
, LOKDocView
* pDocView
)
276 m_aPayload(rPayload
),
277 m_pDocView(pDocView
) {}
281 payloadToSize(const char* pPayload
, long& rWidth
, long& rHeight
)
283 rWidth
= rHeight
= 0;
284 gchar
** ppCoordinates
= g_strsplit(pPayload
, ", ", 2);
285 gchar
** ppCoordinate
= ppCoordinates
;
288 rWidth
= atoi(*ppCoordinate
);
292 rHeight
= atoi(*ppCoordinate
);
293 g_strfreev(ppCoordinates
);
296 /// Returns the string representation of a LibreOfficeKitCallbackType enumeration element.
298 callbackTypeToString (int nType
)
302 case LOK_CALLBACK_INVALIDATE_TILES
:
303 return "LOK_CALLBACK_INVALIDATE_TILES";
304 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
305 return "LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR";
306 case LOK_CALLBACK_TEXT_SELECTION
:
307 return "LOK_CALLBACK_TEXT_SELECTION";
308 case LOK_CALLBACK_TEXT_SELECTION_START
:
309 return "LOK_CALLBACK_TEXT_SELECTION_START";
310 case LOK_CALLBACK_TEXT_SELECTION_END
:
311 return "LOK_CALLBACK_TEXT_SELECTION_END";
312 case LOK_CALLBACK_CURSOR_VISIBLE
:
313 return "LOK_CALLBACK_CURSOR_VISIBLE";
314 case LOK_CALLBACK_GRAPHIC_SELECTION
:
315 return "LOK_CALLBACK_GRAPHIC_SELECTION";
316 case LOK_CALLBACK_CELL_CURSOR
:
317 return "LOK_CALLBACK_CELL_CURSOR";
318 case LOK_CALLBACK_HYPERLINK_CLICKED
:
319 return "LOK_CALLBACK_HYPERLINK_CLICKED";
320 case LOK_CALLBACK_MOUSE_POINTER
:
321 return "LOK_CALLBACK_MOUSE_POINTER";
322 case LOK_CALLBACK_STATE_CHANGED
:
323 return "LOK_CALLBACK_STATE_CHANGED";
324 case LOK_CALLBACK_STATUS_INDICATOR_START
:
325 return "LOK_CALLBACK_STATUS_INDICATOR_START";
326 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
327 return "LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE";
328 case LOK_CALLBACK_STATUS_INDICATOR_FINISH
:
329 return "LOK_CALLBACK_STATUS_INDICATOR_FINISH";
330 case LOK_CALLBACK_SEARCH_NOT_FOUND
:
331 return "LOK_CALLBACK_SEARCH_NOT_FOUND";
332 case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
:
333 return "LOK_CALLBACK_DOCUMENT_SIZE_CHANGED";
334 case LOK_CALLBACK_SET_PART
:
335 return "LOK_CALLBACK_SET_PART";
336 case LOK_CALLBACK_SEARCH_RESULT_SELECTION
:
337 return "LOK_CALLBACK_SEARCH_RESULT_SELECTION";
338 case LOK_CALLBACK_DOCUMENT_PASSWORD
:
339 return "LOK_CALLBACK_DOCUMENT_PASSWORD";
340 case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY
:
341 return "LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY";
342 case LOK_CALLBACK_CONTEXT_MENU
:
343 return "LOK_CALLBACK_CONTEXT_MENU";
349 LOKPostCommand (LOKDocView
* pDocView
,
350 const gchar
* pCommand
,
351 const gchar
* pArguments
,
352 gboolean bNotifyWhenFinished
)
354 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
355 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
356 LOEvent
* pLOEvent
= new LOEvent(LOK_POST_COMMAND
);
357 GError
* error
= nullptr;
358 pLOEvent
->m_pCommand
= pCommand
;
359 pLOEvent
->m_pArguments
= g_strdup(pArguments
);
360 pLOEvent
->m_bNotifyWhenFinished
= bNotifyWhenFinished
;
362 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
363 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
364 if (error
!= nullptr)
366 g_warning("Unable to call LOK_POST_COMMAND: %s", error
->message
);
367 g_clear_error(&error
);
369 g_object_unref(task
);
373 doSearch(LOKDocView
* pDocView
, const char* pText
, bool bBackwards
, bool highlightAll
)
375 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
376 if (!priv
->m_pDocument
)
379 boost::property_tree::ptree aTree
;
380 GtkWidget
* drawingWidget
= GTK_WIDGET(pDocView
);
381 GdkWindow
* drawingWindow
= gtk_widget_get_window(drawingWidget
);
384 std::shared_ptr
<cairo_region_t
> cairoVisRegion( gdk_window_get_visible_region(drawingWindow
),
385 cairo_region_destroy
);
386 cairo_rectangle_int_t cairoVisRect
;
387 cairo_region_get_rectangle(cairoVisRegion
.get(), 0, &cairoVisRect
);
388 int x
= pixelToTwip (cairoVisRect
.x
, priv
->m_fZoom
);
389 int y
= pixelToTwip (cairoVisRect
.y
, priv
->m_fZoom
);
391 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.SearchString/type", '/'), "string");
392 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.SearchString/value", '/'), pText
);
393 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.Backward/type", '/'), "boolean");
394 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.Backward/value", '/'), bBackwards
);
397 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.Command/type", '/'), "unsigned short");
398 // SvxSearchCmd::FIND_ALL
399 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.Command/value", '/'), "1");
402 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.SearchStartPointX/type", '/'), "long");
403 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.SearchStartPointX/value", '/'), x
);
404 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.SearchStartPointY/type", '/'), "long");
405 aTree
.put(boost::property_tree::ptree::path_type("SearchItem.SearchStartPointY/value", '/'), y
);
407 std::stringstream aStream
;
408 boost::property_tree::write_json(aStream
, aTree
);
410 LOKPostCommand (pDocView
, ".uno:ExecuteSearch", aStream
.str().c_str(), false);
414 isEmptyRectangle(const GdkRectangle
& rRectangle
)
416 return rRectangle
.x
== 0 && rRectangle
.y
== 0 && rRectangle
.width
== 0 && rRectangle
.height
== 0;
419 /// if handled, returns TRUE else FALSE
421 handleTextSelectionOnButtonPress(GdkRectangle
& aClick
, LOKDocView
* pDocView
) {
422 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
424 if (gdk_rectangle_intersect(&aClick
, &priv
->m_aHandleStartRect
, nullptr))
426 g_info("LOKDocView_Impl::signalButton: start of drag start handle");
427 priv
->m_bInDragStartHandle
= true;
430 else if (gdk_rectangle_intersect(&aClick
, &priv
->m_aHandleMiddleRect
, nullptr))
432 g_info("LOKDocView_Impl::signalButton: start of drag middle handle");
433 priv
->m_bInDragMiddleHandle
= true;
436 else if (gdk_rectangle_intersect(&aClick
, &priv
->m_aHandleEndRect
, nullptr))
438 g_info("LOKDocView_Impl::signalButton: start of drag end handle");
439 priv
->m_bInDragEndHandle
= true;
446 /// if handled, returns TRUE else FALSE
448 handleGraphicSelectionOnButtonPress(GdkRectangle
& aClick
, LOKDocView
* pDocView
) {
449 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
450 GError
* error
= nullptr;
452 for (int i
= 0; i
< GRAPHIC_HANDLE_COUNT
; ++i
)
454 if (gdk_rectangle_intersect(&aClick
, &priv
->m_aGraphicHandleRects
[i
], nullptr))
456 g_info("LOKDocView_Impl::signalButton: start of drag graphic handle #%d", i
);
457 priv
->m_bInDragGraphicHandles
[i
] = true;
459 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
460 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_GRAPHIC_SELECTION
);
461 pLOEvent
->m_nSetGraphicSelectionType
= LOK_SETGRAPHICSELECTION_START
;
462 pLOEvent
->m_nSetGraphicSelectionX
= pixelToTwip(priv
->m_aGraphicHandleRects
[i
].x
+ priv
->m_aGraphicHandleRects
[i
].width
/ 2, priv
->m_fZoom
);
463 pLOEvent
->m_nSetGraphicSelectionY
= pixelToTwip(priv
->m_aGraphicHandleRects
[i
].y
+ priv
->m_aGraphicHandleRects
[i
].height
/ 2, priv
->m_fZoom
);
464 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
466 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
467 if (error
!= nullptr)
469 g_warning("Unable to call LOK_SET_GRAPHIC_SELECTION: %s", error
->message
);
470 g_clear_error(&error
);
472 g_object_unref(task
);
481 /// if handled, returns TRUE else FALSE
483 handleTextSelectionOnButtonRelease(LOKDocView
* pDocView
) {
484 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
486 if (priv
->m_bInDragStartHandle
)
488 g_info("LOKDocView_Impl::signalButton: end of drag start handle");
489 priv
->m_bInDragStartHandle
= false;
492 else if (priv
->m_bInDragMiddleHandle
)
494 g_info("LOKDocView_Impl::signalButton: end of drag middle handle");
495 priv
->m_bInDragMiddleHandle
= false;
498 else if (priv
->m_bInDragEndHandle
)
500 g_info("LOKDocView_Impl::signalButton: end of drag end handle");
501 priv
->m_bInDragEndHandle
= false;
508 /// if handled, returns TRUE else FALSE
510 handleGraphicSelectionOnButtonRelease(LOKDocView
* pDocView
, GdkEventButton
* pEvent
) {
511 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
512 GError
* error
= nullptr;
514 for (int i
= 0; i
< GRAPHIC_HANDLE_COUNT
; ++i
)
516 if (priv
->m_bInDragGraphicHandles
[i
])
518 g_info("LOKDocView_Impl::signalButton: end of drag graphic handle #%d", i
);
519 priv
->m_bInDragGraphicHandles
[i
] = false;
521 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
522 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_GRAPHIC_SELECTION
);
523 pLOEvent
->m_nSetGraphicSelectionType
= LOK_SETGRAPHICSELECTION_END
;
524 pLOEvent
->m_nSetGraphicSelectionX
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
525 pLOEvent
->m_nSetGraphicSelectionY
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
526 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
528 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
529 if (error
!= nullptr)
531 g_warning("Unable to call LOK_SET_GRAPHIC_SELECTION: %s", error
->message
);
532 g_clear_error(&error
);
534 g_object_unref(task
);
540 if (priv
->m_bInDragGraphicSelection
)
542 g_info("LOKDocView_Impl::signalButton: end of drag graphic selection");
543 priv
->m_bInDragGraphicSelection
= false;
545 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
546 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_GRAPHIC_SELECTION
);
547 pLOEvent
->m_nSetGraphicSelectionType
= LOK_SETGRAPHICSELECTION_END
;
548 pLOEvent
->m_nSetGraphicSelectionX
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
549 pLOEvent
->m_nSetGraphicSelectionY
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
550 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
552 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
553 if (error
!= nullptr)
555 g_warning("Unable to call LOK_SET_GRAPHIC_SELECTION: %s", error
->message
);
556 g_clear_error(&error
);
558 g_object_unref(task
);
567 postKeyEventInThread(gpointer data
)
569 GTask
* task
= G_TASK(data
);
570 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
571 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
572 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
574 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
576 if (priv
->m_nTileSizeTwips
)
578 std::stringstream ss
;
579 ss
<< "lok::Document::setClientZoom(" << nTileSizePixels
<< ", " << nTileSizePixels
<< ", " << priv
->m_nTileSizeTwips
<< ", " << priv
->m_nTileSizeTwips
<< ")";
580 g_info("%s", ss
.str().c_str());
581 priv
->m_pDocument
->pClass
->setClientZoom(priv
->m_pDocument
,
584 priv
->m_nTileSizeTwips
,
585 priv
->m_nTileSizeTwips
);
586 priv
->m_nTileSizeTwips
= 0;
588 if (priv
->m_bVisibleAreaSet
)
590 std::stringstream ss
;
591 ss
<< "lok::Document::setClientVisibleArea(" << priv
->m_aVisibleArea
.x
<< ", " << priv
->m_aVisibleArea
.y
<< ", ";
592 ss
<< priv
->m_aVisibleArea
.width
<< ", " << priv
->m_aVisibleArea
.height
<< ")";
593 g_info("%s", ss
.str().c_str());
594 priv
->m_pDocument
->pClass
->setClientVisibleArea(priv
->m_pDocument
,
595 priv
->m_aVisibleArea
.x
,
596 priv
->m_aVisibleArea
.y
,
597 priv
->m_aVisibleArea
.width
,
598 priv
->m_aVisibleArea
.height
);
599 priv
->m_bVisibleAreaSet
= false;
602 std::stringstream ss
;
603 ss
<< "lok::Document::postKeyEvent(" << pLOEvent
->m_nKeyEvent
<< ", " << pLOEvent
->m_nCharCode
<< ", " << pLOEvent
->m_nKeyCode
<< ")";
604 g_info("%s", ss
.str().c_str());
605 priv
->m_pDocument
->pClass
->postKeyEvent(priv
->m_pDocument
,
606 pLOEvent
->m_nKeyEvent
,
607 pLOEvent
->m_nCharCode
,
608 pLOEvent
->m_nKeyCode
);
612 signalKey (GtkWidget
* pWidget
, GdkEventKey
* pEvent
)
614 LOKDocView
* pDocView
= LOK_DOC_VIEW(pWidget
);
615 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
618 GError
* error
= nullptr;
622 g_info("signalKey: not in edit mode, ignore");
626 priv
->m_nKeyModifier
&= KEY_MOD2
;
627 switch (pEvent
->keyval
)
629 case GDK_KEY_BackSpace
:
630 nKeyCode
= com::sun::star::awt::Key::BACKSPACE
;
633 nKeyCode
= com::sun::star::awt::Key::DELETE
;
636 nKeyCode
= com::sun::star::awt::Key::RETURN
;
639 nKeyCode
= com::sun::star::awt::Key::ESCAPE
;
642 nKeyCode
= com::sun::star::awt::Key::TAB
;
645 nKeyCode
= com::sun::star::awt::Key::DOWN
;
648 nKeyCode
= com::sun::star::awt::Key::UP
;
651 nKeyCode
= com::sun::star::awt::Key::LEFT
;
654 nKeyCode
= com::sun::star::awt::Key::RIGHT
;
656 case GDK_KEY_Page_Down
:
657 nKeyCode
= com::sun::star::awt::Key::PAGEDOWN
;
659 case GDK_KEY_Page_Up
:
660 nKeyCode
= com::sun::star::awt::Key::PAGEUP
;
662 case GDK_KEY_Shift_L
:
663 case GDK_KEY_Shift_R
:
664 if (pEvent
->type
== GDK_KEY_PRESS
)
665 priv
->m_nKeyModifier
|= KEY_SHIFT
;
667 case GDK_KEY_Control_L
:
668 case GDK_KEY_Control_R
:
669 if (pEvent
->type
== GDK_KEY_PRESS
)
670 priv
->m_nKeyModifier
|= KEY_MOD1
;
674 if (pEvent
->type
== GDK_KEY_PRESS
)
675 priv
->m_nKeyModifier
|= KEY_MOD2
;
677 priv
->m_nKeyModifier
&= ~KEY_MOD2
;
680 if (pEvent
->keyval
>= GDK_KEY_F1
&& pEvent
->keyval
<= GDK_KEY_F26
)
681 nKeyCode
= com::sun::star::awt::Key::F1
+ (pEvent
->keyval
- GDK_KEY_F1
);
683 nCharCode
= gdk_keyval_to_unicode(pEvent
->keyval
);
686 // rsc is not public API, but should be good enough for debugging purposes.
687 // If this is needed for real, then probably a new param of type
688 // css::awt::KeyModifier is needed in postKeyEvent().
689 if (pEvent
->state
& GDK_SHIFT_MASK
)
690 nKeyCode
|= KEY_SHIFT
;
692 if (pEvent
->state
& GDK_CONTROL_MASK
)
693 nKeyCode
|= KEY_MOD1
;
695 if (priv
->m_nKeyModifier
& KEY_MOD2
)
696 nKeyCode
|= KEY_MOD2
;
698 if (nKeyCode
& (KEY_SHIFT
| KEY_MOD1
| KEY_MOD2
)) {
699 if (pEvent
->keyval
>= GDK_KEY_a
&& pEvent
->keyval
<= GDK_KEY_z
)
701 nKeyCode
|= 512 + (pEvent
->keyval
- GDK_KEY_a
);
703 else if (pEvent
->keyval
>= GDK_KEY_A
&& pEvent
->keyval
<= GDK_KEY_Z
) {
704 nKeyCode
|= 512 + (pEvent
->keyval
- GDK_KEY_A
);
706 else if (pEvent
->keyval
>= GDK_KEY_0
&& pEvent
->keyval
<= GDK_KEY_9
) {
707 nKeyCode
|= 256 + (pEvent
->keyval
- GDK_KEY_0
);
711 if (pEvent
->type
== GDK_KEY_RELEASE
)
713 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
714 LOEvent
* pLOEvent
= new LOEvent(LOK_POST_KEY
);
715 pLOEvent
->m_nKeyEvent
= LOK_KEYEVENT_KEYUP
;
716 pLOEvent
->m_nCharCode
= nCharCode
;
717 pLOEvent
->m_nKeyCode
= nKeyCode
;
718 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
719 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
720 if (error
!= nullptr)
722 g_warning("Unable to call LOK_POST_KEY: %s", error
->message
);
723 g_clear_error(&error
);
725 g_object_unref(task
);
729 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
730 LOEvent
* pLOEvent
= new LOEvent(LOK_POST_KEY
);
731 pLOEvent
->m_nKeyEvent
= LOK_KEYEVENT_KEYINPUT
;
732 pLOEvent
->m_nCharCode
= nCharCode
;
733 pLOEvent
->m_nKeyCode
= nKeyCode
;
734 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
735 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
736 if (error
!= nullptr)
738 g_warning("Unable to call LOK_POST_KEY: %s", error
->message
);
739 g_clear_error(&error
);
741 g_object_unref(task
);
748 handleTimeout (gpointer pData
)
750 LOKDocView
* pDocView
= LOK_DOC_VIEW (pData
);
751 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
755 if (priv
->m_bCursorOverlayVisible
)
756 priv
->m_bCursorOverlayVisible
= false;
758 priv
->m_bCursorOverlayVisible
= true;
759 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
762 return G_SOURCE_CONTINUE
;
766 commandChanged(LOKDocView
* pDocView
, const std::string
& rString
)
768 g_signal_emit(pDocView
, doc_view_signals
[COMMAND_CHANGED
], 0, rString
.c_str());
772 searchNotFound(LOKDocView
* pDocView
, const std::string
& rString
)
774 g_signal_emit(pDocView
, doc_view_signals
[SEARCH_NOT_FOUND
], 0, rString
.c_str());
777 static void searchResultCount(LOKDocView
* pDocView
, const std::string
& rString
)
779 g_signal_emit(pDocView
, doc_view_signals
[SEARCH_RESULT_COUNT
], 0, rString
.c_str());
782 static void commandResult(LOKDocView
* pDocView
, const std::string
& rString
)
784 g_signal_emit(pDocView
, doc_view_signals
[COMMAND_RESULT
], 0, rString
.c_str());
787 static void formulaChanged(LOKDocView
* pDocView
, const std::string
& rString
)
789 g_signal_emit(pDocView
, doc_view_signals
[FORMULA_CHANGED
], 0, rString
.c_str());
792 static void reportError(LOKDocView
* /*pDocView*/, const std::string
& rString
)
794 GtkWidget
*dialog
= gtk_message_dialog_new(nullptr,
795 GTK_DIALOG_DESTROY_WITH_PARENT
,
800 gtk_dialog_run(GTK_DIALOG(dialog
));
801 gtk_widget_destroy(dialog
);
805 setPart(LOKDocView
* pDocView
, const std::string
& rString
)
807 g_signal_emit(pDocView
, doc_view_signals
[PART_CHANGED
], 0, std::stoi(rString
));
811 hyperlinkClicked(LOKDocView
* pDocView
, const std::string
& rString
)
813 g_signal_emit(pDocView
, doc_view_signals
[HYPERLINK_CLICKED
], 0, rString
.c_str());
816 /// Trigger a redraw, invoked on the main thread by other functions running in a thread.
817 static gboolean
queueDraw(gpointer pData
)
819 GtkWidget
* pWidget
= static_cast<GtkWidget
*>(pData
);
821 gtk_widget_queue_draw(pWidget
);
823 return G_SOURCE_REMOVE
;
826 /// Set up LOKDocView after the document is loaded, invoked on the main thread by openDocumentInThread() running in a thread.
827 static gboolean
postDocumentLoad(gpointer pData
)
829 LOKDocView
* pLOKDocView
= static_cast<LOKDocView
*>(pData
);
830 LOKDocViewPrivate
& priv
= getPrivate(pLOKDocView
);
832 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
833 priv
->m_pDocument
->pClass
->initializeForRendering(priv
->m_pDocument
, priv
->m_aRenderingArguments
.c_str());
834 priv
->m_pDocument
->pClass
->registerCallback(priv
->m_pDocument
, callbackWorker
, pLOKDocView
);
835 priv
->m_pDocument
->pClass
->getDocumentSize(priv
->m_pDocument
, &priv
->m_nDocumentWidthTwips
, &priv
->m_nDocumentHeightTwips
);
836 priv
->m_nParts
= priv
->m_pDocument
->pClass
->getParts(priv
->m_pDocument
);
837 g_timeout_add(600, handleTimeout
, pLOKDocView
);
839 float zoom
= priv
->m_fZoom
;
840 long nDocumentWidthTwips
= priv
->m_nDocumentWidthTwips
;
841 long nDocumentHeightTwips
= priv
->m_nDocumentHeightTwips
;
842 long nDocumentWidthPixels
= twipToPixel(nDocumentWidthTwips
, zoom
);
843 long nDocumentHeightPixels
= twipToPixel(nDocumentHeightTwips
, zoom
);
844 // Total number of columns in this document.
845 guint nColumns
= ceil((double)nDocumentWidthPixels
/ nTileSizePixels
);
847 priv
->m_pTileBuffer
= std::unique_ptr
<TileBuffer
>(new TileBuffer(priv
->m_pDocument
,
849 gtk_widget_set_size_request(GTK_WIDGET(pLOKDocView
),
850 nDocumentWidthPixels
,
851 nDocumentHeightPixels
);
852 gtk_widget_set_can_focus(GTK_WIDGET(pLOKDocView
), TRUE
);
853 gtk_widget_grab_focus(GTK_WIDGET(pLOKDocView
));
854 lok_doc_view_set_zoom(pLOKDocView
, 1.0);
856 return G_SOURCE_REMOVE
;
859 /// Implementation of the global callback handler, invoked by globalCallback();
861 globalCallback (gpointer pData
)
863 CallbackData
* pCallback
= static_cast<CallbackData
*>(pData
);
864 LOKDocViewPrivate
& priv
= getPrivate(pCallback
->m_pDocView
);
865 gboolean bModify
= false;
867 switch (pCallback
->m_nType
)
869 case LOK_CALLBACK_STATUS_INDICATOR_START
:
871 priv
->m_nLoadProgress
= 0.0;
872 g_signal_emit (pCallback
->m_pDocView
, doc_view_signals
[LOAD_CHANGED
], 0, 0.0);
875 case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE
:
877 priv
->m_nLoadProgress
= static_cast<gdouble
>(std::stoi(pCallback
->m_aPayload
)/100.0);
878 g_signal_emit (pCallback
->m_pDocView
, doc_view_signals
[LOAD_CHANGED
], 0, priv
->m_nLoadProgress
);
881 case LOK_CALLBACK_STATUS_INDICATOR_FINISH
:
883 priv
->m_nLoadProgress
= 1.0;
884 g_signal_emit (pCallback
->m_pDocView
, doc_view_signals
[LOAD_CHANGED
], 0, 1.0);
887 case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY
:
890 case LOK_CALLBACK_DOCUMENT_PASSWORD
:
892 char const*const pURL(pCallback
->m_aPayload
.c_str());
893 g_signal_emit (pCallback
->m_pDocView
, doc_view_signals
[PASSWORD_REQUIRED
], 0, pURL
, bModify
);
902 return G_SOURCE_REMOVE
;
906 globalCallbackWorker(int nType
, const char* pPayload
, void* pData
)
908 LOKDocView
* pDocView
= LOK_DOC_VIEW (pData
);
910 CallbackData
* pCallback
= new CallbackData(nType
, pPayload
? pPayload
: "(nil)", pDocView
);
911 g_info("LOKDocView_Impl::globalCallbackWorkerImpl: %s, '%s'", callbackTypeToString(nType
), pPayload
);
912 gdk_threads_add_idle(globalCallback
, pCallback
);
916 payloadToRectangle (LOKDocView
* pDocView
, const char* pPayload
)
918 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
920 gchar
** ppCoordinates
= g_strsplit(pPayload
, ", ", 4);
921 gchar
** ppCoordinate
= ppCoordinates
;
923 aRet
.width
= aRet
.height
= aRet
.x
= aRet
.y
= 0;
927 aRet
.x
= atoi(*ppCoordinate
);
933 aRet
.y
= atoi(*ppCoordinate
);
939 aRet
.width
= atoi(*ppCoordinate
);
940 if (aRet
.x
+ aRet
.width
> priv
->m_nDocumentWidthTwips
)
941 aRet
.width
= priv
->m_nDocumentWidthTwips
- aRet
.x
;
945 aRet
.height
= atoi(*ppCoordinate
);
946 if (aRet
.y
+ aRet
.height
> priv
->m_nDocumentHeightTwips
)
947 aRet
.height
= priv
->m_nDocumentHeightTwips
- aRet
.y
;
948 g_strfreev(ppCoordinates
);
953 static const std::vector
<GdkRectangle
>
954 payloadToRectangles(LOKDocView
* pDocView
, const char* pPayload
)
956 std::vector
<GdkRectangle
> aRet
;
958 gchar
** ppRectangles
= g_strsplit(pPayload
, "; ", 0);
959 for (gchar
** ppRectangle
= ppRectangles
; *ppRectangle
; ++ppRectangle
)
960 aRet
.push_back(payloadToRectangle(pDocView
, *ppRectangle
));
961 g_strfreev(ppRectangles
);
968 setTilesInvalid (LOKDocView
* pDocView
, const GdkRectangle
& rRectangle
)
970 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
971 GdkRectangle aRectanglePixels
;
972 GdkPoint aStart
, aEnd
;
974 aRectanglePixels
.x
= twipToPixel(rRectangle
.x
, priv
->m_fZoom
);
975 aRectanglePixels
.y
= twipToPixel(rRectangle
.y
, priv
->m_fZoom
);
976 aRectanglePixels
.width
= twipToPixel(rRectangle
.width
, priv
->m_fZoom
);
977 aRectanglePixels
.height
= twipToPixel(rRectangle
.height
, priv
->m_fZoom
);
979 aStart
.x
= aRectanglePixels
.y
/ nTileSizePixels
;
980 aStart
.y
= aRectanglePixels
.x
/ nTileSizePixels
;
981 aEnd
.x
= (aRectanglePixels
.y
+ aRectanglePixels
.height
+ nTileSizePixels
) / nTileSizePixels
;
982 aEnd
.y
= (aRectanglePixels
.x
+ aRectanglePixels
.width
+ nTileSizePixels
) / nTileSizePixels
;
983 for (int i
= aStart
.x
; i
< aEnd
.x
; i
++)
985 for (int j
= aStart
.y
; j
< aEnd
.y
; j
++)
987 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
988 priv
->m_pTileBuffer
->setInvalid(i
, j
, priv
->m_fZoom
, task
, priv
->lokThreadPool
);
989 g_object_unref(task
);
995 callback (gpointer pData
)
997 CallbackData
* pCallback
= static_cast<CallbackData
*>(pData
);
998 LOKDocView
* pDocView
= LOK_DOC_VIEW (pCallback
->m_pDocView
);
999 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1001 switch (pCallback
->m_nType
)
1003 case LOK_CALLBACK_INVALIDATE_TILES
:
1005 if (pCallback
->m_aPayload
!= "EMPTY")
1007 GdkRectangle aRectangle
= payloadToRectangle(pDocView
, pCallback
->m_aPayload
.c_str());
1008 setTilesInvalid(pDocView
, aRectangle
);
1011 priv
->m_pTileBuffer
->resetAllTiles();
1013 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
1016 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
1018 priv
->m_aVisibleCursor
= payloadToRectangle(pDocView
, pCallback
->m_aPayload
.c_str());
1019 priv
->m_bCursorOverlayVisible
= true;
1020 g_signal_emit(pDocView
, doc_view_signals
[CURSOR_CHANGED
], 0,
1021 priv
->m_aVisibleCursor
.x
,
1022 priv
->m_aVisibleCursor
.y
,
1023 priv
->m_aVisibleCursor
.width
,
1024 priv
->m_aVisibleCursor
.height
);
1025 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
1028 case LOK_CALLBACK_TEXT_SELECTION
:
1030 priv
->m_aTextSelectionRectangles
= payloadToRectangles(pDocView
, pCallback
->m_aPayload
.c_str());
1031 gboolean bIsTextSelected
= !priv
->m_aTextSelectionRectangles
.empty();
1032 // In case the selection is empty, then we get no LOK_CALLBACK_TEXT_SELECTION_START/END events.
1033 if (!bIsTextSelected
)
1035 memset(&priv
->m_aTextSelectionStart
, 0, sizeof(priv
->m_aTextSelectionStart
));
1036 memset(&priv
->m_aHandleStartRect
, 0, sizeof(priv
->m_aHandleStartRect
));
1037 memset(&priv
->m_aTextSelectionEnd
, 0, sizeof(priv
->m_aTextSelectionEnd
));
1038 memset(&priv
->m_aHandleEndRect
, 0, sizeof(priv
->m_aHandleEndRect
));
1041 memset(&priv
->m_aHandleMiddleRect
, 0, sizeof(priv
->m_aHandleMiddleRect
));
1043 g_signal_emit(pDocView
, doc_view_signals
[TEXT_SELECTION
], 0, bIsTextSelected
);
1044 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
1047 case LOK_CALLBACK_TEXT_SELECTION_START
:
1049 priv
->m_aTextSelectionStart
= payloadToRectangle(pDocView
, pCallback
->m_aPayload
.c_str());
1052 case LOK_CALLBACK_TEXT_SELECTION_END
:
1054 priv
->m_aTextSelectionEnd
= payloadToRectangle(pDocView
, pCallback
->m_aPayload
.c_str());
1057 case LOK_CALLBACK_CURSOR_VISIBLE
:
1059 priv
->m_bCursorVisible
= pCallback
->m_aPayload
== "true";
1062 case LOK_CALLBACK_MOUSE_POINTER
:
1064 // We do not want the cursor to get changed in view-only mode
1067 // The gtk docs claim that most css cursors should be supported, however
1068 // on my system at least this is not true and many cursors are unsupported.
1069 // In this case pCursor = null, which results in the default cursor
1071 GdkCursor
* pCursor
= gdk_cursor_new_from_name(gtk_widget_get_display(GTK_WIDGET(pDocView
)),
1072 pCallback
->m_aPayload
.c_str());
1073 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(pDocView
)), pCursor
);
1077 case LOK_CALLBACK_GRAPHIC_SELECTION
:
1079 if (pCallback
->m_aPayload
!= "EMPTY")
1080 priv
->m_aGraphicSelection
= payloadToRectangle(pDocView
, pCallback
->m_aPayload
.c_str());
1082 memset(&priv
->m_aGraphicSelection
, 0, sizeof(priv
->m_aGraphicSelection
));
1083 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
1086 case LOK_CALLBACK_CELL_CURSOR
:
1088 if (pCallback
->m_aPayload
!= "EMPTY")
1089 priv
->m_aCellCursor
= payloadToRectangle(pDocView
, pCallback
->m_aPayload
.c_str());
1091 memset(&priv
->m_aCellCursor
, 0, sizeof(priv
->m_aCellCursor
));
1092 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
1095 case LOK_CALLBACK_HYPERLINK_CLICKED
:
1097 hyperlinkClicked(pDocView
, pCallback
->m_aPayload
);
1100 case LOK_CALLBACK_STATE_CHANGED
:
1102 commandChanged(pDocView
, pCallback
->m_aPayload
);
1105 case LOK_CALLBACK_SEARCH_NOT_FOUND
:
1107 searchNotFound(pDocView
, pCallback
->m_aPayload
);
1110 case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
:
1112 payloadToSize(pCallback
->m_aPayload
.c_str(), priv
->m_nDocumentWidthTwips
, priv
->m_nDocumentHeightTwips
);
1113 gtk_widget_set_size_request(GTK_WIDGET(pDocView
),
1114 twipToPixel(priv
->m_nDocumentWidthTwips
, priv
->m_fZoom
),
1115 twipToPixel(priv
->m_nDocumentHeightTwips
, priv
->m_fZoom
));
1117 g_signal_emit(pDocView
, doc_view_signals
[SIZE_CHANGED
], 0, nullptr);
1120 case LOK_CALLBACK_SET_PART
:
1122 setPart(pDocView
, pCallback
->m_aPayload
);
1125 case LOK_CALLBACK_SEARCH_RESULT_SELECTION
:
1127 boost::property_tree::ptree aTree
;
1128 std::stringstream
aStream(pCallback
->m_aPayload
);
1129 boost::property_tree::read_json(aStream
, aTree
);
1130 int nCount
= aTree
.get_child("searchResultSelection").size();
1131 searchResultCount(pDocView
, std::to_string(nCount
));
1134 case LOK_CALLBACK_UNO_COMMAND_RESULT
:
1136 commandResult(pDocView
, pCallback
->m_aPayload
);
1139 case LOK_CALLBACK_CELL_FORMULA
:
1141 formulaChanged(pDocView
, pCallback
->m_aPayload
);
1144 case LOK_CALLBACK_ERROR
:
1146 reportError(pDocView
, pCallback
->m_aPayload
);
1149 case LOK_CALLBACK_CONTEXT_MENU
:
1151 // TODO: Implement me
1160 return G_SOURCE_REMOVE
;
1163 static void callbackWorker (int nType
, const char* pPayload
, void* pData
)
1165 LOKDocView
* pDocView
= LOK_DOC_VIEW (pData
);
1167 CallbackData
* pCallback
= new CallbackData(nType
, pPayload
? pPayload
: "(nil)", pDocView
);
1168 g_info("callbackWorker: %s, '%s'", callbackTypeToString(nType
), pPayload
);
1169 gdk_threads_add_idle(callback
, pCallback
);
1173 renderHandle(LOKDocView
* pDocView
,
1175 const GdkRectangle
& rCursor
,
1176 cairo_surface_t
* pHandle
,
1177 GdkRectangle
& rRectangle
)
1179 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1180 GdkPoint aCursorBottom
;
1181 int nHandleWidth
, nHandleHeight
;
1182 double fHandleScale
;
1184 nHandleWidth
= cairo_image_surface_get_width(pHandle
);
1185 nHandleHeight
= cairo_image_surface_get_height(pHandle
);
1186 // We want to scale down the handle, so that its height is the same as the cursor caret.
1187 fHandleScale
= twipToPixel(rCursor
.height
, priv
->m_fZoom
) / nHandleHeight
;
1188 // We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
1189 aCursorBottom
.x
= twipToPixel(rCursor
.x
, priv
->m_fZoom
) + twipToPixel(rCursor
.width
, priv
->m_fZoom
) / 2 - (nHandleWidth
* fHandleScale
) / 2;
1190 aCursorBottom
.y
= twipToPixel(rCursor
.y
, priv
->m_fZoom
) + twipToPixel(rCursor
.height
, priv
->m_fZoom
);
1192 cairo_save (pCairo
);
1193 cairo_translate(pCairo
, aCursorBottom
.x
, aCursorBottom
.y
);
1194 cairo_scale(pCairo
, fHandleScale
, fHandleScale
);
1195 cairo_set_source_surface(pCairo
, pHandle
, 0, 0);
1196 cairo_paint(pCairo
);
1197 cairo_restore (pCairo
);
1199 rRectangle
.x
= aCursorBottom
.x
;
1200 rRectangle
.y
= aCursorBottom
.y
;
1201 rRectangle
.width
= nHandleWidth
* fHandleScale
;
1202 rRectangle
.height
= nHandleHeight
* fHandleScale
;
1205 /// Renders pHandle around an rSelection rectangle on pCairo.
1207 renderGraphicHandle(LOKDocView
* pDocView
,
1209 const GdkRectangle
& rSelection
,
1210 cairo_surface_t
* pHandle
)
1212 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1213 int nHandleWidth
, nHandleHeight
;
1214 GdkRectangle aSelection
;
1216 nHandleWidth
= cairo_image_surface_get_width(pHandle
);
1217 nHandleHeight
= cairo_image_surface_get_height(pHandle
);
1219 aSelection
.x
= twipToPixel(rSelection
.x
, priv
->m_fZoom
);
1220 aSelection
.y
= twipToPixel(rSelection
.y
, priv
->m_fZoom
);
1221 aSelection
.width
= twipToPixel(rSelection
.width
, priv
->m_fZoom
);
1222 aSelection
.height
= twipToPixel(rSelection
.height
, priv
->m_fZoom
);
1224 for (int i
= 0; i
< GRAPHIC_HANDLE_COUNT
; ++i
)
1226 int x
= aSelection
.x
, y
= aSelection
.y
;
1232 case 1: // top-middle
1233 x
+= aSelection
.width
/ 2;
1235 case 2: // top-right
1236 x
+= aSelection
.width
;
1238 case 3: // middle-left
1239 y
+= aSelection
.height
/ 2;
1241 case 4: // middle-right
1242 x
+= aSelection
.width
;
1243 y
+= aSelection
.height
/ 2;
1245 case 5: // bottom-left
1246 y
+= aSelection
.height
;
1248 case 6: // bottom-middle
1249 x
+= aSelection
.width
/ 2;
1250 y
+= aSelection
.height
;
1252 case 7: // bottom-right
1253 x
+= aSelection
.width
;
1254 y
+= aSelection
.height
;
1258 // Center the handle.
1259 x
-= nHandleWidth
/ 2;
1260 y
-= nHandleHeight
/ 2;
1262 priv
->m_aGraphicHandleRects
[i
].x
= x
;
1263 priv
->m_aGraphicHandleRects
[i
].y
= y
;
1264 priv
->m_aGraphicHandleRects
[i
].width
= nHandleWidth
;
1265 priv
->m_aGraphicHandleRects
[i
].height
= nHandleHeight
;
1267 cairo_save (pCairo
);
1268 cairo_translate(pCairo
, x
, y
);
1269 cairo_set_source_surface(pCairo
, pHandle
, 0, 0);
1270 cairo_paint(pCairo
);
1271 cairo_restore (pCairo
);
1275 /// Finishes the paint tile operation and returns the result, if any
1277 paintTileFinish(LOKDocView
* pDocView
, GAsyncResult
* res
, GError
**error
)
1279 GTask
* task
= G_TASK(res
);
1281 g_return_val_if_fail(LOK_IS_DOC_VIEW(pDocView
), nullptr);
1282 g_return_val_if_fail(g_task_is_valid(res
, pDocView
), nullptr);
1283 g_return_val_if_fail(error
== nullptr || *error
== nullptr, nullptr);
1285 return g_task_propagate_pointer(task
, error
);
1288 /// Callback called in the main UI thread when paintTileInThread in LOK thread has finished
1290 paintTileCallback(GObject
* sourceObject
, GAsyncResult
* res
, gpointer userData
)
1292 LOKDocView
* pDocView
= LOK_DOC_VIEW(sourceObject
);
1293 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1294 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(userData
);
1295 std::unique_ptr
<TileBuffer
>& buffer
= priv
->m_pTileBuffer
;
1296 int index
= pLOEvent
->m_nPaintTileX
* buffer
->m_nWidth
+ pLOEvent
->m_nPaintTileY
;
1300 cairo_surface_t
* pSurface
= static_cast<cairo_surface_t
*>(paintTileFinish(pDocView
, res
, &error
));
1301 if (error
!= nullptr)
1303 if (error
->domain
== LOK_TILEBUFFER_ERROR
&&
1304 error
->code
== LOK_TILEBUFFER_CHANGED
)
1305 g_info("Skipping paint tile request because corresponding"
1306 "tile buffer has been destroyed");
1308 g_warning("Unable to get painted GdkPixbuf: %s", error
->message
);
1309 g_error_free(error
);
1313 buffer
->m_mTiles
[index
].setSurface(pSurface
);
1314 buffer
->m_mTiles
[index
].valid
= true;
1315 gdk_threads_add_idle(queueDraw
, GTK_WIDGET(pDocView
));
1317 cairo_surface_destroy(pSurface
);
1322 renderDocument(LOKDocView
* pDocView
, cairo_t
* pCairo
)
1324 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1325 GdkRectangle aVisibleArea
;
1326 long nDocumentWidthPixels
= twipToPixel(priv
->m_nDocumentWidthTwips
, priv
->m_fZoom
);
1327 long nDocumentHeightPixels
= twipToPixel(priv
->m_nDocumentHeightTwips
, priv
->m_fZoom
);
1328 // Total number of rows / columns in this document.
1329 guint nRows
= ceil((double)nDocumentHeightPixels
/ nTileSizePixels
);
1330 guint nColumns
= ceil((double)nDocumentWidthPixels
/ nTileSizePixels
);
1332 gdk_cairo_get_clip_rectangle (pCairo
, &aVisibleArea
);
1333 aVisibleArea
.x
= pixelToTwip (aVisibleArea
.x
, priv
->m_fZoom
);
1334 aVisibleArea
.y
= pixelToTwip (aVisibleArea
.y
, priv
->m_fZoom
);
1335 aVisibleArea
.width
= pixelToTwip (aVisibleArea
.width
, priv
->m_fZoom
);
1336 aVisibleArea
.height
= pixelToTwip (aVisibleArea
.height
, priv
->m_fZoom
);
1338 // Render the tiles.
1339 for (guint nRow
= 0; nRow
< nRows
; ++nRow
)
1341 for (guint nColumn
= 0; nColumn
< nColumns
; ++nColumn
)
1343 GdkRectangle aTileRectangleTwips
, aTileRectanglePixels
;
1346 // Determine size of the tile: the rightmost/bottommost tiles may
1347 // be smaller, and we need the size to decide if we need to repaint.
1348 if (nColumn
== nColumns
- 1)
1349 aTileRectanglePixels
.width
= nDocumentWidthPixels
- nColumn
* nTileSizePixels
;
1351 aTileRectanglePixels
.width
= nTileSizePixels
;
1352 if (nRow
== nRows
- 1)
1353 aTileRectanglePixels
.height
= nDocumentHeightPixels
- nRow
* nTileSizePixels
;
1355 aTileRectanglePixels
.height
= nTileSizePixels
;
1357 // Determine size and position of the tile in document coordinates,
1358 // so we can decide if we can skip painting for partial rendering.
1359 aTileRectangleTwips
.x
= pixelToTwip(nTileSizePixels
, priv
->m_fZoom
) * nColumn
;
1360 aTileRectangleTwips
.y
= pixelToTwip(nTileSizePixels
, priv
->m_fZoom
) * nRow
;
1361 aTileRectangleTwips
.width
= pixelToTwip(aTileRectanglePixels
.width
, priv
->m_fZoom
);
1362 aTileRectangleTwips
.height
= pixelToTwip(aTileRectanglePixels
.height
, priv
->m_fZoom
);
1364 if (!gdk_rectangle_intersect(&aVisibleArea
, &aTileRectangleTwips
, nullptr))
1369 LOEvent
* pLOEvent
= new LOEvent(LOK_PAINT_TILE
);
1370 pLOEvent
->m_nPaintTileX
= nRow
;
1371 pLOEvent
->m_nPaintTileY
= nColumn
;
1372 pLOEvent
->m_fPaintTileZoom
= priv
->m_fZoom
;
1373 pLOEvent
->m_pTileBuffer
= &*priv
->m_pTileBuffer
;
1374 GTask
* task
= g_task_new(pDocView
, nullptr, paintTileCallback
, pLOEvent
);
1375 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
1377 Tile
& currentTile
= priv
->m_pTileBuffer
->getTile(nRow
, nColumn
, task
, priv
->lokThreadPool
);
1378 cairo_surface_t
* pSurface
= currentTile
.getBuffer();
1379 cairo_set_source_surface(pCairo
, pSurface
,
1380 twipToPixel(aTileRectangleTwips
.x
, priv
->m_fZoom
),
1381 twipToPixel(aTileRectangleTwips
.y
, priv
->m_fZoom
));
1382 cairo_paint(pCairo
);
1383 g_object_unref(task
);
1392 renderOverlay(LOKDocView
* pDocView
, cairo_t
* pCairo
)
1394 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1396 if (priv
->m_bEdit
&& priv
->m_bCursorVisible
&& priv
->m_bCursorOverlayVisible
&& !isEmptyRectangle(priv
->m_aVisibleCursor
))
1398 if (priv
->m_aVisibleCursor
.width
< 30)
1399 // Set a minimal width if it would be 0.
1400 priv
->m_aVisibleCursor
.width
= 30;
1402 cairo_set_source_rgb(pCairo
, 0, 0, 0);
1403 cairo_rectangle(pCairo
,
1404 twipToPixel(priv
->m_aVisibleCursor
.x
, priv
->m_fZoom
),
1405 twipToPixel(priv
->m_aVisibleCursor
.y
, priv
->m_fZoom
),
1406 twipToPixel(priv
->m_aVisibleCursor
.width
, priv
->m_fZoom
),
1407 twipToPixel(priv
->m_aVisibleCursor
.height
, priv
->m_fZoom
));
1411 if (priv
->m_bEdit
&& priv
->m_bCursorVisible
&& !isEmptyRectangle(priv
->m_aVisibleCursor
) && priv
->m_aTextSelectionRectangles
.empty())
1413 // Have a cursor, but no selection: we need the middle handle.
1414 gchar
* handleMiddlePath
= g_strconcat (priv
->m_aLOPath
, CURSOR_HANDLE_DIR
, "handle_image_middle.png", nullptr);
1415 if (!priv
->m_pHandleMiddle
)
1417 priv
->m_pHandleMiddle
= cairo_image_surface_create_from_png(handleMiddlePath
);
1418 assert(cairo_surface_status(priv
->m_pHandleMiddle
) == CAIRO_STATUS_SUCCESS
);
1420 g_free (handleMiddlePath
);
1421 renderHandle(pDocView
, pCairo
, priv
->m_aVisibleCursor
, priv
->m_pHandleMiddle
, priv
->m_aHandleMiddleRect
);
1424 if (!priv
->m_aTextSelectionRectangles
.empty())
1426 for (GdkRectangle
& rRectangle
: priv
->m_aTextSelectionRectangles
)
1428 // Blue with 75% transparency.
1429 cairo_set_source_rgba(pCairo
, ((double)0x43)/255, ((double)0xac)/255, ((double)0xe8)/255, 0.25);
1430 cairo_rectangle(pCairo
,
1431 twipToPixel(rRectangle
.x
, priv
->m_fZoom
),
1432 twipToPixel(rRectangle
.y
, priv
->m_fZoom
),
1433 twipToPixel(rRectangle
.width
, priv
->m_fZoom
),
1434 twipToPixel(rRectangle
.height
, priv
->m_fZoom
));
1439 if (!isEmptyRectangle(priv
->m_aTextSelectionStart
))
1441 // Have a start position: we need a start handle.
1442 gchar
* handleStartPath
= g_strconcat (priv
->m_aLOPath
, CURSOR_HANDLE_DIR
, "handle_image_start.png", nullptr);
1443 if (!priv
->m_pHandleStart
)
1445 priv
->m_pHandleStart
= cairo_image_surface_create_from_png(handleStartPath
);
1446 assert(cairo_surface_status(priv
->m_pHandleStart
) == CAIRO_STATUS_SUCCESS
);
1448 renderHandle(pDocView
, pCairo
, priv
->m_aTextSelectionStart
, priv
->m_pHandleStart
, priv
->m_aHandleStartRect
);
1449 g_free (handleStartPath
);
1451 if (!isEmptyRectangle(priv
->m_aTextSelectionEnd
))
1453 // Have a start position: we need an end handle.
1454 gchar
* handleEndPath
= g_strconcat (priv
->m_aLOPath
, CURSOR_HANDLE_DIR
, "handle_image_end.png", nullptr);
1455 if (!priv
->m_pHandleEnd
)
1457 priv
->m_pHandleEnd
= cairo_image_surface_create_from_png(handleEndPath
);
1458 assert(cairo_surface_status(priv
->m_pHandleEnd
) == CAIRO_STATUS_SUCCESS
);
1460 renderHandle(pDocView
, pCairo
, priv
->m_aTextSelectionEnd
, priv
->m_pHandleEnd
, priv
->m_aHandleEndRect
);
1461 g_free (handleEndPath
);
1465 if (!isEmptyRectangle(priv
->m_aGraphicSelection
))
1467 gchar
* handleGraphicPath
= g_strconcat (priv
->m_aLOPath
, CURSOR_HANDLE_DIR
, "handle_graphic.png", nullptr);
1468 if (!priv
->m_pGraphicHandle
)
1470 priv
->m_pGraphicHandle
= cairo_image_surface_create_from_png(handleGraphicPath
);
1471 assert(cairo_surface_status(priv
->m_pGraphicHandle
) == CAIRO_STATUS_SUCCESS
);
1473 renderGraphicHandle(pDocView
, pCairo
, priv
->m_aGraphicSelection
, priv
->m_pGraphicHandle
);
1474 g_free (handleGraphicPath
);
1477 if (!isEmptyRectangle(priv
->m_aCellCursor
))
1479 cairo_set_source_rgb(pCairo
, 0, 0, 0);
1480 cairo_rectangle(pCairo
,
1481 twipToPixel(priv
->m_aCellCursor
.x
, priv
->m_fZoom
),
1482 twipToPixel(priv
->m_aCellCursor
.y
, priv
->m_fZoom
),
1483 twipToPixel(priv
->m_aCellCursor
.width
, priv
->m_fZoom
),
1484 twipToPixel(priv
->m_aCellCursor
.height
, priv
->m_fZoom
));
1485 // priv->m_aCellCursor.x - 1,
1486 // priv->m_aCellCursor.y - 1,
1487 // priv->m_aCellCursor.width + 2,
1488 // priv->m_aCellCursor.height + 2);
1489 cairo_set_line_width(pCairo
, 2.0);
1490 cairo_stroke(pCairo
);
1497 lok_doc_view_signal_button(GtkWidget
* pWidget
, GdkEventButton
* pEvent
)
1499 LOKDocView
* pDocView
= LOK_DOC_VIEW (pWidget
);
1500 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1501 GError
* error
= nullptr;
1503 g_info("LOKDocView_Impl::signalButton: %d, %d (in twips: %d, %d)",
1504 (int)pEvent
->x
, (int)pEvent
->y
,
1505 (int)pixelToTwip(pEvent
->x
, priv
->m_fZoom
),
1506 (int)pixelToTwip(pEvent
->y
, priv
->m_fZoom
));
1507 gtk_widget_grab_focus(GTK_WIDGET(pDocView
));
1509 switch (pEvent
->type
)
1511 case GDK_BUTTON_PRESS
:
1513 GdkRectangle aClick
;
1514 aClick
.x
= pEvent
->x
;
1515 aClick
.y
= pEvent
->y
;
1519 if (handleTextSelectionOnButtonPress(aClick
, pDocView
))
1521 if (handleGraphicSelectionOnButtonPress(aClick
, pDocView
))
1525 if ((pEvent
->time
- priv
->m_nLastButtonPressTime
) < 250)
1527 priv
->m_nLastButtonPressTime
= pEvent
->time
;
1528 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
1529 LOEvent
* pLOEvent
= new LOEvent(LOK_POST_MOUSE_EVENT
);
1530 pLOEvent
->m_nPostMouseEventType
= LOK_MOUSEEVENT_MOUSEBUTTONDOWN
;
1531 pLOEvent
->m_nPostMouseEventX
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
1532 pLOEvent
->m_nPostMouseEventY
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
1533 pLOEvent
->m_nPostMouseEventCount
= nCount
;
1534 switch (pEvent
->button
)
1537 pLOEvent
->m_nPostMouseEventButton
= MOUSE_LEFT
;
1540 pLOEvent
->m_nPostMouseEventButton
= MOUSE_MIDDLE
;
1543 pLOEvent
->m_nPostMouseEventButton
= MOUSE_RIGHT
;
1546 pLOEvent
->m_nPostMouseEventModifier
= priv
->m_nKeyModifier
;
1547 priv
->m_nLastButtonPressed
= pLOEvent
->m_nPostMouseEventButton
;
1548 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
1550 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
1551 if (error
!= nullptr)
1553 g_warning("Unable to call LOK_POST_MOUSE_EVENT: %s", error
->message
);
1554 g_clear_error(&error
);
1556 g_object_unref(task
);
1559 case GDK_BUTTON_RELEASE
:
1561 if (handleTextSelectionOnButtonRelease(pDocView
))
1563 if (handleGraphicSelectionOnButtonRelease(pDocView
, pEvent
))
1567 if ((pEvent
->time
- priv
->m_nLastButtonReleaseTime
) < 250)
1569 priv
->m_nLastButtonReleaseTime
= pEvent
->time
;
1570 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
1571 LOEvent
* pLOEvent
= new LOEvent(LOK_POST_MOUSE_EVENT
);
1572 pLOEvent
->m_nPostMouseEventType
= LOK_MOUSEEVENT_MOUSEBUTTONUP
;
1573 pLOEvent
->m_nPostMouseEventX
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
1574 pLOEvent
->m_nPostMouseEventY
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
1575 pLOEvent
->m_nPostMouseEventCount
= nCount
;
1576 switch (pEvent
->button
)
1579 pLOEvent
->m_nPostMouseEventButton
= MOUSE_LEFT
;
1582 pLOEvent
->m_nPostMouseEventButton
= MOUSE_MIDDLE
;
1585 pLOEvent
->m_nPostMouseEventButton
= MOUSE_RIGHT
;
1588 pLOEvent
->m_nPostMouseEventModifier
= priv
->m_nKeyModifier
;
1589 priv
->m_nLastButtonPressed
= pLOEvent
->m_nPostMouseEventButton
;
1590 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
1592 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
1593 if (error
!= nullptr)
1595 g_warning("Unable to call LOK_POST_MOUSE_EVENT: %s", error
->message
);
1596 g_clear_error(&error
);
1598 g_object_unref(task
);
1608 getDragPoint(GdkRectangle
* pHandle
,
1609 GdkEventMotion
* pEvent
,
1612 GdkPoint aCursor
, aHandle
;
1614 // Center of the cursor rectangle: we know that it's above the handle.
1615 aCursor
.x
= pHandle
->x
+ pHandle
->width
/ 2;
1616 aCursor
.y
= pHandle
->y
- pHandle
->height
/ 2;
1617 // Center of the handle rectangle.
1618 aHandle
.x
= pHandle
->x
+ pHandle
->width
/ 2;
1619 aHandle
.y
= pHandle
->y
+ pHandle
->height
/ 2;
1620 // Our target is the original cursor position + the dragged offset.
1621 pPoint
->x
= aCursor
.x
+ (pEvent
->x
- aHandle
.x
);
1622 pPoint
->y
= aCursor
.y
+ (pEvent
->y
- aHandle
.y
);
1626 lok_doc_view_signal_motion (GtkWidget
* pWidget
, GdkEventMotion
* pEvent
)
1628 LOKDocView
* pDocView
= LOK_DOC_VIEW (pWidget
);
1629 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1631 GError
* error
= nullptr;
1633 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1634 if (priv
->m_bInDragMiddleHandle
)
1636 g_info("lcl_signalMotion: dragging the middle handle");
1637 getDragPoint(&priv
->m_aHandleMiddleRect
, pEvent
, &aPoint
);
1638 priv
->m_pDocument
->pClass
->setTextSelection(priv
->m_pDocument
, LOK_SETTEXTSELECTION_RESET
, pixelToTwip(aPoint
.x
, priv
->m_fZoom
), pixelToTwip(aPoint
.y
, priv
->m_fZoom
));
1641 if (priv
->m_bInDragStartHandle
)
1643 g_info("lcl_signalMotion: dragging the start handle");
1644 getDragPoint(&priv
->m_aHandleStartRect
, pEvent
, &aPoint
);
1645 priv
->m_pDocument
->pClass
->setTextSelection(priv
->m_pDocument
, LOK_SETTEXTSELECTION_START
, pixelToTwip(aPoint
.x
, priv
->m_fZoom
), pixelToTwip(aPoint
.y
, priv
->m_fZoom
));
1648 if (priv
->m_bInDragEndHandle
)
1650 g_info("lcl_signalMotion: dragging the end handle");
1651 getDragPoint(&priv
->m_aHandleEndRect
, pEvent
, &aPoint
);
1652 priv
->m_pDocument
->pClass
->setTextSelection(priv
->m_pDocument
, LOK_SETTEXTSELECTION_END
, pixelToTwip(aPoint
.x
, priv
->m_fZoom
), pixelToTwip(aPoint
.y
, priv
->m_fZoom
));
1655 for (int i
= 0; i
< GRAPHIC_HANDLE_COUNT
; ++i
)
1657 if (priv
->m_bInDragGraphicHandles
[i
])
1659 g_info("lcl_signalMotion: dragging the graphic handle #%d", i
);
1663 if (priv
->m_bInDragGraphicSelection
)
1665 g_info("lcl_signalMotion: dragging the graphic selection");
1669 GdkRectangle aMotionInTwipsInTwips
;
1670 aMotionInTwipsInTwips
.x
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
1671 aMotionInTwipsInTwips
.y
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
1672 aMotionInTwipsInTwips
.width
= 1;
1673 aMotionInTwipsInTwips
.height
= 1;
1674 if (gdk_rectangle_intersect(&aMotionInTwipsInTwips
, &priv
->m_aGraphicSelection
, nullptr))
1676 g_info("lcl_signalMotion: start of drag graphic selection");
1677 priv
->m_bInDragGraphicSelection
= true;
1679 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
1680 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_GRAPHIC_SELECTION
);
1681 pLOEvent
->m_nSetGraphicSelectionType
= LOK_SETGRAPHICSELECTION_START
;
1682 pLOEvent
->m_nSetGraphicSelectionX
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
1683 pLOEvent
->m_nSetGraphicSelectionY
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
1684 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
1686 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
1687 if (error
!= nullptr)
1689 g_warning("Unable to call LOK_SET_GRAPHIC_SELECTION: %s", error
->message
);
1690 g_clear_error(&error
);
1692 g_object_unref(task
);
1697 // Otherwise a mouse move, as on the desktop.
1699 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
1700 LOEvent
* pLOEvent
= new LOEvent(LOK_POST_MOUSE_EVENT
);
1701 pLOEvent
->m_nPostMouseEventType
= LOK_MOUSEEVENT_MOUSEMOVE
;
1702 pLOEvent
->m_nPostMouseEventX
= pixelToTwip(pEvent
->x
, priv
->m_fZoom
);
1703 pLOEvent
->m_nPostMouseEventY
= pixelToTwip(pEvent
->y
, priv
->m_fZoom
);
1704 pLOEvent
->m_nPostMouseEventCount
= 1;
1705 pLOEvent
->m_nPostMouseEventButton
= priv
->m_nLastButtonPressed
;
1706 pLOEvent
->m_nPostMouseEventModifier
= priv
->m_nKeyModifier
;
1708 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
1710 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
1711 if (error
!= nullptr)
1713 g_warning("Unable to call LOK_MOUSEEVENT_MOUSEMOVE: %s", error
->message
);
1714 g_clear_error(&error
);
1716 g_object_unref(task
);
1722 setGraphicSelectionInThread(gpointer data
)
1724 GTask
* task
= G_TASK(data
);
1725 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1726 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1727 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1729 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1730 std::stringstream ss
;
1731 ss
<< "lok::Document::setGraphicSelection(" << pLOEvent
->m_nSetGraphicSelectionType
;
1732 ss
<< ", " << pLOEvent
->m_nSetGraphicSelectionX
;
1733 ss
<< ", " << pLOEvent
->m_nSetGraphicSelectionY
<< ")";
1734 g_info("%s", ss
.str().c_str());
1735 priv
->m_pDocument
->pClass
->setGraphicSelection(priv
->m_pDocument
,
1736 pLOEvent
->m_nSetGraphicSelectionType
,
1737 pLOEvent
->m_nSetGraphicSelectionX
,
1738 pLOEvent
->m_nSetGraphicSelectionY
);
1742 setClientZoomInThread(gpointer data
)
1744 GTask
* task
= G_TASK(data
);
1745 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1746 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1747 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1749 priv
->m_pDocument
->pClass
->setClientZoom(priv
->m_pDocument
,
1750 pLOEvent
->m_nTilePixelWidth
,
1751 pLOEvent
->m_nTilePixelHeight
,
1752 pLOEvent
->m_nTileTwipWidth
,
1753 pLOEvent
->m_nTileTwipHeight
);
1757 postMouseEventInThread(gpointer data
)
1759 GTask
* task
= G_TASK(data
);
1760 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1761 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1762 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1764 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1765 std::stringstream ss
;
1766 ss
<< "lok::Document::postMouseEvent(" << pLOEvent
->m_nPostMouseEventType
;
1767 ss
<< ", " << pLOEvent
->m_nPostMouseEventX
;
1768 ss
<< ", " << pLOEvent
->m_nPostMouseEventY
;
1769 ss
<< ", " << pLOEvent
->m_nPostMouseEventCount
;
1770 ss
<< ", " << pLOEvent
->m_nPostMouseEventButton
;
1771 ss
<< ", " << pLOEvent
->m_nPostMouseEventModifier
<< ")";
1772 g_info("%s", ss
.str().c_str());
1773 priv
->m_pDocument
->pClass
->postMouseEvent(priv
->m_pDocument
,
1774 pLOEvent
->m_nPostMouseEventType
,
1775 pLOEvent
->m_nPostMouseEventX
,
1776 pLOEvent
->m_nPostMouseEventY
,
1777 pLOEvent
->m_nPostMouseEventCount
,
1778 pLOEvent
->m_nPostMouseEventButton
,
1779 pLOEvent
->m_nPostMouseEventModifier
);
1783 openDocumentInThread (gpointer data
)
1785 GTask
* task
= G_TASK(data
);
1786 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1787 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1789 if ( priv
->m_pDocument
)
1791 priv
->m_pDocument
->pClass
->destroy( priv
->m_pDocument
);
1792 priv
->m_pDocument
= nullptr;
1795 priv
->m_pOffice
->pClass
->registerCallback(priv
->m_pOffice
, globalCallbackWorker
, pDocView
);
1796 priv
->m_pDocument
= priv
->m_pOffice
->pClass
->documentLoad( priv
->m_pOffice
, priv
->m_aDocPath
);
1797 if ( !priv
->m_pDocument
)
1799 char *pError
= priv
->m_pOffice
->pClass
->getError( priv
->m_pOffice
);
1800 g_task_return_new_error(task
, g_quark_from_static_string ("LOK error"), 0, "%s", pError
);
1804 gdk_threads_add_idle(postDocumentLoad
, pDocView
);
1805 g_task_return_boolean (task
, true);
1810 setPartInThread(gpointer data
)
1812 GTask
* task
= G_TASK(data
);
1813 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1814 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1815 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1816 int nPart
= pLOEvent
->m_nPart
;
1818 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1819 priv
->m_pDocument
->pClass
->setPart( priv
->m_pDocument
, nPart
);
1821 lok_doc_view_reset_view(pDocView
);
1825 setPartmodeInThread(gpointer data
)
1827 GTask
* task
= G_TASK(data
);
1828 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1829 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1830 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1831 int nPartMode
= pLOEvent
->m_nPartMode
;
1833 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1834 priv
->m_pDocument
->pClass
->setPartMode( priv
->m_pDocument
, nPartMode
);
1838 setEditInThread(gpointer data
)
1840 GTask
* task
= G_TASK(data
);
1841 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1842 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1843 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1844 gboolean bWasEdit
= priv
->m_bEdit
;
1845 gboolean bEdit
= pLOEvent
->m_bEdit
;
1847 if (!priv
->m_bEdit
&& bEdit
)
1848 g_info("lok_doc_view_set_edit: entering edit mode");
1849 else if (priv
->m_bEdit
&& !bEdit
)
1851 g_info("lok_doc_view_set_edit: leaving edit mode");
1852 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1853 priv
->m_pDocument
->pClass
->resetSelection(priv
->m_pDocument
);
1855 priv
->m_bEdit
= bEdit
;
1856 g_signal_emit(pDocView
, doc_view_signals
[EDIT_CHANGED
], 0, bWasEdit
);
1857 gdk_threads_add_idle(queueDraw
, GTK_WIDGET(pDocView
));
1861 postCommandInThread (gpointer data
)
1863 GTask
* task
= G_TASK(data
);
1864 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1865 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1866 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1868 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1869 std::stringstream ss
;
1870 ss
<< "lok::Document::postUnoCommand(" << pLOEvent
->m_pCommand
<< ", " << pLOEvent
->m_pArguments
<< ")";
1871 g_info("%s", ss
.str().c_str());
1872 priv
->m_pDocument
->pClass
->postUnoCommand(priv
->m_pDocument
, pLOEvent
->m_pCommand
, pLOEvent
->m_pArguments
, pLOEvent
->m_bNotifyWhenFinished
);
1876 paintTileInThread (gpointer data
)
1878 GTask
* task
= G_TASK(data
);
1879 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1880 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1881 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1883 // check if "source" tile buffer is different from "current" tile buffer
1884 if (pLOEvent
->m_pTileBuffer
!= &*priv
->m_pTileBuffer
)
1886 pLOEvent
->m_pTileBuffer
= nullptr;
1887 g_task_return_new_error(task
,
1888 LOK_TILEBUFFER_ERROR
,
1889 LOK_TILEBUFFER_CHANGED
,
1890 "TileBuffer has changed");
1893 std::unique_ptr
<TileBuffer
>& buffer
= priv
->m_pTileBuffer
;
1894 int index
= pLOEvent
->m_nPaintTileX
* buffer
->m_nWidth
+ pLOEvent
->m_nPaintTileY
;
1895 if (buffer
->m_mTiles
.find(index
) != buffer
->m_mTiles
.end() &&
1896 buffer
->m_mTiles
[index
].valid
)
1899 cairo_surface_t
*pSurface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, nTileSizePixels
, nTileSizePixels
);
1900 if (cairo_surface_status(pSurface
) != CAIRO_STATUS_SUCCESS
)
1902 cairo_surface_destroy(pSurface
);
1903 g_task_return_new_error(task
,
1904 LOK_TILEBUFFER_ERROR
,
1905 LOK_TILEBUFFER_MEMORY
,
1906 "Error allocating Surface");
1910 unsigned char* pBuffer
= cairo_image_surface_get_data(pSurface
);
1911 GdkRectangle aTileRectangle
;
1912 aTileRectangle
.x
= pixelToTwip(nTileSizePixels
, pLOEvent
->m_fPaintTileZoom
) * pLOEvent
->m_nPaintTileY
;
1913 aTileRectangle
.y
= pixelToTwip(nTileSizePixels
, pLOEvent
->m_fPaintTileZoom
) * pLOEvent
->m_nPaintTileX
;
1915 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
1916 std::stringstream ss
;
1917 GTimer
* aTimer
= g_timer_new();
1919 ss
<< "lok::Document::paintTile(" << static_cast<void*>(pBuffer
) << ", "
1920 << nTileSizePixels
<< ", " << nTileSizePixels
<< ", "
1921 << aTileRectangle
.x
<< ", " << aTileRectangle
.y
<< ", "
1922 << pixelToTwip(nTileSizePixels
, pLOEvent
->m_fPaintTileZoom
) << ", "
1923 << pixelToTwip(nTileSizePixels
, pLOEvent
->m_fPaintTileZoom
) << ")";
1925 priv
->m_pDocument
->pClass
->paintTile(priv
->m_pDocument
,
1927 nTileSizePixels
, nTileSizePixels
,
1928 aTileRectangle
.x
, aTileRectangle
.y
,
1929 pixelToTwip(nTileSizePixels
, pLOEvent
->m_fPaintTileZoom
),
1930 pixelToTwip(nTileSizePixels
, pLOEvent
->m_fPaintTileZoom
));
1932 g_timer_elapsed(aTimer
, &nElapsedMs
);
1933 ss
<< " rendered in " << (nElapsedMs
/ 1000.) << " milliseconds";
1934 g_info("%s", ss
.str().c_str());
1935 g_timer_destroy(aTimer
);
1937 cairo_surface_mark_dirty(pSurface
);
1939 // Its likely that while the tilebuffer has changed, one of the paint tile
1940 // requests has passed the previous check at start of this function, and has
1941 // rendered the tile already. We want to stop such rendered tiles from being
1942 // stored in new tile buffer.
1943 if (pLOEvent
->m_pTileBuffer
!= &*priv
->m_pTileBuffer
)
1945 pLOEvent
->m_pTileBuffer
= nullptr;
1946 g_task_return_new_error(task
,
1947 LOK_TILEBUFFER_ERROR
,
1948 LOK_TILEBUFFER_CHANGED
,
1949 "TileBuffer has changed");
1953 g_task_return_pointer(task
, pSurface
, reinterpret_cast<GDestroyNotify
>(cairo_surface_destroy
));
1958 lokThreadFunc(gpointer data
, gpointer
/*user_data*/)
1960 GTask
* task
= G_TASK(data
);
1961 LOEvent
* pLOEvent
= static_cast<LOEvent
*>(g_task_get_task_data(task
));
1962 LOKDocView
* pDocView
= LOK_DOC_VIEW(g_task_get_source_object(task
));
1963 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
1965 switch (pLOEvent
->m_nType
)
1968 openDocumentInThread(task
);
1970 case LOK_POST_COMMAND
:
1971 postCommandInThread(task
);
1974 setEditInThread(task
);
1977 setPartInThread(task
);
1979 case LOK_SET_PARTMODE
:
1980 setPartmodeInThread(task
);
1983 // view-only/editable mode already checked during signal key signal emission
1984 postKeyEventInThread(task
);
1986 case LOK_PAINT_TILE
:
1987 paintTileInThread(task
);
1989 case LOK_POST_MOUSE_EVENT
:
1990 postMouseEventInThread(task
);
1992 case LOK_SET_GRAPHIC_SELECTION
:
1994 setGraphicSelectionInThread(task
);
1996 g_info ("LOK_SET_GRAPHIC_SELECTION: skipping graphical operation in view-only mode");
1998 case LOK_SET_CLIENT_ZOOM
:
1999 setClientZoomInThread(task
);
2003 g_object_unref(task
);
2006 static void lok_doc_view_init (LOKDocView
* pDocView
)
2008 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2009 priv
.m_pImpl
= new LOKDocViewPrivateImpl();
2011 gtk_widget_add_events(GTK_WIDGET(pDocView
),
2012 GDK_BUTTON_PRESS_MASK
2013 |GDK_BUTTON_RELEASE_MASK
2014 |GDK_BUTTON_MOTION_MASK
2016 |GDK_KEY_RELEASE_MASK
);
2018 priv
->lokThreadPool
= g_thread_pool_new(lokThreadFunc
,
2025 static void lok_doc_view_set_property (GObject
* object
, guint propId
, const GValue
*value
, GParamSpec
*pspec
)
2027 LOKDocView
* pDocView
= LOK_DOC_VIEW (object
);
2028 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2029 gboolean bDocPasswordEnabled
= priv
->m_nLOKFeatures
& LOK_FEATURE_DOCUMENT_PASSWORD
;
2030 gboolean bDocPasswordToModifyEnabled
= priv
->m_nLOKFeatures
& LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
;
2035 priv
->m_aLOPath
= g_value_dup_string (value
);
2037 case PROP_LO_POINTER
:
2038 priv
->m_pOffice
= static_cast<LibreOfficeKit
*>(g_value_get_pointer(value
));
2040 case PROP_USER_PROFILE_URL
:
2041 priv
->m_pUserProfileURL
= g_value_dup_string(value
);
2044 priv
->m_aDocPath
= g_value_dup_string (value
);
2046 case PROP_DOC_POINTER
:
2047 priv
->m_pDocument
= static_cast<LibreOfficeKitDocument
*>(g_value_get_pointer(value
));
2050 lok_doc_view_set_edit (pDocView
, g_value_get_boolean (value
));
2053 lok_doc_view_set_zoom (pDocView
, g_value_get_float (value
));
2055 case PROP_DOC_WIDTH
:
2056 priv
->m_nDocumentWidthTwips
= g_value_get_long (value
);
2058 case PROP_DOC_HEIGHT
:
2059 priv
->m_nDocumentHeightTwips
= g_value_get_long (value
);
2061 case PROP_DOC_PASSWORD
:
2062 if (g_value_get_boolean (value
) != bDocPasswordEnabled
)
2064 priv
->m_nLOKFeatures
= priv
->m_nLOKFeatures
^ LOK_FEATURE_DOCUMENT_PASSWORD
;
2065 priv
->m_pOffice
->pClass
->setOptionalFeatures(priv
->m_pOffice
, priv
->m_nLOKFeatures
);
2068 case PROP_DOC_PASSWORD_TO_MODIFY
:
2069 if ( g_value_get_boolean (value
) != bDocPasswordToModifyEnabled
)
2071 priv
->m_nLOKFeatures
= priv
->m_nLOKFeatures
^ LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
;
2072 priv
->m_pOffice
->pClass
->setOptionalFeatures(priv
->m_pOffice
, priv
->m_nLOKFeatures
);
2076 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, propId
, pspec
);
2080 static void lok_doc_view_get_property (GObject
* object
, guint propId
, GValue
*value
, GParamSpec
*pspec
)
2082 LOKDocView
* pDocView
= LOK_DOC_VIEW (object
);
2083 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2088 g_value_set_string (value
, priv
->m_aLOPath
);
2090 case PROP_LO_POINTER
:
2091 g_value_set_pointer(value
, priv
->m_pOffice
);
2093 case PROP_USER_PROFILE_URL
:
2094 g_value_set_string(value
, priv
->m_pUserProfileURL
);
2097 g_value_set_string (value
, priv
->m_aDocPath
);
2099 case PROP_DOC_POINTER
:
2100 g_value_set_pointer(value
, priv
->m_pDocument
);
2103 g_value_set_boolean (value
, priv
->m_bEdit
);
2105 case PROP_LOAD_PROGRESS
:
2106 g_value_set_double (value
, priv
->m_nLoadProgress
);
2109 g_value_set_float (value
, priv
->m_fZoom
);
2111 case PROP_IS_LOADING
:
2112 g_value_set_boolean (value
, priv
->m_bIsLoading
);
2114 case PROP_DOC_WIDTH
:
2115 g_value_set_long (value
, priv
->m_nDocumentWidthTwips
);
2117 case PROP_DOC_HEIGHT
:
2118 g_value_set_long (value
, priv
->m_nDocumentHeightTwips
);
2120 case PROP_CAN_ZOOM_IN
:
2121 g_value_set_boolean (value
, priv
->m_bCanZoomIn
);
2123 case PROP_CAN_ZOOM_OUT
:
2124 g_value_set_boolean (value
, priv
->m_bCanZoomOut
);
2126 case PROP_DOC_PASSWORD
:
2127 g_value_set_boolean (value
, priv
->m_nLOKFeatures
& LOK_FEATURE_DOCUMENT_PASSWORD
);
2129 case PROP_DOC_PASSWORD_TO_MODIFY
:
2130 g_value_set_boolean (value
, priv
->m_nLOKFeatures
& LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY
);
2133 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, propId
, pspec
);
2137 static gboolean
lok_doc_view_draw (GtkWidget
* pWidget
, cairo_t
* pCairo
)
2139 LOKDocView
*pDocView
= LOK_DOC_VIEW (pWidget
);
2141 renderDocument (pDocView
, pCairo
);
2142 renderOverlay (pDocView
, pCairo
);
2147 static void lok_doc_view_finalize (GObject
* object
)
2149 LOKDocView
* pDocView
= LOK_DOC_VIEW (object
);
2150 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2152 if (priv
->m_pDocument
)
2153 priv
->m_pDocument
->pClass
->destroy (priv
->m_pDocument
);
2154 if (priv
->m_pOffice
)
2155 priv
->m_pOffice
->pClass
->destroy (priv
->m_pOffice
);
2156 delete priv
.m_pImpl
;
2157 priv
.m_pImpl
= nullptr;
2159 G_OBJECT_CLASS (lok_doc_view_parent_class
)->finalize (object
);
2162 static gboolean
lok_doc_view_initable_init (GInitable
*initable
, GCancellable
* /*cancellable*/, GError
**error
)
2164 LOKDocView
*pDocView
= LOK_DOC_VIEW (initable
);
2165 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2167 if (priv
->m_pOffice
!= nullptr)
2170 priv
->m_pOffice
= lok_init_2(priv
->m_aLOPath
, priv
->m_pUserProfileURL
);
2172 if (priv
->m_pOffice
== nullptr)
2175 g_quark_from_static_string ("LOK initialization error"), 0,
2176 "Failed to get LibreOfficeKit context. Make sure path (%s) is correct",
2184 static void lok_doc_view_initable_iface_init (GInitableIface
*iface
)
2186 iface
->init
= lok_doc_view_initable_init
;
2189 static void lok_doc_view_class_init (LOKDocViewClass
* pClass
)
2191 GObjectClass
*pGObjectClass
= G_OBJECT_CLASS(pClass
);
2192 GtkWidgetClass
*pWidgetClass
= GTK_WIDGET_CLASS(pClass
);
2194 pGObjectClass
->get_property
= lok_doc_view_get_property
;
2195 pGObjectClass
->set_property
= lok_doc_view_set_property
;
2196 pGObjectClass
->finalize
= lok_doc_view_finalize
;
2198 pWidgetClass
->draw
= lok_doc_view_draw
;
2199 pWidgetClass
->button_press_event
= lok_doc_view_signal_button
;
2200 pWidgetClass
->button_release_event
= lok_doc_view_signal_button
;
2201 pWidgetClass
->key_press_event
= signalKey
;
2202 pWidgetClass
->key_release_event
= signalKey
;
2203 pWidgetClass
->motion_notify_event
= lok_doc_view_signal_motion
;
2206 * LOKDocView:lopath:
2208 * The absolute path of the LibreOffice install.
2210 properties
[PROP_LO_PATH
] =
2211 g_param_spec_string("lopath",
2213 "LibreOffice Install Path",
2215 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2216 G_PARAM_CONSTRUCT_ONLY
|
2217 G_PARAM_STATIC_STRINGS
));
2220 * LOKDocView:lopointer:
2222 * A LibreOfficeKit* in case lok_init() is already called
2225 properties
[PROP_LO_POINTER
] =
2226 g_param_spec_pointer("lopointer",
2228 "A LibreOfficeKit* from lok_init()",
2229 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2230 G_PARAM_CONSTRUCT_ONLY
|
2231 G_PARAM_STATIC_STRINGS
));
2234 * LOKDocView:userprofileurl:
2236 * The absolute path of the LibreOffice user profile.
2238 properties
[PROP_USER_PROFILE_URL
] =
2239 g_param_spec_string("userprofileurl",
2240 "User profile path",
2241 "LibreOffice user profile path",
2243 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2244 G_PARAM_CONSTRUCT_ONLY
|
2245 G_PARAM_STATIC_STRINGS
));
2248 * LOKDocView:docpath:
2250 * The path of the document that is currently being viewed.
2252 properties
[PROP_DOC_PATH
] =
2253 g_param_spec_string("docpath",
2255 "The URI of the document to open",
2257 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2258 G_PARAM_STATIC_STRINGS
));
2261 * LOKDocView:docpointer:
2263 * A LibreOfficeKitDocument* in case documentLoad() is already called
2266 properties
[PROP_DOC_POINTER
] =
2267 g_param_spec_pointer("docpointer",
2269 "A LibreOfficeKitDocument* from documentLoad()",
2270 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2271 G_PARAM_STATIC_STRINGS
));
2274 * LOKDocView:editable:
2276 * Whether the document loaded inside of #LOKDocView is editable or not.
2278 properties
[PROP_EDITABLE
] =
2279 g_param_spec_boolean("editable",
2281 "Whether the content is in edit mode or not",
2283 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2284 G_PARAM_STATIC_STRINGS
));
2287 * LOKDocView:load-progress:
2289 * The percent completion of the current loading operation of the
2290 * document. This can be used for progress bars. Note that this is not a
2291 * very accurate progress indicator, and its value might reset it couple of
2292 * times to 0 and start again. You should not rely on its numbers.
2294 properties
[PROP_LOAD_PROGRESS
] =
2295 g_param_spec_double("load-progress",
2296 "Estimated Load Progress",
2297 "Shows the progress of the document load operation",
2299 static_cast<GParamFlags
>(G_PARAM_READABLE
|
2300 G_PARAM_STATIC_STRINGS
));
2303 * LOKDocView:zoom-level:
2305 * The current zoom level of the document loaded inside #LOKDocView. The
2306 * default value is 1.0.
2308 properties
[PROP_ZOOM
] =
2309 g_param_spec_float("zoom-level",
2311 "The current zoom level of the content",
2313 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2314 G_PARAM_STATIC_STRINGS
));
2317 * LOKDocView:is-loading:
2319 * Whether the requested document is being loaded or not. %TRUE if it is
2320 * being loaded, otherwise %FALSE.
2322 properties
[PROP_IS_LOADING
] =
2323 g_param_spec_boolean("is-loading",
2325 "Whether the view is loading a document",
2327 static_cast<GParamFlags
>(G_PARAM_READABLE
|
2328 G_PARAM_STATIC_STRINGS
));
2331 * LOKDocView:doc-width:
2333 * The width of the currently loaded document in #LOKDocView in twips.
2335 properties
[PROP_DOC_WIDTH
] =
2336 g_param_spec_long("doc-width",
2338 "Width of the document in twips",
2340 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2341 G_PARAM_STATIC_STRINGS
));
2344 * LOKDocView:doc-height:
2346 * The height of the currently loaded document in #LOKDocView in twips.
2348 properties
[PROP_DOC_HEIGHT
] =
2349 g_param_spec_long("doc-height",
2351 "Height of the document in twips",
2353 static_cast<GParamFlags
>(G_PARAM_READWRITE
|
2354 G_PARAM_STATIC_STRINGS
));
2357 * LOKDocView:can-zoom-in:
2359 * It tells whether the view can further be zoomed in or not.
2361 properties
[PROP_CAN_ZOOM_IN
] =
2362 g_param_spec_boolean("can-zoom-in",
2364 "Whether the view can be zoomed in further",
2366 static_cast<GParamFlags
>(G_PARAM_READABLE
2367 | G_PARAM_STATIC_STRINGS
));
2370 * LOKDocView:can-zoom-out:
2372 * It tells whether the view can further be zoomed out or not.
2374 properties
[PROP_CAN_ZOOM_OUT
] =
2375 g_param_spec_boolean("can-zoom-out",
2377 "Whether the view can be zoomed out further",
2379 static_cast<GParamFlags
>(G_PARAM_READABLE
2380 | G_PARAM_STATIC_STRINGS
));
2383 * LOKDocView:doc-password:
2385 * Set it to true if client supports providing password for viewing
2386 * password protected documents
2388 properties
[PROP_DOC_PASSWORD
] =
2389 g_param_spec_boolean("doc-password",
2390 "Document password capability",
2391 "Whether client supports providing document passwords",
2393 static_cast<GParamFlags
>(G_PARAM_READWRITE
2394 | G_PARAM_STATIC_STRINGS
));
2397 * LOKDocView:doc-password-to-modify:
2399 * Set it to true if client supports providing password for edit-protected documents
2401 properties
[PROP_DOC_PASSWORD_TO_MODIFY
] =
2402 g_param_spec_boolean("doc-password-to-modify",
2403 "Edit document password capability",
2404 "Whether the client supports providing passwords to edit documents",
2406 static_cast<GParamFlags
>(G_PARAM_READWRITE
2407 | G_PARAM_STATIC_STRINGS
));
2409 g_object_class_install_properties(pGObjectClass
, PROP_LAST
, properties
);
2412 * LOKDocView::load-changed:
2413 * @pDocView: the #LOKDocView on which the signal is emitted
2414 * @fLoadProgress: the new progress value
2416 doc_view_signals
[LOAD_CHANGED
] =
2417 g_signal_new("load-changed",
2418 G_TYPE_FROM_CLASS (pGObjectClass
),
2422 g_cclosure_marshal_VOID__DOUBLE
,
2427 * LOKDocView::edit-changed:
2428 * @pDocView: the #LOKDocView on which the signal is emitted
2429 * @bEdit: the new edit value of the view
2431 doc_view_signals
[EDIT_CHANGED
] =
2432 g_signal_new("edit-changed",
2433 G_TYPE_FROM_CLASS (pGObjectClass
),
2437 g_cclosure_marshal_VOID__BOOLEAN
,
2442 * LOKDocView::command-changed:
2443 * @pDocView: the #LOKDocView on which the signal is emitted
2444 * @aCommand: the command that was changed
2446 doc_view_signals
[COMMAND_CHANGED
] =
2447 g_signal_new("command-changed",
2448 G_TYPE_FROM_CLASS(pGObjectClass
),
2452 g_cclosure_marshal_VOID__STRING
,
2457 * LOKDocView::search-not-found:
2458 * @pDocView: the #LOKDocView on which the signal is emitted
2459 * @aCommand: the string for which the search was not found.
2461 doc_view_signals
[SEARCH_NOT_FOUND
] =
2462 g_signal_new("search-not-found",
2463 G_TYPE_FROM_CLASS(pGObjectClass
),
2467 g_cclosure_marshal_VOID__STRING
,
2472 * LOKDocView::part-changed:
2473 * @pDocView: the #LOKDocView on which the signal is emitted
2474 * @aCommand: the part number which the view changed to
2476 doc_view_signals
[PART_CHANGED
] =
2477 g_signal_new("part-changed",
2478 G_TYPE_FROM_CLASS(pGObjectClass
),
2482 g_cclosure_marshal_VOID__INT
,
2487 * LOKDocView::size-changed:
2488 * @pDocView: the #LOKDocView on which the signal is emitted
2489 * @aCommand: NULL, we just notify that want to notify the UI elements that are interested.
2491 doc_view_signals
[SIZE_CHANGED
] =
2492 g_signal_new("size-changed",
2493 G_TYPE_FROM_CLASS(pGObjectClass
),
2497 g_cclosure_marshal_VOID__VOID
,
2502 * LOKDocView::hyperlinked-clicked:
2503 * @pDocView: the #LOKDocView on which the signal is emitted
2504 * @aHyperlink: the URI which the application should handle
2506 doc_view_signals
[HYPERLINK_CLICKED
] =
2507 g_signal_new("hyperlink-clicked",
2508 G_TYPE_FROM_CLASS(pGObjectClass
),
2512 g_cclosure_marshal_VOID__STRING
,
2517 * LOKDocView::cursor-changed:
2518 * @pDocView: the #LOKDocView on which the signal is emitted
2519 * @nX: The new cursor position (X coordinate) in pixels
2520 * @nY: The new cursor position (Y coordinate) in pixels
2521 * @nWidth: The width of new cursor
2522 * @nHeight: The height of new cursor
2524 doc_view_signals
[CURSOR_CHANGED
] =
2525 g_signal_new("cursor-changed",
2526 G_TYPE_FROM_CLASS(pGObjectClass
),
2530 g_cclosure_marshal_generic
,
2532 G_TYPE_INT
, G_TYPE_INT
,
2533 G_TYPE_INT
, G_TYPE_INT
);
2536 * LOKDocView::search-result-count:
2537 * @pDocView: the #LOKDocView on which the signal is emitted
2538 * @aCommand: number of matches.
2540 doc_view_signals
[SEARCH_RESULT_COUNT
] =
2541 g_signal_new("search-result-count",
2542 G_TYPE_FROM_CLASS(pGObjectClass
),
2546 g_cclosure_marshal_VOID__STRING
,
2551 * LOKDocView::command-result:
2552 * @pDocView: the #LOKDocView on which the signal is emitted
2553 * @aCommand: JSON containing the info about the command that finished,
2554 * and its success status.
2556 doc_view_signals
[COMMAND_RESULT
] =
2557 g_signal_new("command-result",
2558 G_TYPE_FROM_CLASS(pGObjectClass
),
2562 g_cclosure_marshal_VOID__STRING
,
2567 * LOKDocView::formula-changed:
2568 * @pDocView: the #LOKDocView on which the signal is emitted
2569 * @aCommand: formula text content
2571 doc_view_signals
[FORMULA_CHANGED
] =
2572 g_signal_new("formula-changed",
2573 G_TYPE_FROM_CLASS(pGObjectClass
),
2577 g_cclosure_marshal_VOID__STRING
,
2582 * LOKDocView::text-selection:
2583 * @pDocView: the #LOKDocView on which the signal is emitted
2584 * @bIsTextSelected: whether text selected is non-null
2586 doc_view_signals
[TEXT_SELECTION
] =
2587 g_signal_new("text-selection",
2588 G_TYPE_FROM_CLASS(pGObjectClass
),
2592 g_cclosure_marshal_VOID__BOOLEAN
,
2597 * LOKDocView::password-required:
2598 * @pDocView: the #LOKDocView on which the signal is emitted
2599 * @pUrl: URL of the document for which password is required
2600 * @bModify: whether password id required to modify the document
2601 * This is true when password is required to edit the document,
2602 * while it can still be viewed without password. In such cases, provide a NULL
2603 * password for read-only access to the document.
2604 * If false, password is required for opening the document, and document
2605 * cannot be opened without providing a valid password.
2607 * Password must be provided by calling lok_doc_view_set_document_password
2608 * function with pUrl as provided by the callback.
2610 * Upon entering a invalid password, another `password-required` signal is
2612 * Upon entering a valid password, document starts to load.
2613 * Upon entering a NULL password: if bModify is %TRUE, document starts to
2614 * open in view-only mode, else loading of document is aborted.
2616 doc_view_signals
[PASSWORD_REQUIRED
] =
2617 g_signal_new("password-required",
2618 G_TYPE_FROM_CLASS(pGObjectClass
),
2622 g_cclosure_marshal_generic
,
2628 SAL_DLLPUBLIC_EXPORT GtkWidget
*
2629 lok_doc_view_new (const gchar
* pPath
, GCancellable
*cancellable
, GError
**error
)
2631 return GTK_WIDGET (g_initable_new (LOK_TYPE_DOC_VIEW
, cancellable
, error
,
2632 "lopath", pPath
== nullptr ? LOK_PATH
: pPath
,
2633 "halign", GTK_ALIGN_CENTER
,
2634 "valign", GTK_ALIGN_CENTER
,
2638 SAL_DLLPUBLIC_EXPORT GtkWidget
*
2639 lok_doc_view_new_from_user_profile (const gchar
* pPath
, const gchar
* pUserProfile
, GCancellable
*cancellable
, GError
**error
)
2641 return GTK_WIDGET(g_initable_new(LOK_TYPE_DOC_VIEW
, cancellable
, error
,
2642 "lopath", pPath
== nullptr ? LOK_PATH
: pPath
,
2643 "userprofileurl", pUserProfile
,
2644 "halign", GTK_ALIGN_CENTER
,
2645 "valign", GTK_ALIGN_CENTER
,
2649 SAL_DLLPUBLIC_EXPORT GtkWidget
* lok_doc_view_new_from_widget(LOKDocView
* pOldLOKDocView
)
2651 LOKDocViewPrivate
& pOldPriv
= getPrivate(pOldLOKDocView
);
2652 GtkWidget
* pNewDocView
= GTK_WIDGET(g_initable_new(LOK_TYPE_DOC_VIEW
, /*cancellable=*/nullptr, /*error=*/nullptr,
2653 "lopath", pOldPriv
->m_aLOPath
,
2654 "userprofileurl", pOldPriv
->m_pUserProfileURL
,
2655 "lopointer", pOldPriv
->m_pOffice
,
2656 "docpointer", pOldPriv
->m_pDocument
,
2657 "halign", GTK_ALIGN_CENTER
,
2658 "valign", GTK_ALIGN_CENTER
,
2661 // No documentLoad(), just a createView().
2662 LibreOfficeKitDocument
* pDocument
= lok_doc_view_get_document(LOK_DOC_VIEW(pNewDocView
));
2663 LOKDocViewPrivate
& pNewPriv
= getPrivate(LOK_DOC_VIEW(pNewDocView
));
2664 pNewPriv
->m_nViewId
= pDocument
->pClass
->createView(pDocument
);
2665 pNewPriv
->m_aRenderingArguments
= pOldPriv
->m_aRenderingArguments
;
2667 postDocumentLoad(pNewDocView
);
2671 SAL_DLLPUBLIC_EXPORT gboolean
2672 lok_doc_view_open_document_finish (LOKDocView
* pDocView
, GAsyncResult
* res
, GError
** error
)
2674 GTask
* task
= G_TASK(res
);
2676 g_return_val_if_fail(g_task_is_valid(res
, pDocView
), false);
2677 g_return_val_if_fail(g_task_get_source_tag(task
) == lok_doc_view_open_document
, false);
2678 g_return_val_if_fail(error
== nullptr || *error
== nullptr, false);
2680 return g_task_propagate_boolean(task
, error
);
2683 SAL_DLLPUBLIC_EXPORT
void
2684 lok_doc_view_open_document (LOKDocView
* pDocView
,
2686 const gchar
* pRenderingArguments
,
2687 GCancellable
* cancellable
,
2688 GAsyncReadyCallback callback
,
2691 GTask
* task
= g_task_new(pDocView
, cancellable
, callback
, userdata
);
2692 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2693 GError
* error
= nullptr;
2695 LOEvent
* pLOEvent
= new LOEvent(LOK_LOAD_DOC
);
2696 pLOEvent
->m_pPath
= pPath
;
2698 priv
->m_aDocPath
= pPath
;
2699 if (pRenderingArguments
)
2700 priv
->m_aRenderingArguments
= pRenderingArguments
;
2701 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
2702 g_task_set_source_tag(task
, reinterpret_cast<gpointer
>(lok_doc_view_open_document
));
2704 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
2705 if (error
!= nullptr)
2707 g_warning("Unable to call LOK_LOAD_DOC: %s", error
->message
);
2708 g_clear_error(&error
);
2710 g_object_unref(task
);
2713 SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument
*
2714 lok_doc_view_get_document (LOKDocView
* pDocView
)
2716 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2717 return priv
->m_pDocument
;
2720 SAL_DLLPUBLIC_EXPORT
void
2721 lok_doc_view_set_visible_area (LOKDocView
* pDocView
, GdkRectangle
* pVisibleArea
)
2726 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2727 priv
->m_aVisibleArea
= *pVisibleArea
;
2728 priv
->m_bVisibleAreaSet
= true;
2731 SAL_DLLPUBLIC_EXPORT
void
2732 lok_doc_view_set_zoom (LOKDocView
* pDocView
, float fZoom
)
2734 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2735 GError
* error
= nullptr;
2737 if (!priv
->m_pDocument
)
2740 // Clamp the input value in [MIN_ZOOM, MAX_ZOOM]
2741 fZoom
= fZoom
< MIN_ZOOM
? MIN_ZOOM
: fZoom
;
2742 fZoom
= fZoom
> MAX_ZOOM
? MAX_ZOOM
: fZoom
;
2744 if (rtl::math::approxEqual(fZoom
, priv
->m_fZoom
))
2747 priv
->m_fZoom
= fZoom
;
2748 long nDocumentWidthPixels
= twipToPixel(priv
->m_nDocumentWidthTwips
, fZoom
);
2749 long nDocumentHeightPixels
= twipToPixel(priv
->m_nDocumentHeightTwips
, fZoom
);
2750 // Total number of columns in this document.
2751 guint nColumns
= ceil((double)nDocumentWidthPixels
/ nTileSizePixels
);
2753 priv
->m_pTileBuffer
= std::unique_ptr
<TileBuffer
>(new TileBuffer(priv
->m_pDocument
,
2755 gtk_widget_set_size_request(GTK_WIDGET(pDocView
),
2756 nDocumentWidthPixels
,
2757 nDocumentHeightPixels
);
2759 g_object_notify_by_pspec(G_OBJECT(pDocView
), properties
[PROP_ZOOM
]);
2761 // set properties to indicate if view can be further zoomed in/out
2762 bool bCanZoomIn
= priv
->m_fZoom
< MAX_ZOOM
;
2763 bool bCanZoomOut
= priv
->m_fZoom
> MIN_ZOOM
;
2764 if (bCanZoomIn
!= bool(priv
->m_bCanZoomIn
))
2766 priv
->m_bCanZoomIn
= bCanZoomIn
;
2767 g_object_notify_by_pspec(G_OBJECT(pDocView
), properties
[PROP_CAN_ZOOM_IN
]);
2769 if (bCanZoomOut
!= bool(priv
->m_bCanZoomOut
))
2771 priv
->m_bCanZoomOut
= bCanZoomOut
;
2772 g_object_notify_by_pspec(G_OBJECT(pDocView
), properties
[PROP_CAN_ZOOM_OUT
]);
2775 // Update the client's view size
2776 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
2777 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_CLIENT_ZOOM
);
2778 pLOEvent
->m_nTilePixelWidth
= nTileSizePixels
;
2779 pLOEvent
->m_nTilePixelHeight
= nTileSizePixels
;
2780 pLOEvent
->m_nTileTwipWidth
= pixelToTwip(nTileSizePixels
, fZoom
);
2781 pLOEvent
->m_nTileTwipHeight
= pixelToTwip(nTileSizePixels
, fZoom
);
2782 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
2784 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
2785 if (error
!= nullptr)
2787 g_warning("Unable to call LOK_SET_CLIENT_ZOOM: %s", error
->message
);
2788 g_clear_error(&error
);
2790 g_object_unref(task
);
2792 priv
->m_nTileSizeTwips
= pixelToTwip(nTileSizePixels
, priv
->m_fZoom
);
2795 SAL_DLLPUBLIC_EXPORT gfloat
2796 lok_doc_view_get_zoom (LOKDocView
* pDocView
)
2798 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2799 return priv
->m_fZoom
;
2802 SAL_DLLPUBLIC_EXPORT gint
2803 lok_doc_view_get_parts (LOKDocView
* pDocView
)
2805 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2806 if (!priv
->m_pDocument
)
2809 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
2810 return priv
->m_pDocument
->pClass
->getParts( priv
->m_pDocument
);
2813 SAL_DLLPUBLIC_EXPORT gint
2814 lok_doc_view_get_part (LOKDocView
* pDocView
)
2816 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2817 if (!priv
->m_pDocument
)
2820 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
2821 return priv
->m_pDocument
->pClass
->getPart( priv
->m_pDocument
);
2824 SAL_DLLPUBLIC_EXPORT
void
2825 lok_doc_view_set_part (LOKDocView
* pDocView
, int nPart
)
2827 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2828 if (!priv
->m_pDocument
)
2831 if (nPart
< 0 || nPart
>= priv
->m_nParts
)
2833 g_warning("Invalid part request : %d", nPart
);
2837 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
2838 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_PART
);
2839 GError
* error
= nullptr;
2841 pLOEvent
->m_nPart
= nPart
;
2842 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
2844 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
2845 if (error
!= nullptr)
2847 g_warning("Unable to call LOK_SET_PART: %s", error
->message
);
2848 g_clear_error(&error
);
2850 g_object_unref(task
);
2853 SAL_DLLPUBLIC_EXPORT gchar
*
2854 lok_doc_view_get_part_name (LOKDocView
* pDocView
, int nPart
)
2856 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2857 if (!priv
->m_pDocument
)
2860 priv
->m_pDocument
->pClass
->setView(priv
->m_pDocument
, priv
->m_nViewId
);
2861 return priv
->m_pDocument
->pClass
->getPartName( priv
->m_pDocument
, nPart
);
2864 SAL_DLLPUBLIC_EXPORT
void
2865 lok_doc_view_set_partmode(LOKDocView
* pDocView
,
2868 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2869 if (!priv
->m_pDocument
)
2872 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
2873 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_PARTMODE
);
2874 GError
* error
= nullptr;
2876 pLOEvent
->m_nPartMode
= nPartMode
;
2877 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
2879 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
2880 if (error
!= nullptr)
2882 g_warning("Unable to call LOK_SET_PARTMODE: %s", error
->message
);
2883 g_clear_error(&error
);
2885 g_object_unref(task
);
2888 SAL_DLLPUBLIC_EXPORT
void
2889 lok_doc_view_reset_view(LOKDocView
* pDocView
)
2891 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2893 if (priv
->m_pTileBuffer
!= nullptr)
2894 priv
->m_pTileBuffer
->resetAllTiles();
2895 priv
->m_nLoadProgress
= 0.0;
2897 memset(&priv
->m_aVisibleCursor
, 0, sizeof(priv
->m_aVisibleCursor
));
2898 priv
->m_bCursorOverlayVisible
= false;
2899 priv
->m_bCursorVisible
= false;
2901 priv
->m_nLastButtonPressTime
= 0;
2902 priv
->m_nLastButtonReleaseTime
= 0;
2903 priv
->m_aTextSelectionRectangles
.clear();
2905 memset(&priv
->m_aTextSelectionStart
, 0, sizeof(priv
->m_aTextSelectionStart
));
2906 memset(&priv
->m_aTextSelectionEnd
, 0, sizeof(priv
->m_aTextSelectionEnd
));
2907 memset(&priv
->m_aGraphicSelection
, 0, sizeof(priv
->m_aGraphicSelection
));
2908 priv
->m_bInDragGraphicSelection
= false;
2909 memset(&priv
->m_aCellCursor
, 0, sizeof(priv
->m_aCellCursor
));
2911 cairo_surface_destroy(priv
->m_pHandleStart
);
2912 priv
->m_pHandleStart
= nullptr;
2913 memset(&priv
->m_aHandleStartRect
, 0, sizeof(priv
->m_aHandleStartRect
));
2914 priv
->m_bInDragStartHandle
= false;
2916 cairo_surface_destroy(priv
->m_pHandleMiddle
);
2917 priv
->m_pHandleMiddle
= nullptr;
2918 memset(&priv
->m_aHandleMiddleRect
, 0, sizeof(priv
->m_aHandleMiddleRect
));
2919 priv
->m_bInDragMiddleHandle
= false;
2921 cairo_surface_destroy(priv
->m_pHandleEnd
);
2922 priv
->m_pHandleEnd
= nullptr;
2923 memset(&priv
->m_aHandleEndRect
, 0, sizeof(priv
->m_aHandleEndRect
));
2924 priv
->m_bInDragEndHandle
= false;
2926 cairo_surface_destroy(priv
->m_pGraphicHandle
);
2927 priv
->m_pGraphicHandle
= nullptr;
2928 memset(&priv
->m_aGraphicHandleRects
, 0, sizeof(priv
->m_aGraphicHandleRects
));
2929 memset(&priv
->m_bInDragGraphicHandles
, 0, sizeof(priv
->m_bInDragGraphicHandles
));
2931 priv
->m_nViewId
= 0;
2933 gtk_widget_queue_draw(GTK_WIDGET(pDocView
));
2936 SAL_DLLPUBLIC_EXPORT
void
2937 lok_doc_view_set_edit(LOKDocView
* pDocView
,
2940 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2941 if (!priv
->m_pDocument
)
2944 GTask
* task
= g_task_new(pDocView
, nullptr, nullptr, nullptr);
2945 LOEvent
* pLOEvent
= new LOEvent(LOK_SET_EDIT
);
2946 GError
* error
= nullptr;
2948 pLOEvent
->m_bEdit
= bEdit
;
2949 g_task_set_task_data(task
, pLOEvent
, LOEvent::destroy
);
2951 g_thread_pool_push(priv
->lokThreadPool
, g_object_ref(task
), &error
);
2952 if (error
!= nullptr)
2954 g_warning("Unable to call LOK_SET_EDIT: %s", error
->message
);
2955 g_clear_error(&error
);
2957 g_object_unref(task
);
2960 SAL_DLLPUBLIC_EXPORT gboolean
2961 lok_doc_view_get_edit (LOKDocView
* pDocView
)
2963 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2964 return priv
->m_bEdit
;
2967 SAL_DLLPUBLIC_EXPORT
void
2968 lok_doc_view_post_command (LOKDocView
* pDocView
,
2969 const gchar
* pCommand
,
2970 const gchar
* pArguments
,
2971 gboolean bNotifyWhenFinished
)
2973 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
2974 if (!priv
->m_pDocument
)
2978 LOKPostCommand(pDocView
, pCommand
, pArguments
, bNotifyWhenFinished
);
2980 g_info ("LOK_POST_COMMAND: ignoring commands in view-only mode");
2983 SAL_DLLPUBLIC_EXPORT
void
2984 lok_doc_view_find_prev (LOKDocView
* pDocView
,
2986 gboolean bHighlightAll
)
2988 doSearch(pDocView
, pText
, true, bHighlightAll
);
2991 SAL_DLLPUBLIC_EXPORT
void
2992 lok_doc_view_find_next (LOKDocView
* pDocView
,
2994 gboolean bHighlightAll
)
2996 doSearch(pDocView
, pText
, false, bHighlightAll
);
2999 SAL_DLLPUBLIC_EXPORT
void
3000 lok_doc_view_highlight_all (LOKDocView
* pDocView
,
3003 doSearch(pDocView
, pText
, false, true);
3006 SAL_DLLPUBLIC_EXPORT gchar
*
3007 lok_doc_view_copy_selection (LOKDocView
* pDocView
,
3008 const gchar
* pMimeType
,
3009 gchar
** pUsedMimeType
)
3011 LibreOfficeKitDocument
* pDocument
= lok_doc_view_get_document(pDocView
);
3015 std::stringstream ss
;
3016 ss
<< "lok::Document::getTextSelection('" << pMimeType
<< "')";
3017 g_info("%s", ss
.str().c_str());
3018 return pDocument
->pClass
->getTextSelection(pDocument
, pMimeType
, pUsedMimeType
);
3021 SAL_DLLPUBLIC_EXPORT gboolean
3022 lok_doc_view_paste (LOKDocView
* pDocView
,
3023 const gchar
* pMimeType
,
3027 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
3028 LibreOfficeKitDocument
* pDocument
= priv
->m_pDocument
;
3036 g_info ("ignoring paste in view-only mode");
3042 std::stringstream ss
;
3043 ss
<< "lok::Document::paste('" << pMimeType
<< "', '" << std::string(pData
, nSize
) << ", "<<nSize
<<"')";
3044 g_info("%s", ss
.str().c_str());
3045 ret
= pDocument
->pClass
->paste(pDocument
, pMimeType
, pData
, nSize
);
3051 SAL_DLLPUBLIC_EXPORT
void
3052 lok_doc_view_set_document_password (LOKDocView
* pDocView
,
3054 const gchar
* pPassword
)
3056 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
3058 priv
->m_pOffice
->pClass
->setDocumentPassword(priv
->m_pOffice
, pURL
, pPassword
);
3061 SAL_DLLPUBLIC_EXPORT gfloat
3062 lok_doc_view_pixel_to_twip (LOKDocView
* pDocView
, float fInput
)
3064 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
3065 return pixelToTwip(fInput
, priv
->m_fZoom
);
3068 SAL_DLLPUBLIC_EXPORT gfloat
3069 lok_doc_view_twip_to_pixel (LOKDocView
* pDocView
, float fInput
)
3071 LOKDocViewPrivate
& priv
= getPrivate(pDocView
);
3072 return twipToPixel(fInput
, priv
->m_fZoom
);
3075 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */