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/config.h>
12 #include <string_view>
14 #include <sfx2/lokhelper.hxx>
16 #include <com/sun/star/frame/Desktop.hpp>
18 #include <comphelper/processfactory.hxx>
19 #include <rtl/strbuf.hxx>
20 #include <vcl/lok.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/commandevent.hxx>
23 #include <vcl/window.hxx>
24 #include <sal/log.hxx>
25 #include <sfx2/app.hxx>
26 #include <sfx2/msg.hxx>
27 #include <sfx2/viewsh.hxx>
28 #include <sfx2/request.hxx>
29 #include <sfx2/sfxsids.hrc>
30 #include <sfx2/viewfrm.hxx>
31 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
32 #include <comphelper/lok.hxx>
33 #include <editeng/outliner.hxx>
34 #include <sfx2/msgpool.hxx>
36 #include <boost/property_tree/json_parser.hpp>
38 using namespace com::sun::star
;
41 /// Used to disable callbacks.
42 /// Needed to avoid recursion when switching views,
43 /// which can cause clients to invoke LOKit API and
44 /// implicitly set the view, which might cause an
45 /// infinite recursion if not detected and prevented.
46 class DisableCallbacks
51 assert(m_nDisabled
>= 0 && "Expected non-negative DisabledCallbacks state when disabling.");
57 assert(m_nDisabled
> 0 && "Expected positive DisabledCallbacks state when re-enabling.");
61 static inline bool disabled()
63 return !comphelper::LibreOfficeKit::isActive() || m_nDisabled
!= 0;
67 static int m_nDisabled
;
70 int DisableCallbacks::m_nDisabled
= 0;
75 LanguageTag
g_defaultLanguageTag("en-US", true);
76 LOKDeviceFormFactor g_deviceFormFactor
= LOKDeviceFormFactor::UNKNOWN
;
79 int SfxLokHelper::createView(SfxViewFrame
* pViewFrame
, ViewShellDocId docId
)
81 assert(docId
>= ViewShellDocId(0) && "Cannot createView for invalid (negative) DocId.");
83 if (pViewFrame
== nullptr)
86 SfxViewShell::SetCurrentDocId(docId
);
87 SfxRequest
aRequest(pViewFrame
, SID_NEWWINDOW
);
88 pViewFrame
->ExecView_Impl(aRequest
);
89 SfxViewShell
* pViewShell
= SfxViewShell::Current();
90 if (pViewShell
== nullptr)
93 assert(pViewShell
->GetDocId() == docId
&& "DocId must be already set!");
94 return static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
97 int SfxLokHelper::createView()
99 // Assumes a single document, or at least that the
100 // current view belongs to the document on which the
101 // view will be created.
102 SfxViewShell
* pViewShell
= SfxViewShell::Current();
103 if (pViewShell
== nullptr)
106 return createView(pViewShell
->GetViewFrame(), pViewShell
->GetDocId());
109 int SfxLokHelper::createView(int nDocId
)
111 const SfxApplication
* pApp
= SfxApplication::Get();
115 // Find a shell with the given DocId.
116 const ViewShellDocId
docId(nDocId
);
117 for (const SfxViewShell
* pViewShell
: pApp
->GetViewShells_Impl())
119 if (pViewShell
->GetDocId() == docId
)
120 return createView(pViewShell
->GetViewFrame(), docId
);
123 // No frame with nDocId found.
127 void SfxLokHelper::destroyView(int nId
)
129 const SfxApplication
* pApp
= SfxApplication::Get();
133 const ViewShellId
nViewShellId(nId
);
134 std::vector
<SfxViewShell
*>& rViewArr
= pApp
->GetViewShells_Impl();
136 for (const SfxViewShell
* pViewShell
: rViewArr
)
138 if (pViewShell
->GetViewShellId() == nViewShellId
)
140 SfxViewFrame
* pViewFrame
= pViewShell
->GetViewFrame();
141 SfxRequest
aRequest(pViewFrame
, SID_CLOSEWIN
);
142 pViewFrame
->Exec_Impl(aRequest
);
148 void SfxLokHelper::setView(int nId
)
150 SfxApplication
* pApp
= SfxApplication::Get();
154 const ViewShellId
nViewShellId(nId
);
155 std::vector
<SfxViewShell
*>& rViewArr
= pApp
->GetViewShells_Impl();
157 for (const SfxViewShell
* pViewShell
: rViewArr
)
159 if (pViewShell
->GetViewShellId() == nViewShellId
)
163 // update the current LOK language and locale for the dialog tunneling
164 comphelper::LibreOfficeKit::setLanguageTag(pViewShell
->GetLOKLanguageTag());
165 comphelper::LibreOfficeKit::setLocale(pViewShell
->GetLOKLocale());
167 if (pViewShell
== SfxViewShell::Current())
170 SfxViewFrame
* pViewFrame
= pViewShell
->GetViewFrame();
171 pViewFrame
->MakeActive_Impl(false);
173 // Make comphelper::dispatchCommand() find the correct frame.
174 uno::Reference
<frame::XFrame
> xFrame
= pViewFrame
->GetFrame().GetFrameInterface();
175 uno::Reference
<frame::XDesktop2
> xDesktop
= frame::Desktop::create(comphelper::getProcessComponentContext());
176 xDesktop
->setActiveFrame(xFrame
);
183 SfxViewShell
* SfxLokHelper::getViewOfId(int nId
)
185 SfxApplication
* pApp
= SfxApplication::Get();
189 const ViewShellId
nViewShellId(nId
);
190 std::vector
<SfxViewShell
*>& rViewArr
= pApp
->GetViewShells_Impl();
191 for (SfxViewShell
* pViewShell
: rViewArr
)
193 if (pViewShell
->GetViewShellId() == nViewShellId
)
200 int SfxLokHelper::getView(const SfxViewShell
* pViewShell
)
203 pViewShell
= SfxViewShell::Current();
204 // Still no valid view shell? Then no idea.
208 return static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
211 std::size_t SfxLokHelper::getViewsCount(int nDocId
)
213 assert(nDocId
!= -1 && "Cannot getViewsCount for invalid DocId -1");
215 SfxApplication
* pApp
= SfxApplication::Get();
219 const ViewShellDocId
nCurrentDocId(nDocId
);
221 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
224 if (pViewShell
->GetDocId() == nCurrentDocId
)
226 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
232 bool SfxLokHelper::getViewIds(int nDocId
, int* pArray
, size_t nSize
)
234 assert(nDocId
!= -1 && "Cannot getViewsIds for invalid DocId -1");
236 SfxApplication
* pApp
= SfxApplication::Get();
240 const ViewShellDocId
nCurrentDocId(nDocId
);
242 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
245 if (pViewShell
->GetDocId() == nCurrentDocId
)
250 pArray
[n
] = static_cast<sal_Int32
>(pViewShell
->GetViewShellId());
254 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
260 int SfxLokHelper::getDocumentIdOfView(int nViewId
)
262 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
265 if (pViewShell
->GetViewShellId() == ViewShellId(nViewId
))
266 return static_cast<int>(pViewShell
->GetDocId());
267 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
272 const LanguageTag
& SfxLokHelper::getDefaultLanguage()
274 return g_defaultLanguageTag
;
277 void SfxLokHelper::setDefaultLanguage(const OUString
& rBcp47LanguageTag
)
279 g_defaultLanguageTag
= LanguageTag(rBcp47LanguageTag
, true);
282 void SfxLokHelper::setViewLanguage(int nId
, const OUString
& rBcp47LanguageTag
)
284 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
286 for (SfxViewShell
* pViewShell
: rViewArr
)
288 if (pViewShell
->GetViewShellId() == ViewShellId(nId
))
290 pViewShell
->SetLOKLanguageTag(rBcp47LanguageTag
);
296 void SfxLokHelper::setViewLocale(int nId
, const OUString
& rBcp47LanguageTag
)
298 std::vector
<SfxViewShell
*>& rViewArr
= SfxGetpApp()->GetViewShells_Impl();
300 for (SfxViewShell
* pViewShell
: rViewArr
)
302 if (pViewShell
->GetViewShellId() == ViewShellId(nId
))
304 pViewShell
->SetLOKLocale(rBcp47LanguageTag
);
310 LOKDeviceFormFactor
SfxLokHelper::getDeviceFormFactor()
312 return g_deviceFormFactor
;
315 void SfxLokHelper::setDeviceFormFactor(std::u16string_view rDeviceFormFactor
)
317 if (rDeviceFormFactor
== u
"desktop")
318 g_deviceFormFactor
= LOKDeviceFormFactor::DESKTOP
;
319 else if (rDeviceFormFactor
== u
"tablet")
320 g_deviceFormFactor
= LOKDeviceFormFactor::TABLET
;
321 else if (rDeviceFormFactor
== u
"mobile")
322 g_deviceFormFactor
= LOKDeviceFormFactor::MOBILE
;
324 g_deviceFormFactor
= LOKDeviceFormFactor::UNKNOWN
;
328 * Used for putting a whole JSON string into a string value
329 * e.g { key: "{JSON}" }
331 static OString
lcl_sanitizeJSONAsValue(const OString
&rStr
)
333 if (rStr
.getLength() < 1)
335 // FIXME: need an optimized 'escape' method for O[U]String.
336 OStringBuffer
aBuf(rStr
.getLength() + 8);
337 for (sal_Int32 i
= 0; i
< rStr
.getLength(); ++i
)
339 if (rStr
[i
] == '"' || rStr
[i
] == '\\')
343 aBuf
.append(rStr
[i
]);
345 return aBuf
.makeStringAndClear();
348 static OString
lcl_generateJSON(const SfxViewShell
* pView
, const boost::property_tree::ptree
& rTree
)
350 assert(pView
!= nullptr && "pView must be valid");
351 boost::property_tree::ptree aMessageProps
= rTree
;
352 aMessageProps
.put("viewId", SfxLokHelper::getView(pView
));
353 aMessageProps
.put("part", pView
->getPart());
354 std::stringstream aStream
;
355 boost::property_tree::write_json(aStream
, aMessageProps
, false /* pretty */);
356 const std::string aString
= aStream
.str();
357 return OString(aString
.c_str(), aString
.size()).trim();
360 static inline OString
lcl_generateJSON(const SfxViewShell
* pView
, int nViewId
, std::string_view rKey
,
361 const OString
& rPayload
)
363 assert(pView
!= nullptr && "pView must be valid");
364 return OString::Concat("{ \"viewId\": \"") + OString::number(nViewId
)
365 + "\", \"part\": \"" + OString::number(pView
->getPart()) + "\", \"" + rKey
+ "\": \""
366 + lcl_sanitizeJSONAsValue(rPayload
) + "\" }";
369 static inline OString
lcl_generateJSON(const SfxViewShell
* pView
, std::string_view rKey
,
370 const OString
& rPayload
)
372 return lcl_generateJSON(pView
, SfxLokHelper::getView(pView
), rKey
, rPayload
);
375 void SfxLokHelper::notifyOtherView(const SfxViewShell
* pThisView
, SfxViewShell
const* pOtherView
,
376 int nType
, std::string_view rKey
, const OString
& rPayload
)
378 assert(pThisView
!= nullptr && "pThisView must be valid");
379 if (DisableCallbacks::disabled())
382 const OString aPayload
= lcl_generateJSON(pThisView
, rKey
, rPayload
);
383 const int viewId
= SfxLokHelper::getView(pThisView
);
384 pOtherView
->libreOfficeKitViewCallbackWithViewId(nType
, aPayload
.getStr(), viewId
);
387 void SfxLokHelper::notifyOtherView(const SfxViewShell
* pThisView
, SfxViewShell
const* pOtherView
,
388 int nType
, const boost::property_tree::ptree
& rTree
)
390 assert(pThisView
!= nullptr && "pThisView must be valid");
391 if (DisableCallbacks::disabled())
394 const int viewId
= SfxLokHelper::getView(pThisView
);
395 pOtherView
->libreOfficeKitViewCallbackWithViewId(nType
, lcl_generateJSON(pThisView
, rTree
).getStr(), viewId
);
398 void SfxLokHelper::notifyOtherViews(const SfxViewShell
* pThisView
, int nType
, std::string_view rKey
,
399 const OString
& rPayload
)
401 assert(pThisView
!= nullptr && "pThisView must be valid");
402 if (DisableCallbacks::disabled())
405 // Cache the payload so we only have to generate it once, at most.
409 const ViewShellDocId nCurrentDocId
= pThisView
->GetDocId();
410 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
413 if (pViewShell
!= pThisView
&& nCurrentDocId
== pViewShell
->GetDocId())
415 // Payload is only dependent on pThisView.
416 if (aPayload
.isEmpty())
418 aPayload
= lcl_generateJSON(pThisView
, rKey
, rPayload
);
419 viewId
= SfxLokHelper::getView(pThisView
);
422 pViewShell
->libreOfficeKitViewCallbackWithViewId(nType
, aPayload
.getStr(), viewId
);
425 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
429 void SfxLokHelper::notifyOtherViews(const SfxViewShell
* pThisView
, int nType
,
430 const boost::property_tree::ptree
& rTree
)
432 assert(pThisView
!= nullptr && "pThisView must be valid");
433 if (DisableCallbacks::disabled())
436 // Cache the payload so we only have to generate it once, at most.
440 const ViewShellDocId nCurrentDocId
= pThisView
->GetDocId();
441 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
444 if (pViewShell
!= pThisView
&& nCurrentDocId
== pViewShell
->GetDocId())
446 // Payload is only dependent on pThisView.
447 if (aPayload
.isEmpty())
449 aPayload
= lcl_generateJSON(pThisView
, rTree
);
450 viewId
= SfxLokHelper::getView(pThisView
);
453 pViewShell
->libreOfficeKitViewCallbackWithViewId(nType
, aPayload
.getStr(), viewId
);
456 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
460 OString
SfxLokHelper::makePayloadJSON(const SfxViewShell
* pThisView
, int nViewId
, std::string_view rKey
, const OString
& rPayload
)
462 return lcl_generateJSON(pThisView
, nViewId
, rKey
, rPayload
);
466 OUString
lcl_getNameForSlot(const SfxViewShell
* pShell
, sal_uInt16 nWhich
)
468 if (pShell
&& pShell
->GetFrame())
470 const SfxSlot
* pSlot
= SfxSlotPool::GetSlotPool(pShell
->GetFrame()).GetSlot(nWhich
);
473 const char* pName
= pSlot
->GetUnoName();
476 return ".uno:" + OStringToOUString(pName
, RTL_TEXTENCODING_ASCII_US
);
485 void SfxLokHelper::sendUnoStatus(const SfxViewShell
* pShell
, const SfxPoolItem
* pItem
)
487 if (!pShell
|| !pItem
|| pItem
== INVALID_POOL_ITEM
|| DisableCallbacks::disabled())
490 boost::property_tree::ptree aItem
= pItem
->dumpAsJSON();
492 if (aItem
.count("state"))
494 OUString sCommand
= lcl_getNameForSlot(pShell
, pItem
->Which());
495 if (!sCommand
.isEmpty())
496 aItem
.put("commandName", sCommand
);
498 std::stringstream aStream
;
499 boost::property_tree::write_json(aStream
, aItem
);
500 pShell
->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED
, aStream
.str().c_str());
504 void SfxLokHelper::notifyWindow(const SfxViewShell
* pThisView
,
505 vcl::LOKWindowId nLOKWindowId
,
506 std::u16string_view rAction
,
507 const std::vector
<vcl::LOKPayloadItem
>& rPayload
)
509 assert(pThisView
!= nullptr && "pThisView must be valid");
511 if (nLOKWindowId
== 0 || DisableCallbacks::disabled())
514 OStringBuffer aPayload
=
515 "{ \"id\": \"" + OString::number(nLOKWindowId
) + "\""
516 ", \"action\": \"" + OUStringToOString(rAction
, RTL_TEXTENCODING_UTF8
) + "\"";
518 for (const auto& rItem
: rPayload
)
520 if (!rItem
.first
.isEmpty() && !rItem
.second
.isEmpty())
522 aPayload
.append(", \"" + rItem
.first
+ "\": \"" +
523 rItem
.second
).append('"');
526 aPayload
.append('}');
528 const OString s
= aPayload
.makeStringAndClear();
529 pThisView
->libreOfficeKitViewCallback(LOK_CALLBACK_WINDOW
, s
.getStr());
532 void SfxLokHelper::notifyInvalidation(SfxViewShell
const* pThisView
, tools::Rectangle
const* pRect
)
534 if (DisableCallbacks::disabled())
537 const int nPart
= comphelper::LibreOfficeKit::isPartInInvalidation() ? pThisView
->getPart() : INT_MIN
;
538 pThisView
->libreOfficeKitViewInvalidateTilesCallback(pRect
, nPart
);
541 void SfxLokHelper::notifyDocumentSizeChanged(SfxViewShell
const* pThisView
, const OString
& rPayload
, vcl::ITiledRenderable
* pDoc
, bool bInvalidateAll
)
543 if (!pDoc
|| pDoc
->isDisposed() || DisableCallbacks::disabled())
548 for (int i
= 0; i
< pDoc
->getParts(); ++i
)
550 tools::Rectangle
aRectangle(0, 0, 1000000000, 1000000000);
551 pThisView
->libreOfficeKitViewInvalidateTilesCallback(&aRectangle
, i
);
554 pThisView
->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
, rPayload
.getStr());
557 void SfxLokHelper::notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable
* pDoc
, bool bInvalidateAll
)
559 if (DisableCallbacks::disabled())
562 // FIXME: Do we know whether it is the views for the document that is in the "current" view that has changed?
563 const SfxViewShell
* const pCurrentViewShell
= SfxViewShell::Current();
564 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
567 // FIXME: What if SfxViewShell::Current() returned null?
568 // Should we then do this for all views of all open documents
570 if (pCurrentViewShell
== nullptr || pViewShell
->GetDocId() == pCurrentViewShell
-> GetDocId())
572 SfxLokHelper::notifyDocumentSizeChanged(pViewShell
, "", pDoc
, bInvalidateAll
);
573 bInvalidateAll
= false; // we direct invalidations to all views anyway.
575 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
579 OString
SfxLokHelper::makeVisCursorInvalidation(int nViewId
, const OString
& rRectangle
,
580 bool bMispelledWord
, const OString
& rHyperlink
)
582 if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
584 OString sHyperlink
= rHyperlink
.isEmpty() ? "{}" : rHyperlink
;
585 return OString::Concat("{ \"viewId\": \"") + OString::number(nViewId
) +
586 "\", \"rectangle\": \"" + rRectangle
+
587 "\", \"mispelledWord\": \"" + OString::number(bMispelledWord
? 1 : 0) +
588 "\", \"hyperlink\": " + sHyperlink
+ " }";
596 void SfxLokHelper::notifyAllViews(int nType
, const OString
& rPayload
)
598 if (DisableCallbacks::disabled())
601 const auto payload
= rPayload
.getStr();
602 const SfxViewShell
* const pCurrentViewShell
= SfxViewShell::Current();
603 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
606 if (pViewShell
->GetDocId() == pCurrentViewShell
->GetDocId())
607 pViewShell
->libreOfficeKitViewCallback(nType
, payload
);
608 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
612 void SfxLokHelper::notifyContextChange(SfxViewShell
const* pViewShell
, const OUString
& aApplication
, const OUString
& aContext
)
614 if (DisableCallbacks::disabled())
618 OUStringToOString(aApplication
.replace(' ', '_'), RTL_TEXTENCODING_UTF8
) +
620 OUStringToOString(aContext
.replace(' ', '_'), RTL_TEXTENCODING_UTF8
);
621 pViewShell
->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_CHANGED
, aBuffer
.getStr());
624 void SfxLokHelper::notifyUpdate(SfxViewShell
const* pThisView
, int nType
)
626 if (DisableCallbacks::disabled())
629 pThisView
->libreOfficeKitViewUpdatedCallback(nType
);
632 void SfxLokHelper::notifyUpdatePerViewId(SfxViewShell
const* pThisView
, int nType
)
634 notifyUpdatePerViewId(pThisView
, pThisView
, pThisView
, nType
);
637 void SfxLokHelper::notifyUpdatePerViewId(SfxViewShell
const* pTargetShell
, SfxViewShell
const* pViewShell
,
638 SfxViewShell
const* pSourceShell
, int nType
)
640 if (DisableCallbacks::disabled())
643 int viewId
= SfxLokHelper::getView(pViewShell
);
644 int sourceViewId
= SfxLokHelper::getView(pSourceShell
);
645 pTargetShell
->libreOfficeKitViewUpdatedCallbackPerViewId(nType
, viewId
, sourceViewId
);
648 void SfxLokHelper::notifyOtherViewsUpdatePerViewId(SfxViewShell
const* pThisView
, int nType
)
650 assert(pThisView
!= nullptr && "pThisView must be valid");
651 if (DisableCallbacks::disabled())
654 int viewId
= SfxLokHelper::getView(pThisView
);
655 const ViewShellDocId nCurrentDocId
= pThisView
->GetDocId();
656 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
659 if (pViewShell
!= pThisView
&& nCurrentDocId
== pViewShell
->GetDocId())
660 pViewShell
->libreOfficeKitViewUpdatedCallbackPerViewId(nType
, viewId
, viewId
);
662 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
668 struct LOKAsyncEventData
670 int mnView
; // Window is not enough.
671 VclPtr
<vcl::Window
> mpWindow
;
673 MouseEvent maMouseEvent
;
678 void LOKPostAsyncEvent(void* pEv
, void*)
680 std::unique_ptr
<LOKAsyncEventData
> pLOKEv(static_cast<LOKAsyncEventData
*>(pEv
));
681 if (pLOKEv
->mpWindow
->isDisposed())
684 int nView
= SfxLokHelper::getView(nullptr);
685 if (nView
!= pLOKEv
->mnView
)
687 SAL_INFO("sfx.view", "LOK - view mismatch " << nView
<< " vs. " << pLOKEv
->mnView
);
688 SfxLokHelper::setView(pLOKEv
->mnView
);
691 if (!pLOKEv
->mpWindow
->HasChildPathFocus(true))
693 SAL_INFO("sfx.view", "LOK - focus mismatch, switching focus");
694 pLOKEv
->mpWindow
->GrabFocus();
697 VclPtr
<vcl::Window
> pFocusWindow
= pLOKEv
->mpWindow
->GetFocusedWindow();
699 pFocusWindow
= pLOKEv
->mpWindow
;
701 if (pLOKEv
->mpWindow
->isDisposed())
704 switch (pLOKEv
->mnEvent
)
706 case VclEventId::WindowKeyInput
:
708 sal_uInt16 nRepeat
= pLOKEv
->maKeyEvent
.GetRepeat();
709 KeyEvent
singlePress(pLOKEv
->maKeyEvent
.GetCharCode(),
710 pLOKEv
->maKeyEvent
.GetKeyCode());
711 for (sal_uInt16 i
= 0; i
<= nRepeat
; ++i
)
712 if (!pFocusWindow
->isDisposed())
713 pFocusWindow
->KeyInput(singlePress
);
716 case VclEventId::WindowKeyUp
:
717 if (!pFocusWindow
->isDisposed())
718 pFocusWindow
->KeyUp(pLOKEv
->maKeyEvent
);
720 case VclEventId::WindowMouseButtonDown
:
721 pLOKEv
->mpWindow
->LogicMouseButtonDown(pLOKEv
->maMouseEvent
);
722 // Invoke the context menu
723 if (pLOKEv
->maMouseEvent
.GetButtons() & MOUSE_RIGHT
)
725 const CommandEvent
aCEvt(pLOKEv
->maMouseEvent
.GetPosPixel(), CommandEventId::ContextMenu
, true, nullptr);
726 pLOKEv
->mpWindow
->Command(aCEvt
);
729 case VclEventId::WindowMouseButtonUp
:
730 pLOKEv
->mpWindow
->LogicMouseButtonUp(pLOKEv
->maMouseEvent
);
732 // sometimes MouseButtonDown captures mouse and starts tracking, and VCL
733 // will not take care of releasing that with tiled rendering
734 if (pLOKEv
->mpWindow
->IsTracking())
735 pLOKEv
->mpWindow
->EndTracking();
738 case VclEventId::WindowMouseMove
:
739 pLOKEv
->mpWindow
->LogicMouseMove(pLOKEv
->maMouseEvent
);
741 case VclEventId::ExtTextInput
:
742 case VclEventId::EndExtTextInput
:
743 pLOKEv
->mpWindow
->PostExtTextInputEvent(pLOKEv
->mnEvent
, pLOKEv
->maText
);
751 void postEventAsync(LOKAsyncEventData
*pEvent
)
753 if (!pEvent
->mpWindow
|| pEvent
->mpWindow
->isDisposed())
755 SAL_WARN("vcl", "Async event post - but no valid window as destination " << pEvent
->mpWindow
.get());
760 pEvent
->mnView
= SfxLokHelper::getView(nullptr);
761 if (vcl::lok::isUnipoll())
763 if (!Application::IsMainThread())
764 SAL_WARN("lok", "Posting event directly but not called from main thread!");
765 LOKPostAsyncEvent(pEvent
, nullptr);
768 Application::PostUserEvent(Link
<void*, void>(pEvent
, LOKPostAsyncEvent
));
772 void SfxLokHelper::postKeyEventAsync(const VclPtr
<vcl::Window
> &xWindow
,
773 int nType
, int nCharCode
, int nKeyCode
, int nRepeat
)
775 LOKAsyncEventData
* pLOKEv
= new LOKAsyncEventData
;
778 case LOK_KEYEVENT_KEYINPUT
:
779 pLOKEv
->mnEvent
= VclEventId::WindowKeyInput
;
781 case LOK_KEYEVENT_KEYUP
:
782 pLOKEv
->mnEvent
= VclEventId::WindowKeyUp
;
787 pLOKEv
->maKeyEvent
= KeyEvent(nCharCode
, nKeyCode
, nRepeat
);
788 pLOKEv
->mpWindow
= xWindow
;
789 postEventAsync(pLOKEv
);
792 void SfxLokHelper::setBlockedCommandList(int nViewId
, const char* blockedCommandList
)
794 SfxViewShell
* pViewShell
= SfxLokHelper::getViewOfId(nViewId
);
798 pViewShell
->setBlockedCommandList(blockedCommandList
);
802 void SfxLokHelper::postExtTextEventAsync(const VclPtr
<vcl::Window
> &xWindow
,
803 int nType
, const OUString
&rText
)
805 LOKAsyncEventData
* pLOKEv
= new LOKAsyncEventData
;
808 case LOK_EXT_TEXTINPUT
:
809 pLOKEv
->mnEvent
= VclEventId::ExtTextInput
;
810 pLOKEv
->maText
= rText
;
812 case LOK_EXT_TEXTINPUT_END
:
813 pLOKEv
->mnEvent
= VclEventId::EndExtTextInput
;
819 pLOKEv
->mpWindow
= xWindow
;
820 postEventAsync(pLOKEv
);
823 void SfxLokHelper::postMouseEventAsync(const VclPtr
<vcl::Window
> &xWindow
, LokMouseEventData
const & rLokMouseEventData
)
825 LOKAsyncEventData
* pLOKEv
= new LOKAsyncEventData
;
826 switch (rLokMouseEventData
.mnType
)
828 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN
:
829 pLOKEv
->mnEvent
= VclEventId::WindowMouseButtonDown
;
831 case LOK_MOUSEEVENT_MOUSEBUTTONUP
:
832 pLOKEv
->mnEvent
= VclEventId::WindowMouseButtonUp
;
834 case LOK_MOUSEEVENT_MOUSEMOVE
:
835 pLOKEv
->mnEvent
= VclEventId::WindowMouseMove
;
841 // no reason - just always true so far.
842 assert (rLokMouseEventData
.meModifiers
== MouseEventModifiers::SIMPLECLICK
);
844 pLOKEv
->maMouseEvent
= MouseEvent(rLokMouseEventData
.maPosition
, rLokMouseEventData
.mnCount
,
845 rLokMouseEventData
.meModifiers
, rLokMouseEventData
.mnButtons
,
846 rLokMouseEventData
.mnModifier
);
847 if (rLokMouseEventData
.maLogicPosition
)
849 pLOKEv
->maMouseEvent
.setLogicPosition(*rLokMouseEventData
.maLogicPosition
);
851 pLOKEv
->mpWindow
= xWindow
;
852 postEventAsync(pLOKEv
);
855 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */