Get the style color and number just once
[LibreOffice.git] / vcl / source / app / svapp.cxx
blob06a21d733177242b904d06c14f094db46510a65d
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>
21 #include <config_version.h>
23 #include <osl/diagnose.h>
24 #include <osl/file.hxx>
25 #include <osl/thread.hxx>
26 #include <osl/module.hxx>
27 #include <rtl/ustrbuf.hxx>
29 #include <sal/log.hxx>
31 #include <tools/debug.hxx>
32 #include <tools/time.hxx>
33 #include <tools/stream.hxx>
34 #include <tools/json_writer.hxx>
36 #include <comphelper/configuration.hxx>
37 #include <unotools/resmgr.hxx>
38 #include <unotools/syslocale.hxx>
39 #include <unotools/syslocaleoptions.hxx>
41 #include <vcl/toolkit/dialog.hxx>
42 #include <vcl/dialoghelper.hxx>
43 #include <vcl/lok.hxx>
44 #include <vcl/toolkit/floatwin.hxx>
45 #include <vcl/settings.hxx>
46 #include <vcl/keycod.hxx>
47 #include <vcl/event.hxx>
48 #include <vcl/vclevent.hxx>
49 #include <vcl/virdev.hxx>
50 #include <vcl/wrkwin.hxx>
51 #include <vcl/svapp.hxx>
52 #include <vcl/cvtgrf.hxx>
53 #include <vcl/toolkit/unowrap.hxx>
54 #include <vcl/timer.hxx>
55 #include <vcl/scheduler.hxx>
56 #include <vcl/skia/SkiaHelper.hxx>
58 #include <dbggui.hxx>
59 #include <salinst.hxx>
60 #include <graphic/Manager.hxx>
61 #include <salframe.hxx>
62 #include <salsys.hxx>
63 #include <svdata.hxx>
64 #include <displayconnectiondispatch.hxx>
65 #include <window.h>
66 #include <accmgr.hxx>
67 #include <strings.hrc>
68 #include <strings.hxx>
69 #if OSL_DEBUG_LEVEL > 0
70 #include <schedulerimpl.hxx>
71 #endif
73 #include <com/sun/star/uno/Reference.h>
74 #include <com/sun/star/awt/XToolkit.hpp>
75 #include <comphelper/lok.hxx>
76 #include <comphelper/threadpool.hxx>
77 #include <comphelper/solarmutex.hxx>
78 #include <osl/process.h>
80 #ifdef DBG_UTIL
81 #include <svl/poolitem.hxx>
82 #include <svl/itemset.hxx>
83 #include <svl/itempool.hxx>
84 #endif
86 #include <cassert>
87 #include <limits>
88 #include <string_view>
89 #include <utility>
90 #include <thread>
92 using namespace ::com::sun::star;
93 using namespace ::com::sun::star::uno;
95 namespace {
96 void InitSettings(ImplSVData* pSVData);
99 // keycodes handled internally by VCL
100 vcl::KeyCode const ReservedKeys[]
102 vcl::KeyCode(KEY_F1,0) , // Help
103 vcl::KeyCode(KEY_F1,KEY_SHIFT) , // Context help
104 vcl::KeyCode(KEY_F2,KEY_SHIFT) , // Activate extended tooltips
105 vcl::KeyCode(KEY_F4,KEY_MOD1) , // Close document
106 vcl::KeyCode(KEY_F4,KEY_MOD2) , // Close document
107 vcl::KeyCode(KEY_F6,0) , // Set focus to next visible subwindow
108 vcl::KeyCode(KEY_F6,KEY_MOD1) , // Set focus to the document canvas/data source
109 vcl::KeyCode(KEY_F6,KEY_SHIFT) , // Set focus to previous subwindow
110 vcl::KeyCode(KEY_F10,0) // Activate the first menu
113 extern "C" {
114 typedef UnoWrapperBase* (*FN_TkCreateUnoWrapper)();
117 struct ImplPostEventData
119 VclPtr<vcl::Window> mpWin;
120 ImplSVEvent * mnEventId;
121 MouseEvent maMouseEvent;
122 VclEventId mnEvent;
123 KeyEvent maKeyEvent;
124 GestureEventPan maGestureEvent;
126 ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent)
127 : mpWin(pWin)
128 , mnEventId(nullptr)
129 , mnEvent(nEvent)
130 , maKeyEvent(rKeyEvent)
132 ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent)
133 : mpWin(pWin)
134 , mnEventId(nullptr)
135 , maMouseEvent(rMouseEvent)
136 , mnEvent(nEvent)
138 ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const GestureEventPan& rGestureEvent)
139 : mpWin(pWin)
140 , mnEventId(nullptr)
141 , mnEvent(nEvent)
142 , maGestureEvent(rGestureEvent)
146 Application* GetpApp()
148 ImplSVData* pSVData = ImplGetSVData();
149 if ( !pSVData )
150 return nullptr;
151 return pSVData->mpApp;
154 Application::Application()
156 // useful for themes at least, perhaps extensions too
157 OUString aVar(u"LIBO_VERSION"_ustr), aValue(u"" LIBO_VERSION_DOTTED ""_ustr);
158 osl_setEnvironment(aVar.pData, aValue.pData);
160 ImplGetSVData()->mpApp = this;
161 m_pCallbackData = nullptr;
162 m_pCallback = nullptr;
165 Application::~Application()
167 ImplDeInitSVData();
168 ImplGetSVData()->mpApp = nullptr;
169 #ifdef DBG_UTIL
170 // Due to
171 // svx/source/dialog/framelinkarray.cxx
172 // class Cell final : public SfxPoolItem
173 // const Cell OBJ_CELL_NONE;
174 // being a static held SfxPoolItem which is not yet de-initialized here
175 // number often is (1), even higher with other modules loaded (like 5).
176 // These get de-allocated reliably in module-deinitializations, so this
177 // is no memory loss. These counters are more to be able to have an eye
178 // on amounts of SfxPoolItems used during office usage and to be able to
179 // detect if an error in future changes may lead to memory losses - these
180 // would show in dramatically higher numbers then immediately
181 SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemCount() << " SfxPoolItems still allocated at shutdown");
182 SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemCount() << " SfxPoolItems were incarnated during runtime");
184 // Same mechanism for SfxItemSet(s)
185 SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxItemSetCount() << " SfxItemSets still allocated at shutdown");
186 SAL_INFO("vcl.items", "ITEM: " << getUsedSfxItemSetCount() << " SfxItemSets were incarnated during runtime");
188 // Same mechanism for PoolItemHolder(s)
189 SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemHolderCount() << " SfxPoolItemHolders still allocated at shutdown");
190 SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemHolderCount() << " SfxPoolItemHolders were incarnated during runtime");
192 // Additional call to list still incarnated SfxPoolItems (under 'svl.items')
193 listAllocatedSfxPoolItems();
195 // List SfxPoolItems with highest RefCounts, these are the best
196 // candidates to add a ItemInstanceManager mechanism
197 listSfxPoolItemsWithHighestUsage(20);
198 listSfxItemSetUsage();
199 #endif
202 int Application::Main()
204 SAL_WARN("vcl", "Application is a base class and should be overridden.");
205 return EXIT_SUCCESS;
208 bool Application::QueryExit()
210 WorkWindow* pAppWin = ImplGetSVData()->maFrameData.mpAppWin;
212 // call the close handler of the application window
213 if ( pAppWin )
214 return pAppWin->Close();
215 else
216 return true;
219 void Application::Shutdown()
223 void Application::Init()
227 void Application::InitFinished()
231 void Application::DeInit()
235 sal_uInt16 Application::GetCommandLineParamCount()
237 return static_cast<sal_uInt16>(osl_getCommandArgCount());
240 OUString Application::GetCommandLineParam( sal_uInt16 nParam )
242 OUString aParam;
243 osl_getCommandArg( nParam, &aParam.pData );
244 return aParam;
247 OUString Application::GetAppFileName()
249 ImplSVData* pSVData = ImplGetSVData();
250 SAL_WARN_IF( !pSVData->maAppData.mxAppFileName, "vcl", "AppFileName should be set to something after SVMain!" );
251 if ( pSVData->maAppData.mxAppFileName )
252 return *pSVData->maAppData.mxAppFileName;
255 * provide a fallback for people without initialized vcl here (like setup
256 * in responsefile mode)
258 OUString aAppFileName;
259 OUString aExeFileName;
260 osl_getExecutableFile(&aExeFileName.pData);
262 // convert path to native file format
263 osl::FileBase::getSystemPathFromFileURL(aExeFileName, aAppFileName);
265 return aAppFileName;
268 void Application::Exception( ExceptionCategory nCategory )
270 switch ( nCategory )
272 // System has precedence (so do nothing)
273 case ExceptionCategory::System:
274 case ExceptionCategory::UserInterface:
275 break;
276 default:
277 Abort(u"Unknown Error"_ustr);
278 break;
282 void Application::Abort( const OUString& rErrorText )
284 //HACK: Dump core iff --norestore command line argument is given (assuming
285 // this process is run by developers who are interested in cores, vs. end
286 // users who are not):
287 #if OSL_DEBUG_LEVEL > 0
288 bool dumpCore = true;
289 #else
290 bool dumpCore = false;
291 sal_uInt16 n = GetCommandLineParamCount();
292 for (sal_uInt16 i = 0; i != n; ++i) {
293 if (GetCommandLineParam(i) == "--norestore") {
294 dumpCore = true;
295 break;
298 #endif
300 SalAbort( rErrorText, dumpCore );
303 size_t Application::GetReservedKeyCodeCount()
305 return SAL_N_ELEMENTS(ReservedKeys);
308 const vcl::KeyCode* Application::GetReservedKeyCode( size_t i )
310 if( i >= GetReservedKeyCodeCount() )
311 return nullptr;
312 else
313 return &ReservedKeys[i];
316 void Application::notifyWindow(vcl::LOKWindowId /*nLOKWindowId*/,
317 const OUString& /*rAction*/,
318 const std::vector<vcl::LOKPayloadItem>& /*rPayload = std::vector<LOKPayloadItem>()*/) const
320 SAL_WARN("vcl", "Invoked not implemented method: Application::notifyWindow");
323 OString Application::dumpNotifyState() const
325 SAL_WARN("vcl", "Invoked not implemented method: Application::dumpNotifyState");
326 return "notimpl"_ostr;
329 void Application::libreOfficeKitViewCallback(int nType, const OString& pPayload) const
331 if (!comphelper::LibreOfficeKit::isActive())
332 return;
334 if (m_pCallback)
336 m_pCallback(nType, pPayload.getStr(), m_pCallbackData);
340 void Application::notifyInvalidation(tools::Rectangle const* /*pRect*/) const
344 void Application::Execute()
346 ImplSVData* pSVData = ImplGetSVData();
347 pSVData->maAppData.mbInAppExecute = true;
348 pSVData->maAppData.mbAppQuit = false;
350 int nExitCode = 0;
351 if (!pSVData->mpDefInst->DoExecute(nExitCode))
353 if (Application::IsUseSystemEventLoop())
355 SAL_WARN("vcl.schedule", "Can't omit DoExecute when running on system event loop!");
356 std::abort();
358 while (!pSVData->maAppData.mbAppQuit)
360 Application::Yield();
361 SolarMutexReleaser releaser; // Give a chance for the waiting threads to lock the mutex
362 pSVData->m_inExecuteCondtion.set();
366 pSVData->maAppData.mbInAppExecute = false;
368 GetpApp()->Shutdown();
371 static bool ImplYield(bool i_bWait, bool i_bAllEvents)
373 ImplSVData* pSVData = ImplGetSVData();
375 SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
376 ": " << (i_bAllEvents ? "all events" : "one event"));
378 // there's a data race here on WNT only because ImplYield may be
379 // called without SolarMutex; but the only remaining use of mnDispatchLevel
380 // is in OSX specific code
381 pSVData->maAppData.mnDispatchLevel++;
383 // do not wait for events if application was already quit; in that
384 // case only dispatch events already available
385 bool bProcessedEvent = pSVData->mpDefInst->DoYield(
386 i_bWait && !pSVData->maAppData.mbAppQuit, i_bAllEvents );
388 pSVData->maAppData.mnDispatchLevel--;
390 DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
392 SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent );
393 return bProcessedEvent;
396 bool Application::Reschedule( bool i_bAllEvents )
398 static const bool bAbort = Application::IsUseSystemEventLoop();
399 if (bAbort)
401 SAL_WARN("vcl.schedule", "Application::Reschedule(" << i_bAllEvents << ")");
402 return false;
404 return ImplYield(false, i_bAllEvents);
407 bool Application::IsUseSystemEventLoop()
409 return ImplGetSVData()->maAppData.m_bUseSystemLoop;
412 void Scheduler::ProcessEventsToIdle()
414 #if OSL_DEBUG_LEVEL > 0
415 const ImplSVData* pSVData = ImplGetSVData();
416 if (pSVData->mpDefInst->IsMainThread())
417 assert(pSVData->maSchedCtx.mnIdlesLockCount == 0);
418 #endif
419 int nSanity = 1;
420 while (ImplYield(false, true))
422 if (0 == ++nSanity % 1000)
424 SAL_WARN("vcl.schedule", "ProcessEventsToIdle: " << nSanity);
427 #if OSL_DEBUG_LEVEL > 0
428 // If we yield from a non-main thread we just can guarantee that all idle
429 // events were processed at some point, but our check can't prevent further
430 // processing in the main thread, which may add new events, so skip it.
431 if ( !pSVData->mpDefInst->IsMainThread() )
432 return;
433 for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
435 const ImplSchedulerData* pSchedulerData = pSVData->maSchedCtx.mpFirstSchedulerData[nTaskPriority];
436 while (pSchedulerData)
438 assert(!pSchedulerData->mbInScheduler);
439 if (pSchedulerData->mpTask)
441 Idle *pIdle = dynamic_cast<Idle*>(pSchedulerData->mpTask);
442 if (pIdle && pIdle->IsActive())
444 SAL_WARN("vcl.schedule",
445 "Unprocessed Idle: "
446 << pIdle << " "
447 << (pIdle->GetDebugName() ? pIdle->GetDebugName() : "(nullptr)"));
450 pSchedulerData = pSchedulerData->mpNext;
453 #endif
456 extern "C" {
457 /// used by unit tests that test only via the LOK API
458 SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
460 const SolarMutexGuard aGuard;
461 Scheduler::ProcessEventsToIdle();
465 void Application::Yield()
467 static const bool bAbort = Application::IsUseSystemEventLoop();
468 if (bAbort)
470 SAL_WARN("vcl.schedule", "Application::Yield()");
471 std::abort();
473 ImplYield(true, false);
476 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
478 assert(ImplGetSVData()->maAppData.mbAppQuit);
479 ImplGetSVData()->mpDefInst->DoQuit();
482 void Application::Quit()
484 ImplGetSVData()->maAppData.mbAppQuit = true;
485 Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplQuitMsg ) );
488 comphelper::SolarMutex& Application::GetSolarMutex()
490 ImplSVData* pSVData = ImplGetSVData();
491 return *(pSVData->mpDefInst->GetYieldMutex());
494 bool Application::IsMainThread()
496 return ImplGetSVData()->mnMainThreadId == osl::Thread::getCurrentIdentifier();
499 sal_uInt32 Application::ReleaseSolarMutex()
501 ImplSVData* pSVData = ImplGetSVData();
502 return pSVData->mpDefInst->ReleaseYieldMutex(true);
505 void Application::AcquireSolarMutex( sal_uInt32 nCount )
507 ImplSVData* pSVData = ImplGetSVData();
508 pSVData->mpDefInst->AcquireYieldMutex( nCount );
511 bool Application::IsInMain()
513 ImplSVData* pSVData = ImplGetSVData();
514 return pSVData && pSVData->maAppData.mbInAppMain;
517 bool Application::IsInExecute()
519 return ImplGetSVData()->maAppData.mbInAppExecute;
522 bool Application::IsQuit()
524 return ImplGetSVData()->maAppData.mbAppQuit;
527 bool Application::IsInModalMode()
529 return (ImplGetSVData()->maAppData.mnModalMode != 0);
532 sal_uInt16 Application::GetDispatchLevel()
534 return ImplGetSVData()->maAppData.mnDispatchLevel;
537 bool Application::AnyInput( VclInputFlags nType )
539 return ImplGetSVData()->mpDefInst->AnyInput( nType );
542 sal_uInt64 Application::GetLastInputInterval()
544 return (tools::Time::GetSystemTicks()-ImplGetSVData()->maAppData.mnLastInputTime);
547 bool Application::IsUICaptured()
549 ImplSVData* pSVData = ImplGetSVData();
551 // If mouse was captured, or if in tracking- or in select-mode of a floatingwindow (e.g. menus
552 // or pulldown toolboxes) another window should be created
553 // D&D active !!!
554 return pSVData->mpWinData->mpCaptureWin || pSVData->mpWinData->mpTrackWin
555 || pSVData->mpWinData->mpFirstFloat || nImplSysDialog;
558 void Application::OverrideSystemSettings( AllSettings& /*rSettings*/ )
562 void Application::MergeSystemSettings( AllSettings& rSettings )
564 vcl::Window* pWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
565 if( ! pWindow )
566 pWindow = ImplGetDefaultWindow();
567 if( pWindow )
569 ImplSVData* pSVData = ImplGetSVData();
570 if ( !pSVData->maAppData.mbSettingsInit )
572 // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
573 pWindow->ImplUpdateGlobalSettings( *pSVData->maAppData.mxSettings );
574 pSVData->maAppData.mbSettingsInit = true;
576 // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
577 pWindow->ImplUpdateGlobalSettings( rSettings, false );
581 void Application::SetSettings( const AllSettings& rSettings )
583 const SolarMutexGuard aGuard;
585 ImplSVData* pSVData = ImplGetSVData();
586 if ( !pSVData->maAppData.mxSettings )
588 InitSettings(pSVData);
589 *pSVData->maAppData.mxSettings = rSettings;
591 else
593 AllSettings aOldSettings = *pSVData->maAppData.mxSettings;
594 if (aOldSettings.GetUILanguageTag().getLanguageType() != rSettings.GetUILanguageTag().getLanguageType() &&
595 pSVData->mbResLocaleSet)
597 pSVData->mbResLocaleSet = false;
599 *pSVData->maAppData.mxSettings = rSettings;
600 AllSettingsFlags nChangeFlags = aOldSettings.GetChangeFlags( *pSVData->maAppData.mxSettings );
601 if ( bool(nChangeFlags) )
603 DataChangedEvent aDCEvt( DataChangedEventType::SETTINGS, &aOldSettings, nChangeFlags );
605 // notify data change handler
606 ImplCallEventListenersApplicationDataChanged( &aDCEvt);
608 // Update all windows
609 vcl::Window* pFirstFrame = pSVData->maFrameData.mpFirstFrame;
610 // Reset data that needs to be re-calculated
611 tools::Long nOldDPIX = 0;
612 tools::Long nOldDPIY = 0;
613 if ( pFirstFrame )
615 nOldDPIX = pFirstFrame->GetOutDev()->GetDPIX();
616 nOldDPIY = pFirstFrame->GetOutDev()->GetDPIY();
617 vcl::Window::ImplInitAppFontData(pFirstFrame);
619 vcl::Window* pFrame = pFirstFrame;
620 while ( pFrame )
622 // call UpdateSettings from ClientWindow in order to prevent updating data twice
623 vcl::Window* pClientWin = pFrame;
624 while ( pClientWin->ImplGetClientWindow() )
625 pClientWin = pClientWin->ImplGetClientWindow();
626 pClientWin->UpdateSettings( rSettings, true );
628 vcl::Window* pTempWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
629 while ( pTempWin )
631 // call UpdateSettings from ClientWindow in order to prevent updating data twice
632 pClientWin = pTempWin;
633 while ( pClientWin->ImplGetClientWindow() )
634 pClientWin = pClientWin->ImplGetClientWindow();
635 pClientWin->UpdateSettings( rSettings, true );
636 pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
639 pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
642 // if DPI resolution for screen output was changed set the new resolution for all
643 // screen compatible VirDev's
644 pFirstFrame = pSVData->maFrameData.mpFirstFrame;
645 if ( pFirstFrame )
647 if ( (pFirstFrame->GetOutDev()->GetDPIX() != nOldDPIX) ||
648 (pFirstFrame->GetOutDev()->GetDPIY() != nOldDPIY) )
650 VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
651 while ( pVirDev )
653 if ( pVirDev->mbScreenComp &&
654 (pVirDev->GetDPIX() == nOldDPIX) &&
655 (pVirDev->GetDPIY() == nOldDPIY) )
657 pVirDev->SetDPIX( pFirstFrame->GetOutDev()->GetDPIX() );
658 pVirDev->SetDPIY( pFirstFrame->GetOutDev()->GetDPIY() );
659 if ( pVirDev->IsMapModeEnabled() )
661 MapMode aMapMode = pVirDev->GetMapMode();
662 pVirDev->SetMapMode();
663 pVirDev->SetMapMode( aMapMode );
667 pVirDev = pVirDev->mpNext;
675 const AllSettings& Application::GetSettings()
677 ImplSVData* pSVData = ImplGetSVData();
678 if ( !pSVData->maAppData.mxSettings )
680 InitSettings(pSVData);
683 return *(pSVData->maAppData.mxSettings);
686 namespace {
688 void InitSettings(ImplSVData* pSVData)
690 assert(!pSVData->maAppData.mxSettings && "initialization should not happen twice!");
692 pSVData->maAppData.mxSettings.emplace();
693 if (!comphelper::IsFuzzing())
695 pSVData->maAppData.mpCfgListener = new LocaleConfigurationListener;
696 pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().AddListener( pSVData->maAppData.mpCfgListener );
702 void Application::NotifyAllWindows( DataChangedEvent& rDCEvt )
704 ImplSVData* pSVData = ImplGetSVData();
705 vcl::Window* pFrame = pSVData->maFrameData.mpFirstFrame;
706 while ( pFrame )
708 pFrame->NotifyAllChildren( rDCEvt );
710 vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
711 while ( pSysWin )
713 pSysWin->NotifyAllChildren( rDCEvt );
714 pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
717 pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
721 void Application::ImplCallEventListenersApplicationDataChanged( void* pData )
723 ImplSVData* pSVData = ImplGetSVData();
724 VclWindowEvent aEvent( nullptr, VclEventId::ApplicationDataChanged, pData );
726 pSVData->maAppData.maEventListeners.Call( aEvent );
729 void Application::ImplCallEventListeners( VclSimpleEvent& rEvent )
731 ImplSVData* pSVData = ImplGetSVData();
732 pSVData->maAppData.maEventListeners.Call( rEvent );
735 void Application::AddEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
737 ImplSVData* pSVData = ImplGetSVData();
738 pSVData->maAppData.maEventListeners.addListener( rEventListener );
741 void Application::RemoveEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
743 ImplSVData* pSVData = ImplGetSVData();
744 pSVData->maAppData.maEventListeners.removeListener( rEventListener );
747 void Application::AddKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
749 ImplSVData* pSVData = ImplGetSVData();
750 pSVData->maAppData.maKeyListeners.push_back( rKeyListener );
753 void Application::RemoveKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
755 ImplSVData* pSVData = ImplGetSVData();
756 auto & rVec = pSVData->maAppData.maKeyListeners;
757 std::erase(rVec, rKeyListener);
760 bool Application::HandleKey( VclEventId nEvent, vcl::Window *pWin, KeyEvent* pKeyEvent )
762 // let listeners process the key event
763 VclWindowEvent aEvent( pWin, nEvent, static_cast<void *>(pKeyEvent) );
765 ImplSVData* pSVData = ImplGetSVData();
767 if ( pSVData->maAppData.maKeyListeners.empty() )
768 return false;
770 bool bProcessed = false;
771 // Copy the list, because this can be destroyed when calling a Link...
772 std::vector<Link<VclWindowEvent&,bool>> aCopy( pSVData->maAppData.maKeyListeners );
773 for ( const Link<VclWindowEvent&,bool>& rLink : aCopy )
775 if( rLink.Call( aEvent ) )
777 bProcessed = true;
778 break;
781 return bProcessed;
784 ImplSVEvent * Application::PostKeyEvent( VclEventId nEvent, vcl::Window *pWin, KeyEvent const * pKeyEvent )
786 const SolarMutexGuard aGuard;
787 ImplSVEvent * nEventId = nullptr;
789 if( pWin && pKeyEvent )
791 std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, *pKeyEvent ));
793 nEventId = PostUserEvent(
794 LINK( nullptr, Application, PostEventHandler ),
795 pPostEventData.get() );
797 if( nEventId )
799 pPostEventData->mnEventId = nEventId;
800 ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
804 return nEventId;
807 ImplSVEvent* Application::PostGestureEvent(VclEventId nEvent, vcl::Window* pWin,
808 GestureEventPan const * pGestureEvent)
810 const SolarMutexGuard aGuard;
811 ImplSVEvent * nEventId = nullptr;
813 if (pWin && pGestureEvent)
815 Point aTransformedPosition(pGestureEvent->mnX, pGestureEvent->mnY);
817 aTransformedPosition.AdjustX(pWin->GetOutOffXPixel());
818 aTransformedPosition.AdjustY(pWin->GetOutOffYPixel());
820 const GestureEventPan aGestureEvent(
821 sal_Int32(aTransformedPosition.X()),
822 sal_Int32(aTransformedPosition.Y()),
823 pGestureEvent->meEventType,
824 pGestureEvent->mnOffset,
825 pGestureEvent->meOrientation
828 std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData(nEvent, pWin, aGestureEvent));
830 nEventId = PostUserEvent(
831 LINK( nullptr, Application, PostEventHandler ),
832 pPostEventData.get());
834 if (nEventId)
836 pPostEventData->mnEventId = nEventId;
837 ImplGetSVData()->maAppData.maPostedEventList.emplace_back(pWin, pPostEventData.release());
841 return nEventId;
844 bool Application::LOKHandleMouseEvent(VclEventId nEvent, vcl::Window* pWindow, const MouseEvent* pEvent)
846 bool bSuccess = false;
847 SalMouseEvent aMouseEvent;
849 if (!pWindow)
850 return false;
852 if (!pEvent)
853 return false;
855 aMouseEvent.mnTime = tools::Time::GetSystemTicks();
856 aMouseEvent.mnX = pEvent->GetPosPixel().X();
857 aMouseEvent.mnY = pEvent->GetPosPixel().Y();
858 aMouseEvent.mnCode = pEvent->GetButtons() | pEvent->GetModifier();
860 switch (nEvent)
862 case VclEventId::WindowMouseMove:
863 aMouseEvent.mnButton = 0;
864 bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEMOVE, false,
865 aMouseEvent.mnX, aMouseEvent.mnY,
866 aMouseEvent.mnTime, aMouseEvent.mnCode,
867 ImplGetMouseMoveMode(&aMouseEvent),
868 pEvent->GetClicks());
869 break;
871 case VclEventId::WindowMouseButtonDown:
872 aMouseEvent.mnButton = pEvent->GetButtons();
873 bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONDOWN, false,
874 aMouseEvent.mnX, aMouseEvent.mnY,
875 aMouseEvent.mnTime,
876 #ifdef MACOSX
877 aMouseEvent.mnButton |
878 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
879 #else
880 aMouseEvent.mnButton |
881 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
882 #endif
883 ImplGetMouseButtonMode(&aMouseEvent),
884 pEvent->GetClicks());
885 break;
887 case VclEventId::WindowMouseButtonUp:
888 aMouseEvent.mnButton = pEvent->GetButtons();
889 bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONUP, false,
890 aMouseEvent.mnX, aMouseEvent.mnY,
891 aMouseEvent.mnTime,
892 #ifdef MACOSX
893 aMouseEvent.mnButton |
894 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
895 #else
896 aMouseEvent.mnButton |
897 (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
898 #endif
899 ImplGetMouseButtonMode(&aMouseEvent),
900 pEvent->GetClicks());
901 break;
903 default:
904 SAL_WARN( "vcl.layout", "Application::HandleMouseEvent unknown event (" << static_cast<int>(nEvent) << ")" );
905 break;
908 return bSuccess;
912 ImplSVEvent* Application::PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent )
914 const SolarMutexGuard aGuard;
915 ImplSVEvent * nEventId = nullptr;
917 if( pWin && pMouseEvent )
919 Point aTransformedPos( pMouseEvent->GetPosPixel() );
921 // LOK uses (0, 0) as the origin of all windows; don't offset.
922 if (!comphelper::LibreOfficeKit::isActive())
924 aTransformedPos.AdjustX(pWin->GetOutOffXPixel());
925 aTransformedPos.AdjustY(pWin->GetOutOffYPixel());
928 const MouseEvent aTransformedEvent( aTransformedPos, pMouseEvent->GetClicks(), pMouseEvent->GetMode(),
929 pMouseEvent->GetButtons(), pMouseEvent->GetModifier() );
931 std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, aTransformedEvent ));
933 nEventId = PostUserEvent(
934 LINK( nullptr, Application, PostEventHandler ),
935 pPostEventData.get() );
937 if( nEventId )
939 pPostEventData->mnEventId = nEventId;
940 ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
944 return nEventId;
948 IMPL_STATIC_LINK( Application, PostEventHandler, void*, pCallData, void )
950 const SolarMutexGuard aGuard;
951 ImplPostEventData* pData = static_cast< ImplPostEventData * >( pCallData );
952 const void* pEventData;
953 SalEvent nEvent;
954 ImplSVEvent * const nEventId = pData->mnEventId;
956 switch( pData->mnEvent )
958 case VclEventId::WindowMouseMove:
959 nEvent = SalEvent::ExternalMouseMove;
960 pEventData = &pData->maMouseEvent;
961 break;
963 case VclEventId::WindowMouseButtonDown:
964 nEvent = SalEvent::ExternalMouseButtonDown;
965 pEventData = &pData->maMouseEvent;
966 break;
968 case VclEventId::WindowMouseButtonUp:
969 nEvent = SalEvent::ExternalMouseButtonUp;
970 pEventData = &pData->maMouseEvent;
971 break;
973 case VclEventId::WindowKeyInput:
974 nEvent = SalEvent::ExternalKeyInput;
975 pEventData = &pData->maKeyEvent;
976 break;
978 case VclEventId::WindowKeyUp:
979 nEvent = SalEvent::ExternalKeyUp;
980 pEventData = &pData->maKeyEvent;
981 break;
983 case VclEventId::WindowGestureEvent:
984 nEvent = SalEvent::ExternalGesture;
985 pEventData = &pData->maGestureEvent;
986 break;
988 default:
989 nEvent = SalEvent::NONE;
990 pEventData = nullptr;
991 break;
994 if( pData->mpWin && pData->mpWin->mpWindowImpl->mpFrameWindow && pEventData )
995 ImplWindowFrameProc( pData->mpWin->mpWindowImpl->mpFrameWindow.get(), nEvent, pEventData );
997 // remove this event from list of posted events, watch for destruction of internal data
998 auto svdata = ImplGetSVData();
999 ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
1001 while( aIter != svdata->maAppData.maPostedEventList.end() )
1003 if( nEventId == (*aIter).second->mnEventId )
1005 delete (*aIter).second;
1006 aIter = svdata->maAppData.maPostedEventList.erase( aIter );
1008 else
1009 ++aIter;
1013 void Application::RemoveMouseAndKeyEvents( vcl::Window* pWin )
1015 const SolarMutexGuard aGuard;
1017 // remove all events for specific window, watch for destruction of internal data
1018 auto svdata = ImplGetSVData();
1019 ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
1021 while( aIter != svdata->maAppData.maPostedEventList.end() )
1023 if( pWin == (*aIter).first )
1025 if( (*aIter).second->mnEventId )
1026 RemoveUserEvent( (*aIter).second->mnEventId );
1028 delete (*aIter).second;
1029 aIter = svdata->maAppData.maPostedEventList.erase( aIter );
1031 else
1032 ++aIter;
1036 ImplSVEvent * Application::PostUserEvent( const Link<void*,void>& rLink, void* pCaller,
1037 bool bReferenceLink )
1039 vcl::Window* pDefWindow = ImplGetDefaultWindow();
1040 if ( pDefWindow == nullptr )
1041 return nullptr;
1043 std::unique_ptr<ImplSVEvent> pSVEvent(new ImplSVEvent);
1044 pSVEvent->mpData = pCaller;
1045 pSVEvent->maLink = rLink;
1046 pSVEvent->mpWindow = nullptr;
1047 pSVEvent->mbCall = true;
1048 if (bReferenceLink)
1050 SolarMutexGuard aGuard;
1051 pSVEvent->mpInstanceRef = static_cast<vcl::Window *>(rLink.GetInstance());
1054 auto pTmpEvent = pSVEvent.get();
1055 if (!pDefWindow->ImplGetFrame()->PostEvent( std::move(pSVEvent) ))
1056 return nullptr;
1057 return pTmpEvent;
1060 void Application::RemoveUserEvent( ImplSVEvent * nUserEvent )
1062 if(nUserEvent)
1064 SAL_WARN_IF( nUserEvent->mpWindow, "vcl",
1065 "Application::RemoveUserEvent(): Event is send to a window" );
1066 SAL_WARN_IF( !nUserEvent->mbCall, "vcl",
1067 "Application::RemoveUserEvent(): Event is already removed" );
1069 nUserEvent->mpWindow.clear();
1070 nUserEvent->mpInstanceRef.clear();
1071 nUserEvent->mbCall = false;
1075 vcl::Window* Application::GetFocusWindow()
1077 return ImplGetSVData()->mpWinData->mpFocusWin;
1080 OutputDevice* Application::GetDefaultDevice()
1082 vcl::Window* pWindow = ImplGetDefaultWindow();
1083 if (pWindow != nullptr)
1085 return pWindow->GetOutDev();
1087 else
1089 return nullptr;
1093 basegfx::SystemDependentDataManager& Application::GetSystemDependentDataManager()
1095 return ImplGetSystemDependentDataManager();
1098 vcl::Window* Application::GetFirstTopLevelWindow()
1100 ImplSVData* pSVData = ImplGetSVData();
1101 return pSVData->maFrameData.mpFirstFrame;
1104 vcl::Window* Application::GetNextTopLevelWindow( vcl::Window const * pWindow )
1106 return pWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1109 tools::Long Application::GetTopWindowCount()
1111 tools::Long nRet = 0;
1112 ImplSVData* pSVData = ImplGetSVData();
1113 vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
1114 while( pWin )
1116 if( pWin->ImplGetWindow()->IsTopWindow() )
1117 nRet++;
1118 pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1120 return nRet;
1123 vcl::Window* Application::GetTopWindow( tools::Long nIndex )
1125 tools::Long nIdx = 0;
1126 ImplSVData* pSVData = ImplGetSVData();
1127 vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
1128 while( pWin )
1130 if( pWin->ImplGetWindow()->IsTopWindow() )
1132 if( nIdx == nIndex )
1133 return pWin->ImplGetWindow();
1134 else
1135 nIdx++;
1137 pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1139 return nullptr;
1142 vcl::Window* Application::GetActiveTopWindow()
1144 vcl::Window *pWin = ImplGetSVData()->mpWinData->mpFocusWin;
1145 while( pWin )
1147 if( pWin->IsTopWindow() )
1148 return pWin;
1149 pWin = pWin->mpWindowImpl->mpParent;
1151 return nullptr;
1154 void Application::SetAppName( const OUString& rUniqueName )
1156 ImplSVData* pSVData = ImplGetSVData();
1157 pSVData->maAppData.mxAppName = rUniqueName;
1160 const OUString & Application::GetAppName()
1162 ImplSVData* pSVData = ImplGetSVData();
1163 if ( pSVData->maAppData.mxAppName )
1164 return *(pSVData->maAppData.mxAppName);
1165 else
1166 return EMPTY_OUSTRING;
1169 enum {hwAll=0, hwEnv=1, hwUI=2};
1171 static OUString Localize(TranslateId aId, const bool bLocalize)
1173 if (bLocalize)
1174 return VclResId(aId);
1175 else
1176 return Translate::get(aId, Translate::Create("vcl", LanguageTag(u"en-US"_ustr)));
1179 OUString Application::GetOSVersion()
1181 ImplSVData* pSVData = ImplGetSVData();
1182 OUString aVersion;
1183 if (pSVData && pSVData->mpDefInst)
1184 aVersion = pSVData->mpDefInst->getOSVersion();
1185 else
1186 aVersion = "-";
1187 return aVersion;
1190 OUString Application::GetHWOSConfInfo(const int bSelection, const bool bLocalize)
1192 OUStringBuffer aDetails;
1194 const auto appendDetails = [&aDetails](std::u16string_view sep, auto&& val) {
1195 if (!aDetails.isEmpty() && !sep.empty())
1196 aDetails.append(sep);
1197 aDetails.append(std::move(val));
1200 if (bSelection != hwUI) {
1201 appendDetails(u"; ", Localize(SV_APP_CPUTHREADS, bLocalize)
1202 + OUString::number(std::thread::hardware_concurrency()));
1204 OUString aVersion = GetOSVersion();
1206 appendDetails(u"; ", Localize(SV_APP_OSVERSION, bLocalize) + aVersion);
1209 if (bSelection != hwEnv) {
1210 appendDetails(u"; ", Localize(SV_APP_UIRENDER, bLocalize));
1211 #if HAVE_FEATURE_SKIA
1212 if ( SkiaHelper::isVCLSkiaEnabled() )
1214 switch(SkiaHelper::renderMethodToUse())
1216 case SkiaHelper::RenderVulkan:
1217 appendDetails(u"", Localize(SV_APP_SKIA_VULKAN, bLocalize));
1218 break;
1219 case SkiaHelper::RenderMetal:
1220 appendDetails(u"", Localize(SV_APP_SKIA_METAL, bLocalize));
1221 break;
1222 case SkiaHelper::RenderRaster:
1223 appendDetails(u"", Localize(SV_APP_SKIA_RASTER, bLocalize));
1224 break;
1227 else
1228 #endif
1229 appendDetails(u"", Localize(SV_APP_DEFAULT, bLocalize));
1231 #if (defined LINUX || defined _WIN32 || defined MACOSX || defined __FreeBSD__ || defined EMSCRIPTEN)
1232 appendDetails(u"; ", SV_APP_VCLBACKEND + GetToolkitName());
1233 #endif
1236 return aDetails.makeStringAndClear();
1239 void Application::SetDisplayName( const OUString& rName )
1241 ImplSVData* pSVData = ImplGetSVData();
1242 pSVData->maAppData.mxDisplayName = rName;
1245 OUString Application::GetDisplayName()
1247 ImplSVData* pSVData = ImplGetSVData();
1248 if ( pSVData->maAppData.mxDisplayName )
1249 return *(pSVData->maAppData.mxDisplayName);
1250 else if (pSVData->maFrameData.mpAppWin)
1251 return pSVData->maFrameData.mpAppWin->GetText();
1252 else
1253 return OUString();
1256 unsigned int Application::GetScreenCount()
1258 SalSystem* pSys = ImplGetSalSystem();
1259 return pSys ? pSys->GetDisplayScreenCount() : 0;
1262 unsigned int Application::GetDisplayBuiltInScreen()
1264 SalSystem* pSys = ImplGetSalSystem();
1265 return pSys ? pSys->GetDisplayBuiltInScreen() : 0;
1268 unsigned int Application::GetDisplayExternalScreen()
1270 // This is really unpleasant, in theory we could have multiple
1271 // external displays etc.
1272 int nExternal(0);
1273 switch (GetDisplayBuiltInScreen())
1275 case 0:
1276 nExternal = 1;
1277 break;
1278 case 1:
1279 nExternal = 0;
1280 break;
1281 default:
1282 // When the built-in display is neither 0 nor 1
1283 // then place the full-screen presentation on the
1284 // first available screen.
1285 nExternal = 0;
1286 break;
1288 return nExternal;
1291 AbsoluteScreenPixelRectangle Application::GetScreenPosSizePixel( unsigned int nScreen )
1293 SalSystem* pSys = ImplGetSalSystem();
1294 if (!pSys)
1296 SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " failed");
1297 assert(false);
1298 return AbsoluteScreenPixelRectangle();
1300 AbsoluteScreenPixelRectangle aRect = pSys->GetDisplayScreenPosSizePixel(nScreen);
1301 if (aRect.GetHeight() == 0)
1302 SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " returned 0 height.");
1303 return aRect;
1306 namespace {
1307 tools::Long calcDistSquare( const AbsoluteScreenPixelPoint& i_rPoint, const AbsoluteScreenPixelRectangle& i_rRect )
1309 const AbsoluteScreenPixelPoint aRectCenter( (i_rRect.Left() + i_rRect.Right())/2,
1310 (i_rRect.Top() + i_rRect.Bottom())/ 2 );
1311 const tools::Long nDX = aRectCenter.X() - i_rPoint.X();
1312 const tools::Long nDY = aRectCenter.Y() - i_rPoint.Y();
1313 return nDX*nDX + nDY*nDY;
1317 unsigned int Application::GetBestScreen( const AbsoluteScreenPixelRectangle& i_rRect )
1319 const unsigned int nScreens = GetScreenCount();
1320 unsigned int nBestMatchScreen = 0;
1321 unsigned long nOverlap = 0;
1322 for( unsigned int i = 0; i < nScreens; i++ )
1324 const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
1325 // if a screen contains the rectangle completely it is obviously the best screen
1326 if( aCurScreenRect.Contains( i_rRect ) )
1327 return i;
1328 // next the screen which contains most of the area of the rect is the best
1329 AbsoluteScreenPixelRectangle aIntersection( aCurScreenRect.GetIntersection( i_rRect ) );
1330 if( ! aIntersection.IsEmpty() )
1332 const unsigned long nCurOverlap( aIntersection.GetWidth() * aIntersection.GetHeight() );
1333 if( nCurOverlap > nOverlap )
1335 nOverlap = nCurOverlap;
1336 nBestMatchScreen = i;
1340 if( nOverlap > 0 )
1341 return nBestMatchScreen;
1343 // finally the screen which center is nearest to the rect is the best
1344 const AbsoluteScreenPixelPoint aCenter( (i_rRect.Left() + i_rRect.Right())/2,
1345 (i_rRect.Top() + i_rRect.Bottom())/2 );
1346 tools::Long nDist = std::numeric_limits<tools::Long>::max();
1347 for( unsigned int i = 0; i < nScreens; i++ )
1349 const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
1350 const tools::Long nCurDist( calcDistSquare( aCenter, aCurScreenRect ) );
1351 if( nCurDist < nDist )
1353 nBestMatchScreen = i;
1354 nDist = nCurDist;
1357 return nBestMatchScreen;
1360 bool Application::InsertAccel( Accelerator* pAccel )
1362 ImplSVData* pSVData = ImplGetSVData();
1364 if ( !pSVData->maAppData.mpAccelMgr )
1365 pSVData->maAppData.mpAccelMgr = new ImplAccelManager();
1366 return pSVData->maAppData.mpAccelMgr->InsertAccel( pAccel );
1369 void Application::RemoveAccel( Accelerator const * pAccel )
1371 ImplSVData* pSVData = ImplGetSVData();
1373 if ( pSVData->maAppData.mpAccelMgr )
1374 pSVData->maAppData.mpAccelMgr->RemoveAccel( pAccel );
1377 void Application::SetHelp( Help* pHelp )
1379 ImplGetSVData()->maAppData.mpHelp = pHelp;
1382 void Application::UpdateMainThread()
1384 ImplSVData* pSVData = ImplGetSVData();
1385 if (pSVData && pSVData->mpDefInst)
1386 pSVData->mpDefInst->updateMainThread();
1389 Help* Application::GetHelp()
1391 return ImplGetSVData()->maAppData.mpHelp;
1394 const OUString & Application::GetToolkitName()
1396 ImplSVData* pSVData = ImplGetSVData();
1397 if ( pSVData->maAppData.mxToolkitName )
1398 return *(pSVData->maAppData.mxToolkitName);
1399 else
1400 return EMPTY_OUSTRING;
1403 vcl::Window* Dialog::GetDefDialogParent()
1405 ImplSVData* pSVData = ImplGetSVData();
1406 // find some useful dialog parent
1408 // always use the topmost parent of the candidate
1409 // window to avoid using dialogs or floaters
1410 // as DefDialogParent
1412 // current focus frame
1413 vcl::Window *pWin = pSVData->mpWinData->mpFocusWin;
1414 if (pWin && !pWin->IsMenuFloatingWindow())
1416 while (pWin->mpWindowImpl && pWin->mpWindowImpl->mpParent)
1417 pWin = pWin->mpWindowImpl->mpParent;
1419 // check for corrupted window hierarchy, #122232#, may be we now crash somewhere else
1420 if (!pWin->mpWindowImpl)
1422 OSL_FAIL( "Window hierarchy corrupted!" );
1423 pSVData->mpWinData->mpFocusWin = nullptr; // avoid further access
1424 return nullptr;
1427 if ((pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0)
1429 return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1433 // last active application frame
1434 pWin = pSVData->maFrameData.mpActiveApplicationFrame;
1435 if (pWin)
1437 return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1440 // first visible top window (may be totally wrong...)
1441 pWin = pSVData->maFrameData.mpFirstFrame;
1442 while (pWin)
1444 if( pWin->ImplGetWindow()->IsTopWindow() &&
1445 pWin->mpWindowImpl->mbReallyVisible &&
1446 (pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0
1449 while( pWin->mpWindowImpl->mpParent )
1450 pWin = pWin->mpWindowImpl->mpParent;
1451 return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1453 pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1456 // use the desktop
1457 return nullptr;
1460 weld::Window* Application::GetDefDialogParent()
1462 vcl::Window* pWindow = Dialog::GetDefDialogParent();
1463 return pWindow ? pWindow->GetFrameWeld() : nullptr;
1466 DialogCancelMode Application::GetDialogCancelMode()
1468 return ImplGetSVData()->maAppData.meDialogCancel;
1471 void Application::SetDialogCancelMode( DialogCancelMode mode )
1473 ImplGetSVData()->maAppData.meDialogCancel = mode;
1476 bool Application::IsDialogCancelEnabled()
1478 return ImplGetSVData()->maAppData.meDialogCancel != DialogCancelMode::Off;
1481 void Application::SetSystemWindowMode( SystemWindowFlags nMode )
1483 ImplGetSVData()->maAppData.mnSysWinMode = nMode;
1486 SystemWindowFlags Application::GetSystemWindowMode()
1488 return ImplGetSVData()->maAppData.mnSysWinMode;
1491 css::uno::Reference< css::awt::XToolkit > Application::GetVCLToolkit()
1493 css::uno::Reference< css::awt::XToolkit > xT;
1494 UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
1495 if ( pWrapper )
1496 xT = pWrapper->GetVCLToolkit();
1497 return xT;
1500 #ifdef DISABLE_DYNLOADING
1502 extern "C" { UnoWrapperBase* CreateUnoWrapper(); }
1504 #else
1506 extern "C" { static void thisModule() {} }
1508 #endif
1510 UnoWrapperBase* UnoWrapperBase::GetUnoWrapper( bool bCreateIfNotExist )
1512 ImplSVData* pSVData = ImplGetSVData();
1513 static bool bAlreadyTriedToCreate = false;
1514 if ( !pSVData->mpUnoWrapper && bCreateIfNotExist && !bAlreadyTriedToCreate )
1516 #ifndef DISABLE_DYNLOADING
1517 osl::Module aTkLib;
1518 aTkLib.loadRelative(&thisModule, TK_DLL_NAME);
1519 if (aTkLib.is())
1521 FN_TkCreateUnoWrapper fnCreateWrapper = reinterpret_cast<FN_TkCreateUnoWrapper>(aTkLib.getFunctionSymbol("CreateUnoWrapper"));
1522 if ( fnCreateWrapper )
1524 pSVData->mpUnoWrapper = fnCreateWrapper();
1526 aTkLib.release();
1528 SAL_WARN_IF( !pSVData->mpUnoWrapper, "vcl", "UnoWrapper could not be created!" );
1529 #else
1530 pSVData->mpUnoWrapper = CreateUnoWrapper();
1531 #endif
1532 bAlreadyTriedToCreate = true;
1534 return pSVData->mpUnoWrapper;
1537 void UnoWrapperBase::SetUnoWrapper( UnoWrapperBase* pWrapper )
1539 ImplSVData* pSVData = ImplGetSVData();
1540 SAL_WARN_IF( pSVData->mpUnoWrapper, "vcl", "SetUnoWrapper: Wrapper already exists" );
1541 pSVData->mpUnoWrapper = pWrapper;
1544 css::uno::Reference< css::awt::XDisplayConnection > Application::GetDisplayConnection()
1546 ImplSVData* pSVData = ImplGetSVData();
1548 if( !pSVData->mxDisplayConnection.is() )
1550 pSVData->mxDisplayConnection.set( new vcl::DisplayConnectionDispatch );
1551 pSVData->mxDisplayConnection->start();
1554 return pSVData->mxDisplayConnection;
1557 void Application::SetFilterHdl( const Link<ConvertData&,bool>& rLink )
1559 ImplGetSVData()->maGDIData.mxGrfConverter->SetFilterHdl( rLink );
1562 const LocaleDataWrapper& Application::GetAppLocaleDataWrapper()
1564 return GetSettings().GetLocaleDataWrapper();
1567 void Application::EnableHeadlessMode( bool dialogsAreFatal )
1569 DialogCancelMode eNewMode = dialogsAreFatal ? DialogCancelMode::Fatal : DialogCancelMode::Silent;
1570 DialogCancelMode eOldMode = GetDialogCancelMode();
1571 assert(eOldMode == DialogCancelMode::Off || GetDialogCancelMode() == eNewMode);
1572 if (eOldMode != eNewMode)
1573 SetDialogCancelMode( eNewMode );
1576 bool Application::IsHeadlessModeEnabled()
1578 return IsDialogCancelEnabled() || comphelper::LibreOfficeKit::isActive();
1581 void Application::EnableBitmapRendering()
1583 ImplGetSVData()->maAppData.mbRenderToBitmaps = true;
1586 bool Application::IsBitmapRendering()
1588 return ImplGetSVData()->maAppData.mbRenderToBitmaps;
1591 void Application::EnableConsoleOnly()
1593 EnableHeadlessMode(true);
1594 EnableBitmapRendering();
1597 static bool bSafeMode = false;
1599 bool Application::IsSafeModeEnabled()
1601 return bSafeMode;
1604 void Application::EnableSafeMode()
1606 bSafeMode = true;
1609 void Application::ShowNativeErrorBox(const OUString& sTitle ,
1610 const OUString& sMessage)
1612 int btn = ImplGetSalSystem()->ShowNativeMessageBox(
1613 sTitle,
1614 sMessage);
1615 if (btn != SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK) {
1616 SAL_WARN( "vcl", "ShowNativeMessageBox returned " << btn);
1620 const OUString& Application::GetDesktopEnvironment()
1622 if (IsHeadlessModeEnabled())
1624 static constexpr OUString aNone(u"none"_ustr);
1625 return aNone;
1627 else
1628 return SalGetDesktopEnvironment();
1631 void Application::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService)
1633 ImplSVData* pSVData = ImplGetSVData();
1634 pSVData->mpDefInst->AddToRecentDocumentList(rFileUrl, rMimeType, rDocumentService);
1637 // MT: AppEvent was in oldsv.cxx, but is still needed...
1638 void Application::AppEvent( const ApplicationEvent& /*rAppEvent*/ )
1642 bool Application::hasNativeFileSelection()
1644 ImplSVData* pSVData = ImplGetSVData();
1645 return pSVData->mpDefInst->hasNativeFileSelection();
1648 Reference< ui::dialogs::XFilePicker2 >
1649 Application::createFilePicker( const Reference< uno::XComponentContext >& xSM )
1651 ImplSVData* pSVData = ImplGetSVData();
1652 return pSVData->mpDefInst->createFilePicker( xSM );
1655 Reference< ui::dialogs::XFolderPicker2 >
1656 Application::createFolderPicker( const Reference< uno::XComponentContext >& xSM )
1658 ImplSVData* pSVData = ImplGetSVData();
1659 return pSVData->mpDefInst->createFolderPicker( xSM );
1662 void Application::setDeInitHook(Link<LinkParamNone*,void> const & hook) {
1663 ImplSVData * pSVData = ImplGetSVData();
1664 assert(!pSVData->maDeInitHook.IsSet());
1665 pSVData->maDeInitHook = hook;
1666 // Fake this for VCLXToolkit ctor instantiated from
1667 // postprocess/CppunitTest_services.mk:
1668 pSVData->maAppData.mbInAppMain = true;
1671 namespace vcl::lok {
1673 void registerPollCallbacks(
1674 LibreOfficeKitPollCallback pPollCallback,
1675 LibreOfficeKitWakeCallback pWakeCallback,
1676 void *pData) {
1678 ImplSVData * pSVData = ImplGetSVData();
1679 if (pSVData)
1681 pSVData->mpPollCallback = pPollCallback;
1682 pSVData->mpWakeCallback = pWakeCallback;
1683 pSVData->mpPollClosure = pData;
1687 void unregisterPollCallbacks()
1689 ImplSVData * pSVData = ImplGetSVData();
1690 if (!pSVData)
1691 return;
1693 // Not hyper-elegant - but in the case of Android & unipoll we need to detach
1694 // this thread from the JVM's clutches to avoid a crash closing document
1695 if (pSVData->mpPollClosure && pSVData->mpDefInst)
1696 pSVData->mpDefInst->releaseMainThread();
1698 // Just set mpPollClosure to null as that is what calling this means, that the callback data
1699 // points to an object that no longer exists. In particular, don't set
1700 // pSVData->mpPollCallback to nullptr as that is used to detect whether Unipoll is in use in
1701 // isUnipoll().
1702 pSVData->mpPollClosure = nullptr;
1705 bool isUnipoll()
1707 ImplSVData * pSVData = ImplGetSVData();
1708 return pSVData && pSVData->mpPollCallback != nullptr;
1711 void numberOfViewsChanged(int count)
1713 if (count == 0)
1714 return;
1715 ImplSVData * pSVData = ImplGetSVData();
1716 auto& rCache = pSVData->maGDIData.maScaleCache;
1717 // Normally the cache size is set to 10, scale according to the number of users.
1718 rCache.setMaxSize(count * 10);
1721 void dumpState(rtl::OStringBuffer &rState)
1723 ImplSVData* pSVData = ImplGetSVData();
1724 if (!pSVData)
1725 return;
1727 #ifndef NDEBUG
1728 // lo_dumpState deliberately doesn't take SolarMutexGuard
1729 // so disable these checks during dumpState
1730 DbgGUIDeInitSolarMutexCheck();
1731 #endif
1733 rState.append("\nWindows:\t");
1734 rState.append(static_cast<sal_Int32>(Application::GetTopWindowCount()));
1736 vcl::Window *pWin = Application::GetFirstTopLevelWindow();
1737 while (pWin)
1739 tools::JsonWriter aProps;
1740 pWin->DumpAsPropertyTree(aProps);
1742 rState.append("\n\tWindow: ");
1744 auto notifier = pWin->GetLOKNotifier();
1745 if (notifier)
1747 rState.append(notifier->dumpNotifyState());
1748 rState.append(" ");
1750 else
1751 rState.append("no notifier ");
1753 OString aPropStr = aProps.finishAndGetAsOString();
1754 if (aPropStr.getLength() > 256)
1756 rState.append(aPropStr.subView(0, 256));
1757 rState.append("...");
1758 } else
1759 rState.append(aPropStr);
1761 pWin = Application::GetNextTopLevelWindow( pWin );
1764 vcl::graphic::MemoryManager::get().dumpState(rState);
1766 pSVData->dumpState(rState);
1768 #ifndef NDEBUG
1769 DbgGUIInitSolarMutexCheck();
1770 #endif
1773 void trimMemory(int nTarget)
1775 if (nTarget >= 1000)
1777 ImplSVData* pSVData = ImplGetSVData();
1778 if (!pSVData) // shutting down
1779 return;
1780 pSVData->dropCaches();
1781 vcl::graphic::MemoryManager::get().reduceAllAndNow();
1782 // TODO: ideally - free up any deeper dirtied thread stacks.
1783 // comphelper::ThreadPool::getSharedOptimalPool().shutdown();
1785 // else for now caches re-fill themselves as/when used.
1788 } // namespace lok, namespace vcl
1790 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */