xref: /core/vcl/source/app/svapp.cxx (revision 57654c90fa61f99453baacdad7f88d41eb55490c)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <config_features.h>
21 #include <config_version.h>
22 
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>
28 
29 #include <sal/log.hxx>
30 
31 #include <tools/debug.hxx>
32 #include <tools/time.hxx>
33 #include <tools/stream.hxx>
34 #include <tools/json_writer.hxx>
35 
36 #include <comphelper/configuration.hxx>
37 #include <unotools/resmgr.hxx>
38 #include <unotools/syslocale.hxx>
39 #include <unotools/syslocaleoptions.hxx>
40 
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>
57 
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
72 
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>
79 
80 #ifdef DBG_UTIL
81 #include <svl/poolitem.hxx>
82 #include <svl/itemset.hxx>
83 #include <svl/itempool.hxx>
84 #endif
85 
86 #include <cassert>
87 #include <limits>
88 #include <string_view>
89 #include <utility>
90 #include <thread>
91 
92 using namespace ::com::sun::star;
93 using namespace ::com::sun::star::uno;
94 
95 namespace {
96 void InitSettings(ImplSVData* pSVData);
97 }
98 
99 // keycodes handled internally by VCL
100 vcl::KeyCode const ReservedKeys[]
101 {
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
111 };
112 
113 extern "C" {
114     typedef UnoWrapperBase* (*FN_TkCreateUnoWrapper)();
115 }
116 
117 struct ImplPostEventData
118 {
119     VclPtr<vcl::Window> mpWin;
120     ImplSVEvent *   mnEventId;
121     MouseEvent      maMouseEvent;
122     VclEventId      mnEvent;
123     KeyEvent        maKeyEvent;
124     GestureEventPan maGestureEvent;
125 
ImplPostEventDataImplPostEventData126     ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const KeyEvent& rKeyEvent)
127         : mpWin(pWin)
128         , mnEventId(nullptr)
129         , mnEvent(nEvent)
130         , maKeyEvent(rKeyEvent)
131     {}
ImplPostEventDataImplPostEventData132     ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const MouseEvent& rMouseEvent)
133         : mpWin(pWin)
134         , mnEventId(nullptr)
135         , maMouseEvent(rMouseEvent)
136         , mnEvent(nEvent)
137     {}
ImplPostEventDataImplPostEventData138     ImplPostEventData(VclEventId nEvent, vcl::Window* pWin, const GestureEventPan& rGestureEvent)
139         : mpWin(pWin)
140         , mnEventId(nullptr)
141         , mnEvent(nEvent)
142         , maGestureEvent(rGestureEvent)
143     {}
144 };
145 
GetpApp()146 Application* GetpApp()
147 {
148     ImplSVData* pSVData = ImplGetSVData();
149     if ( !pSVData )
150         return nullptr;
151     return pSVData->mpApp;
152 }
153 
Application()154 Application::Application()
155 {
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);
159 
160     ImplGetSVData()->mpApp = this;
161     m_pCallbackData = nullptr;
162     m_pCallback = nullptr;
163 }
164 
~Application()165 Application::~Application()
166 {
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");
183 
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");
187 
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");
191 
192     // Additional call to list still incarnated SfxPoolItems (under 'svl.items')
193     listAllocatedSfxPoolItems();
194 
195     // List SfxPoolItems with highest RefCounts, these are the best
196     // candidates to add a ItemInstanceManager mechanism
197     listSfxPoolItemsWithHighestUsage(20);
198     listSfxItemSetUsage();
199 #endif
200 }
201 
Main()202 int Application::Main()
203 {
204     SAL_WARN("vcl", "Application is a base class and should be overridden.");
205     return EXIT_SUCCESS;
206 }
207 
QueryExit()208 bool Application::QueryExit()
209 {
210     WorkWindow* pAppWin = ImplGetSVData()->maFrameData.mpAppWin;
211 
212     // call the close handler of the application window
213     if ( pAppWin )
214         return pAppWin->Close();
215     else
216         return true;
217 }
218 
Shutdown()219 void Application::Shutdown()
220 {
221 }
222 
Init()223 void Application::Init()
224 {
225 }
226 
InitFinished()227 void Application::InitFinished()
228 {
229 }
230 
DeInit()231 void Application::DeInit()
232 {
233 }
234 
GetCommandLineParamCount()235 sal_uInt16 Application::GetCommandLineParamCount()
236 {
237     return static_cast<sal_uInt16>(osl_getCommandArgCount());
238 }
239 
GetCommandLineParam(sal_uInt16 nParam)240 OUString Application::GetCommandLineParam( sal_uInt16 nParam )
241 {
242     OUString aParam;
243     osl_getCommandArg( nParam, &aParam.pData );
244     return aParam;
245 }
246 
GetAppFileName()247 OUString Application::GetAppFileName()
248 {
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;
253 
254     /*
255      *  provide a fallback for people without initialized vcl here (like setup
256      *  in responsefile mode)
257      */
258     OUString aAppFileName;
259     OUString aExeFileName;
260     osl_getExecutableFile(&aExeFileName.pData);
261 
262     // convert path to native file format
263     osl::FileBase::getSystemPathFromFileURL(aExeFileName, aAppFileName);
264 
265     return aAppFileName;
266 }
267 
Exception(ExceptionCategory nCategory)268 void Application::Exception( ExceptionCategory nCategory )
269 {
270     switch ( nCategory )
271     {
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;
279     }
280 }
281 
Abort(const OUString & rErrorText)282 void Application::Abort( const OUString& rErrorText )
283 {
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;
296         }
297     }
298 #endif
299 
300     SalAbort( rErrorText, dumpCore );
301 }
302 
GetReservedKeyCodeCount()303 size_t Application::GetReservedKeyCodeCount()
304 {
305     return SAL_N_ELEMENTS(ReservedKeys);
306 }
307 
GetReservedKeyCode(size_t i)308 const vcl::KeyCode* Application::GetReservedKeyCode( size_t i )
309 {
310     if( i >= GetReservedKeyCodeCount() )
311         return nullptr;
312     else
313         return &ReservedKeys[i];
314 }
315 
notifyWindow(vcl::LOKWindowId,const OUString &,const std::vector<vcl::LOKPayloadItem> &) const316 void Application::notifyWindow(vcl::LOKWindowId /*nLOKWindowId*/,
317                                const OUString& /*rAction*/,
318                                const std::vector<vcl::LOKPayloadItem>& /*rPayload = std::vector<LOKPayloadItem>()*/) const
319 {
320     SAL_WARN("vcl", "Invoked not implemented method: Application::notifyWindow");
321 }
322 
dumpNotifyState() const323 OString Application::dumpNotifyState() const
324 {
325     SAL_WARN("vcl", "Invoked not implemented method: Application::dumpNotifyState");
326     return "notimpl"_ostr;
327 }
328 
libreOfficeKitViewCallback(int nType,const OString & pPayload) const329 void Application::libreOfficeKitViewCallback(int nType, const OString& pPayload) const
330 {
331     if (!comphelper::LibreOfficeKit::isActive())
332         return;
333 
334     if (m_pCallback)
335     {
336         m_pCallback(nType, pPayload.getStr(), m_pCallbackData);
337     }
338 }
339 
notifyInvalidation(tools::Rectangle const *) const340 void Application::notifyInvalidation(tools::Rectangle const* /*pRect*/) const
341 {
342 }
343 
Execute()344 void Application::Execute()
345 {
346     ImplSVData* pSVData = ImplGetSVData();
347     pSVData->maAppData.mbInAppExecute = true;
348     pSVData->maAppData.mbAppQuit = false;
349 
350     int nExitCode = 0;
351     if (!pSVData->mpDefInst->DoExecute(nExitCode))
352     {
353         if (Application::IsUseSystemEventLoop())
354         {
355             SAL_WARN("vcl.schedule", "Can't omit DoExecute when running on system event loop!");
356             std::abort();
357         }
358         while (!pSVData->maAppData.mbAppQuit)
359         {
360             Application::Yield();
361             SolarMutexReleaser releaser; // Give a chance for the waiting threads to lock the mutex
362             pSVData->m_inExecuteCondtion.set();
363         }
364     }
365 
366     pSVData->maAppData.mbInAppExecute = false;
367 
368     GetpApp()->Shutdown();
369 }
370 
ImplYield(bool i_bWait,bool i_bAllEvents)371 static bool ImplYield(bool i_bWait, bool i_bAllEvents)
372 {
373     ImplSVData* pSVData = ImplGetSVData();
374 
375     SAL_INFO("vcl.schedule", "Enter ImplYield: " << (i_bWait ? "wait" : "no wait") <<
376              ": " << (i_bAllEvents ? "all events" : "one event"));
377 
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++;
382 
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 );
387 
388     pSVData->maAppData.mnDispatchLevel--;
389 
390     DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
391 
392     SAL_INFO("vcl.schedule", "Leave ImplYield with return " << bProcessedEvent );
393     return bProcessedEvent;
394 }
395 
Reschedule(bool i_bAllEvents)396 bool Application::Reschedule( bool i_bAllEvents )
397 {
398     static const bool bAbort = Application::IsUseSystemEventLoop();
399     if (bAbort)
400     {
401         SAL_WARN("vcl.schedule", "Application::Reschedule(" << i_bAllEvents << ")");
402         return false;
403     }
404     int nOldView = -1;
405     if (comphelper::LibreOfficeKit::isActive())
406     {
407         nOldView = comphelper::LibreOfficeKit::getView();
408     }
409     bool bRet = ImplYield(false, i_bAllEvents);
410     if (comphelper::LibreOfficeKit::isActive())
411     {
412         int nNewView = comphelper::LibreOfficeKit::getView();
413         if (nOldView != -1 && nNewView != -1 && nOldView != nNewView)
414         {
415             // Yield changed the current view, restore the old value.
416             comphelper::LibreOfficeKit::setView(nOldView);
417         }
418     }
419     return bRet;
420 }
421 
IsUseSystemEventLoop()422 bool Application::IsUseSystemEventLoop()
423 {
424     return ImplGetSVData()->maAppData.m_bUseSystemLoop;
425 }
426 
ProcessEventsToIdle()427 void Scheduler::ProcessEventsToIdle()
428 {
429 #if OSL_DEBUG_LEVEL > 0
430     const ImplSVData* pSVData = ImplGetSVData();
431     if (pSVData->mpDefInst->IsMainThread())
432         assert(pSVData->maSchedCtx.mnIdlesLockCount == 0);
433 #endif
434     int nSanity = 1;
435     while (ImplYield(false, true))
436     {
437         if (0 == ++nSanity % 1000)
438         {
439             SAL_WARN("vcl.schedule", "ProcessEventsToIdle: " << nSanity);
440         }
441     }
442 #if OSL_DEBUG_LEVEL > 0
443     // If we yield from a non-main thread we just can guarantee that all idle
444     // events were processed at some point, but our check can't prevent further
445     // processing in the main thread, which may add new events, so skip it.
446     if ( !pSVData->mpDefInst->IsMainThread() )
447         return;
448     for (int nTaskPriority = 0; nTaskPriority < PRIO_COUNT; ++nTaskPriority)
449     {
450         const ImplSchedulerData* pSchedulerData = pSVData->maSchedCtx.mpFirstSchedulerData[nTaskPriority];
451         while (pSchedulerData)
452         {
453             assert(!pSchedulerData->mbInScheduler);
454             if (pSchedulerData->mpTask)
455             {
456                 Idle *pIdle = dynamic_cast<Idle*>(pSchedulerData->mpTask);
457                 if (pIdle && pIdle->IsActive())
458                 {
459                     SAL_WARN("vcl.schedule",
460                              "Unprocessed Idle: "
461                                  << pIdle << " "
462                                  << (pIdle->GetDebugName() ? pIdle->GetDebugName() : "(nullptr)"));
463                 }
464             }
465             pSchedulerData = pSchedulerData->mpNext;
466         }
467     }
468 #endif
469 }
470 
471 extern "C" {
472 /// used by unit tests that test only via the LOK API
unit_lok_process_events_to_idle()473 SAL_DLLPUBLIC_EXPORT void unit_lok_process_events_to_idle()
474 {
475     const SolarMutexGuard aGuard;
476     Scheduler::ProcessEventsToIdle();
477 }
478 }
479 
Yield()480 void Application::Yield()
481 {
482     static const bool bAbort = Application::IsUseSystemEventLoop();
483     if (bAbort)
484     {
485         SAL_WARN("vcl.schedule", "Application::Yield()");
486         std::abort();
487     }
488     ImplYield(true, false);
489 }
490 
IMPL_STATIC_LINK_NOARG(ImplSVAppData,ImplQuitMsg,void *,void)491 IMPL_STATIC_LINK_NOARG( ImplSVAppData, ImplQuitMsg, void*, void )
492 {
493     assert(ImplGetSVData()->maAppData.mbAppQuit);
494     ImplGetSVData()->mpDefInst->DoQuit();
495 }
496 
Quit()497 void Application::Quit()
498 {
499     ImplGetSVData()->maAppData.mbAppQuit = true;
500     Application::PostUserEvent( LINK( nullptr, ImplSVAppData, ImplQuitMsg ) );
501 }
502 
GetSolarMutex()503 comphelper::SolarMutex& Application::GetSolarMutex()
504 {
505     ImplSVData* pSVData = ImplGetSVData();
506     return *(pSVData->mpDefInst->GetYieldMutex());
507 }
508 
IsMainThread()509 bool Application::IsMainThread()
510 {
511     return ImplGetSVData()->mnMainThreadId == osl::Thread::getCurrentIdentifier();
512 }
513 
ReleaseSolarMutex()514 sal_uInt32 Application::ReleaseSolarMutex()
515 {
516     ImplSVData* pSVData = ImplGetSVData();
517     return pSVData->mpDefInst->ReleaseYieldMutex(true);
518 }
519 
AcquireSolarMutex(sal_uInt32 nCount)520 void Application::AcquireSolarMutex( sal_uInt32 nCount )
521 {
522     ImplSVData* pSVData = ImplGetSVData();
523     pSVData->mpDefInst->AcquireYieldMutex( nCount );
524 }
525 
IsInMain()526 bool Application::IsInMain()
527 {
528     ImplSVData* pSVData = ImplGetSVData();
529     return pSVData && pSVData->maAppData.mbInAppMain;
530 }
531 
IsInExecute()532 bool Application::IsInExecute()
533 {
534     return ImplGetSVData()->maAppData.mbInAppExecute;
535 }
536 
IsQuit()537 bool Application::IsQuit()
538 {
539     return ImplGetSVData()->maAppData.mbAppQuit;
540 }
541 
IsInModalMode()542 bool Application::IsInModalMode()
543 {
544     return (ImplGetSVData()->maAppData.mnModalMode != 0);
545 }
546 
GetDispatchLevel()547 sal_uInt16 Application::GetDispatchLevel()
548 {
549     return ImplGetSVData()->maAppData.mnDispatchLevel;
550 }
551 
AnyInput(VclInputFlags nType)552 bool Application::AnyInput( VclInputFlags nType )
553 {
554     return ImplGetSVData()->mpDefInst->AnyInput( nType );
555 }
556 
GetLastInputInterval()557 sal_uInt64 Application::GetLastInputInterval()
558 {
559     return (tools::Time::GetSystemTicks()-ImplGetSVData()->maAppData.mnLastInputTime);
560 }
561 
IsUICaptured()562 bool Application::IsUICaptured()
563 {
564     ImplSVData* pSVData = ImplGetSVData();
565 
566     // If mouse was captured, or if in tracking- or in select-mode of a floatingwindow (e.g. menus
567     // or pulldown toolboxes) another window should be created
568     // D&D active !!!
569     return pSVData->mpWinData->mpCaptureWin || pSVData->mpWinData->mpTrackWin
570            || pSVData->mpWinData->mpFirstFloat || nImplSysDialog;
571 }
572 
OverrideSystemSettings(AllSettings &)573 void Application::OverrideSystemSettings( AllSettings& /*rSettings*/ )
574 {
575 }
576 
MergeSystemSettings(AllSettings & rSettings)577 void Application::MergeSystemSettings( AllSettings& rSettings )
578 {
579     vcl::Window* pWindow = ImplGetSVData()->maFrameData.mpFirstFrame;
580     if( ! pWindow )
581         pWindow = ImplGetDefaultWindow();
582     if( pWindow )
583     {
584         ImplSVData* pSVData = ImplGetSVData();
585         if ( !pSVData->maAppData.mbSettingsInit )
586         {
587             // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
588             pWindow->ImplUpdateGlobalSettings( *pSVData->maAppData.mxSettings );
589             pSVData->maAppData.mbSettingsInit = true;
590         }
591         // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings
592         pWindow->ImplUpdateGlobalSettings( rSettings, false );
593     }
594 }
595 
SetSettings(const AllSettings & rSettings,bool bTemporary)596 void Application::SetSettings(const AllSettings& rSettings, bool bTemporary)
597 {
598     const SolarMutexGuard aGuard;
599 
600     ImplSVData* pSVData = ImplGetSVData();
601     if ( !pSVData->maAppData.mxSettings )
602     {
603         InitSettings(pSVData);
604         *pSVData->maAppData.mxSettings = rSettings;
605     }
606     else
607     {
608         AllSettings aOldSettings = *pSVData->maAppData.mxSettings;
609         if (aOldSettings.GetUILanguageTag().getLanguageType() != rSettings.GetUILanguageTag().getLanguageType() &&
610                 pSVData->mbResLocaleSet)
611         {
612             pSVData->mbResLocaleSet = false;
613         }
614         *pSVData->maAppData.mxSettings = rSettings;
615         // Don't broadcast temporary changes
616         AllSettingsFlags nChangeFlags = bTemporary ? AllSettingsFlags::NONE
617                                                    : aOldSettings.GetChangeFlags(*pSVData->maAppData.mxSettings);
618         if (nChangeFlags != AllSettingsFlags::NONE)
619         {
620             DataChangedEvent aDCEvt( DataChangedEventType::SETTINGS, &aOldSettings, nChangeFlags );
621 
622             // notify data change handler
623             ImplCallEventListenersApplicationDataChanged( &aDCEvt);
624 
625             // Update all windows
626             vcl::Window* pFirstFrame = pSVData->maFrameData.mpFirstFrame;
627             // Reset data that needs to be re-calculated
628             tools::Long nOldDPIX = 0;
629             tools::Long nOldDPIY = 0;
630             if ( pFirstFrame )
631             {
632                 nOldDPIX = pFirstFrame->GetOutDev()->GetDPIX();
633                 nOldDPIY = pFirstFrame->GetOutDev()->GetDPIY();
634                 vcl::Window::ImplInitAppFontData(pFirstFrame);
635             }
636             vcl::Window* pFrame = pFirstFrame;
637             while ( pFrame )
638             {
639                 // call UpdateSettings from ClientWindow in order to prevent updating data twice
640                 vcl::Window* pClientWin = pFrame;
641                 while ( pClientWin->ImplGetClientWindow() )
642                     pClientWin = pClientWin->ImplGetClientWindow();
643                 pClientWin->UpdateSettings( rSettings, true );
644 
645                 vcl::Window* pTempWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
646                 while ( pTempWin )
647                 {
648                     // call UpdateSettings from ClientWindow in order to prevent updating data twice
649                     pClientWin = pTempWin;
650                     while ( pClientWin->ImplGetClientWindow() )
651                         pClientWin = pClientWin->ImplGetClientWindow();
652                     pClientWin->UpdateSettings( rSettings, true );
653                     pTempWin = pTempWin->mpWindowImpl->mpNextOverlap;
654                 }
655 
656                 pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
657             }
658 
659             // if DPI resolution for screen output was changed set the new resolution for all
660             // screen compatible VirDev's
661             pFirstFrame = pSVData->maFrameData.mpFirstFrame;
662             if ( pFirstFrame )
663             {
664                 if ( (pFirstFrame->GetOutDev()->GetDPIX() != nOldDPIX) ||
665                      (pFirstFrame->GetOutDev()->GetDPIY() != nOldDPIY) )
666                 {
667                     VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
668                     while ( pVirDev )
669                     {
670                         if ( pVirDev->mbScreenComp &&
671                              (pVirDev->GetDPIX() == nOldDPIX) &&
672                              (pVirDev->GetDPIY() == nOldDPIY) )
673                         {
674                             pVirDev->SetDPIX( pFirstFrame->GetOutDev()->GetDPIX() );
675                             pVirDev->SetDPIY( pFirstFrame->GetOutDev()->GetDPIY() );
676                             if ( pVirDev->IsMapModeEnabled() )
677                             {
678                                 MapMode aMapMode = pVirDev->GetMapMode();
679                                 pVirDev->SetMapMode();
680                                 pVirDev->SetMapMode( aMapMode );
681                             }
682                         }
683 
684                         pVirDev = pVirDev->mpNext;
685                     }
686                 }
687             }
688         }
689     }
690 }
691 
GetSettings()692 const AllSettings& Application::GetSettings()
693 {
694     ImplSVData* pSVData = ImplGetSVData();
695     if ( !pSVData->maAppData.mxSettings )
696     {
697         InitSettings(pSVData);
698     }
699 
700     return *(pSVData->maAppData.mxSettings);
701 }
702 
703 namespace {
704 
InitSettings(ImplSVData * pSVData)705 void InitSettings(ImplSVData* pSVData)
706 {
707     assert(!pSVData->maAppData.mxSettings && "initialization should not happen twice!");
708 
709     pSVData->maAppData.mxSettings.emplace();
710     if (!comphelper::IsFuzzing())
711     {
712         pSVData->maAppData.mpCfgListener = new LocaleConfigurationListener;
713         pSVData->maAppData.mxSettings->GetSysLocale().GetOptions().AddListener( pSVData->maAppData.mpCfgListener );
714     }
715 }
716 
717 }
718 
NotifyAllWindows(DataChangedEvent & rDCEvt)719 void Application::NotifyAllWindows( DataChangedEvent& rDCEvt )
720 {
721     ImplSVData* pSVData = ImplGetSVData();
722     vcl::Window* pFrame = pSVData->maFrameData.mpFirstFrame;
723     while ( pFrame )
724     {
725         pFrame->NotifyAllChildren( rDCEvt );
726 
727         vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
728         while ( pSysWin )
729         {
730             pSysWin->NotifyAllChildren( rDCEvt );
731             pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
732         }
733 
734         pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
735     }
736 }
737 
ImplCallEventListenersApplicationDataChanged(void * pData)738 void Application::ImplCallEventListenersApplicationDataChanged( void* pData )
739 {
740     ImplSVData* pSVData = ImplGetSVData();
741     VclWindowEvent aEvent( nullptr, VclEventId::ApplicationDataChanged, pData );
742 
743     pSVData->maAppData.maEventListeners.Call( aEvent );
744 }
745 
ImplCallEventListeners(VclSimpleEvent & rEvent)746 void Application::ImplCallEventListeners( VclSimpleEvent& rEvent )
747 {
748     ImplSVData* pSVData = ImplGetSVData();
749     pSVData->maAppData.maEventListeners.Call( rEvent );
750 }
751 
AddEventListener(const Link<VclSimpleEvent &,void> & rEventListener)752 void Application::AddEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
753 {
754     ImplSVData* pSVData = ImplGetSVData();
755     pSVData->maAppData.maEventListeners.addListener( rEventListener );
756 }
757 
RemoveEventListener(const Link<VclSimpleEvent &,void> & rEventListener)758 void Application::RemoveEventListener( const Link<VclSimpleEvent&,void>& rEventListener )
759 {
760     ImplSVData* pSVData = ImplGetSVData();
761     pSVData->maAppData.maEventListeners.removeListener( rEventListener );
762 }
763 
AddKeyListener(const Link<VclWindowEvent &,bool> & rKeyListener)764 void Application::AddKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
765 {
766     ImplSVData* pSVData = ImplGetSVData();
767     pSVData->maAppData.maKeyListeners.push_back( rKeyListener );
768 }
769 
RemoveKeyListener(const Link<VclWindowEvent &,bool> & rKeyListener)770 void Application::RemoveKeyListener( const Link<VclWindowEvent&,bool>& rKeyListener )
771 {
772     ImplSVData* pSVData = ImplGetSVData();
773     auto & rVec = pSVData->maAppData.maKeyListeners;
774     std::erase(rVec, rKeyListener);
775 }
776 
HandleKey(VclEventId nEvent,vcl::Window * pWin,KeyEvent * pKeyEvent)777 bool Application::HandleKey( VclEventId nEvent, vcl::Window *pWin, KeyEvent* pKeyEvent )
778 {
779     // let listeners process the key event
780     VclWindowEvent aEvent( pWin, nEvent, static_cast<void *>(pKeyEvent) );
781 
782     ImplSVData* pSVData = ImplGetSVData();
783 
784     if ( pSVData->maAppData.maKeyListeners.empty() )
785         return false;
786 
787     bool bProcessed = false;
788     // Copy the list, because this can be destroyed when calling a Link...
789     std::vector<Link<VclWindowEvent&,bool>> aCopy( pSVData->maAppData.maKeyListeners );
790     for ( const Link<VclWindowEvent&,bool>& rLink : aCopy )
791     {
792         if( rLink.Call( aEvent ) )
793         {
794             bProcessed = true;
795             break;
796         }
797     }
798     return bProcessed;
799 }
800 
PostKeyEvent(VclEventId nEvent,vcl::Window * pWin,KeyEvent const * pKeyEvent)801 ImplSVEvent * Application::PostKeyEvent( VclEventId nEvent, vcl::Window *pWin, KeyEvent const * pKeyEvent )
802 {
803     const SolarMutexGuard aGuard;
804     ImplSVEvent * nEventId = nullptr;
805 
806     if( pWin && pKeyEvent )
807     {
808         std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, *pKeyEvent ));
809 
810         nEventId = PostUserEvent(
811                        LINK( nullptr, Application, PostEventHandler ),
812                        pPostEventData.get() );
813 
814         if( nEventId )
815         {
816             pPostEventData->mnEventId = nEventId;
817             ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
818         }
819     }
820 
821     return nEventId;
822 }
823 
PostGestureEvent(VclEventId nEvent,vcl::Window * pWin,GestureEventPan const * pGestureEvent)824 ImplSVEvent* Application::PostGestureEvent(VclEventId nEvent, vcl::Window* pWin,
825                                            GestureEventPan const * pGestureEvent)
826 {
827     const SolarMutexGuard aGuard;
828     ImplSVEvent * nEventId = nullptr;
829 
830     if (pWin && pGestureEvent)
831     {
832         Point aTransformedPosition(pGestureEvent->mnX, pGestureEvent->mnY);
833 
834         aTransformedPosition.AdjustX(pWin->GetOutOffXPixel());
835         aTransformedPosition.AdjustY(pWin->GetOutOffYPixel());
836 
837         const GestureEventPan aGestureEvent(
838             sal_Int32(aTransformedPosition.X()),
839             sal_Int32(aTransformedPosition.Y()),
840             pGestureEvent->meEventType,
841             pGestureEvent->mnOffset,
842             pGestureEvent->meOrientation
843         );
844 
845         std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData(nEvent, pWin, aGestureEvent));
846 
847         nEventId = PostUserEvent(
848                        LINK( nullptr, Application, PostEventHandler ),
849                        pPostEventData.get());
850 
851         if (nEventId)
852         {
853             pPostEventData->mnEventId = nEventId;
854             ImplGetSVData()->maAppData.maPostedEventList.emplace_back(pWin, pPostEventData.release());
855         }
856     }
857 
858     return nEventId;
859 }
860 
LOKHandleMouseEvent(VclEventId nEvent,vcl::Window * pWindow,const MouseEvent * pEvent)861 bool Application::LOKHandleMouseEvent(VclEventId nEvent, vcl::Window* pWindow, const MouseEvent* pEvent)
862 {
863     bool bSuccess = false;
864     SalMouseEvent aMouseEvent;
865 
866     if (!pWindow)
867         return false;
868 
869     if (!pEvent)
870         return false;
871 
872     aMouseEvent.mnTime = tools::Time::GetSystemTicks();
873     aMouseEvent.mnX = pEvent->GetPosPixel().X();
874     aMouseEvent.mnY = pEvent->GetPosPixel().Y();
875     aMouseEvent.mnCode = pEvent->GetButtons() | pEvent->GetModifier();
876 
877     switch (nEvent)
878     {
879         case VclEventId::WindowMouseMove:
880             aMouseEvent.mnButton = 0;
881             bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEMOVE, false,
882                                                aMouseEvent.mnX, aMouseEvent.mnY,
883                                                aMouseEvent.mnTime, aMouseEvent.mnCode,
884                                                ImplGetMouseMoveMode(&aMouseEvent),
885                                                pEvent->GetClicks());
886         break;
887 
888         case VclEventId::WindowMouseButtonDown:
889             aMouseEvent.mnButton = pEvent->GetButtons();
890             bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONDOWN, false,
891                                                aMouseEvent.mnX, aMouseEvent.mnY,
892                                                aMouseEvent.mnTime,
893 #ifdef MACOSX
894                                                aMouseEvent.mnButton |
895                                                (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
896 #else
897                                                aMouseEvent.mnButton |
898                                                (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
899 #endif
900                                                ImplGetMouseButtonMode(&aMouseEvent),
901                                                pEvent->GetClicks());
902             break;
903 
904         case VclEventId::WindowMouseButtonUp:
905             aMouseEvent.mnButton = pEvent->GetButtons();
906             bSuccess = ImplLOKHandleMouseEvent(pWindow, NotifyEventType::MOUSEBUTTONUP, false,
907                                                aMouseEvent.mnX, aMouseEvent.mnY,
908                                                aMouseEvent.mnTime,
909 #ifdef MACOSX
910                                                aMouseEvent.mnButton |
911                                                (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)),
912 #else
913                                                aMouseEvent.mnButton |
914                                                (aMouseEvent.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)),
915 #endif
916                                                ImplGetMouseButtonMode(&aMouseEvent),
917                                                pEvent->GetClicks());
918             break;
919 
920         default:
921             SAL_WARN( "vcl.layout", "Application::HandleMouseEvent unknown event (" << static_cast<int>(nEvent) << ")" );
922             break;
923     }
924 
925     return bSuccess;
926 }
927 
928 
PostMouseEvent(VclEventId nEvent,vcl::Window * pWin,MouseEvent const * pMouseEvent)929 ImplSVEvent* Application::PostMouseEvent( VclEventId nEvent, vcl::Window *pWin, MouseEvent const * pMouseEvent )
930 {
931     const SolarMutexGuard aGuard;
932     ImplSVEvent * nEventId = nullptr;
933 
934     if( pWin && pMouseEvent )
935     {
936         Point aTransformedPos( pMouseEvent->GetPosPixel() );
937 
938         // LOK uses (0, 0) as the origin of all windows; don't offset.
939         if (!comphelper::LibreOfficeKit::isActive())
940         {
941             aTransformedPos.AdjustX(pWin->GetOutOffXPixel());
942             aTransformedPos.AdjustY(pWin->GetOutOffYPixel());
943         }
944 
945         const MouseEvent aTransformedEvent( aTransformedPos, pMouseEvent->GetClicks(), pMouseEvent->GetMode(),
946                                             pMouseEvent->GetButtons(), pMouseEvent->GetModifier() );
947 
948         std::unique_ptr<ImplPostEventData> pPostEventData(new ImplPostEventData( nEvent, pWin, aTransformedEvent ));
949 
950         nEventId = PostUserEvent(
951                        LINK( nullptr, Application, PostEventHandler ),
952                        pPostEventData.get() );
953 
954         if( nEventId )
955         {
956             pPostEventData->mnEventId = nEventId;
957             ImplGetSVData()->maAppData.maPostedEventList.emplace_back( pWin, pPostEventData.release() );
958         }
959     }
960 
961     return nEventId;
962 }
963 
964 
IMPL_STATIC_LINK(Application,PostEventHandler,void *,pCallData,void)965 IMPL_STATIC_LINK( Application, PostEventHandler, void*, pCallData, void )
966 {
967     const SolarMutexGuard aGuard;
968     ImplPostEventData*  pData = static_cast< ImplPostEventData * >( pCallData );
969     const void*         pEventData;
970     SalEvent            nEvent;
971     ImplSVEvent * const nEventId = pData->mnEventId;
972 
973     switch( pData->mnEvent )
974     {
975         case VclEventId::WindowMouseMove:
976             nEvent = SalEvent::ExternalMouseMove;
977             pEventData = &pData->maMouseEvent;
978         break;
979 
980         case VclEventId::WindowMouseButtonDown:
981             nEvent = SalEvent::ExternalMouseButtonDown;
982             pEventData = &pData->maMouseEvent;
983         break;
984 
985         case VclEventId::WindowMouseButtonUp:
986             nEvent = SalEvent::ExternalMouseButtonUp;
987             pEventData = &pData->maMouseEvent;
988         break;
989 
990         case VclEventId::WindowKeyInput:
991             nEvent = SalEvent::ExternalKeyInput;
992             pEventData = &pData->maKeyEvent;
993         break;
994 
995         case VclEventId::WindowKeyUp:
996             nEvent = SalEvent::ExternalKeyUp;
997             pEventData = &pData->maKeyEvent;
998         break;
999 
1000         case VclEventId::WindowGestureEvent:
1001             nEvent = SalEvent::ExternalGesture;
1002             pEventData = &pData->maGestureEvent;
1003         break;
1004 
1005         default:
1006             nEvent = SalEvent::NONE;
1007             pEventData = nullptr;
1008         break;
1009     }
1010 
1011     if( pData->mpWin && pData->mpWin->mpWindowImpl->mpFrameWindow && pEventData )
1012         ImplWindowFrameProc( pData->mpWin->mpWindowImpl->mpFrameWindow.get(), nEvent, pEventData );
1013 
1014     // remove this event from list of posted events, watch for destruction of internal data
1015     auto svdata = ImplGetSVData();
1016     ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
1017 
1018     while( aIter != svdata->maAppData.maPostedEventList.end() )
1019     {
1020         if( nEventId == (*aIter).second->mnEventId )
1021         {
1022             delete (*aIter).second;
1023             aIter = svdata->maAppData.maPostedEventList.erase( aIter );
1024         }
1025         else
1026             ++aIter;
1027     }
1028 }
1029 
RemoveMouseAndKeyEvents(vcl::Window * pWin)1030 void Application::RemoveMouseAndKeyEvents( vcl::Window* pWin )
1031 {
1032     const SolarMutexGuard aGuard;
1033 
1034     // remove all events for specific window, watch for destruction of internal data
1035     auto svdata = ImplGetSVData();
1036     ::std::vector< ImplPostEventPair >::iterator aIter( svdata->maAppData.maPostedEventList.begin() );
1037 
1038     while( aIter != svdata->maAppData.maPostedEventList.end() )
1039     {
1040         if( pWin == (*aIter).first )
1041         {
1042             if( (*aIter).second->mnEventId )
1043                 RemoveUserEvent( (*aIter).second->mnEventId );
1044 
1045             delete (*aIter).second;
1046             aIter = svdata->maAppData.maPostedEventList.erase( aIter );
1047         }
1048         else
1049             ++aIter;
1050     }
1051 }
1052 
PostUserEvent(const Link<void *,void> & rLink,void * pCaller,bool bReferenceLink)1053 ImplSVEvent * Application::PostUserEvent( const Link<void*,void>& rLink, void* pCaller,
1054                                           bool bReferenceLink )
1055 {
1056     vcl::Window* pDefWindow = ImplGetDefaultWindow();
1057     if ( pDefWindow == nullptr )
1058         return nullptr;
1059 
1060     std::unique_ptr<ImplSVEvent> pSVEvent(new ImplSVEvent);
1061     pSVEvent->mpData    = pCaller;
1062     pSVEvent->maLink    = rLink;
1063     pSVEvent->mpWindow  = nullptr;
1064     pSVEvent->mbCall    = true;
1065     if (bReferenceLink)
1066     {
1067         SolarMutexGuard aGuard;
1068         pSVEvent->mpInstanceRef = static_cast<vcl::Window *>(rLink.GetInstance());
1069     }
1070 
1071     auto pTmpEvent = pSVEvent.get();
1072     if (!pDefWindow->ImplGetFrame()->PostEvent( std::move(pSVEvent) ))
1073         return nullptr;
1074     return pTmpEvent;
1075 }
1076 
RemoveUserEvent(ImplSVEvent * nUserEvent)1077 void Application::RemoveUserEvent( ImplSVEvent * nUserEvent )
1078 {
1079     if(nUserEvent)
1080     {
1081         SAL_WARN_IF( nUserEvent->mpWindow, "vcl",
1082                     "Application::RemoveUserEvent(): Event is send to a window" );
1083         SAL_WARN_IF( !nUserEvent->mbCall, "vcl",
1084                     "Application::RemoveUserEvent(): Event is already removed" );
1085 
1086         nUserEvent->mpWindow.reset();
1087         nUserEvent->mpInstanceRef.reset();
1088         nUserEvent->mbCall = false;
1089     }
1090 }
1091 
GetFocusWindow()1092 vcl::Window* Application::GetFocusWindow()
1093 {
1094     return ImplGetSVData()->mpWinData->mpFocusWin;
1095 }
1096 
GetDefaultDevice()1097 OutputDevice* Application::GetDefaultDevice()
1098 {
1099     vcl::Window* pWindow = ImplGetDefaultWindow();
1100     if (pWindow != nullptr)
1101     {
1102         return pWindow->GetOutDev();
1103     }
1104     else
1105     {
1106         return nullptr;
1107     }
1108 }
1109 
GetSystemDependentDataManager()1110 basegfx::SystemDependentDataManager& Application::GetSystemDependentDataManager()
1111 {
1112     return ImplGetSystemDependentDataManager();
1113 }
1114 
GetFirstTopLevelWindow()1115 vcl::Window* Application::GetFirstTopLevelWindow()
1116 {
1117     ImplSVData* pSVData = ImplGetSVData();
1118     return pSVData->maFrameData.mpFirstFrame;
1119 }
1120 
GetNextTopLevelWindow(vcl::Window const * pWindow)1121 vcl::Window* Application::GetNextTopLevelWindow( vcl::Window const * pWindow )
1122 {
1123     return pWindow->mpWindowImpl->mpFrameData->mpNextFrame;
1124 }
1125 
GetTopWindowCount()1126 tools::Long    Application::GetTopWindowCount()
1127 {
1128     tools::Long nRet = 0;
1129     ImplSVData* pSVData = ImplGetSVData();
1130     vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
1131     while( pWin )
1132     {
1133         if( pWin->ImplGetWindow()->IsTopWindow() )
1134             nRet++;
1135         pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1136     }
1137     return nRet;
1138 }
1139 
GetTopWindow(tools::Long nIndex)1140 vcl::Window* Application::GetTopWindow( tools::Long nIndex )
1141 {
1142     tools::Long nIdx = 0;
1143     ImplSVData* pSVData = ImplGetSVData();
1144     vcl::Window *pWin = pSVData ? pSVData->maFrameData.mpFirstFrame.get() : nullptr;
1145     while( pWin )
1146     {
1147         if( pWin->ImplGetWindow()->IsTopWindow() )
1148         {
1149             if( nIdx == nIndex )
1150                 return pWin->ImplGetWindow();
1151             else
1152                 nIdx++;
1153         }
1154         pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1155     }
1156     return nullptr;
1157 }
1158 
GetActiveTopWindow()1159 vcl::Window* Application::GetActiveTopWindow()
1160 {
1161     vcl::Window *pWin = ImplGetSVData()->mpWinData->mpFocusWin;
1162     while( pWin )
1163     {
1164         if( pWin->IsTopWindow() )
1165             return pWin;
1166         pWin = pWin->mpWindowImpl->mpParent;
1167     }
1168     return nullptr;
1169 }
1170 
SetAppName(const OUString & rUniqueName)1171 void Application::SetAppName( const OUString& rUniqueName )
1172 {
1173     ImplSVData* pSVData = ImplGetSVData();
1174     pSVData->maAppData.mxAppName = rUniqueName;
1175 }
1176 
GetAppName()1177 const OUString & Application::GetAppName()
1178 {
1179     ImplSVData* pSVData = ImplGetSVData();
1180     if ( pSVData->maAppData.mxAppName )
1181         return *(pSVData->maAppData.mxAppName);
1182     else
1183         return EMPTY_OUSTRING;
1184 }
1185 
1186 enum {hwAll=0, hwEnv=1, hwUI=2};
1187 
Localize(TranslateId aId,const bool bLocalize)1188 static OUString Localize(TranslateId aId, const bool bLocalize)
1189 {
1190     if (bLocalize)
1191         return VclResId(aId);
1192     else
1193         return Translate::get(aId, Translate::Create("vcl", LanguageTag(u"en-US"_ustr)));
1194 }
1195 
GetOSVersion()1196 OUString Application::GetOSVersion()
1197 {
1198     ImplSVData* pSVData = ImplGetSVData();
1199     OUString aVersion;
1200     if (pSVData && pSVData->mpDefInst)
1201         aVersion = pSVData->mpDefInst->getOSVersion();
1202     else
1203         aVersion = "-";
1204     return aVersion;
1205 }
1206 
GetHWOSConfInfo(const int bSelection,const bool bLocalize)1207 OUString Application::GetHWOSConfInfo(const int bSelection, const bool bLocalize)
1208 {
1209     OUStringBuffer aDetails;
1210 
1211     const auto appendDetails = [&aDetails](std::u16string_view sep, auto&& val) {
1212         if (!aDetails.isEmpty() && !sep.empty())
1213             aDetails.append(sep);
1214         aDetails.append(std::move(val));
1215     };
1216 
1217     if (bSelection != hwUI) {
1218         appendDetails(u"; ", Localize(SV_APP_CPUTHREADS, bLocalize)
1219                                 + OUString::number(std::thread::hardware_concurrency()));
1220 
1221         OUString aVersion = GetOSVersion();
1222 
1223         appendDetails(u"; ", Localize(SV_APP_OSVERSION, bLocalize) + aVersion);
1224     }
1225 
1226     if (bSelection != hwEnv) {
1227         appendDetails(u"; ", Localize(SV_APP_UIRENDER, bLocalize));
1228 #if HAVE_FEATURE_SKIA
1229         if ( SkiaHelper::isVCLSkiaEnabled() )
1230         {
1231             switch(SkiaHelper::renderMethodToUse())
1232             {
1233                 case SkiaHelper::RenderVulkan:
1234                     appendDetails(u"", Localize(SV_APP_SKIA_VULKAN, bLocalize));
1235                     break;
1236                 case SkiaHelper::RenderMetal:
1237                     appendDetails(u"", Localize(SV_APP_SKIA_METAL, bLocalize));
1238                     break;
1239                 case SkiaHelper::RenderRaster:
1240                     appendDetails(u"", Localize(SV_APP_SKIA_RASTER, bLocalize));
1241                     break;
1242             }
1243         }
1244         else
1245 #endif
1246             appendDetails(u"", Localize(SV_APP_DEFAULT, bLocalize));
1247 
1248 #if (defined LINUX || defined _WIN32 || defined MACOSX || defined __FreeBSD__ || defined EMSCRIPTEN)
1249         appendDetails(u"; ", SV_APP_VCLBACKEND + GetToolkitName());
1250 #endif
1251     }
1252 
1253     return aDetails.makeStringAndClear();
1254 }
1255 
SetDisplayName(const OUString & rName)1256 void Application::SetDisplayName( const OUString& rName )
1257 {
1258     ImplSVData* pSVData = ImplGetSVData();
1259     pSVData->maAppData.mxDisplayName = rName;
1260 }
1261 
GetDisplayName()1262 OUString Application::GetDisplayName()
1263 {
1264     ImplSVData* pSVData = ImplGetSVData();
1265     if ( pSVData->maAppData.mxDisplayName )
1266         return *(pSVData->maAppData.mxDisplayName);
1267     else if (pSVData->maFrameData.mpAppWin)
1268         return pSVData->maFrameData.mpAppWin->GetText();
1269     else
1270         return OUString();
1271 }
1272 
GetScreenCount()1273 unsigned int Application::GetScreenCount()
1274 {
1275     SalSystem* pSys = ImplGetSalSystem();
1276     return pSys ? pSys->GetDisplayScreenCount() : 0;
1277 }
1278 
GetDisplayBuiltInScreen()1279 unsigned int Application::GetDisplayBuiltInScreen()
1280 {
1281     SalSystem* pSys = ImplGetSalSystem();
1282     return pSys ? pSys->GetDisplayBuiltInScreen() : 0;
1283 }
1284 
GetDisplayExternalScreen()1285 unsigned int Application::GetDisplayExternalScreen()
1286 {
1287     // This is really unpleasant, in theory we could have multiple
1288     // external displays etc.
1289     int nExternal(0);
1290     switch (GetDisplayBuiltInScreen())
1291     {
1292     case 0:
1293         nExternal = 1;
1294         break;
1295     case 1:
1296         nExternal = 0;
1297         break;
1298     default:
1299         // When the built-in display is neither 0 nor 1
1300         // then place the full-screen presentation on the
1301         // first available screen.
1302         nExternal = 0;
1303         break;
1304     }
1305     return nExternal;
1306 }
1307 
GetScreenPosSizePixel(unsigned int nScreen)1308 AbsoluteScreenPixelRectangle Application::GetScreenPosSizePixel( unsigned int nScreen )
1309 {
1310     SalSystem* pSys = ImplGetSalSystem();
1311     if (!pSys)
1312     {
1313         SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " failed");
1314         assert(false);
1315         return AbsoluteScreenPixelRectangle();
1316     }
1317     AbsoluteScreenPixelRectangle aRect = pSys->GetDisplayScreenPosSizePixel(nScreen);
1318     if (aRect.GetHeight() == 0)
1319         SAL_WARN("vcl", "Requesting screen size/pos for screen #" << nScreen << " returned 0 height.");
1320     return aRect;
1321 }
1322 
1323 namespace {
calcDistSquare(const AbsoluteScreenPixelPoint & i_rPoint,const AbsoluteScreenPixelRectangle & i_rRect)1324 tools::Long calcDistSquare( const AbsoluteScreenPixelPoint& i_rPoint, const AbsoluteScreenPixelRectangle& i_rRect )
1325 {
1326     const AbsoluteScreenPixelPoint aRectCenter( (i_rRect.Left() + i_rRect.Right())/2,
1327                        (i_rRect.Top() + i_rRect.Bottom())/ 2 );
1328     const tools::Long nDX = aRectCenter.X() - i_rPoint.X();
1329     const tools::Long nDY = aRectCenter.Y() - i_rPoint.Y();
1330     return nDX*nDX + nDY*nDY;
1331 }
1332 }
1333 
GetBestScreen(const AbsoluteScreenPixelRectangle & i_rRect)1334 unsigned int Application::GetBestScreen( const AbsoluteScreenPixelRectangle& i_rRect )
1335 {
1336     const unsigned int nScreens = GetScreenCount();
1337     unsigned int nBestMatchScreen = 0;
1338     unsigned long nOverlap = 0;
1339     for( unsigned int i = 0; i < nScreens; i++ )
1340     {
1341         const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
1342         // if a screen contains the rectangle completely it is obviously the best screen
1343         if( aCurScreenRect.Contains( i_rRect ) )
1344             return i;
1345         // next the screen which contains most of the area of the rect is the best
1346         AbsoluteScreenPixelRectangle aIntersection( aCurScreenRect.GetIntersection( i_rRect ) );
1347         if( ! aIntersection.IsEmpty() )
1348         {
1349             const unsigned long nCurOverlap( aIntersection.GetWidth() * aIntersection.GetHeight() );
1350             if( nCurOverlap > nOverlap )
1351             {
1352                 nOverlap = nCurOverlap;
1353                 nBestMatchScreen = i;
1354             }
1355         }
1356     }
1357     if( nOverlap > 0 )
1358         return nBestMatchScreen;
1359 
1360     // finally the screen which center is nearest to the rect is the best
1361     const AbsoluteScreenPixelPoint aCenter( (i_rRect.Left() + i_rRect.Right())/2,
1362                          (i_rRect.Top() + i_rRect.Bottom())/2 );
1363     tools::Long nDist = std::numeric_limits<tools::Long>::max();
1364     for( unsigned int i = 0; i < nScreens; i++ )
1365     {
1366         const AbsoluteScreenPixelRectangle aCurScreenRect( GetScreenPosSizePixel( i ) );
1367         const tools::Long nCurDist( calcDistSquare( aCenter, aCurScreenRect ) );
1368         if( nCurDist < nDist )
1369         {
1370             nBestMatchScreen = i;
1371             nDist = nCurDist;
1372         }
1373     }
1374     return nBestMatchScreen;
1375 }
1376 
InsertAccel(Accelerator * pAccel)1377 bool Application::InsertAccel( Accelerator* pAccel )
1378 {
1379     ImplSVData* pSVData = ImplGetSVData();
1380 
1381     if ( !pSVData->maAppData.mpAccelMgr )
1382         pSVData->maAppData.mpAccelMgr = new ImplAccelManager();
1383     return pSVData->maAppData.mpAccelMgr->InsertAccel( pAccel );
1384 }
1385 
RemoveAccel(Accelerator const * pAccel)1386 void Application::RemoveAccel( Accelerator const * pAccel )
1387 {
1388     ImplSVData* pSVData = ImplGetSVData();
1389 
1390     if ( pSVData->maAppData.mpAccelMgr )
1391         pSVData->maAppData.mpAccelMgr->RemoveAccel( pAccel );
1392 }
1393 
SetHelp(Help * pHelp)1394 void Application::SetHelp( Help* pHelp )
1395 {
1396     ImplGetSVData()->maAppData.mpHelp = pHelp;
1397 }
1398 
UpdateMainThread()1399 void Application::UpdateMainThread()
1400 {
1401     ImplSVData* pSVData = ImplGetSVData();
1402     if (pSVData && pSVData->mpDefInst)
1403         pSVData->mpDefInst->updateMainThread();
1404 }
1405 
GetHelp()1406 Help* Application::GetHelp()
1407 {
1408     return ImplGetSVData()->maAppData.mpHelp;
1409 }
1410 
GetToolkitName()1411 const OUString & Application::GetToolkitName()
1412 {
1413     ImplSVData* pSVData = ImplGetSVData();
1414     if ( pSVData->maAppData.mxToolkitName )
1415         return *(pSVData->maAppData.mxToolkitName);
1416     else
1417         return EMPTY_OUSTRING;
1418 }
1419 
GetDefDialogParent()1420 vcl::Window* Dialog::GetDefDialogParent()
1421 {
1422     ImplSVData* pSVData = ImplGetSVData();
1423     // find some useful dialog parent
1424 
1425     // always use the topmost parent of the candidate
1426     // window to avoid using dialogs or floaters
1427     // as DefDialogParent
1428 
1429     // current focus frame
1430     vcl::Window *pWin = pSVData->mpWinData->mpFocusWin;
1431     if (pWin && !pWin->IsMenuFloatingWindow())
1432     {
1433         while (pWin->mpWindowImpl && pWin->mpWindowImpl->mpParent)
1434             pWin = pWin->mpWindowImpl->mpParent;
1435 
1436         // check for corrupted window hierarchy, #122232#, may be we now crash somewhere else
1437         if (!pWin->mpWindowImpl)
1438         {
1439             OSL_FAIL( "Window hierarchy corrupted!" );
1440             pSVData->mpWinData->mpFocusWin = nullptr;   // avoid further access
1441             return nullptr;
1442         }
1443 
1444         if ((pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0)
1445         {
1446             return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1447         }
1448     }
1449 
1450     // last active application frame
1451     pWin = pSVData->maFrameData.mpActiveApplicationFrame;
1452     if (pWin)
1453     {
1454         return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1455     }
1456 
1457     // first visible top window (may be totally wrong...)
1458     pWin = pSVData->maFrameData.mpFirstFrame;
1459     while (pWin)
1460     {
1461         if( pWin->ImplGetWindow()->IsTopWindow() &&
1462             pWin->mpWindowImpl->mbReallyVisible &&
1463             (pWin->mpWindowImpl->mnStyle & WB_INTROWIN) == 0
1464         )
1465         {
1466             while( pWin->mpWindowImpl->mpParent )
1467                 pWin = pWin->mpWindowImpl->mpParent;
1468             return pWin->mpWindowImpl->mpFrameWindow->ImplGetWindow();
1469         }
1470         pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame;
1471     }
1472 
1473     // use the desktop
1474     return nullptr;
1475 }
1476 
GetDefDialogParent()1477 weld::Window* Application::GetDefDialogParent()
1478 {
1479     vcl::Window* pWindow = Dialog::GetDefDialogParent();
1480     return pWindow ? pWindow->GetFrameWeld() : nullptr;
1481 }
1482 
GetDialogCancelMode()1483 DialogCancelMode Application::GetDialogCancelMode()
1484 {
1485     return ImplGetSVData()->maAppData.meDialogCancel;
1486 }
1487 
SetDialogCancelMode(DialogCancelMode mode)1488 void Application::SetDialogCancelMode( DialogCancelMode mode )
1489 {
1490     ImplGetSVData()->maAppData.meDialogCancel = mode;
1491 }
1492 
IsDialogCancelEnabled()1493 bool Application::IsDialogCancelEnabled()
1494 {
1495     return ImplGetSVData()->maAppData.meDialogCancel != DialogCancelMode::Off;
1496 }
1497 
SetSystemWindowMode(SystemWindowFlags nMode)1498 void Application::SetSystemWindowMode( SystemWindowFlags nMode )
1499 {
1500     ImplGetSVData()->maAppData.mnSysWinMode = nMode;
1501 }
1502 
GetSystemWindowMode()1503 SystemWindowFlags Application::GetSystemWindowMode()
1504 {
1505     return ImplGetSVData()->maAppData.mnSysWinMode;
1506 }
1507 
GetVCLToolkit()1508 css::uno::Reference< css::awt::XToolkit > Application::GetVCLToolkit()
1509 {
1510     css::uno::Reference< css::awt::XToolkit > xT;
1511     UnoWrapperBase* pWrapper = UnoWrapperBase::GetUnoWrapper();
1512     if ( pWrapper )
1513         xT = pWrapper->GetVCLToolkit();
1514     return xT;
1515 }
1516 
1517 #ifdef DISABLE_DYNLOADING
1518 
1519 extern "C" { UnoWrapperBase* CreateUnoWrapper(); }
1520 
1521 #else
1522 
thisModule()1523 extern "C" { static void thisModule() {} }
1524 
1525 #endif
1526 
GetUnoWrapper(bool bCreateIfNotExist)1527 UnoWrapperBase* UnoWrapperBase::GetUnoWrapper( bool bCreateIfNotExist )
1528 {
1529     ImplSVData* pSVData = ImplGetSVData();
1530     static bool bAlreadyTriedToCreate = false;
1531     if ( !pSVData->mpUnoWrapper && bCreateIfNotExist && !bAlreadyTriedToCreate )
1532     {
1533 #ifndef DISABLE_DYNLOADING
1534         osl::Module aTkLib;
1535         aTkLib.loadRelative(&thisModule, TK_DLL_NAME);
1536         if (aTkLib.is())
1537         {
1538             FN_TkCreateUnoWrapper fnCreateWrapper = reinterpret_cast<FN_TkCreateUnoWrapper>(aTkLib.getFunctionSymbol("CreateUnoWrapper"));
1539             if ( fnCreateWrapper )
1540             {
1541                 pSVData->mpUnoWrapper = fnCreateWrapper();
1542             }
1543             aTkLib.release();
1544         }
1545         SAL_WARN_IF( !pSVData->mpUnoWrapper, "vcl", "UnoWrapper could not be created!" );
1546 #else
1547         pSVData->mpUnoWrapper = CreateUnoWrapper();
1548 #endif
1549         bAlreadyTriedToCreate = true;
1550     }
1551     return pSVData->mpUnoWrapper;
1552 }
1553 
SetUnoWrapper(UnoWrapperBase * pWrapper)1554 void UnoWrapperBase::SetUnoWrapper( UnoWrapperBase* pWrapper )
1555 {
1556     ImplSVData* pSVData = ImplGetSVData();
1557     SAL_WARN_IF( pSVData->mpUnoWrapper, "vcl", "SetUnoWrapper: Wrapper already exists" );
1558     pSVData->mpUnoWrapper = pWrapper;
1559 }
1560 
GetDisplayConnection()1561 rtl::Reference<vcl::DisplayConnectionDispatch> Application::GetDisplayConnection()
1562 {
1563     ImplSVData* pSVData = ImplGetSVData();
1564 
1565     if( !pSVData->mxDisplayConnection.is() )
1566     {
1567         pSVData->mxDisplayConnection.set( new vcl::DisplayConnectionDispatch );
1568         pSVData->mxDisplayConnection->start();
1569     }
1570 
1571     return pSVData->mxDisplayConnection;
1572 }
1573 
SetFilterHdl(const Link<ConvertData &,bool> & rLink)1574 void Application::SetFilterHdl( const Link<ConvertData&,bool>& rLink )
1575 {
1576     ImplGetSVData()->maGDIData.mxGrfConverter->SetFilterHdl( rLink );
1577 }
1578 
GetAppLocaleDataWrapper()1579 const LocaleDataWrapper& Application::GetAppLocaleDataWrapper()
1580 {
1581     return GetSettings().GetLocaleDataWrapper();
1582 }
1583 
EnableHeadlessMode(bool dialogsAreFatal)1584 void Application::EnableHeadlessMode( bool dialogsAreFatal )
1585 {
1586     DialogCancelMode eNewMode = dialogsAreFatal ? DialogCancelMode::Fatal : DialogCancelMode::Silent;
1587     DialogCancelMode eOldMode = GetDialogCancelMode();
1588     assert(eOldMode == DialogCancelMode::Off || GetDialogCancelMode() == eNewMode);
1589     if (eOldMode != eNewMode)
1590         SetDialogCancelMode( eNewMode );
1591 }
1592 
IsHeadlessModeEnabled()1593 bool Application::IsHeadlessModeEnabled()
1594 {
1595     return IsDialogCancelEnabled() || comphelper::LibreOfficeKit::isActive();
1596 }
1597 
EnableBitmapRendering()1598 void Application::EnableBitmapRendering()
1599 {
1600     ImplGetSVData()->maAppData.mbRenderToBitmaps = true;
1601 }
1602 
IsBitmapRendering()1603 bool Application::IsBitmapRendering()
1604 {
1605     return ImplGetSVData()->maAppData.mbRenderToBitmaps;
1606 }
1607 
EnableConsoleOnly()1608 void Application::EnableConsoleOnly()
1609 {
1610     EnableHeadlessMode(true);
1611     EnableBitmapRendering();
1612 }
1613 
1614 static bool bSafeMode = false;
1615 
IsSafeModeEnabled()1616 bool Application::IsSafeModeEnabled()
1617 {
1618     return bSafeMode;
1619 }
1620 
EnableSafeMode()1621 void Application::EnableSafeMode()
1622 {
1623     bSafeMode = true;
1624 }
1625 
ShowNativeErrorBox(const OUString & sTitle,const OUString & sMessage)1626 void Application::ShowNativeErrorBox(const OUString& sTitle  ,
1627                                      const OUString& sMessage)
1628 {
1629     int btn = ImplGetSalSystem()->ShowNativeMessageBox(
1630             sTitle,
1631             sMessage);
1632     if (btn != SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK) {
1633         SAL_WARN( "vcl", "ShowNativeMessageBox returned " << btn);
1634     }
1635 }
1636 
GetDesktopEnvironment()1637 const OUString& Application::GetDesktopEnvironment()
1638 {
1639     if (IsHeadlessModeEnabled())
1640     {
1641         static constexpr OUString aNone(u"none"_ustr);
1642         return aNone;
1643     }
1644     else
1645         return SalGetDesktopEnvironment();
1646 }
1647 
AddToRecentDocumentList(const OUString & rFileUrl,const OUString & rMimeType,const OUString & rDocumentService)1648 void Application::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService)
1649 {
1650     ImplSVData* pSVData = ImplGetSVData();
1651     pSVData->mpDefInst->AddToRecentDocumentList(rFileUrl, rMimeType, rDocumentService);
1652 }
1653 
1654 // MT: AppEvent was in oldsv.cxx, but is still needed...
AppEvent(const ApplicationEvent &)1655 void Application::AppEvent( const ApplicationEvent& /*rAppEvent*/ )
1656 {
1657 }
1658 
hasNativeFileSelection()1659 bool Application::hasNativeFileSelection()
1660 {
1661     ImplSVData* pSVData = ImplGetSVData();
1662     return pSVData->mpDefInst->hasNativeFileSelection();
1663 }
1664 
1665 Reference< ui::dialogs::XFilePicker2 >
createFilePicker(const Reference<uno::XComponentContext> & xSM)1666 Application::createFilePicker( const Reference< uno::XComponentContext >& xSM )
1667 {
1668     ImplSVData* pSVData = ImplGetSVData();
1669     return pSVData->mpDefInst->createFilePicker( xSM );
1670 }
1671 
1672 Reference< ui::dialogs::XFolderPicker2 >
createFolderPicker(const Reference<uno::XComponentContext> & xSM)1673 Application::createFolderPicker( const Reference< uno::XComponentContext >& xSM )
1674 {
1675     ImplSVData* pSVData = ImplGetSVData();
1676     return pSVData->mpDefInst->createFolderPicker( xSM );
1677 }
1678 
setDeInitHook(Link<LinkParamNone *,void> const & hook)1679 void Application::setDeInitHook(Link<LinkParamNone*,void> const & hook) {
1680     ImplSVData * pSVData = ImplGetSVData();
1681     assert(!pSVData->maDeInitHook.IsSet());
1682     pSVData->maDeInitHook = hook;
1683     // Fake this for VCLXToolkit ctor instantiated from
1684     // postprocess/CppunitTest_services.mk:
1685     pSVData->maAppData.mbInAppMain = true;
1686 }
1687 
1688 namespace vcl::lok {
1689 
registerPollCallbacks(LibreOfficeKitPollCallback pPollCallback,LibreOfficeKitWakeCallback pWakeCallback,void * pData)1690 void registerPollCallbacks(
1691     LibreOfficeKitPollCallback pPollCallback,
1692     LibreOfficeKitWakeCallback pWakeCallback,
1693     void *pData) {
1694 
1695     ImplSVData * pSVData = ImplGetSVData();
1696     if (pSVData)
1697     {
1698         pSVData->mpPollCallback = pPollCallback;
1699         pSVData->mpWakeCallback = pWakeCallback;
1700         pSVData->mpPollClosure = pData;
1701     }
1702 }
1703 
unregisterPollCallbacks()1704 void unregisterPollCallbacks()
1705 {
1706     ImplSVData * pSVData = ImplGetSVData();
1707     if (!pSVData)
1708         return;
1709 
1710     // Not hyper-elegant - but in the case of Android & unipoll we need to detach
1711     // this thread from the JVM's clutches to avoid a crash closing document
1712     if (pSVData->mpPollClosure && pSVData->mpDefInst)
1713         pSVData->mpDefInst->releaseMainThread();
1714 
1715     // Just set mpPollClosure to null as that is what calling this means, that the callback data
1716     // points to an object that no longer exists. In particular, don't set
1717     // pSVData->mpPollCallback to nullptr as that is used to detect whether Unipoll is in use in
1718     // isUnipoll().
1719     pSVData->mpPollClosure = nullptr;
1720 }
1721 
isUnipoll()1722 bool isUnipoll()
1723 {
1724     ImplSVData * pSVData = ImplGetSVData();
1725     return pSVData && pSVData->mpPollCallback != nullptr;
1726 }
1727 
numberOfViewsChanged(int count)1728 void numberOfViewsChanged(int count)
1729 {
1730     if (count == 0)
1731         return;
1732     ImplSVData * pSVData = ImplGetSVData();
1733     auto& rCache = pSVData->maGDIData.maScaleCache;
1734     // Normally the cache size is set to 10, scale according to the number of users.
1735     rCache.setMaxSize(count * 10);
1736 }
1737 
dumpState(rtl::OStringBuffer & rState)1738 void dumpState(rtl::OStringBuffer &rState)
1739 {
1740     ImplSVData* pSVData = ImplGetSVData();
1741     if (!pSVData)
1742         return;
1743 
1744 #ifndef NDEBUG
1745     // lo_dumpState deliberately doesn't take SolarMutexGuard
1746     // so disable these checks during dumpState
1747     DbgGUIDeInitSolarMutexCheck();
1748 #endif
1749 
1750     rState.append("\nWindows:\t");
1751     rState.append(static_cast<sal_Int32>(Application::GetTopWindowCount()));
1752 
1753     vcl::Window *pWin = Application::GetFirstTopLevelWindow();
1754     while (pWin)
1755     {
1756         tools::JsonWriter aProps;
1757         pWin->DumpAsPropertyTree(aProps);
1758 
1759         rState.append("\n\tWindow: ");
1760 
1761         auto notifier = pWin->GetLOKNotifier();
1762         if (notifier)
1763         {
1764             rState.append(notifier->dumpNotifyState());
1765             rState.append(" ");
1766         }
1767         else
1768             rState.append("no notifier ");
1769 
1770         OString aPropStr = aProps.finishAndGetAsOString();
1771         if (aPropStr.getLength() > 256)
1772         {
1773             rState.append(aPropStr.subView(0, 256));
1774             rState.append("...");
1775         } else
1776             rState.append(aPropStr);
1777 
1778         pWin = Application::GetNextTopLevelWindow( pWin );
1779     }
1780 
1781     pSVData->dumpState(rState);
1782 
1783 #ifndef NDEBUG
1784     DbgGUIInitSolarMutexCheck();
1785 #endif
1786 }
1787 
trimMemory(int nTarget)1788 void trimMemory(int nTarget)
1789 {
1790     if (nTarget >= 1000)
1791     {
1792         SolarMutexGuard aGuard;
1793         ImplSVData* pSVData = ImplGetSVData();
1794         if (!pSVData) // shutting down
1795             return;
1796         pSVData->dropCaches();
1797     }
1798     // else for now caches re-fill themselves as/when used.
1799 }
1800 
1801 } // namespace lok, namespace vcl
1802 
1803 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1804