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