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