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