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