lokit: double check for disposed windows & fix leak.
[LibreOffice.git] / sfx2 / source / view / lokhelper.cxx
blobcb8194c1cabf1603d1c3dd3456a16edabe7b6687
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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;
40 namespace {
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
48 public:
49 DisableCallbacks()
51 assert(m_nDisabled >= 0 && "Expected non-negative DisabledCallbacks state when disabling.");
52 ++m_nDisabled;
55 ~DisableCallbacks()
57 assert(m_nDisabled > 0 && "Expected positive DisabledCallbacks state when re-enabling.");
58 --m_nDisabled;
61 static inline bool disabled()
63 return !comphelper::LibreOfficeKit::isActive() || m_nDisabled != 0;
66 private:
67 static int m_nDisabled;
70 int DisableCallbacks::m_nDisabled = 0;
73 namespace
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)
84 return -1;
86 SfxViewShell::SetCurrentDocId(docId);
87 SfxRequest aRequest(pViewFrame, SID_NEWWINDOW);
88 pViewFrame->ExecView_Impl(aRequest);
89 SfxViewShell* pViewShell = SfxViewShell::Current();
90 if (pViewShell == nullptr)
91 return -1;
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)
104 return -1;
106 return createView(pViewShell->GetViewFrame(), pViewShell->GetDocId());
109 int SfxLokHelper::createView(int nDocId)
111 const SfxApplication* pApp = SfxApplication::Get();
112 if (pApp == nullptr)
113 return -1;
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.
124 return -1;
127 void SfxLokHelper::destroyView(int nId)
129 const SfxApplication* pApp = SfxApplication::Get();
130 if (pApp == nullptr)
131 return;
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);
143 break;
148 void SfxLokHelper::setView(int nId)
150 SfxApplication* pApp = SfxApplication::Get();
151 if (pApp == nullptr)
152 return;
154 const ViewShellId nViewShellId(nId);
155 std::vector<SfxViewShell*>& rViewArr = pApp->GetViewShells_Impl();
157 for (const SfxViewShell* pViewShell : rViewArr)
159 if (pViewShell->GetViewShellId() == nViewShellId)
161 DisableCallbacks dc;
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())
168 return;
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);
177 return;
183 SfxViewShell* SfxLokHelper::getViewOfId(int nId)
185 SfxApplication* pApp = SfxApplication::Get();
186 if (pApp == nullptr)
187 return nullptr;
189 const ViewShellId nViewShellId(nId);
190 std::vector<SfxViewShell*>& rViewArr = pApp->GetViewShells_Impl();
191 for (SfxViewShell* pViewShell : rViewArr)
193 if (pViewShell->GetViewShellId() == nViewShellId)
194 return pViewShell;
197 return nullptr;
200 int SfxLokHelper::getView(const SfxViewShell* pViewShell)
202 if (!pViewShell)
203 pViewShell = SfxViewShell::Current();
204 // Still no valid view shell? Then no idea.
205 if (!pViewShell)
206 return -1;
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();
216 if (!pApp)
217 return 0;
219 const ViewShellDocId nCurrentDocId(nDocId);
220 std::size_t n = 0;
221 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
222 while (pViewShell)
224 if (pViewShell->GetDocId() == nCurrentDocId)
225 n++;
226 pViewShell = SfxViewShell::GetNext(*pViewShell);
229 return n;
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();
237 if (!pApp)
238 return false;
240 const ViewShellDocId nCurrentDocId(nDocId);
241 std::size_t n = 0;
242 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
243 while (pViewShell)
245 if (pViewShell->GetDocId() == nCurrentDocId)
247 if (n == nSize)
248 return false;
250 pArray[n] = static_cast<sal_Int32>(pViewShell->GetViewShellId());
251 n++;
254 pViewShell = SfxViewShell::GetNext(*pViewShell);
257 return true;
260 int SfxLokHelper::getDocumentIdOfView(int nViewId)
262 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
263 while (pViewShell)
265 if (pViewShell->GetViewShellId() == ViewShellId(nViewId))
266 return static_cast<int>(pViewShell->GetDocId());
267 pViewShell = SfxViewShell::GetNext(*pViewShell);
269 return -1;
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);
291 return;
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);
305 return;
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;
323 else
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)
334 return rStr;
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] == '\\')
340 aBuf.append('\\');
342 if (rStr[i] != '\n')
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())
380 return;
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())
392 return;
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())
403 return;
405 // Cache the payload so we only have to generate it once, at most.
406 OString aPayload;
407 int viewId = -1;
409 const ViewShellDocId nCurrentDocId = pThisView->GetDocId();
410 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
411 while (pViewShell)
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())
434 return;
436 // Cache the payload so we only have to generate it once, at most.
437 OString aPayload;
438 int viewId = -1;
440 const ViewShellDocId nCurrentDocId = pThisView->GetDocId();
441 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
442 while (pViewShell)
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);
465 namespace {
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);
471 if (pSlot)
473 const char* pName = pSlot->GetUnoName();
474 if (pName)
476 return ".uno:" + OStringToOUString(pName, RTL_TEXTENCODING_ASCII_US);
481 return "";
485 void SfxLokHelper::sendUnoStatus(const SfxViewShell* pShell, const SfxPoolItem* pItem)
487 if (!pShell || !pItem || pItem == INVALID_POOL_ITEM || DisableCallbacks::disabled())
488 return;
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())
512 return;
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())
535 return;
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())
544 return;
546 if (bInvalidateAll)
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())
560 return;
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();
565 while (pViewShell)
567 // FIXME: What if SfxViewShell::Current() returned null?
568 // Should we then do this for all views of all open documents
569 // or not?
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 + " }";
590 else
592 return rRectangle;
596 void SfxLokHelper::notifyAllViews(int nType, const OString& rPayload)
598 if (DisableCallbacks::disabled())
599 return;
601 const auto payload = rPayload.getStr();
602 const SfxViewShell* const pCurrentViewShell = SfxViewShell::Current();
603 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
604 while (pViewShell)
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())
615 return;
617 OString aBuffer =
618 OUStringToOString(aApplication.replace(' ', '_'), RTL_TEXTENCODING_UTF8) +
619 " " +
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())
627 return;
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())
641 return;
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())
652 return;
654 int viewId = SfxLokHelper::getView(pThisView);
655 const ViewShellDocId nCurrentDocId = pThisView->GetDocId();
656 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
657 while (pViewShell)
659 if (pViewShell != pThisView && nCurrentDocId == pViewShell->GetDocId())
660 pViewShell->libreOfficeKitViewUpdatedCallbackPerViewId(nType, viewId, viewId);
662 pViewShell = SfxViewShell::GetNext(*pViewShell);
666 namespace
668 struct LOKAsyncEventData
670 int mnView; // Window is not enough.
671 VclPtr<vcl::Window> mpWindow;
672 VclEventId mnEvent;
673 MouseEvent maMouseEvent;
674 KeyEvent maKeyEvent;
675 OUString maText;
678 void LOKPostAsyncEvent(void* pEv, void*)
680 std::unique_ptr<LOKAsyncEventData> pLOKEv(static_cast<LOKAsyncEventData*>(pEv));
681 if (pLOKEv->mpWindow->isDisposed())
682 return;
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();
698 if (!pFocusWindow)
699 pFocusWindow = pLOKEv->mpWindow;
701 if (pLOKEv->mpWindow->isDisposed())
702 return;
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);
714 break;
716 case VclEventId::WindowKeyUp:
717 if (!pFocusWindow->isDisposed())
718 pFocusWindow->KeyUp(pLOKEv->maKeyEvent);
719 break;
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);
728 break;
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();
737 break;
738 case VclEventId::WindowMouseMove:
739 pLOKEv->mpWindow->LogicMouseMove(pLOKEv->maMouseEvent);
740 break;
741 case VclEventId::ExtTextInput:
742 case VclEventId::EndExtTextInput:
743 pLOKEv->mpWindow->PostExtTextInputEvent(pLOKEv->mnEvent, pLOKEv->maText);
744 break;
745 default:
746 assert(false);
747 break;
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());
756 delete pEvent;
757 return;
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);
767 else
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;
776 switch (nType)
778 case LOK_KEYEVENT_KEYINPUT:
779 pLOKEv->mnEvent = VclEventId::WindowKeyInput;
780 break;
781 case LOK_KEYEVENT_KEYUP:
782 pLOKEv->mnEvent = VclEventId::WindowKeyUp;
783 break;
784 default:
785 assert(false);
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);
796 if(pViewShell)
798 pViewShell->setBlockedCommandList(blockedCommandList);
802 void SfxLokHelper::postExtTextEventAsync(const VclPtr<vcl::Window> &xWindow,
803 int nType, const OUString &rText)
805 LOKAsyncEventData* pLOKEv = new LOKAsyncEventData;
806 switch (nType)
808 case LOK_EXT_TEXTINPUT:
809 pLOKEv->mnEvent = VclEventId::ExtTextInput;
810 pLOKEv->maText = rText;
811 break;
812 case LOK_EXT_TEXTINPUT_END:
813 pLOKEv->mnEvent = VclEventId::EndExtTextInput;
814 pLOKEv->maText = "";
815 break;
816 default:
817 assert(false);
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;
830 break;
831 case LOK_MOUSEEVENT_MOUSEBUTTONUP:
832 pLOKEv->mnEvent = VclEventId::WindowMouseButtonUp;
833 break;
834 case LOK_MOUSEEVENT_MOUSEMOVE:
835 pLOKEv->mnEvent = VclEventId::WindowMouseMove;
836 break;
837 default:
838 assert(false);
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: */