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