bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / app / svapp.cxx
blobc61d9ea0f2aa1a0f355300a323dae93ad507ef03
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <osl/file.hxx>
23 #include <osl/thread.hxx>
24 #include <osl/module.hxx>
25 #include <rtl/ustrbuf.hxx>
27 #include <sal/log.hxx>
29 #include <tools/debug.hxx>
30 #include <tools/time.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/json_writer.hxx>
34 #include <unotools/configmgr.hxx>
35 #include <unotools/resmgr.hxx>
36 #include <unotools/syslocale.hxx>
37 #include <unotools/syslocaleoptions.hxx>
39 #include <vcl/toolkit/dialog.hxx>
40 #include <vcl/dialoghelper.hxx>
41 #include <vcl/lok.hxx>
42 #include <vcl/toolkit/floatwin.hxx>
43 #include <vcl/settings.hxx>
44 #include <vcl/keycod.hxx>
45 #include <vcl/event.hxx>
46 #include <vcl/vclevent.hxx>
47 #include <vcl/virdev.hxx>
48 #include <vcl/wrkwin.hxx>
49 #include <vcl/svapp.hxx>
50 #include <vcl/cvtgrf.hxx>
51 #include <vcl/toolkit/unowrap.hxx>
52 #include <vcl/timer.hxx>
53 #include <vcl/scheduler.hxx>
54 #include <vcl/skia/SkiaHelper.hxx>
56 #include <salinst.hxx>
57 #include <graphic/Manager.hxx>
58 #include <salframe.hxx>
59 #include <salsys.hxx>
60 #include <svdata.hxx>
61 #include <displayconnectiondispatch.hxx>
62 #include <window.h>
63 #include <accmgr.hxx>
64 #include <strings.hrc>
65 #include <strings.hxx>
66 #if OSL_DEBUG_LEVEL > 0
67 #include <schedulerimpl.hxx>
68 #endif
70 #include <com/sun/star/uno/Reference.h>
71 #include <com/sun/star/awt/XToolkit.hpp>
72 #include <comphelper/lok.hxx>
73 #include <comphelper/threadpool.hxx>
74 #include <comphelper/solarmutex.hxx>
75 #include <osl/process.h>
77 #include <cassert>
78 #include <limits>
79 #include <string_view>
80 #include <utility>
81 #include <thread>
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::uno;
86 namespace {
87 void InitSettings(ImplSVData* pSVData);
90 // keycodes handled internally by VCL
91 vcl::KeyCode const ReservedKeys[]
93 vcl::KeyCode(KEY_F1,0) ,
94 vcl::KeyCode(KEY_F1,KEY_SHIFT) ,
95 vcl::KeyCode(KEY_F1,KEY_MOD1) ,
96 vcl::KeyCode(KEY_F2,KEY_SHIFT) ,
97 vcl::KeyCode(KEY_F4,KEY_MOD1) ,
98 vcl::KeyCode(KEY_F4,KEY_MOD2) ,
99 vcl::KeyCode(KEY_F4,KEY_MOD1|KEY_MOD2) ,
100 vcl::KeyCode(KEY_F6,0) ,
101 vcl::KeyCode(KEY_F6,KEY_MOD1) ,
102 vcl::KeyCode(KEY_F6,KEY_SHIFT) ,
103 vcl::KeyCode(KEY_F6,KEY_MOD1|KEY_SHIFT) ,
104 vcl::KeyCode(KEY_F10,0)
105 #ifdef UNX
107 vcl::KeyCode(KEY_1,KEY_SHIFT|KEY_MOD1),
108 vcl::KeyCode(KEY_2,KEY_SHIFT|KEY_MOD1),
109 vcl::KeyCode(KEY_3,KEY_SHIFT|KEY_MOD1),
110 vcl::KeyCode(KEY_4,KEY_SHIFT|KEY_MOD1),
111 vcl::KeyCode(KEY_5,KEY_SHIFT|KEY_MOD1),
112 vcl::KeyCode(KEY_6,KEY_SHIFT|KEY_MOD1),
113 vcl::KeyCode(KEY_7,KEY_SHIFT|KEY_MOD1),
114 vcl::KeyCode(KEY_8,KEY_SHIFT|KEY_MOD1),
115 vcl::KeyCode(KEY_9,KEY_SHIFT|KEY_MOD1),
116 vcl::KeyCode(KEY_0,KEY_SHIFT|KEY_MOD1),
117 vcl::KeyCode(KEY_ADD,KEY_SHIFT|KEY_MOD1)
118 #endif
121 extern "C" {
122 typedef UnoWrapperBase* (*FN_TkCreateUnoWrapper)();
125 struct ImplPostEventData
127 VclPtr<vcl::Window> mpWin;
128 ImplSVEvent * mnEventId;
129 MouseEvent maMouseEvent;
130 VclEventId mnEvent;
131 KeyEvent maKeyEvent;
132 GestureEventPan maGestureEvent;
134 ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent)
135 : mpWin(pWin)
136 , mnEventId(nullptr)
137 , mnEvent(nEvent)
138 , maKeyEvent(rKeyEvent)
140 ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent)
141 : mpWin(pWin)
142 , mnEventId(nullptr)
143 , maMouseEvent(rMouseEvent)
144 , mnEvent(nEvent)
146 ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const GestureEventPan& rGestureEvent)
147 : mpWin(pWin)
148 , mnEventId(nullptr)
149 , mnEvent(nEvent)
150 , maGestureEvent(rGestureEvent)
154 Application* GetpApp()
156 ImplSVData* pSVData = ImplGetSVData();
157 if ( !pSVData )
158 return nullptr;
159 return pSVData->mpApp;
162 Application::Application()
164 // useful for themes at least, perhaps extensions too
165 OUString aVar("LIBO_VERSION"), aValue(LIBO_VERSION_DOTTED);
166 osl_setEnvironment(aVar.pData, aValue.pData);
168 ImplGetSVData()->mpApp = this;
169 m_pCallbackData = nullptr;
170 m_pCallback = nullptr;
173 Application::~Application()
175 ImplDeInitSVData();
176 ImplGetSVData()->mpApp = nullptr;
179 int Application::Main()
181 SAL_WARN("vcl", "Application is a base class and should be overridden.");
182 return EXIT_SUCCESS;
185 bool Application::QueryExit()
187 WorkWindow* pAppWin = ImplGetSVData()->maFrameData.mpAppWin;
189 // call the close handler of the application window
190 if ( pAppWin )
191 return pAppWin->Close();
192 else
193 return true;
196 void Application::Shutdown()
200 void Application::Init()
204 void Application::InitFinished()
208 void Application::DeInit()
212 sal_uInt16 Application::GetCommandLineParamCount()
214 return static_cast<sal_uInt16>(osl_getCommandArgCount());
217 OUString Application::GetCommandLineParam( sal_uInt16 nParam )
219 OUString aParam;
220 osl_getCommandArg( nParam, &aParam.pData );
221 return aParam;
224 OUString Application::GetAppFileName()
226 ImplSVData* pSVData = ImplGetSVData();
227 SAL_WARN_IF( !pSVData->maAppData.mxAppFileName, "vcl", "AppFileName should be set to something after SVMain!" );
228 if ( pSVData->maAppData.mxAppFileName )
229 return *pSVData->maAppData.mxAppFileName;
232 * provide a fallback for people without initialized vcl here (like setup
233 * in responsefile mode)
235 OUString aAppFileName;
236 OUString aExeFileName;
237 osl_getExecutableFile(&aExeFileName.pData);
239 // convert path to native file format
240 osl::FileBase::getSystemPathFromFileURL(aExeFileName, aAppFileName);
242 return aAppFileName;
245 void Application::Exception( ExceptionCategory nCategory )
247 switch ( nCategory )
249 // System has precedence (so do nothing)
250 case ExceptionCategory::System:
251 case ExceptionCategory::UserInterface:
252 break;
253 default:
254 Abort("Unknown Error");
255 break;
259 void Application::Abort( const OUString& rErrorText )
261 //HACK: Dump core iff --norestore command line argument is given (assuming
262 // this process is run by developers who are interested in cores, vs. end
263 // users who are not):
264 #if OSL_DEBUG_LEVEL > 0
265 bool dumpCore = true;
266 #else
267 bool dumpCore = false;
268 sal_uInt16 n = GetCommandLineParamCount();
269 for (sal_uInt16 i = 0; i != n; ++i) {
270 if (GetCommandLineParam(i) == "--norestore") {
271 dumpCore = true;
272 break;
275 #endif
277 SalAbort( rErrorText, dumpCore );
280 size_t Application::GetReservedKeyCodeCount()
282 return SAL_N_ELEMENTS(ReservedKeys);
285 const vcl::KeyCode* Application::GetReservedKeyCode( size_t i )
287 if( i >= GetReservedKeyCodeCount() )
288 return nullptr;
289 else
290 return &ReservedKeys[i];
293 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplEndAllPopupsMsg, void*, void )
295 ImplSVData* pSVData = ImplGetSVData();
296 while (pSVData->mpWinData->mpFirstFloat)
297 pSVData->mpWinData->mpFirstFloat->EndPopupMode(FloatWinPopupEndFlags::Cancel);
300 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplEndAllDialogsMsg, void*, void )
302 vcl::Window* pAppWindow = Application::GetFirstTopLevelWindow();
303 while (pAppWindow)
305 vcl::EndAllDialogs(pAppWindow);
306 pAppWindow = Application::GetNextTopLevelWindow(pAppWindow);
310 void Application::EndAllDialogs()
312 Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplEndAllDialogsMsg ) );
315 void Application::EndAllPopups()
317 Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplEndAllPopupsMsg ) );
320 void Application::notifyWindow(vcl::LOKWindowId /*nLOKWindowId*/,
321 const OUString& /*rAction*/,
322 const std::vector<vcl::LOKPayloadItem>& /*rPayload = std::vector<LOKPayloadItem>()*/) const
324 SAL_WARN("vcl", "Invoked not implemented method: Application::notifyWindow");
327 void Application::libreOfficeKitViewCallback(int nType, const OString& pPayload) const
329 if (!comphelper::LibreOfficeKit::isActive())
330 return;
332 if (m_pCallback)
334 m_pCallback(nType, pPayload.getStr(), m_pCallbackData);
338 void Application::notifyInvalidation(tools::Rectangle const* /*pRect*/) const
342 void Application::Execute()
344 ImplSVData* pSVData = ImplGetSVData();
345 pSVData->maAppData.mbInAppExecute = true;
346 pSVData->maAppData.mbAppQuit = false;
348 int nExitCode = 0;
349 if (!pSVData->mpDefInst->DoExecute(nExitCode))
351 if (Application::IsOnSystemEventLoop())
353 SAL_WARN("vcl.schedule", "Can't omit DoExecute when running on system event loop!");
354 std::abort();
356 while (!pSVData->maAppData.mbAppQuit)
357 Application::Yield();
360 pSVData->maAppData.mbInAppExecute = false;
362 GetpApp()->Shutdown();
365 static bool ImplYield(bool i_bWait, bool i_bAllEvents)
367 ImplSVData* pSVData = ImplGetSVData();
369 SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
370 ": " << (i_bAllEvents ? "all events" : "one event"));
372 // there's a data race here on WNT only because ImplYield may be
373 // called without SolarMutex; but the only remaining use of mnDispatchLevel
374 // is in OSX specific code
375 pSVData->maAppData.mnDispatchLevel++;
377 // do not wait for events if application was already quit; in that
378 // case only dispatch events already available
379 bool bProcessedEvent = pSVData->mpDefInst->DoYield(
380 i_bWait && !pSVData->maAppData.mbAppQuit, i_bAllEvents );
382 pSVData->maAppData.mnDispatchLevel--;
384 DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
386 SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent );
387 return bProcessedEvent;
390 bool Application::Reschedule( bool i_bAllEvents )
392 static const bool bAbort = Application::IsOnSystemEventLoop();
393 if (bAbort)
395 SAL_WARN("vcl.schedule", "Application::Reschedule(" << i_bAllEvents << ")");
396 std::abort();
398 return ImplYield(false, i_bAllEvents);
401 bool Application::IsOnSystemEventLoop()
403 return ImplGetSVData()->maAppData.m_bUseSystemLoop;
406 void Scheduler::ProcessEventsToIdle()
408 int nSanity = 1;
409 while (ImplYield(false, true))
411 if (0 == ++nSanity % 1000)
413 SAL_WARN("vcl.schedule", "ProcessEventsToIdle: " << nSanity);
416 #if OSL_DEBUG_LEVEL > 0
417 // If we yield from a non-main thread we just can guarantee that all idle
418 // events were processed at some point, but our check can't prevent further
419 // processing in the main thread, which may add new events, so skip it.
420 const ImplSVData* pSVData = ImplGetSVData();
421 if ( !pSVData->mpDefInst->IsMainThread() )
422 return;
423 for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
425 const ImplSchedulerData* pSchedulerData = pSVData->maSchedCtx.mpFirstSchedulerData[nTaskPriority];
426 while (pSchedulerData)
428 assert(!pSchedulerData->mbInScheduler);
429 if (pSchedulerData->mpTask)
431 Idle *pIdle = dynamic_cast<Idle*>(pSchedulerData->mpTask);
432 if (pIdle && pIdle->IsActive())
434 SAL_WARN("vcl.schedule",
435 "Unprocessed Idle: "
436 << pIdle << " "
437 << (pIdle->GetDebugName() ? pIdle->GetDebugName() : "(nullptr)"));
440 pSchedulerData = pSchedulerData->mpNext;
443 #endif
446 extern "C" {
447 /// used by unit tests that test only via the LOK API
448 SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
450 const SolarMutexGuard aGuard;
451 Scheduler::ProcessEventsToIdle();
455 void Application::Yield()
457 static const bool bAbort = Application::IsOnSystemEventLoop();
458 if (bAbort)
460 SAL_WARN("vcl.schedule", "Application::Yield()");
461 std::abort();
463 ImplYield(true, false);
466 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
468 assert(ImplGetSVData()->maAppData.mbAppQuit);
469 ImplGetSVData()->mpDefInst->DoQuit();
472 void Application::Quit()
474 ImplGetSVData()->maAppData.mbAppQuit = true;
475 Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplQuitMsg ) );
478 comphelper::SolarMutex& Application::GetSolarMutex()
480 ImplSVData* pSVData = ImplGetSVData();
481 return *(pSVData->mpDefInst->GetYieldMutex());
484 bool Application::IsMainThread()
486 return ImplGetSVData()->mnMainThreadId == osl::Thread::getCurrentIdentifier();
489 sal_uInt32 Application::ReleaseSolarMutex()
491 ImplSVData* pSVData = ImplGetSVData();
492 return pSVData->mpDefInst->ReleaseYieldMutexAll();
495 void Application::AcquireSolarMutex( sal_uInt32 nCount )
497 ImplSVData* pSVData = ImplGetSVData();
498 pSVData->mpDefInst->AcquireYieldMutex( nCount );
501 bool Application::IsInMain()
503 ImplSVData* pSVData = ImplGetSVData();
504 return pSVData && pSVData->maAppData.mbInAppMain;
507 bool Application::IsInExecute()
509 return ImplGetSVData()->maAppData.mbInAppExecute;
512 bool Application::IsQuit()
514 return ImplGetSVData()->maAppData.mbAppQuit;
517 bool Application::IsInModalMode()
519 return (ImplGetSVData()->maAppData.mnModalMode != 0);
522 sal_uInt16 Application::GetDispatchLevel()
524 return ImplGetSVData()->maAppData.mnDispatchLevel;
527 bool Application::AnyInput( VclInputFlags nType )
529 return ImplGetSVData()->mpDefInst->AnyInput( nType );
532 sal_uInt64 Application::GetLastInputInterval()
534 return (tools::Time::GetSystemTicks()-ImplGetSVData()->maAppData.mnLastInputTime);
537 bool Application::IsUICaptured()
539 ImplSVData* pSVData = ImplGetSVData();
541 // If mouse was captured, or if in tracking- or in select-mode of a floatingwindow (e.g. menus
542 // or pulldown toolboxes) another window should be created
543 // D&D active !!!
544 return pSVData->mpWinData->mpCaptureWin || pSVData->mpWinData->mpTrackWin
545 || pSVData->mpWinData->mpFirstFloat || nImplSysDialog;
548 void Application::OverrideSystemSettings( AllSettings& /*rSettings*/ )
552 void Application::MergeSystemSettings( AllSettings& rSettings )
554 vcl::Window* pWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
555 if( ! pWindow )
556 pWindow = ImplGetDefaultWindow();
557 if( pWindow )
559 ImplSVData* pSVData = ImplGetSVData();
560 if ( !pSVData->maAppData.mbSettingsInit )
562 // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
563 pWindow->ImplUpdateGlobalSettings( *pSVData->maAppData.mxSettings );
564 pSVData->maAppData.mbSettingsInit = true;
566 // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
567 pWindow->ImplUpdateGlobalSettings( rSettings, false );
571 void Application::SetSettings( const AllSettings& rSettings )
573 const SolarMutexGuard aGuard;
575 ImplSVData* pSVData = ImplGetSVData();
576 if ( !pSVData->maAppData.mxSettings )
578 InitSettings(pSVData);
579 *pSVData->maAppData.mxSettings = rSettings;
581 else
583 AllSettings aOldSettings = *pSVData->maAppData.mxSettings;
584 if (aOldSettings.GetUILanguageTag().getLanguageType() != rSettings.GetUILanguageTag().getLanguageType() &&
585 pSVData->mbResLocaleSet)
587 pSVData->mbResLocaleSet = false;
589 *pSVData->maAppData.mxSettings = rSettings;
590 AllSettingsFlags nChangeFlags = aOldSettings.GetChangeFlags( *pSVData->maAppData.mxSettings );
591 if ( bool(nChangeFlags) )
593 DataChangedEvent aDCEvt( DataChangedEventType::SETTINGS, &aOldSettings, nChangeFlags );
595 // notify data change handler
596 ImplCallEventListenersApplicationDataChanged( &aDCEvt);
598 // Update all windows
599 vcl::Window* pFirstFrame = pSVData->maFrameData.mpFirstFrame;
600 // Reset data that needs to be re-calculated
601 tools::Long nOldDPIX = 0;
602 tools::Long nOldDPIY = 0;
603 if ( pFirstFrame )
605 nOldDPIX = pFirstFrame->GetOutDev()->GetDPIX();
606 nOldDPIY = pFirstFrame->GetOutDev()->GetDPIY();
607 vcl::Window::ImplInitAppFontData(pFirstFrame);
609 vcl::Window* pFrame = pFirstFrame;
610 while ( pFrame )
612 // call UpdateSettings from ClientWindow in order to prevent updating data twice
613 vcl::Window* pClientWin = pFrame;
614 while ( pClientWin->ImplGetClientWindow() )
615 pClientWin = pClientWin->ImplGetClientWindow();
616 pClientWin->UpdateSettings( rSettings, true );
618 vcl::Window* pTempWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
619 while ( pTempWin )
621 // call UpdateSettings from ClientWindow in order to prevent updating data twice
622 pClientWin = pTempWin;
623 while ( pClientWin->ImplGetClientWindow() )
624 pClientWin = pClientWin->ImplGetClientWindow();
625 pClientWin->UpdateSettings( rSettings, true );
626 pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
629 pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
632 // if DPI resolution for screen output was changed set the new resolution for all
633 // screen compatible VirDev's
634 pFirstFrame = pSVData->maFrameData.mpFirstFrame;
635 if ( pFirstFrame )
637 if ( (pFirstFrame->GetOutDev()->GetDPIX() != nOldDPIX) ||
638 (pFirstFrame->GetOutDev()->GetDPIY() != nOldDPIY) )
640 VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
641 while ( pVirDev )
643 if ( pVirDev->mbScreenComp &&
644 (pVirDev->GetDPIX() == nOldDPIX) &&
645 (pVirDev->GetDPIY() == nOldDPIY) )
647 pVirDev->SetDPIX( pFirstFrame->GetOutDev()->GetDPIX() );
648 pVirDev->SetDPIY( pFirstFrame->GetOutDev()->GetDPIY() );
649 if ( pVirDev->IsMapModeEnabled() )
651 MapMode aMapMode = pVirDev->GetMapMode();
652 pVirDev->SetMapMode();
653 pVirDev->SetMapMode( aMapMode );
657 pVirDev = pVirDev->mpNext;
665 const AllSettings& Application::GetSettings()
667 ImplSVData* pSVData = ImplGetSVData();
668 if ( !pSVData->maAppData.mxSettings )
670 InitSettings(pSVData);
673 return *(pSVData->maAppData.mxSettings);
676 namespace {
678 void InitSettings(ImplSVData* pSVData)
680 assert(!pSVData->maAppData.mxSettings && "initialization should not happen twice!");
682 pSVData->maAppData.mxSettings.emplace();
683 if (!utl::ConfigManager::IsFuzzing())
685 pSVData->maAppData.mpCfgListener = new LocaleConfigurationListener;
686 pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().AddListener( pSVData->maAppData.mpCfgListener );
692 void Application::NotifyAllWindows( DataChangedEvent& rDCEvt )
694 ImplSVData* pSVData = ImplGetSVData();
695 vcl::Window* pFrame = pSVData->maFrameData.mpFirstFrame;
696 while ( pFrame )
698 pFrame->NotifyAllChildren( rDCEvt );
700 vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
701 while ( pSysWin )
703 pSysWin->NotifyAllChildren( rDCEvt );
704 pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
707 pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
711 void Application::ImplCallEventListenersApplicationDataChanged( void* pData )
713 ImplSVData* pSVData = ImplGetSVData();
714 VclWindowEvent aEvent( nullptr, VclEventId::ApplicationDataChanged, pData );
716 pSVData->maAppData.maEventListeners.Call( aEvent );
719 void Application::ImplCallEventListeners( VclSimpleEvent& rEvent )
721 ImplSVData* pSVData = ImplGetSVData();
722 pSVData->maAppData.maEventListeners.Call( rEvent );
725 void Application::AddEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
727 ImplSVData* pSVData = ImplGetSVData();
728 pSVData->maAppData.maEventListeners.addListener( rEventListener );
731 void Application::RemoveEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
733 ImplSVData* pSVData = ImplGetSVData();
734 pSVData->maAppData.maEventListeners.removeListener( rEventListener );
737 void Application::AddKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
739 ImplSVData* pSVData = ImplGetSVData();
740 pSVData->maAppData.maKeyListeners.push_back( rKeyListener );
743 void Application::RemoveKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
745 ImplSVData* pSVData = ImplGetSVData();
746 auto & rVec = pSVData->maAppData.maKeyListeners;
747 rVec.erase( std::remove(rVec.begin(), rVec.end(), rKeyListener ), rVec.end() );
750 bool Application::HandleKey( VclEventId nEvent, vcl::Window *pWin, KeyEvent* pKeyEvent )
752 // let listeners process the key event
753 VclWindowEvent aEvent( pWin, nEvent, static_cast<void *>(pKeyEvent) );
755 ImplSVData* pSVData = ImplGetSVData();
757 if ( pSVData->maAppData.maKeyListeners.empty() )
758 return false;
760 bool bProcessed = false;
761 // Copy the list, because this can be destroyed when calling a Link...
762 std::vector<Link<VclWindowEvent&,bool>> aCopy( pSVData->maAppData.maKeyListeners );
763 for ( const Link<VclWindowEvent&,bool>& rLink : aCopy )
765 if( rLink.Call( aEvent ) )
767 bProcessed = true;
768 break;
771 return bProcessed;
774 ImplSVEvent * Application::PostKeyEvent( VclEventId nEvent, vcl::Window *pWin, KeyEvent const * pKeyEvent )
776 const SolarMutexGuard aGuard;
777 ImplSVEvent * nEventId = nullptr;
779 if( pWin && pKeyEvent )
781 std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, *pKeyEvent ));
783 nEventId = PostUserEvent(
784 LINK( nullptr, Application, PostEventHandler ),
785 pPostEventData.get() );
787 if( nEventId )
789 pPostEventData->mnEventId = nEventId;
790 ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
794 return nEventId;
797 ImplSVEvent* Application::PostGestureEvent(VclEventId nEvent, vcl::Window* pWin,
798 GestureEventPan const * pGestureEvent)
800 const SolarMutexGuard aGuard;
801 ImplSVEvent * nEventId = nullptr;
803 if (pWin && pGestureEvent)
805 Point aTransformedPosition(pGestureEvent->mnX, pGestureEvent->mnY);
807 aTransformedPosition.AdjustX(pWin->GetOutOffXPixel());
808 aTransformedPosition.AdjustY(pWin->GetOutOffYPixel());
810 const GestureEventPan aGestureEvent(
811 sal_Int32(aTransformedPosition.X()),
812 sal_Int32(aTransformedPosition.Y()),
813 pGestureEvent->meEventType,
814 pGestureEvent->mnOffset,
815 pGestureEvent->meOrientation
818 std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData(nEvent, pWin, aGestureEvent));
820 nEventId = PostUserEvent(
821 LINK( nullptr, Application, PostEventHandler ),
822 pPostEventData.get());
824 if (nEventId)
826 pPostEventData->mnEventId = nEventId;
827 ImplGetSVData()->maAppData.maPostedEventList.emplace_back(pWin, pPostEventData.release());
831 return nEventId;
834 bool Application::LOKHandleMouseEvent(VclEventId nEvent, vcl::Window* pWindow, const MouseEvent* pEvent)
836 bool bSuccess = false;
837 SalMouseEvent aMouseEvent;
839 if (!pWindow)
840 return false;
842 if (!pEvent)
843 return false;
845 aMouseEvent.mnTime = tools::Time::GetSystemTicks();
846 aMouseEvent.mnX = pEvent->GetPosPixel().X();
847 aMouseEvent.mnY = pEvent->GetPosPixel().Y();
848 aMouseEvent.mnCode = pEvent->GetButtons() | pEvent->GetModifier();
850 switch (nEvent)
852 case VclEventId::WindowMouseMove:
853 aMouseEvent.mnButton = 0;
854 bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEMOVE, false,
855 aMouseEvent.mnX, aMouseEvent.mnY,
856 aMouseEvent.mnTime, aMouseEvent.mnCode,
857 ImplGetMouseMoveMode(&aMouseEvent),
858 pEvent->GetClicks());
859 break;
861 case VclEventId::WindowMouseButtonDown:
862 aMouseEvent.mnButton = pEvent->GetButtons();
863 bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONDOWN, false,
864 aMouseEvent.mnX, aMouseEvent.mnY,
865 aMouseEvent.mnTime,
866 #ifdef MACOSX
867 aMouseEvent.mnButton |
868 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
869 #else
870 aMouseEvent.mnButton |
871 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
872 #endif
873 ImplGetMouseButtonMode(&aMouseEvent),
874 pEvent->GetClicks());
875 break;
877 case VclEventId::WindowMouseButtonUp:
878 aMouseEvent.mnButton = pEvent->GetButtons();
879 bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONUP, false,
880 aMouseEvent.mnX, aMouseEvent.mnY,
881 aMouseEvent.mnTime,
882 #ifdef MACOSX
883 aMouseEvent.mnButton |
884 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
885 #else
886 aMouseEvent.mnButton |
887 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
888 #endif
889 ImplGetMouseButtonMode(&aMouseEvent),
890 pEvent->GetClicks());
891 break;
893 default:
894 SAL_WARN( "vcl.layout", "Application::HandleMouseEvent unknown event (" << static_cast<int>(nEvent) << ")" );
895 break;
898 return bSuccess;
902 ImplSVEvent* Application::PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent )
904 const SolarMutexGuard aGuard;
905 ImplSVEvent * nEventId = nullptr;
907 if( pWin && pMouseEvent )
909 Point aTransformedPos( pMouseEvent->GetPosPixel() );
911 // LOK uses (0, 0) as the origin of all windows; don't offset.
912 if (!comphelper::LibreOfficeKit::isActive())
914 aTransformedPos.AdjustX(pWin->GetOutOffXPixel());
915 aTransformedPos.AdjustY(pWin->GetOutOffYPixel());
918 const MouseEvent aTransformedEvent( aTransformedPos, pMouseEvent->GetClicks(), pMouseEvent->GetMode(),
919 pMouseEvent->GetButtons(), pMouseEvent->GetModifier() );
921 std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, aTransformedEvent ));
923 nEventId = PostUserEvent(
924 LINK( nullptr, Application, PostEventHandler ),
925 pPostEventData.get() );
927 if( nEventId )
929 pPostEventData->mnEventId = nEventId;
930 ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
934 return nEventId;
938 IMPL_STATIC_LINK( Application, PostEventHandler, void*, pCallData, void )
940 const SolarMutexGuard aGuard;
941 ImplPostEventData* pData = static_cast< ImplPostEventData * >( pCallData );
942 const void* pEventData;
943 SalEvent nEvent;
944 ImplSVEvent * const nEventId = pData->mnEventId;
946 switch( pData->mnEvent )
948 case VclEventId::WindowMouseMove:
949 nEvent = SalEvent::ExternalMouseMove;
950 pEventData = &pData->maMouseEvent;
951 break;
953 case VclEventId::WindowMouseButtonDown:
954 nEvent = SalEvent::ExternalMouseButtonDown;
955 pEventData = &pData->maMouseEvent;
956 break;
958 case VclEventId::WindowMouseButtonUp:
959 nEvent = SalEvent::ExternalMouseButtonUp;
960 pEventData = &pData->maMouseEvent;
961 break;
963 case VclEventId::WindowKeyInput:
964 nEvent = SalEvent::ExternalKeyInput;
965 pEventData = &pData->maKeyEvent;
966 break;
968 case VclEventId::WindowKeyUp:
969 nEvent = SalEvent::ExternalKeyUp;
970 pEventData = &pData->maKeyEvent;
971 break;
973 case VclEventId::WindowGestureEvent:
974 nEvent = SalEvent::ExternalGesture;
975 pEventData = &pData->maGestureEvent;
976 break;
978 default:
979 nEvent = SalEvent::NONE;
980 pEventData = nullptr;
981 break;
984 if( pData->mpWin && pData->mpWin->mpWindowImpl->mpFrameWindow && pEventData )
985 ImplWindowFrameProc( pData->mpWin->mpWindowImpl->mpFrameWindow.get(), nEvent, pEventData );
987 // remove this event from list of posted events, watch for destruction of internal data
988 auto svdata = ImplGetSVData();
989 ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
991 while( aIter != svdata->maAppData.maPostedEventList.end() )
993 if( nEventId == (*aIter).second->mnEventId )
995 delete (*aIter).second;
996 aIter = svdata->maAppData.maPostedEventList.erase( aIter );
998 else
999 ++aIter;
1003 void Application::RemoveMouseAndKeyEvents( vcl::Window* pWin )
1005 const SolarMutexGuard aGuard;
1007 // remove all events for specific window, watch for destruction of internal data
1008 auto svdata = ImplGetSVData();
1009 ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
1011 while( aIter != svdata->maAppData.maPostedEventList.end() )
1013 if( pWin == (*aIter).first )
1015 if( (*aIter).second->mnEventId )
1016 RemoveUserEvent( (*aIter).second->mnEventId );
1018 delete (*aIter).second;
1019 aIter = svdata->maAppData.maPostedEventList.erase( aIter );
1021 else
1022 ++aIter;
1026 ImplSVEvent * Application::PostUserEvent( const Link<void*,void>& rLink, void* pCaller,
1027 bool bReferenceLink )
1029 vcl::Window* pDefWindow = ImplGetDefaultWindow();
1030 if ( pDefWindow == nullptr )
1031 return nullptr;
1033 std::unique_ptr<ImplSVEvent> pSVEvent(new ImplSVEvent);
1034 pSVEvent->mpData = pCaller;
1035 pSVEvent->maLink = rLink;
1036 pSVEvent->mpWindow = nullptr;
1037 pSVEvent->mbCall = true;
1038 if (bReferenceLink)
1040 SolarMutexGuard aGuard;
1041 pSVEvent->mpInstanceRef = static_cast<vcl::Window *>(rLink.GetInstance());
1044 auto pTmpEvent = pSVEvent.get();
1045 if (!pDefWindow->ImplGetFrame()->PostEvent( std::move(pSVEvent) ))
1046 return nullptr;
1047 return pTmpEvent;
1050 void Application::RemoveUserEvent( ImplSVEvent * nUserEvent )
1052 if(nUserEvent)
1054 SAL_WARN_IF( nUserEvent->mpWindow, "vcl",
1055 "Application::RemoveUserEvent(): Event is send to a window" );
1056 SAL_WARN_IF( !nUserEvent->mbCall, "vcl",
1057 "Application::RemoveUserEvent(): Event is already removed" );
1059 nUserEvent->mpWindow.clear();
1060 nUserEvent->mpInstanceRef.clear();
1061 nUserEvent->mbCall = false;
1065 vcl::Window* Application::GetFocusWindow()
1067 return ImplGetSVData()->mpWinData->mpFocusWin;
1070 OutputDevice* Application::GetDefaultDevice()
1072 vcl::Window* pWindow = ImplGetDefaultWindow();
1073 if (pWindow != nullptr)
1075 return pWindow->GetOutDev();
1077 else
1079 return nullptr;
1083 basegfx::SystemDependentDataManager& Application::GetSystemDependentDataManager()
1085 return ImplGetSystemDependentDataManager();
1088 vcl::Window* Application::GetFirstTopLevelWindow()
1090 ImplSVData* pSVData = ImplGetSVData();
1091 return pSVData->maFrameData.mpFirstFrame;
1094 vcl::Window* Application::GetNextTopLevelWindow( vcl::Window const * pWindow )
1096 return pWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1099 tools::Long Application::GetTopWindowCount()
1101 tools::Long nRet = 0;
1102 ImplSVData* pSVData = ImplGetSVData();
1103 vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
1104 while( pWin )
1106 if( pWin->ImplGetWindow()->IsTopWindow() )
1107 nRet++;
1108 pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1110 return nRet;
1113 vcl::Window* Application::GetTopWindow( tools::Long nIndex )
1115 tools::Long nIdx = 0;
1116 ImplSVData* pSVData = ImplGetSVData();
1117 vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
1118 while( pWin )
1120 if( pWin->ImplGetWindow()->IsTopWindow() )
1122 if( nIdx == nIndex )
1123 return pWin->ImplGetWindow();
1124 else
1125 nIdx++;
1127 pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1129 return nullptr;
1132 vcl::Window* Application::GetActiveTopWindow()
1134 vcl::Window *pWin = ImplGetSVData()->mpWinData->mpFocusWin;
1135 while( pWin )
1137 if( pWin->IsTopWindow() )
1138 return pWin;
1139 pWin = pWin->mpWindowImpl->mpParent;
1141 return nullptr;
1144 void Application::SetAppName( const OUString& rUniqueName )
1146 ImplSVData* pSVData = ImplGetSVData();
1147 pSVData->maAppData.mxAppName = rUniqueName;
1150 OUString Application::GetAppName()
1152 ImplSVData* pSVData = ImplGetSVData();
1153 if ( pSVData->maAppData.mxAppName )
1154 return *(pSVData->maAppData.mxAppName);
1155 else
1156 return OUString();
1159 enum {hwAll=0, hwEnv=1, hwUI=2};
1161 static OUString Localize(TranslateId aId, const bool bLocalize)
1163 if (bLocalize)
1164 return VclResId(aId);
1165 else
1166 return Translate::get(aId, Translate::Create("vcl", LanguageTag("en-US")));
1169 OUString Application::GetOSVersion()
1171 ImplSVData* pSVData = ImplGetSVData();
1172 OUString aVersion;
1173 if (pSVData && pSVData->mpDefInst)
1174 aVersion = pSVData->mpDefInst->getOSVersion();
1175 else
1176 aVersion = "-";
1177 return aVersion;
1180 OUString Application::GetHWOSConfInfo(const int bSelection, const bool bLocalize)
1182 OUStringBuffer aDetails;
1184 const auto appendDetails = [&aDetails](std::u16string_view sep, auto&& val) {
1185 if (!aDetails.isEmpty() && !sep.empty())
1186 aDetails.append(sep);
1187 aDetails.append(std::move(val));
1190 if (bSelection != hwUI) {
1191 appendDetails(u"; ", Localize(SV_APP_CPUTHREADS, bLocalize)
1192 + OUString::number(std::thread::hardware_concurrency()));
1194 OUString aVersion = GetOSVersion();
1196 appendDetails(u"; ", Localize(SV_APP_OSVERSION, bLocalize) + aVersion);
1199 if (bSelection != hwEnv) {
1200 appendDetails(u"; ", Localize(SV_APP_UIRENDER, bLocalize));
1201 #if HAVE_FEATURE_SKIA
1202 if ( SkiaHelper::isVCLSkiaEnabled() )
1204 switch(SkiaHelper::renderMethodToUse())
1206 case SkiaHelper::RenderVulkan:
1207 appendDetails(u"", Localize(SV_APP_SKIA_VULKAN, bLocalize));
1208 break;
1209 case SkiaHelper::RenderMetal:
1210 appendDetails(u"", Localize(SV_APP_SKIA_METAL, bLocalize));
1211 break;
1212 case SkiaHelper::RenderRaster:
1213 appendDetails(u"", Localize(SV_APP_SKIA_RASTER, bLocalize));
1214 break;
1217 else
1218 #endif
1219 appendDetails(u"", Localize(SV_APP_DEFAULT, bLocalize));
1221 #if (defined LINUX || defined _WIN32 || defined MACOSX || defined __FreeBSD__ || defined EMSCRIPTEN)
1222 appendDetails(u"; ", SV_APP_VCLBACKEND + GetToolkitName());
1223 #endif
1226 return aDetails.makeStringAndClear();
1229 void Application::SetDisplayName( const OUString& rName )
1231 ImplSVData* pSVData = ImplGetSVData();
1232 pSVData->maAppData.mxDisplayName = rName;
1235 OUString Application::GetDisplayName()
1237 ImplSVData* pSVData = ImplGetSVData();
1238 if ( pSVData->maAppData.mxDisplayName )
1239 return *(pSVData->maAppData.mxDisplayName);
1240 else if (pSVData->maFrameData.mpAppWin)
1241 return pSVData->maFrameData.mpAppWin->GetText();
1242 else
1243 return OUString();
1246 unsigned int Application::GetScreenCount()
1248 SalSystem* pSys = ImplGetSalSystem();
1249 return pSys ? pSys->GetDisplayScreenCount() : 0;
1252 bool Application::IsUnifiedDisplay()
1254 SalSystem* pSys = ImplGetSalSystem();
1255 return pSys == nullptr || pSys->IsUnifiedDisplay();
1258 unsigned int Application::GetDisplayBuiltInScreen()
1260 SalSystem* pSys = ImplGetSalSystem();
1261 return pSys ? pSys->GetDisplayBuiltInScreen() : 0;
1264 unsigned int Application::GetDisplayExternalScreen()
1266 // This is really unpleasant, in theory we could have multiple
1267 // external displays etc.
1268 int nExternal(0);
1269 switch (GetDisplayBuiltInScreen())
1271 case 0:
1272 nExternal = 1;
1273 break;
1274 case 1:
1275 nExternal = 0;
1276 break;
1277 default:
1278 // When the built-in display is neither 0 nor 1
1279 // then place the full-screen presentation on the
1280 // first available screen.
1281 nExternal = 0;
1282 break;
1284 return nExternal;
1287 tools::Rectangle Application::GetScreenPosSizePixel( unsigned int nScreen )
1289 SalSystem* pSys = ImplGetSalSystem();
1290 if (!pSys)
1292 SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " failed");
1293 assert(false);
1294 return tools::Rectangle();
1296 tools::Rectangle aRect = pSys->GetDisplayScreenPosSizePixel(nScreen);
1297 if (aRect.GetHeight() == 0)
1298 SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " returned 0 height.");
1299 return aRect;
1302 namespace {
1303 tools::Long calcDistSquare( const Point& i_rPoint, const tools::Rectangle& i_rRect )
1305 const Point aRectCenter( (i_rRect.Left() + i_rRect.Right())/2,
1306 (i_rRect.Top() + i_rRect.Bottom())/ 2 );
1307 const tools::Long nDX = aRectCenter.X() - i_rPoint.X();
1308 const tools::Long nDY = aRectCenter.Y() - i_rPoint.Y();
1309 return nDX*nDX + nDY*nDY;
1313 unsigned int Application::GetBestScreen( const tools::Rectangle& i_rRect )
1315 if( !IsUnifiedDisplay() )
1316 return GetDisplayBuiltInScreen();
1318 const unsigned int nScreens = GetScreenCount();
1319 unsigned int nBestMatchScreen = 0;
1320 unsigned long nOverlap = 0;
1321 for( unsigned int i = 0; i < nScreens; i++ )
1323 const tools::Rectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
1324 // if a screen contains the rectangle completely it is obviously the best screen
1325 if( aCurScreenRect.Contains( i_rRect ) )
1326 return i;
1327 // next the screen which contains most of the area of the rect is the best
1328 tools::Rectangle aIntersection( aCurScreenRect.GetIntersection( i_rRect ) );
1329 if( ! aIntersection.IsEmpty() )
1331 const unsigned long nCurOverlap( aIntersection.GetWidth() * aIntersection.GetHeight() );
1332 if( nCurOverlap > nOverlap )
1334 nOverlap = nCurOverlap;
1335 nBestMatchScreen = i;
1339 if( nOverlap > 0 )
1340 return nBestMatchScreen;
1342 // finally the screen which center is nearest to the rect is the best
1343 const Point aCenter( (i_rRect.Left() + i_rRect.Right())/2,
1344 (i_rRect.Top() + i_rRect.Bottom())/2 );
1345 tools::Long nDist = std::numeric_limits<tools::Long>::max();
1346 for( unsigned int i = 0; i < nScreens; i++ )
1348 const tools::Rectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
1349 const tools::Long nCurDist( calcDistSquare( aCenter, aCurScreenRect ) );
1350 if( nCurDist < nDist )
1352 nBestMatchScreen = i;
1353 nDist = nCurDist;
1356 return nBestMatchScreen;
1359 bool Application::InsertAccel( Accelerator* pAccel )
1361 ImplSVData* pSVData = ImplGetSVData();
1363 if ( !pSVData->maAppData.mpAccelMgr )
1364 pSVData->maAppData.mpAccelMgr = new ImplAccelManager();
1365 return pSVData->maAppData.mpAccelMgr->InsertAccel( pAccel );
1368 void Application::RemoveAccel( Accelerator const * pAccel )
1370 ImplSVData* pSVData = ImplGetSVData();
1372 if ( pSVData->maAppData.mpAccelMgr )
1373 pSVData->maAppData.mpAccelMgr->RemoveAccel( pAccel );
1376 void Application::SetHelp( Help* pHelp )
1378 ImplGetSVData()->maAppData.mpHelp = pHelp;
1381 void Application::UpdateMainThread()
1383 ImplSVData* pSVData = ImplGetSVData();
1384 if (pSVData && pSVData->mpDefInst)
1385 pSVData->mpDefInst->updateMainThread();
1388 Help* Application::GetHelp()
1390 return ImplGetSVData()->maAppData.mpHelp;
1393 OUString Application::GetToolkitName()
1395 ImplSVData* pSVData = ImplGetSVData();
1396 if ( pSVData->maAppData.mxToolkitName )
1397 return *(pSVData->maAppData.mxToolkitName);
1398 else
1399 return OUString();
1402 vcl::Window* Dialog::GetDefDialogParent()
1404 ImplSVData* pSVData = ImplGetSVData();
1405 // find some useful dialog parent
1407 // always use the topmost parent of the candidate
1408 // window to avoid using dialogs or floaters
1409 // as DefDialogParent
1411 // current focus frame
1412 vcl::Window *pWin = pSVData->mpWinData->mpFocusWin;
1413 if (pWin && !pWin->IsMenuFloatingWindow())
1415 while (pWin->mpWindowImpl && pWin->mpWindowImpl->mpParent)
1416 pWin = pWin->mpWindowImpl->mpParent;
1418 // check for corrupted window hierarchy, #122232#, may be we now crash somewhere else
1419 if (!pWin->mpWindowImpl)
1421 OSL_FAIL( "Window hierarchy corrupted!" );
1422 pSVData->mpWinData->mpFocusWin = nullptr; // avoid further access
1423 return nullptr;
1426 if ((pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0)
1428 return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1432 // last active application frame
1433 pWin = pSVData->maFrameData.mpActiveApplicationFrame;
1434 if (pWin)
1436 return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1439 // first visible top window (may be totally wrong...)
1440 pWin = pSVData->maFrameData.mpFirstFrame;
1441 while (pWin)
1443 if( pWin->ImplGetWindow()->IsTopWindow() &&
1444 pWin->mpWindowImpl->mbReallyVisible &&
1445 (pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0
1448 while( pWin->mpWindowImpl->mpParent )
1449 pWin = pWin->mpWindowImpl->mpParent;
1450 return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1452 pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1455 // use the desktop
1456 return nullptr;
1459 weld::Window* Application::GetDefDialogParent()
1461 vcl::Window* pWindow = Dialog::GetDefDialogParent();
1462 return pWindow ? pWindow->GetFrameWeld() : nullptr;
1465 DialogCancelMode Application::GetDialogCancelMode()
1467 return ImplGetSVData()->maAppData.meDialogCancel;
1470 void Application::SetDialogCancelMode( DialogCancelMode mode )
1472 ImplGetSVData()->maAppData.meDialogCancel = mode;
1475 bool Application::IsDialogCancelEnabled()
1477 return ImplGetSVData()->maAppData.meDialogCancel != DialogCancelMode::Off;
1480 void Application::SetSystemWindowMode( SystemWindowFlags nMode )
1482 ImplGetSVData()->maAppData.mnSysWinMode = nMode;
1485 SystemWindowFlags Application::GetSystemWindowMode()
1487 return ImplGetSVData()->maAppData.mnSysWinMode;
1490 css::uno::Reference< css::awt::XToolkit > Application::GetVCLToolkit()
1492 css::uno::Reference< css::awt::XToolkit > xT;
1493 UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
1494 if ( pWrapper )
1495 xT = pWrapper->GetVCLToolkit();
1496 return xT;
1499 #ifdef DISABLE_DYNLOADING
1501 extern "C" { UnoWrapperBase* CreateUnoWrapper(); }
1503 #else
1505 extern "C" { static void thisModule() {} }
1507 #endif
1509 UnoWrapperBase* UnoWrapperBase::GetUnoWrapper( bool bCreateIfNotExist )
1511 ImplSVData* pSVData = ImplGetSVData();
1512 static bool bAlreadyTriedToCreate = false;
1513 if ( !pSVData->mpUnoWrapper && bCreateIfNotExist && !bAlreadyTriedToCreate )
1515 #ifndef DISABLE_DYNLOADING
1516 osl::Module aTkLib;
1517 aTkLib.loadRelative(&thisModule, TK_DLL_NAME);
1518 if (aTkLib.is())
1520 FN_TkCreateUnoWrapper fnCreateWrapper = reinterpret_cast<FN_TkCreateUnoWrapper>(aTkLib.getFunctionSymbol("CreateUnoWrapper"));
1521 if ( fnCreateWrapper )
1523 pSVData->mpUnoWrapper = fnCreateWrapper();
1525 aTkLib.release();
1527 SAL_WARN_IF( !pSVData->mpUnoWrapper, "vcl", "UnoWrapper could not be created!" );
1528 #else
1529 pSVData->mpUnoWrapper = CreateUnoWrapper();
1530 #endif
1531 bAlreadyTriedToCreate = true;
1533 return pSVData->mpUnoWrapper;
1536 void UnoWrapperBase::SetUnoWrapper( UnoWrapperBase* pWrapper )
1538 ImplSVData* pSVData = ImplGetSVData();
1539 SAL_WARN_IF( pSVData->mpUnoWrapper, "vcl", "SetUnoWrapper: Wrapper already exists" );
1540 pSVData->mpUnoWrapper = pWrapper;
1543 css::uno::Reference< css::awt::XDisplayConnection > Application::GetDisplayConnection()
1545 ImplSVData* pSVData = ImplGetSVData();
1547 if( !pSVData->mxDisplayConnection.is() )
1549 pSVData->mxDisplayConnection.set( new vcl::DisplayConnectionDispatch );
1550 pSVData->mxDisplayConnection->start();
1553 return pSVData->mxDisplayConnection;
1556 void Application::SetFilterHdl( const Link<ConvertData&,bool>& rLink )
1558 ImplGetSVData()->maGDIData.mxGrfConverter->SetFilterHdl( rLink );
1561 const LocaleDataWrapper& Application::GetAppLocaleDataWrapper()
1563 return GetSettings().GetLocaleDataWrapper();
1566 void Application::EnableHeadlessMode( bool dialogsAreFatal )
1568 DialogCancelMode eNewMode = dialogsAreFatal ? DialogCancelMode::Fatal : DialogCancelMode::Silent;
1569 DialogCancelMode eOldMode = GetDialogCancelMode();
1570 assert(eOldMode == DialogCancelMode::Off || GetDialogCancelMode() == eNewMode);
1571 if (eOldMode != eNewMode)
1572 SetDialogCancelMode( eNewMode );
1575 bool Application::IsHeadlessModeEnabled()
1577 return IsDialogCancelEnabled() || comphelper::LibreOfficeKit::isActive();
1580 void Application::EnableBitmapRendering()
1582 ImplGetSVData()->maAppData.mbRenderToBitmaps = true;
1585 bool Application::IsBitmapRendering()
1587 return ImplGetSVData()->maAppData.mbRenderToBitmaps;
1590 void Application::EnableConsoleOnly()
1592 EnableHeadlessMode(true);
1593 EnableBitmapRendering();
1596 static bool bSafeMode = false;
1598 bool Application::IsSafeModeEnabled()
1600 return bSafeMode;
1603 void Application::EnableSafeMode()
1605 bSafeMode = true;
1608 void Application::ShowNativeErrorBox(const OUString& sTitle ,
1609 const OUString& sMessage)
1611 int btn = ImplGetSalSystem()->ShowNativeMessageBox(
1612 sTitle,
1613 sMessage);
1614 if (btn != SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK) {
1615 SAL_WARN( "vcl", "ShowNativeMessageBox returned " << btn);
1619 const OUString& Application::GetDesktopEnvironment()
1621 if (IsHeadlessModeEnabled())
1623 static const OUString aNone("none");
1624 return aNone;
1626 else
1627 return SalGetDesktopEnvironment();
1630 void Application::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService)
1632 ImplSVData* pSVData = ImplGetSVData();
1633 pSVData->mpDefInst->AddToRecentDocumentList(rFileUrl, rMimeType, rDocumentService);
1636 bool InitAccessBridge()
1638 // Disable MSAA bridge on UNIX
1639 #if defined UNX
1640 return true;
1641 #else
1642 bool bRet = ImplInitAccessBridge();
1644 if( !bRet )
1646 // disable accessibility if the user chooses to continue
1647 AllSettings aSettings = Application::GetSettings();
1648 MiscSettings aMisc = aSettings.GetMiscSettings();
1649 aMisc.SetEnableATToolSupport( false );
1650 aSettings.SetMiscSettings( aMisc );
1651 Application::SetSettings( aSettings );
1653 return bRet;
1654 #endif // !UNX
1657 // MT: AppEvent was in oldsv.cxx, but is still needed...
1658 void Application::AppEvent( const ApplicationEvent& /*rAppEvent*/ )
1662 bool Application::hasNativeFileSelection()
1664 ImplSVData* pSVData = ImplGetSVData();
1665 return pSVData->mpDefInst->hasNativeFileSelection();
1668 Reference< ui::dialogs::XFilePicker2 >
1669 Application::createFilePicker( const Reference< uno::XComponentContext >& xSM )
1671 ImplSVData* pSVData = ImplGetSVData();
1672 return pSVData->mpDefInst->createFilePicker( xSM );
1675 Reference< ui::dialogs::XFolderPicker2 >
1676 Application::createFolderPicker( const Reference< uno::XComponentContext >& xSM )
1678 ImplSVData* pSVData = ImplGetSVData();
1679 return pSVData->mpDefInst->createFolderPicker( xSM );
1682 void Application::setDeInitHook(Link<LinkParamNone*,void> const & hook) {
1683 ImplSVData * pSVData = ImplGetSVData();
1684 assert(!pSVData->maDeInitHook.IsSet());
1685 pSVData->maDeInitHook = hook;
1686 // Fake this for VCLXToolkit ctor instantiated from
1687 // postprocess/CppunitTest_services.mk:
1688 pSVData->maAppData.mbInAppMain = true;
1691 namespace vcl::lok {
1693 void registerPollCallbacks(
1694 LibreOfficeKitPollCallback pPollCallback,
1695 LibreOfficeKitWakeCallback pWakeCallback,
1696 void *pData) {
1698 ImplSVData * pSVData = ImplGetSVData();
1699 if (pSVData)
1701 pSVData->mpPollCallback = pPollCallback;
1702 pSVData->mpWakeCallback = pWakeCallback;
1703 pSVData->mpPollClosure = pData;
1707 void unregisterPollCallbacks()
1709 ImplSVData * pSVData = ImplGetSVData();
1710 if (!pSVData)
1711 return;
1713 // Not hyper-elegant - but in the case of Android & unipoll we need to detach
1714 // this thread from the JVM's clutches to avoid a crash closing document
1715 if (pSVData->mpPollClosure && pSVData->mpDefInst)
1716 pSVData->mpDefInst->releaseMainThread();
1718 // Just set mpPollClosure to null as that is what calling this means, that the callback data
1719 // points to an object that no longer exists. In particular, don't set
1720 // pSVData->mpPollCallback to nullptr as that is used to detect whether Unipoll is in use in
1721 // isUnipoll().
1722 pSVData->mpPollClosure = nullptr;
1725 bool isUnipoll()
1727 ImplSVData * pSVData = ImplGetSVData();
1728 return pSVData && pSVData->mpPollCallback != nullptr;
1731 void numberOfViewsChanged(int count)
1733 if (count == 0)
1734 return;
1735 ImplSVData * pSVData = ImplGetSVData();
1736 auto& rCache = pSVData->maGDIData.maScaleCache;
1737 // Normally the cache size is set to 10, scale according to the number of users.
1738 rCache.setMaxSize(count * 10);
1741 void dumpState(rtl::OStringBuffer &rState)
1743 ImplSVData* pSVData = ImplGetSVData();
1744 if (!pSVData)
1745 return;
1747 rState.append("\nWindows:\t");
1748 rState.append(static_cast<sal_Int32>(Application::GetTopWindowCount()));
1750 vcl::Window *pWin = Application::GetFirstTopLevelWindow();
1751 while (pWin)
1753 tools::JsonWriter props;
1754 pWin->DumpAsPropertyTree(props);
1756 rState.append("\n\tWindow: ");
1757 rState.append(props.finishAndGetAsOString());
1759 pWin = Application::GetNextTopLevelWindow( pWin );
1762 vcl::graphic::Manager::get().dumpState(rState);
1764 pSVData->dumpState(rState);
1767 void trimMemory(int nTarget)
1769 if (nTarget >= 1000)
1771 ImplSVData* pSVData = ImplGetSVData();
1772 if (!pSVData) // shutting down
1773 return;
1774 pSVData->dropCaches();
1775 vcl::graphic::Manager::get().dropCache();
1776 // TODO: ideally - free up any deeper dirtied thread stacks.
1777 // comphelper::ThreadPool::getSharedOptimalPool().shutdown();
1779 // else for now caches re-fill themselves as/when used.
1782 } // namespace lok, namespace vcl
1784 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */