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 <memory> 21 #include <config_features.h> 22 #include <config_feature_desktop.h> 23 #include <config_feature_opencl.h> 24 #include <config_java.h> 25 #include <config_folders.h> 26 #include <config_extensions.h> 27 28 #include <sal/config.h> 29 30 #include <iostream> 31 #include <string_view> 32 33 #include <app.hxx> 34 #include <dp_shared.hxx> 35 #include <strings.hrc> 36 #include "cmdlineargs.hxx" 37 #include <lockfile.hxx> 38 #include "userinstall.hxx" 39 #include "desktopcontext.hxx" 40 #include <migration.hxx> 41 #include "officeipcthread.hxx" 42 #if HAVE_FEATURE_UPDATE_MAR 43 #include "updater.hxx" 44 #endif 45 46 #include <framework/desktop.hxx> 47 #include <i18nlangtag/languagetag.hxx> 48 #include <o3tl/char16_t2wchar_t.hxx> 49 #include <svl/languageoptions.hxx> 50 #include <svl/cjkoptions.hxx> 51 #include <svl/ctloptions.hxx> 52 #include <svtools/javacontext.hxx> 53 #include <com/sun/star/beans/XPropertySet.hpp> 54 #include <com/sun/star/frame/theAutoRecovery.hpp> 55 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp> 56 #include <com/sun/star/frame/SessionListener.hpp> 57 #include <com/sun/star/frame/XSynchronousDispatch.hpp> 58 #include <com/sun/star/configuration/theDefaultProvider.hpp> 59 #include <com/sun/star/util/XFlushable.hpp> 60 #include <com/sun/star/system/SystemShellExecuteFlags.hpp> 61 #include <com/sun/star/frame/Desktop.hpp> 62 #include <com/sun/star/frame/StartModule.hpp> 63 #include <com/sun/star/view/XPrintable.hpp> 64 #include <com/sun/star/awt/XTopWindow.hpp> 65 #include <com/sun/star/util/URLTransformer.hpp> 66 #include <com/sun/star/util/XURLTransformer.hpp> 67 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp> 68 #include <com/sun/star/configuration/MissingBootstrapFileException.hpp> 69 #include <com/sun/star/configuration/InvalidBootstrapFileException.hpp> 70 #include <com/sun/star/configuration/InstallationIncompleteException.hpp> 71 #include <com/sun/star/configuration/backend/BackendSetupException.hpp> 72 #include <com/sun/star/configuration/backend/BackendAccessException.hpp> 73 #include <com/sun/star/task/theJobExecutor.hpp> 74 #include <com/sun/star/task/OfficeRestartManager.hpp> 75 #include <com/sun/star/task/XRestartManager.hpp> 76 #include <com/sun/star/document/XDocumentEventListener.hpp> 77 #include <com/sun/star/office/Quickstart.hpp> 78 #include <com/sun/star/system/XSystemShellExecute.hpp> 79 #include <com/sun/star/system/SystemShellExecute.hpp> 80 #include <com/sun/star/loader/XImplementationLoader.hpp> 81 82 #include <desktop/exithelper.h> 83 #include <sal/log.hxx> 84 #include <toolkit/helper/vclunohelper.hxx> 85 #include <comphelper/configuration.hxx> 86 #include <comphelper/fileurl.hxx> 87 #include <comphelper/threadpool.hxx> 88 #include <comphelper/processfactory.hxx> 89 #include <comphelper/backupfilehelper.hxx> 90 #include <uno/current_context.hxx> 91 #include <unotools/bootstrap.hxx> 92 #include <unotools/configmgr.hxx> 93 #include <unotools/moduleoptions.hxx> 94 #include <unotools/localfilehelper.hxx> 95 #include <unotools/ucbhelper.hxx> 96 #include <officecfg/Office/Common.hxx> 97 #include <officecfg/Office/Recovery.hxx> 98 #include <officecfg/Office/Update.hxx> 99 #include <officecfg/Setup.hxx> 100 #include <osl/file.hxx> 101 #include <osl/process.h> 102 #include <rtl/byteseq.hxx> 103 #include <unotools/pathoptions.hxx> 104 #include <unotools/VersionConfig.hxx> 105 #include <rtl/bootstrap.hxx> 106 #include <vcl/test/GraphicsRenderTests.hxx> 107 #include <vcl/glxtestprocess.hxx> 108 #include <vcl/help.hxx> 109 #include <vcl/weld.hxx> 110 #include <vcl/settings.hxx> 111 #include <sfx2/flatpak.hxx> 112 #include <sfx2/sfxsids.hrc> 113 #include <sfx2/app.hxx> 114 #include <sfx2/safemode.hxx> 115 #include <svl/itemset.hxx> 116 #include <svl/eitem.hxx> 117 #include <basic/sbstar.hxx> 118 #include <desktop/crashreport.hxx> 119 #include <tools/urlobj.hxx> 120 #include <tools/diagnose_ex.h> 121 #include <svtools/fontsubstconfig.hxx> 122 #include <svtools/accessibilityoptions.hxx> 123 #include <svtools/apearcfg.hxx> 124 #include <vcl/graphicfilter.hxx> 125 #include <vcl/window.hxx> 126 #include "langselect.hxx" 127 #include <salhelper/thread.hxx> 128 129 #if defined MACOSX 130 #include <errno.h> 131 #include <sys/wait.h> 132 #endif 133 134 #ifdef _WIN32 135 #define WIN32_LEAN_AND_MEAN 136 #include <windows.h> 137 #include <vcl/fileregistration.hxx> 138 #endif 139 140 #if defined(_WIN32) 141 #include <process.h> 142 #define GETPID _getpid 143 #else 144 #include <unistd.h> 145 #define GETPID getpid 146 #endif 147 148 #include <strings.hxx> 149 150 using namespace ::com::sun::star::awt; 151 using namespace ::com::sun::star::uno; 152 using namespace ::com::sun::star::util; 153 using namespace ::com::sun::star::lang; 154 using namespace ::com::sun::star::beans; 155 using namespace ::com::sun::star::frame; 156 using namespace ::com::sun::star::document; 157 using namespace ::com::sun::star::view; 158 using namespace ::com::sun::star::task; 159 using namespace ::com::sun::star::system; 160 using namespace ::com::sun::star::ui; 161 using namespace ::com::sun::star::ui::dialogs; 162 using namespace ::com::sun::star::container; 163 164 namespace desktop 165 { 166 167 static oslSignalHandler pSignalHandler = nullptr; 168 169 namespace { 170 171 #if HAVE_FEATURE_EXTENSIONS 172 173 // Remove any existing UserInstallation's extensions cache data remaining from 174 // old installations. This addresses at least two problems: 175 // 176 // For one, apparently due to the old share/prereg/bundled mechanism (disabled 177 // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying 178 // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled 179 // cache could contain corrupted information (like a UNO component registered 180 // twice, which got changed from active to passive registration in one LO 181 // version, but the version of the corresponding bundled extension only 182 // incremented in a later LO version). 183 // 184 // For another, UserInstallations have been seen in the wild where no extensions 185 // were installed per-user (any longer), but user/uno_packages/cache/registry/ 186 // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files 187 // contained data nevertheless. 188 // 189 // When a LO upgrade is detected (i.e., no user/extensions/buildid or one 190 // containing an old build ID), then user/extensions and 191 // user/uno_packages/cache/registry/ 192 // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are 193 // removed. That should prevent any problems starting the service manager due 194 // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the 195 // removed cache data is recreated. 196 // 197 // Multiple instances of soffice.bin can execute this code in parallel for a 198 // single UserInstallation, as it is called before RequestHandler is set up. 199 // Therefore, any errors here only lead to SAL_WARNs. 200 // 201 // At least in theory, this function could be removed again once no 202 // UserInstallation can be poisoned by old junk any more. 203 bool cleanExtensionCache() { 204 OUString buildId( 205 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"); 206 rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure 207 OUString extDir( 208 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") 209 ":UserInstallation}/user/extensions"); 210 rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure 211 OUString buildIdFile(extDir + "/buildid"); 212 osl::File fr(buildIdFile); 213 osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read); 214 switch (rc) { 215 case osl::FileBase::E_None: 216 { 217 rtl::ByteSequence s1; 218 rc = fr.readLine(s1); 219 osl::FileBase::RC rc2 = fr.close(); 220 SAL_WARN_IF( 221 rc2 != osl::FileBase::E_None, "desktop.app", 222 "cannot close " << fr.getURL() << " after reading: " << +rc2); 223 // readLine returns E_AGAIN for a zero-size file: 224 if (rc != osl::FileBase::E_None && rc != osl::FileBase::E_AGAIN) { 225 SAL_WARN( "desktop.app", "cannot read from " << fr.getURL() << ": " << +rc); 226 break; 227 } 228 OUString s2( 229 reinterpret_cast< char const * >(s1.getConstArray()), 230 s1.getLength(), RTL_TEXTENCODING_ISO_8859_1); 231 // using ISO 8859-1 avoids any and all conversion errors; the 232 // content should only be a subset of ASCII, anyway 233 if (s2 == buildId) { 234 return false; 235 } 236 break; 237 } 238 case osl::FileBase::E_NOENT: 239 break; 240 default: 241 SAL_WARN( "desktop.app", "cannot open " << fr.getURL() << " for reading: " << +rc); 242 break; 243 } 244 utl::removeTree(extDir); 245 OUString userRcFile( 246 "$UNO_USER_PACKAGES_CACHE/registry/" 247 "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc"); 248 rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure 249 rc = osl::File::remove(userRcFile); 250 SAL_WARN_IF( 251 rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop.app", 252 "cannot remove file " << userRcFile << ": " << +rc); 253 rc = osl::Directory::createPath(extDir); 254 SAL_WARN_IF( 255 rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop.app", 256 "cannot create path " << extDir << ": " << +rc); 257 osl::File fw(buildIdFile); 258 rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); 259 if (rc != osl::FileBase::E_None) { 260 SAL_WARN( "desktop.app", "cannot open " << fw.getURL() << " for writing: " << +rc); 261 return true; 262 } 263 OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8)); 264 // using UTF-8 avoids almost all conversion errors (and buildid 265 // containing single surrogate halves should never happen, anyway); the 266 // content should only be a subset of ASCII, anyway 267 sal_uInt64 n = 0; 268 rc = fw.write(buf.getStr(), buf.getLength(), n); 269 SAL_WARN_IF( 270 (rc != osl::FileBase::E_None 271 || n != static_cast< sal_uInt32 >(buf.getLength())), 272 "desktop.app", 273 "cannot write to " << fw.getURL() << ": " << +rc << ", " << n); 274 rc = fw.close(); 275 SAL_WARN_IF( 276 rc != osl::FileBase::E_None, "desktop.app", 277 "cannot close " << fw.getURL() << " after writing: " << +rc); 278 return true; 279 } 280 281 #endif 282 283 bool shouldLaunchQuickstart() 284 { 285 bool bQuickstart = Desktop::GetCommandLineArgs().IsQuickstart(); 286 if (!bQuickstart) 287 { 288 const SfxPoolItem* pItem=nullptr; 289 SfxItemSetFixed<SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER> aQLSet(SfxGetpApp()->GetPool()); 290 SfxGetpApp()->GetOptions(aQLSet); 291 SfxItemState eState = aQLSet.GetItemState(SID_ATTR_QUICKLAUNCHER, false, &pItem); 292 if (SfxItemState::SET == eState) 293 bQuickstart = static_cast<const SfxBoolItem*>(pItem)->GetValue(); 294 } 295 return bQuickstart; 296 } 297 298 void SetRestartState() { 299 try { 300 std::shared_ptr< comphelper::ConfigurationChanges > batch( 301 comphelper::ConfigurationChanges::create()); 302 officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch); 303 batch->commit(); 304 } catch (css::uno::Exception) { 305 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring"); 306 } 307 } 308 309 void DoRestartActionsIfNecessary(bool quickstart) { 310 if (!quickstart) 311 return; 312 313 try { 314 if (officecfg::Setup::Office::OfficeRestartInProgress::get()) { 315 std::shared_ptr< comphelper::ConfigurationChanges > batch( 316 comphelper::ConfigurationChanges::create()); 317 officecfg::Setup::Office::OfficeRestartInProgress::set( 318 false, batch); 319 batch->commit(); 320 css::office::Quickstart::createStart( 321 comphelper::getProcessComponentContext(), 322 shouldLaunchQuickstart()); 323 } 324 } catch (css::uno::Exception &) { 325 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring"); 326 } 327 } 328 329 void RemoveIconCacheDirectory() 330 { 331 // See getIconCacheUrl in vcl/source/image/ImplImageTree.cxx 332 OUString sUrl = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER 333 "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache"; 334 rtl::Bootstrap::expandMacros(sUrl); 335 utl::UCBContentHelper::Kill(sUrl); 336 } 337 338 } 339 340 namespace { 341 342 void runGraphicsRenderTests() 343 { 344 if (!utl::isProductVersionUpgraded(false)) 345 { 346 return; 347 } 348 GraphicsRenderTests TestObject; 349 TestObject.run(); 350 } 351 352 353 OUString MakeStartupErrorMessage(std::u16string_view aErrorMessage) 354 { 355 return DpResId(STR_BOOTSTRAP_ERR_CANNOT_START) + "\n" + aErrorMessage; 356 } 357 358 359 // shows a simple error box with the given message ... but exits from these process ! 360 // Fatal errors can't be solved by the process ... nor any recovery can help. 361 // Mostly the installation was damaged and must be repaired manually .. or by calling 362 // setup again. 363 // On the other side we must make sure that no further actions will be possible within 364 // the current office process ! No pipe requests, no menu/toolbar/shortcut actions 365 // are allowed. Otherwise we will force a "crash inside a crash". 366 // That's why we have to use a special native message box here which does not use yield :-) 367 368 void FatalError(const OUString& sMessage) 369 { 370 OUString sProductKey = ::utl::Bootstrap::getProductKey(); 371 if ( sProductKey.isEmpty()) 372 { 373 osl_getExecutableFile( &sProductKey.pData ); 374 375 ::sal_uInt32 nLastIndex = sProductKey.lastIndexOf('/'); 376 if ( nLastIndex > 0 ) 377 sProductKey = sProductKey.copy( nLastIndex+1 ); 378 } 379 380 OUString sTitle = sProductKey + " - Fatal Error"; 381 Application::ShowNativeErrorBox (sTitle, sMessage); 382 std::cerr << sTitle << ": " << sMessage << std::endl; 383 _exit(EXITHELPER_FATAL_ERROR); 384 } 385 386 } 387 388 CommandLineArgs& Desktop::GetCommandLineArgs() 389 { 390 static CommandLineArgs theCommandLineArgs; 391 return theCommandLineArgs; 392 } 393 394 OUString ReplaceStringHookProc( const OUString& rStr ) 395 { 396 const static OUString sBuildId(utl::Bootstrap::getBuildIdData("development")), 397 sBrandName(utl::ConfigManager::getProductName()), 398 sVersion(utl::ConfigManager::getProductVersion()), 399 sAboutBoxVersion(utl::ConfigManager::getAboutBoxProductVersion()), 400 sAboutBoxVersionSuffix(utl::ConfigManager::getAboutBoxProductVersionSuffix()), 401 sExtension(utl::ConfigManager::getProductExtension()); 402 403 OUString sRet(rStr); 404 if (sRet.indexOf("%PRODUCT") != -1 || sRet.indexOf("%ABOUTBOX") != -1) 405 { 406 sRet = sRet.replaceAll( "%PRODUCTNAME", sBrandName ); 407 sRet = sRet.replaceAll( "%PRODUCTVERSION", sVersion ); 408 sRet = sRet.replaceAll( "%BUILDID", sBuildId ); 409 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", sAboutBoxVersionSuffix ); 410 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion ); 411 sRet = sRet.replaceAll( "%PRODUCTEXTENSION", sExtension ); 412 } 413 414 if ( sRet.indexOf( "%OOOVENDOR" ) != -1 ) 415 { 416 const static OUString sOOOVendor = utl::ConfigManager::getVendor(); 417 sRet = sRet.replaceAll( "%OOOVENDOR", sOOOVendor ); 418 } 419 420 return sRet; 421 } 422 423 Desktop::Desktop() 424 : m_bCleanedExtensionCache(false) 425 , m_bServicesRegistered(false) 426 , m_aBootstrapError(BE_OK) 427 , m_aBootstrapStatus(BS_OK) 428 , m_firstRunTimer( "desktop::Desktop m_firstRunTimer" ) 429 { 430 m_firstRunTimer.SetTimeout(3000); // 3 sec. 431 m_firstRunTimer.SetInvokeHandler(LINK(this, Desktop, AsyncInitFirstRun)); 432 } 433 434 Desktop::~Desktop() 435 { 436 } 437 438 void Desktop::Init() 439 { 440 SetBootstrapStatus(BS_OK); 441 442 #if HAVE_FEATURE_EXTENSIONS 443 m_bCleanedExtensionCache = cleanExtensionCache(); 444 #endif 445 446 // We need to have service factory before going further, but see fdo#37195. 447 // Doing this will mmap common.rdb, making it not overwritable on windows, 448 // so this can't happen before the synchronization above. Lets rework this 449 // so that the above is called *from* CreateApplicationServiceManager or 450 // something to enforce this gotcha 451 try 452 { 453 InitApplicationServiceManager(); 454 } 455 catch (css::uno::Exception & e) 456 { 457 SetBootstrapError( BE_UNO_SERVICEMANAGER, e.Message ); 458 } 459 460 // Check whether safe mode is enabled 461 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); 462 // Check if we are restarting from safe mode - in that case we don't want to enter it again 463 if (sfx2::SafeMode::hasRestartFlag()) 464 sfx2::SafeMode::removeRestartFlag(); 465 else if (rCmdLineArgs.IsSafeMode() || sfx2::SafeMode::hasFlag()) 466 Application::EnableSafeMode(); 467 468 // When we are in SafeMode we need to do changes before the configuration 469 // gets read (langselect::prepareLocale() by UNO API -> Components::Components) 470 // This may prepare SafeMode or restore from it by moving data in 471 // the UserConfiguration directory 472 comphelper::BackupFileHelper::reactOnSafeMode(Application::IsSafeModeEnabled()); 473 474 if ( m_aBootstrapError == BE_OK ) 475 { 476 try 477 { 478 if (!langselect::prepareLocale()) 479 { 480 SetBootstrapError( BE_LANGUAGE_MISSING, OUString() ); 481 } 482 } 483 catch (css::uno::Exception & e) 484 { 485 SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message ); 486 } 487 488 // test code for ProfileSafeMode to allow testing the fail 489 // of loading the office configuration initially. To use, 490 // either set to true and compile, or set a breakpoint 491 // in debugger and change the local bool 492 static bool bTryHardOfficeconfigBroken(false); // loplugin:constvars:ignore 493 494 if (bTryHardOfficeconfigBroken) 495 { 496 SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString()); 497 } 498 } 499 500 // start ipc thread only for non-remote offices 501 RequestHandler::Status aStatus = RequestHandler::Enable(true); 502 if ( aStatus == RequestHandler::IPC_STATUS_PIPE_ERROR ) 503 { 504 #if defined ANDROID 505 // Ignore crack pipe errors on Android 506 #else 507 // Keep using this oddly named BE_PATHINFO_MISSING value 508 // for pipe-related errors on other platforms. Of course 509 // this crack with two (if not more) levels of our own 510 // error codes hiding the actual system error code is 511 // broken, but that is done all over the code, let's leave 512 // reengineering that to another year. 513 SetBootstrapError( BE_PATHINFO_MISSING, OUString() ); 514 #endif 515 } 516 else if ( aStatus == RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR ) 517 { 518 SetBootstrapError( BE_PATHINFO_MISSING, OUString() ); 519 } 520 else if ( aStatus == RequestHandler::IPC_STATUS_2ND_OFFICE ) 521 { 522 // 2nd office startup should terminate after sending cmdlineargs through pipe 523 SetBootstrapStatus(BS_TERMINATE); 524 } 525 else if ( !rCmdLineArgs.GetUnknown().isEmpty() 526 || rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() ) 527 { 528 // disable IPC thread in an instance that is just showing a help message 529 RequestHandler::Disable(); 530 } 531 pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, nullptr); 532 } 533 534 void Desktop::InitFinished() 535 { 536 CloseSplashScreen(); 537 } 538 539 void Desktop::DeInit() 540 { 541 try { 542 // instead of removing of the configManager just let it commit all the changes 543 utl::ConfigManager::storeConfigItems(); 544 FlushConfiguration(); 545 546 // close splashscreen if it's still open 547 CloseSplashScreen(); 548 Reference< XComponent >( 549 comphelper::getProcessComponentContext(), UNO_QUERY_THROW )-> 550 dispose(); 551 // nobody should get a destroyed service factory... 552 ::comphelper::setProcessServiceFactory( nullptr ); 553 554 // clear lockfile 555 m_xLockfile.reset(); 556 557 RequestHandler::Disable(); 558 if( pSignalHandler ) 559 osl_removeSignalHandler( pSignalHandler ); 560 } catch (const RuntimeException&) { 561 // someone threw an exception during shutdown 562 // this will leave some garbage behind... 563 TOOLS_WARN_EXCEPTION("desktop.app", "exception throwing during shutdown, will leave some garbage behind"); 564 } 565 } 566 567 bool Desktop::QueryExit() 568 { 569 try 570 { 571 utl::ConfigManager::storeConfigItems(); 572 } 573 catch ( const RuntimeException& ) 574 { 575 } 576 577 static constexpr OUStringLiteral SUSPEND_QUICKSTARTVETO = u"SuspendQuickstartVeto"; 578 579 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); 580 Reference< XPropertySet > xPropertySet(xDesktop, UNO_QUERY_THROW); 581 xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(true) ); 582 583 bool bExit = xDesktop->terminate(); 584 585 if ( !bExit ) 586 { 587 xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(false) ); 588 } 589 else if (!Application::IsEventTestingModeEnabled()) 590 { 591 FlushConfiguration(); 592 try 593 { 594 // it is no problem to call RequestHandler::Disable() more than once 595 // it also looks to be threadsafe 596 RequestHandler::Disable(); 597 } 598 catch ( const RuntimeException& ) 599 { 600 } 601 602 m_xLockfile.reset(); 603 604 } 605 606 return bExit; 607 } 608 609 void Desktop::Shutdown() 610 { 611 framework::getDesktop(::comphelper::getProcessComponentContext())->shutdown(); 612 } 613 614 void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus, std::u16string_view aDiagnosticMessage ) 615 { 616 if ( aBootstrapStatus == ::utl::Bootstrap::DATA_OK ) 617 return; 618 619 OUString aProductKey; 620 OUString aTemp; 621 622 osl_getExecutableFile( &aProductKey.pData ); 623 sal_uInt32 lastIndex = aProductKey.lastIndexOf('/'); 624 if ( lastIndex > 0 ) 625 aProductKey = aProductKey.copy( lastIndex+1 ); 626 627 aTemp = ::utl::Bootstrap::getProductKey( aProductKey ); 628 if ( !aTemp.isEmpty() ) 629 aProductKey = aTemp; 630 631 OUString const aMessage(OUString::Concat(aDiagnosticMessage) + "\n"); 632 633 std::unique_ptr<weld::MessageDialog> xBootstrapFailedBox(Application::CreateMessageDialog(nullptr, 634 VclMessageType::Warning, VclButtonsType::Ok, aMessage)); 635 xBootstrapFailedBox->set_title(aProductKey); 636 xBootstrapFailedBox->run(); 637 } 638 639 // Create an error message depending on bootstrap failure code and an optional file url 640 OUString Desktop::CreateErrorMsgString( 641 utl::Bootstrap::FailureCode nFailureCode, 642 const OUString& aFileURL ) 643 { 644 OUString aMsg; 645 bool bFileInfo = true; 646 647 switch ( nFailureCode ) 648 { 649 /// the shared installation directory could not be located 650 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY: 651 { 652 aMsg = DpResId(STR_BOOTSTRAP_ERR_PATH_INVALID); 653 bFileInfo = false; 654 } 655 break; 656 657 /// the bootstrap INI file could not be found or read 658 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE: 659 { 660 aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING); 661 } 662 break; 663 664 /// the bootstrap INI is missing a required entry 665 /// the bootstrap INI contains invalid data 666 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: 667 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY: 668 { 669 aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_CORRUPT); 670 } 671 break; 672 673 /// the version locator INI file could not be found or read 674 case ::utl::Bootstrap::MISSING_VERSION_FILE: 675 { 676 aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING); 677 } 678 break; 679 680 /// the version locator INI has no entry for this version 681 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY: 682 { 683 aMsg = DpResId(STR_BOOTSTRAP_ERR_NO_SUPPORT); 684 } 685 break; 686 687 /// the user installation directory does not exist 688 case ::utl::Bootstrap::MISSING_USER_DIRECTORY: 689 { 690 aMsg = DpResId(STR_BOOTSTRAP_ERR_DIR_MISSING); 691 } 692 break; 693 694 /// some bootstrap data was invalid in unexpected ways 695 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA: 696 { 697 aMsg = DpResId(STR_BOOTSTRAP_ERR_INTERNAL); 698 bFileInfo = false; 699 } 700 break; 701 702 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY: 703 { 704 // This needs to be improved, see #i67575#: 705 aMsg = "Invalid version file entry"; 706 bFileInfo = false; 707 } 708 break; 709 710 case ::utl::Bootstrap::NO_FAILURE: 711 { 712 OSL_ASSERT(false); 713 } 714 break; 715 } 716 717 if ( bFileInfo ) 718 { 719 OUString aMsgString( aMsg ); 720 OUString aFilePath; 721 722 osl::File::getSystemPathFromFileURL( aFileURL, aFilePath ); 723 724 aMsgString = aMsgString.replaceFirst( "$1", aFilePath ); 725 aMsg = aMsgString; 726 } 727 728 return MakeStartupErrorMessage( aMsg ); 729 } 730 731 void Desktop::HandleBootstrapErrors( 732 BootstrapError aBootstrapError, OUString const & aErrorMessage ) 733 { 734 if ( aBootstrapError == BE_PATHINFO_MISSING ) 735 { 736 OUString aErrorMsg; 737 OUString aBuffer; 738 utl::Bootstrap::Status aBootstrapStatus; 739 utl::Bootstrap::FailureCode nFailureCode; 740 741 aBootstrapStatus = ::utl::Bootstrap::checkBootstrapStatus( aBuffer, nFailureCode ); 742 if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK ) 743 { 744 switch ( nFailureCode ) 745 { 746 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY: 747 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA: 748 { 749 aErrorMsg = CreateErrorMsgString( nFailureCode, OUString() ); 750 } 751 break; 752 753 /// the bootstrap INI file could not be found or read 754 /// the bootstrap INI is missing a required entry 755 /// the bootstrap INI contains invalid data 756 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: 757 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY: 758 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE: 759 { 760 OUString aBootstrapFileURL; 761 762 utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL ); 763 aErrorMsg = CreateErrorMsgString( nFailureCode, aBootstrapFileURL ); 764 } 765 break; 766 767 /// the version locator INI file could not be found or read 768 /// the version locator INI has no entry for this version 769 /// the version locator INI entry is not a valid directory URL 770 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY: 771 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY: 772 case ::utl::Bootstrap::MISSING_VERSION_FILE: 773 { 774 OUString aVersionFileURL; 775 776 utl::Bootstrap::locateVersionFile( aVersionFileURL ); 777 aErrorMsg = CreateErrorMsgString( nFailureCode, aVersionFileURL ); 778 } 779 break; 780 781 /// the user installation directory does not exist 782 case ::utl::Bootstrap::MISSING_USER_DIRECTORY: 783 { 784 OUString aUserInstallationURL; 785 786 utl::Bootstrap::locateUserInstallation( aUserInstallationURL ); 787 aErrorMsg = CreateErrorMsgString( nFailureCode, aUserInstallationURL ); 788 } 789 break; 790 791 case ::utl::Bootstrap::NO_FAILURE: 792 { 793 OSL_ASSERT(false); 794 } 795 break; 796 } 797 798 HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg ); 799 } 800 } 801 else if ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING ) 802 { 803 // UNO service manager is not available. VCL needs a UNO service manager to display a message box!!! 804 // Currently we are not able to display a message box with a service manager due to this limitations inside VCL. 805 806 // When UNO is not properly initialized, all kinds of things can fail 807 // and cause the process to crash. To give the user a hint even if 808 // generating and displaying a message box below crashes, print a 809 // hard-coded message on stderr first: 810 std::cerr 811 << "The application cannot be started.\n" 812 // STR_BOOTSTRAP_ERR_CANNOT_START 813 << (aBootstrapError == BE_UNO_SERVICEMANAGER 814 ? "The component manager is not available.\n" 815 // STR_BOOTSTRAP_ERR_NO_SERVICE 816 : "The configuration service is not available.\n"); 817 // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE 818 if ( !aErrorMessage.isEmpty() ) 819 { 820 std::cerr << "(\"" << aErrorMessage << "\")\n"; 821 } 822 823 // First sentence. We cannot bootstrap office further! 824 OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NO_CFG_SERVICE) + "\n"; 825 if ( !aErrorMessage.isEmpty() ) 826 { 827 aDiagnosticMessage += "(\"" + aErrorMessage + "\")\n"; 828 } 829 830 // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to 831 // repair the installation with the setup executable besides the office executable. Now 832 // we have to ask the user to start the setup on CD/installation directory manually!! 833 aDiagnosticMessage += DpResId(STR_ASK_START_SETUP_MANUALLY); 834 835 FatalError(MakeStartupErrorMessage(aDiagnosticMessage)); 836 } 837 else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN ) 838 { 839 // set flag at BackupFileHelper to be able to know if _exit was called and 840 // actions are executed after this. This method we are in will not return, 841 // but end up in a _exit() call 842 comphelper::BackupFileHelper::setExitWasCalled(); 843 844 // enter safe mode, too 845 sfx2::SafeMode::putFlag(); 846 847 OUString msg(DpResId(STR_CONFIG_ERR_ACCESS_GENERAL)); 848 if (!aErrorMessage.isEmpty()) { 849 msg += "\n(\"" + aErrorMessage + "\")"; 850 } 851 FatalError(MakeStartupErrorMessage(msg)); 852 } 853 else if ( aBootstrapError == BE_USERINSTALL_FAILED ) 854 { 855 OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_USERINSTALL_FAILED); 856 FatalError(MakeStartupErrorMessage(aDiagnosticMessage)); 857 } 858 else if ( aBootstrapError == BE_LANGUAGE_MISSING ) 859 { 860 OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_LANGUAGE_MISSING); 861 FatalError(MakeStartupErrorMessage(aDiagnosticMessage)); 862 } 863 else if (( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) || 864 ( aBootstrapError == BE_USERINSTALL_NOWRITEACCESS )) 865 { 866 OUString aUserInstallationURL; 867 OUString aUserInstallationPath; 868 utl::Bootstrap::locateUserInstallation( aUserInstallationURL ); 869 osl::File::getSystemPathFromFileURL( aUserInstallationURL, aUserInstallationPath ); 870 871 OUString aDiagnosticMessage; 872 if ( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) 873 aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NOTENOUGHDISKSPACE); 874 else 875 aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NOACCESSRIGHTS); 876 aDiagnosticMessage += aUserInstallationPath; 877 878 FatalError(MakeStartupErrorMessage(aDiagnosticMessage)); 879 } 880 } 881 882 883 namespace { 884 885 886 #if HAVE_FEATURE_BREAKPAD 887 void handleCrashReport() 888 { 889 static constexpr OUStringLiteral SERVICENAME_CRASHREPORT = u"com.sun.star.comp.svx.CrashReportUI"; 890 891 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 892 893 Reference< css::frame::XSynchronousDispatch > xRecoveryUI( 894 xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_CRASHREPORT, xContext), 895 css::uno::UNO_QUERY_THROW); 896 897 Reference< css::util::XURLTransformer > xURLParser = 898 css::util::URLTransformer::create(::comphelper::getProcessComponentContext()); 899 900 css::util::URL aURL; 901 css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >()); 902 bool bRet = false; 903 aRet >>= bRet; 904 } 905 #endif 906 907 #if !defined ANDROID 908 void handleSafeMode() 909 { 910 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 911 912 Reference< css::frame::XSynchronousDispatch > xSafeModeUI( 913 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.SafeModeUI", xContext), 914 css::uno::UNO_QUERY_THROW); 915 916 css::util::URL aURL; 917 css::uno::Any aRet = xSafeModeUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >()); 918 bool bRet = false; 919 aRet >>= bRet; 920 } 921 #endif 922 923 /** @short check if recovery must be started or not. 924 925 @param bCrashed [boolean ... out!] 926 the office crashed last times. 927 But may be there are no recovery data. 928 Useful to trigger the error report tool without 929 showing the recovery UI. 930 931 @param bRecoveryDataExists [boolean ... out!] 932 there exists some recovery data. 933 934 @param bSessionDataExists [boolean ... out!] 935 there exists some session data. 936 Because the user may be logged out last time from its 937 unix session... 938 */ 939 void impl_checkRecoveryState(bool& bCrashed , 940 bool& bRecoveryDataExists, 941 bool& bSessionDataExists ) 942 { 943 bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get() 944 #if HAVE_FEATURE_BREAKPAD 945 || CrashReporter::crashReportInfoExists(); 946 #else 947 ; 948 #endif 949 bool elements = officecfg::Office::Recovery::RecoveryList::get()-> 950 hasElements(); 951 bool session 952 = officecfg::Office::Recovery::RecoveryInfo::SessionData::get(); 953 bRecoveryDataExists = elements && !session; 954 bSessionDataExists = elements && session; 955 } 956 957 Reference< css::frame::XSynchronousDispatch > g_xRecoveryUI; 958 959 template <class Ref> 960 struct RefClearGuard 961 { 962 Ref& m_Ref; 963 RefClearGuard(Ref& ref) : m_Ref(ref) {} 964 ~RefClearGuard() { m_Ref.clear(); } 965 }; 966 967 /* @short start the recovery wizard. 968 969 @param bEmergencySave 970 differs between EMERGENCY_SAVE and RECOVERY 971 */ 972 bool impl_callRecoveryUI(bool bEmergencySave , 973 bool bExistsRecoveryData) 974 { 975 constexpr OUStringLiteral COMMAND_EMERGENCYSAVE = u"vnd.sun.star.autorecovery:/doEmergencySave"; 976 constexpr OUStringLiteral COMMAND_RECOVERY = u"vnd.sun.star.autorecovery:/doAutoRecovery"; 977 978 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 979 980 g_xRecoveryUI.set( 981 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.RecoveryUI", xContext), 982 css::uno::UNO_QUERY_THROW); 983 RefClearGuard<Reference< css::frame::XSynchronousDispatch >> refClearGuard(g_xRecoveryUI); 984 985 Reference< css::util::XURLTransformer > xURLParser = 986 css::util::URLTransformer::create(xContext); 987 988 css::util::URL aURL; 989 if (bEmergencySave) 990 aURL.Complete = COMMAND_EMERGENCYSAVE; 991 else if (bExistsRecoveryData) 992 aURL.Complete = COMMAND_RECOVERY; 993 else 994 return false; 995 996 xURLParser->parseStrict(aURL); 997 998 css::uno::Any aRet = g_xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >()); 999 bool bRet = false; 1000 aRet >>= bRet; 1001 return bRet; 1002 } 1003 1004 bool impl_bringToFrontRecoveryUI() 1005 { 1006 Reference< css::frame::XSynchronousDispatch > xRecoveryUI(g_xRecoveryUI); 1007 if (!xRecoveryUI.is()) 1008 return false; 1009 1010 css::util::URL aURL; 1011 aURL.Complete = "vnd.sun.star.autorecovery:/doBringToFront"; 1012 Reference< css::util::XURLTransformer > xURLParser = 1013 css::util::URLTransformer::create(::comphelper::getProcessComponentContext()); 1014 xURLParser->parseStrict(aURL); 1015 1016 css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >()); 1017 bool bRet = false; 1018 aRet >>= bRet; 1019 return bRet; 1020 } 1021 1022 } 1023 1024 namespace { 1025 1026 void restartOnMac(bool passArguments) { 1027 #if defined MACOSX 1028 RequestHandler::Disable(); 1029 #if HAVE_FEATURE_MACOSX_SANDBOX 1030 (void) passArguments; // avoid warnings 1031 OUString aMessage = DpResId(STR_LO_MUST_BE_RESTARTED); 1032 1033 std::unique_ptr<weld::MessageDialog> xRestartBox(Application::CreateMessageDialog(nullptr, 1034 VclMessageType::Warning, VclButtonsType::Ok, aMessage)); 1035 xRestartBox->run(); 1036 #else 1037 OUString execUrl; 1038 OSL_VERIFY(osl_getExecutableFile(&execUrl.pData) == osl_Process_E_None); 1039 OUString execPath; 1040 OString execPath8; 1041 if ((osl::FileBase::getSystemPathFromFileURL(execUrl, execPath) 1042 != osl::FileBase::E_None) || 1043 !execPath.convertToString( 1044 &execPath8, osl_getThreadTextEncoding(), 1045 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | 1046 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) 1047 { 1048 std::abort(); 1049 } 1050 std::vector< OString > args { execPath8 }; 1051 bool wait = false; 1052 if (passArguments) { 1053 sal_uInt32 n = osl_getCommandArgCount(); 1054 for (sal_uInt32 i = 0; i < n; ++i) { 1055 OUString arg; 1056 osl_getCommandArg(i, &arg.pData); 1057 if (arg.match("--accept=")) { 1058 wait = true; 1059 } 1060 OString arg8; 1061 if (!arg.convertToString( 1062 &arg8, osl_getThreadTextEncoding(), 1063 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | 1064 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) 1065 { 1066 std::abort(); 1067 } 1068 args.push_back(arg8); 1069 } 1070 } 1071 std::vector< char const * > argPtrs; 1072 for (auto const& elem : args) 1073 { 1074 argPtrs.push_back(elem.getStr()); 1075 } 1076 argPtrs.push_back(nullptr); 1077 execv(execPath8.getStr(), const_cast< char ** >(argPtrs.data())); 1078 if (errno == ENOTSUP) { // happens when multithreaded on macOS < 10.6 1079 pid_t pid = fork(); 1080 if (pid == 0) { 1081 execv(execPath8.getStr(), const_cast< char ** >(argPtrs.data())); 1082 } else if (pid > 0) { 1083 // Two simultaneously running soffice processes lead to two dock 1084 // icons, so avoid waiting here unless it must be assumed that the 1085 // process invoking soffice itself wants to wait for soffice to 1086 // finish: 1087 if (!wait) { 1088 return; 1089 } 1090 int stat; 1091 if (waitpid(pid, &stat, 0) == pid && WIFEXITED(stat)) { 1092 _exit(WEXITSTATUS(stat)); 1093 } 1094 } 1095 } 1096 std::abort(); 1097 #endif 1098 #else 1099 (void) passArguments; // avoid warnings 1100 #endif 1101 } 1102 1103 #if HAVE_FEATURE_UPDATE_MAR 1104 bool isTimeForUpdateCheck() 1105 { 1106 sal_uInt64 nLastUpdate = officecfg::Office::Update::Update::LastUpdateTime::get(); 1107 sal_uInt64 nNow = tools::Time::GetSystemTicks(); 1108 1109 sal_uInt64 n7DayInMS = 1000 * 60 * 60 * 12 * 1; // 12 hours in ms 1110 if (nNow - n7DayInMS >= nLastUpdate) 1111 return true; 1112 1113 return false; 1114 } 1115 #endif 1116 1117 } 1118 1119 void Desktop::Exception(ExceptionCategory nCategory) 1120 { 1121 // protect against recursive calls 1122 static bool bInException = false; 1123 1124 #if HAVE_FEATURE_BREAKPAD 1125 CrashReporter::removeExceptionHandler(); // disallow re-entry 1126 #endif 1127 1128 SystemWindowFlags nOldMode = Application::GetSystemWindowMode(); 1129 Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE ); 1130 if ( bInException ) 1131 { 1132 Application::Abort( OUString() ); 1133 } 1134 1135 bInException = true; 1136 const CommandLineArgs& rArgs = GetCommandLineArgs(); 1137 1138 // save all modified documents ... if it's allowed doing so. 1139 bool bRestart = false; 1140 bool bAllowRecoveryAndSessionManagement = ( 1141 ( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery 1142 ( !rArgs.IsHeadless() ) && 1143 ( nCategory != ExceptionCategory::UserInterface ) && // recovery can't work without UI ... but UI layer seems to be the reason for this crash 1144 ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicate a corrupted installation...) 1145 ); 1146 if ( bAllowRecoveryAndSessionManagement ) 1147 { 1148 // Save all open documents so they will be reopened 1149 // the next time the application is started 1150 // returns true if at least one document could be saved... 1151 bRestart = impl_callRecoveryUI( 1152 true , // force emergency save 1153 false); 1154 } 1155 1156 FlushConfiguration(); 1157 1158 m_xLockfile.reset(); 1159 1160 if( bRestart ) 1161 { 1162 RequestHandler::Disable(); 1163 if( pSignalHandler ) 1164 osl_removeSignalHandler( pSignalHandler ); 1165 1166 restartOnMac(false); 1167 if ( m_rSplashScreen.is() ) 1168 m_rSplashScreen->reset(); 1169 1170 _exit( EXITHELPER_CRASH_WITH_RESTART ); 1171 } 1172 else 1173 { 1174 Application::Abort( OUString() ); 1175 } 1176 1177 OSL_ASSERT(false); // unreachable 1178 } 1179 1180 void Desktop::AppEvent( const ApplicationEvent& rAppEvent ) 1181 { 1182 HandleAppEvent( rAppEvent ); 1183 } 1184 1185 namespace { 1186 1187 class JVMloadThread : public salhelper::Thread { 1188 public: 1189 JVMloadThread() : salhelper::Thread("Preload JVM thread") 1190 { 1191 } 1192 1193 private: 1194 virtual void execute() override final 1195 { 1196 Reference< XMultiServiceFactory > xSMgr = comphelper::getProcessServiceFactory(); 1197 1198 Reference< css::loader::XImplementationLoader > xJavaComponentLoader( 1199 xSMgr->createInstance("com.sun.star.comp.stoc.JavaComponentLoader"), 1200 css::uno::UNO_QUERY_THROW); 1201 1202 if (xJavaComponentLoader.is()) 1203 { 1204 const css::uno::Reference< ::com::sun::star::registry::XRegistryKey > xRegistryKey; 1205 try 1206 { 1207 xJavaComponentLoader->activate("", "", "", xRegistryKey); 1208 } 1209 catch (...) 1210 { 1211 SAL_WARN("desktop.app", "Cannot activate factory during JVM preloading"); 1212 } 1213 } 1214 } 1215 }; 1216 1217 struct ExecuteGlobals 1218 { 1219 Reference < css::document::XDocumentEventListener > xGlobalBroadcaster; 1220 bool bRestartRequested; 1221 bool bUseSystemFileDialog; 1222 std::unique_ptr<SvtCTLOptions> pCTLLanguageOptions; 1223 std::unique_ptr<SvtPathOptions> pPathOptions; 1224 rtl::Reference< JVMloadThread > xJVMloadThread; 1225 1226 ExecuteGlobals() 1227 : bRestartRequested( false ) 1228 , bUseSystemFileDialog( true ) 1229 {} 1230 }; 1231 1232 } 1233 1234 static ExecuteGlobals* pExecGlobals = nullptr; 1235 1236 int Desktop::Main() 1237 { 1238 pExecGlobals = new ExecuteGlobals(); 1239 1240 // Remember current context object 1241 css::uno::ContextLayer layer( css::uno::getCurrentContext() ); 1242 1243 if ( m_aBootstrapError != BE_OK ) 1244 { 1245 HandleBootstrapErrors( m_aBootstrapError, m_aBootstrapErrorMessage ); 1246 return EXIT_FAILURE; 1247 } 1248 1249 BootstrapStatus eStatus = GetBootstrapStatus(); 1250 if (eStatus == BS_TERMINATE) { 1251 return EXIT_SUCCESS; 1252 } 1253 1254 // Detect desktop environment - need to do this as early as possible 1255 css::uno::setCurrentContext( new DesktopContext( css::uno::getCurrentContext() ) ); 1256 1257 if (officecfg::Office::Common::Misc::PreloadJVM::get() && pExecGlobals) 1258 { 1259 SAL_INFO("desktop.app", "Preload JVM"); 1260 1261 // pre-load JVM 1262 pExecGlobals->xJVMloadThread = new JVMloadThread(); 1263 pExecGlobals->xJVMloadThread->launch(); 1264 } 1265 1266 CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); 1267 1268 Translate::SetReadStringHook(ReplaceStringHookProc); 1269 1270 // Startup screen 1271 OpenSplashScreen(); 1272 1273 SetSplashScreenProgress(10); 1274 1275 userinstall::Status inst_fin = userinstall::finalize(); 1276 if (inst_fin != userinstall::EXISTED && inst_fin != userinstall::CREATED) 1277 { 1278 SAL_WARN( "desktop.app", "userinstall failed"); 1279 if ( inst_fin == userinstall::ERROR_NO_SPACE ) 1280 HandleBootstrapErrors( 1281 BE_USERINSTALL_NOTENOUGHDISKSPACE, OUString() ); 1282 else if ( inst_fin == userinstall::ERROR_CANT_WRITE ) 1283 HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS, OUString() ); 1284 else 1285 HandleBootstrapErrors( BE_USERINSTALL_FAILED, OUString() ); 1286 return EXIT_FAILURE; 1287 } 1288 // refresh path information 1289 utl::Bootstrap::reloadData(); 1290 SetSplashScreenProgress(20); 1291 1292 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 1293 1294 Reference< XRestartManager > xRestartManager( OfficeRestartManager::get(xContext) ); 1295 1296 Reference< XDesktop2 > xDesktop; 1297 1298 RegisterServices(xContext); 1299 1300 SetSplashScreenProgress(25); 1301 1302 #if HAVE_FEATURE_DESKTOP 1303 // check user installation directory for lockfile so we can be sure 1304 // there is no other instance using our data files from a remote host 1305 1306 bool bMustLockProfile = ( getenv( "SAL_NOLOCK_PROFILE" ) == nullptr ); 1307 if ( bMustLockProfile ) 1308 { 1309 m_xLockfile.reset(new Lockfile); 1310 1311 if ( !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsInvisible() && 1312 !rCmdLineArgs.IsNoLockcheck() && !m_xLockfile->check( Lockfile_execWarning )) 1313 { 1314 // Lockfile exists, and user clicked 'no' 1315 return EXIT_FAILURE; 1316 } 1317 } 1318 1319 // check if accessibility is enabled but not working and allow to quit 1320 if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() ) 1321 { 1322 if( !InitAccessBridge() ) 1323 return EXIT_FAILURE; 1324 } 1325 #endif 1326 1327 // terminate if requested... 1328 if( rCmdLineArgs.IsTerminateAfterInit() ) 1329 return EXIT_SUCCESS; 1330 1331 // Read the common configuration items for optimization purpose 1332 if ( !InitializeConfiguration() ) 1333 return EXIT_FAILURE; 1334 1335 #if HAVE_FEATURE_UPDATE_MAR 1336 const char* pUpdaterTestEnable = std::getenv("LIBO_UPDATER_TEST_ENABLE"); 1337 if (pUpdaterTestEnable || officecfg::Office::Update::Update::Enabled::get()) 1338 { 1339 // check if we just updated 1340 const char* pUpdaterRunning = std::getenv("LIBO_UPDATER_TEST_RUNNING"); 1341 bool bUpdateRunning = officecfg::Office::Update::Update::UpdateRunning::get() || pUpdaterRunning; 1342 if (bUpdateRunning) 1343 { 1344 OUString aSeeAlso = officecfg::Office::Update::Update::SeeAlso::get(); 1345 OUString aOldBuildID = officecfg::Office::Update::Update::OldBuildID::get(); 1346 1347 OUString aBuildID = Updater::getBuildID(); 1348 if (aOldBuildID == aBuildID) 1349 { 1350 Updater::log("Old and new Build ID are the same. No Updating took place."); 1351 } 1352 else 1353 { 1354 if (!aSeeAlso.isEmpty()) 1355 { 1356 SAL_INFO("desktop.updater", "See also: " << aSeeAlso); 1357 Reference< css::system::XSystemShellExecute > xSystemShell( 1358 SystemShellExecute::create(::comphelper::getProcessComponentContext()) ); 1359 1360 xSystemShell->execute( aSeeAlso, OUString(), SystemShellExecuteFlags::URIS_ONLY ); 1361 } 1362 } 1363 1364 // reset all the configuration values, 1365 // all values need to be read before this code 1366 std::shared_ptr< comphelper::ConfigurationChanges > batch( 1367 comphelper::ConfigurationChanges::create()); 1368 officecfg::Office::Update::Update::UpdateRunning::set(false, batch); 1369 officecfg::Office::Update::Update::SeeAlso::set(OUString(), batch); 1370 officecfg::Office::Update::Update::OldBuildID::set(OUString(), batch); 1371 batch->commit(); 1372 1373 Updater::removeUpdateFiles(); 1374 } 1375 1376 osl::DirectoryItem aUpdateFile; 1377 osl::DirectoryItem::get(Updater::getUpdateFileURL(), aUpdateFile); 1378 1379 const char* pUpdaterTestUpdate = std::getenv("LIBO_UPDATER_TEST_UPDATE"); 1380 const char* pForcedUpdateCheck = std::getenv("LIBO_UPDATER_TEST_UPDATE_CHECK"); 1381 if (pUpdaterTestUpdate || aUpdateFile.is()) 1382 { 1383 OUString aBuildID("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"); 1384 rtl::Bootstrap::expandMacros(aBuildID); 1385 std::shared_ptr< comphelper::ConfigurationChanges > batch( 1386 comphelper::ConfigurationChanges::create()); 1387 officecfg::Office::Update::Update::OldBuildID::set(aBuildID, batch); 1388 officecfg::Office::Update::Update::UpdateRunning::set(true, batch); 1389 batch->commit(); 1390 1391 // make sure the change is written to the configuration before we start the update 1392 css::uno::Reference<css::util::XFlushable> xFlushable(css::configuration::theDefaultProvider::get(xContext), UNO_QUERY); 1393 xFlushable->flush(); 1394 // avoid the old oosplash staying around 1395 CloseSplashScreen(); 1396 bool bSuccess = update(); 1397 if (bSuccess) 1398 return EXIT_SUCCESS; 1399 } 1400 else if (isTimeForUpdateCheck() || pForcedUpdateCheck) 1401 { 1402 sal_uInt64 nNow = tools::Time::GetSystemTicks(); 1403 Updater::log("Update Check Time: " + OUString::number(nNow)); 1404 std::shared_ptr< comphelper::ConfigurationChanges > batch( 1405 comphelper::ConfigurationChanges::create()); 1406 officecfg::Office::Update::Update::LastUpdateTime::set(nNow, batch); 1407 batch->commit(); 1408 m_aUpdateThread = std::thread(update_checker); 1409 } 1410 } 1411 #endif 1412 1413 SetSplashScreenProgress(30); 1414 1415 // create title string 1416 OUString aTitle(ReplaceStringHookProc(RID_APPTITLE)); 1417 #ifdef DBG_UTIL 1418 //include buildid in non product builds 1419 aTitle += " [" + utl::Bootstrap::getBuildIdData("development") + "]"; 1420 #endif 1421 1422 SetDisplayName( aTitle ); 1423 SetSplashScreenProgress(35); 1424 pExecGlobals->pPathOptions.reset( new SvtPathOptions); 1425 SetSplashScreenProgress(40); 1426 1427 xDesktop = css::frame::Desktop::create( xContext ); 1428 1429 // create service for loading SFX (still needed in startup) 1430 pExecGlobals->xGlobalBroadcaster = Reference < css::document::XDocumentEventListener > 1431 ( css::frame::theGlobalEventBroadcaster::get(xContext), UNO_SET_THROW ); 1432 1433 /* ensure existence of a default window that messages can be dispatched to 1434 This is for the benefit of testtool which uses PostUserEvent extensively 1435 and else can deadlock while creating this window from another thread while 1436 the main thread is not yet in the event loop. 1437 */ 1438 Application::GetDefaultDevice(); 1439 1440 #if HAVE_FEATURE_EXTENSIONS 1441 // Check if bundled or shared extensions were added /removed 1442 // and process those extensions (has to be done before checking 1443 // the extension dependencies! 1444 SynchronizeExtensionRepositories(m_bCleanedExtensionCache, this); 1445 bool bAbort = CheckExtensionDependencies(); 1446 if ( bAbort ) 1447 return EXIT_FAILURE; 1448 1449 if (inst_fin == userinstall::CREATED) 1450 { 1451 Migration::migrateSettingsIfNecessary(); 1452 } 1453 #endif 1454 1455 // keep a language options instance... 1456 pExecGlobals->pCTLLanguageOptions.reset( new SvtCTLOptions(true)); 1457 1458 css::document::DocumentEvent aEvent; 1459 aEvent.EventName = "OnStartApp"; 1460 pExecGlobals->xGlobalBroadcaster->documentEventOccured(aEvent); 1461 1462 SetSplashScreenProgress(50); 1463 1464 // Backing Component 1465 bool bCrashed = false; 1466 bool bExistsRecoveryData = false; 1467 bool bExistsSessionData = false; 1468 1469 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData); 1470 1471 OUString pidfileName = rCmdLineArgs.GetPidfileName(); 1472 if ( !pidfileName.isEmpty() ) 1473 { 1474 OUString pidfileURL; 1475 1476 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None ) 1477 { 1478 osl::File pidfile( pidfileURL ); 1479 osl::FileBase::RC rc; 1480 1481 osl::File::remove( pidfileURL ); 1482 if ( (rc = pidfile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ) ) == osl::File::E_None ) 1483 { 1484 OString pid( OString::number( GETPID() ) ); 1485 sal_uInt64 written = 0; 1486 if ( pidfile.write(pid.getStr(), pid.getLength(), written) != osl::File::E_None ) 1487 { 1488 SAL_WARN("desktop.app", "cannot write pidfile " << pidfile.getURL()); 1489 } 1490 pidfile.close(); 1491 } 1492 else 1493 { 1494 SAL_WARN("desktop.app", "cannot open pidfile " << pidfile.getURL() << rc); 1495 } 1496 } 1497 else 1498 { 1499 SAL_WARN("desktop.app", "cannot get pidfile URL from path" << pidfileName); 1500 } 1501 } 1502 1503 if ( rCmdLineArgs.IsHeadless() || rCmdLineArgs.IsEventTesting() ) 1504 { 1505 // Ensure that we use not the system file dialogs as 1506 // headless mode relies on Application::EnableHeadlessMode() 1507 // which does only work for VCL dialogs!! 1508 pExecGlobals->bUseSystemFileDialog = officecfg::Office::Common::Misc::UseSystemFileDialog::get(); 1509 std::shared_ptr< comphelper::ConfigurationChanges > xChanges( 1510 comphelper::ConfigurationChanges::create()); 1511 officecfg::Office::Common::Misc::UseSystemFileDialog::set( false, xChanges ); 1512 xChanges->commit(); 1513 } 1514 1515 pExecGlobals->bRestartRequested = xRestartManager->isRestartRequested(true); 1516 if ( !pExecGlobals->bRestartRequested ) 1517 { 1518 if ((!rCmdLineArgs.WantsToLoadDocument() && !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsQuickstart()) && 1519 (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE)) && 1520 (!bExistsRecoveryData ) && 1521 (!bExistsSessionData ) && 1522 (!Application::AnyInput( VclInputFlags::APPEVENT ) )) 1523 { 1524 ShowBackingComponent(this); 1525 } 1526 } 1527 1528 SetSplashScreenProgress(55); 1529 1530 svtools::ApplyFontSubstitutionsToVcl(); 1531 1532 SvtTabAppearanceCfg aAppearanceCfg; 1533 SvtTabAppearanceCfg::SetInitialized(); 1534 aAppearanceCfg.SetApplicationDefaults( this ); 1535 SvtAccessibilityOptions aOptions; 1536 aOptions.SetVCLSettings(); 1537 SetSplashScreenProgress(60); 1538 1539 if ( !pExecGlobals->bRestartRequested ) 1540 { 1541 Application::SetFilterHdl( LINK( this, Desktop, ImplInitFilterHdl ) ); 1542 1543 // Preload function depends on an initialized sfx application! 1544 SetSplashScreenProgress(75); 1545 1546 // use system window dialogs 1547 Application::SetSystemWindowMode( SystemWindowFlags::DIALOG ); 1548 1549 SetSplashScreenProgress(80); 1550 1551 if ( !rCmdLineArgs.IsInvisible() && 1552 !rCmdLineArgs.IsNoQuickstart() ) 1553 InitializeQuickstartMode( xContext ); 1554 1555 if ( xDesktop.is() ) 1556 xDesktop->addTerminateListener( new RequestHandlerController ); 1557 SetSplashScreenProgress(100); 1558 1559 // FIXME: move this somewhere sensible. 1560 #if HAVE_FEATURE_OPENCL 1561 CheckOpenCLCompute(xDesktop); 1562 #endif 1563 1564 //Running the VCL graphics rendering tests 1565 runGraphicsRenderTests(); 1566 1567 // Reap the process started by fire_glxtest_process(). 1568 reap_glxtest_process(); 1569 1570 // Release solar mutex just before we wait for our client to connect 1571 { 1572 SolarMutexReleaser aReleaser; 1573 1574 // Post user event to startup first application component window 1575 // We have to send this OpenClients message short before execute() to 1576 // minimize the risk that this message overtakes type detection construction!! 1577 Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) ); 1578 1579 // Post event to enable acceptors 1580 Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) ); 1581 1582 // Acquire solar mutex just before we enter our message loop 1583 } 1584 1585 // call Application::Execute to process messages in vcl message loop 1586 #if HAVE_FEATURE_JAVA 1587 // The JavaContext contains an interaction handler which is used when 1588 // the creation of a Java Virtual Machine fails 1589 css::uno::ContextLayer layer2( 1590 new svt::JavaContext( css::uno::getCurrentContext() ) ); 1591 #endif 1592 // check whether the shutdown is caused by restart just before entering the Execute 1593 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested || 1594 xRestartManager->isRestartRequested(true); 1595 1596 if ( !pExecGlobals->bRestartRequested ) 1597 { 1598 // if this run of the office is triggered by restart, some additional actions should be done 1599 DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() ); 1600 1601 Execute(); 1602 } 1603 } 1604 else 1605 { 1606 if (xDesktop.is()) 1607 xDesktop->terminate(); 1608 } 1609 // CAUTION: you do not necessarily get here e.g. on the Mac. 1610 // please put all deinitialization code into doShutdown 1611 return doShutdown(); 1612 } 1613 1614 int Desktop::doShutdown() 1615 { 1616 if( ! pExecGlobals ) 1617 return EXIT_SUCCESS; 1618 1619 if (m_aUpdateThread.joinable()) 1620 m_aUpdateThread.join(); 1621 1622 if (pExecGlobals->xJVMloadThread.is()) 1623 { 1624 pExecGlobals->xJVMloadThread->join(); 1625 pExecGlobals->xJVMloadThread.clear(); 1626 } 1627 1628 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested || 1629 OfficeRestartManager::get(comphelper::getProcessComponentContext())-> 1630 isRestartRequested(true); 1631 if ( pExecGlobals->bRestartRequested ) 1632 SetRestartState(); 1633 1634 // Restore old value 1635 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); 1636 if ( rCmdLineArgs.IsHeadless() || rCmdLineArgs.IsEventTesting() ) 1637 { 1638 std::shared_ptr< comphelper::ConfigurationChanges > xChanges( 1639 comphelper::ConfigurationChanges::create()); 1640 officecfg::Office::Common::Misc::UseSystemFileDialog::set( pExecGlobals->bUseSystemFileDialog, xChanges ); 1641 xChanges->commit(); 1642 } 1643 1644 OUString pidfileName = rCmdLineArgs.GetPidfileName(); 1645 if ( !pidfileName.isEmpty() ) 1646 { 1647 OUString pidfileURL; 1648 1649 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None ) 1650 { 1651 if ( osl::File::remove( pidfileURL ) != osl::FileBase::E_None ) 1652 { 1653 SAL_WARN("desktop.app", "shutdown: cannot remove pidfile " << pidfileURL); 1654 } 1655 } 1656 else 1657 { 1658 SAL_WARN("desktop.app", "shutdown: cannot get pidfile URL from path" << pidfileName); 1659 } 1660 } 1661 1662 // remove temp directory 1663 RemoveTemporaryDirectory(); 1664 flatpak::removeTemporaryHtmlDirectory(); 1665 1666 // flush evtl. configuration changes so that all config files in user 1667 // dir are written 1668 FlushConfiguration(); 1669 1670 if (pExecGlobals->bRestartRequested) 1671 { 1672 // tdf#128523 1673 RemoveIconCacheDirectory(); 1674 1675 // a restart is already requested, usually due to a configuration change 1676 // that needs a restart to get active. If this is the case, do not try 1677 // to use SecureUserConfig to safe this still untested new configuration 1678 } 1679 else 1680 { 1681 // Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown 1682 // is in progress and the currently used configuration was working. Try to secure this 1683 // working configuration for later eventually necessary restores 1684 comphelper::BackupFileHelper aBackupFileHelper; 1685 1686 aBackupFileHelper.tryPush(); 1687 aBackupFileHelper.tryPushExtensionInfo(); 1688 } 1689 1690 // The acceptors in the AcceptorMap must be released (in DeregisterServices) 1691 // with the solar mutex unlocked, to avoid deadlock: 1692 { 1693 SolarMutexReleaser aReleaser; 1694 DeregisterServices(); 1695 #if HAVE_FEATURE_SCRIPTING 1696 StarBASIC::DetachAllDocBasicItems(); 1697 #endif 1698 } 1699 1700 // be sure that path/language options gets destroyed before 1701 // UCB is deinitialized 1702 pExecGlobals->pCTLLanguageOptions.reset(); 1703 pExecGlobals->pPathOptions.reset(); 1704 1705 comphelper::ThreadPool::getSharedOptimalPool().shutdown(); 1706 1707 bool bRR = pExecGlobals->bRestartRequested; 1708 delete pExecGlobals; 1709 pExecGlobals = nullptr; 1710 1711 if ( bRR ) 1712 { 1713 restartOnMac(true); 1714 if ( m_rSplashScreen.is() ) 1715 m_rSplashScreen->reset(); 1716 1717 return EXITHELPER_NORMAL_RESTART; 1718 } 1719 return EXIT_SUCCESS; 1720 } 1721 1722 IMPL_STATIC_LINK( Desktop, ImplInitFilterHdl, ::ConvertData&, rData, bool ) 1723 { 1724 return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( rData ); 1725 } 1726 1727 bool Desktop::InitializeConfiguration() 1728 { 1729 try 1730 { 1731 css::configuration::theDefaultProvider::get( 1732 comphelper::getProcessComponentContext() ); 1733 return true; 1734 } 1735 catch( css::lang::ServiceNotRegisteredException & e ) 1736 { 1737 HandleBootstrapErrors( 1738 Desktop::BE_UNO_SERVICE_CONFIG_MISSING, e.Message ); 1739 } 1740 catch( const css::configuration::MissingBootstrapFileException& e ) 1741 { 1742 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE, 1743 e.BootstrapFileURL )); 1744 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL, aMsg ); 1745 } 1746 catch( const css::configuration::InvalidBootstrapFileException& e ) 1747 { 1748 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY, 1749 e.BootstrapFileURL )); 1750 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg ); 1751 } 1752 catch( const css::configuration::InstallationIncompleteException& ) 1753 { 1754 OUString aVersionFileURL; 1755 OUString aMsg; 1756 utl::Bootstrap::PathStatus aPathStatus = utl::Bootstrap::locateVersionFile( aVersionFileURL ); 1757 if ( aPathStatus == utl::Bootstrap::PATH_EXISTS ) 1758 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY, aVersionFileURL ); 1759 else 1760 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE, aVersionFileURL ); 1761 1762 HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL, aMsg ); 1763 } 1764 catch ( const css::configuration::backend::BackendAccessException& exception) 1765 { 1766 // [cm122549] It is assumed in this case that the message 1767 // coming from InitConfiguration (in fact CreateApplicationConf...) 1768 // is suitable for display directly. 1769 FatalError( MakeStartupErrorMessage( exception.Message ) ); 1770 } 1771 catch ( const css::configuration::backend::BackendSetupException& exception) 1772 { 1773 // [cm122549] It is assumed in this case that the message 1774 // coming from InitConfiguration (in fact CreateApplicationConf...) 1775 // is suitable for display directly. 1776 FatalError( MakeStartupErrorMessage( exception.Message ) ); 1777 } 1778 catch ( const css::configuration::CannotLoadConfigurationException& ) 1779 { 1780 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA, 1781 OUString() )); 1782 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg ); 1783 } 1784 catch( const css::uno::Exception& ) 1785 { 1786 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA, 1787 OUString() )); 1788 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg ); 1789 } 1790 return false; 1791 } 1792 1793 void Desktop::FlushConfiguration() 1794 { 1795 css::uno::Reference< css::util::XFlushable >( 1796 css::configuration::theDefaultProvider::get( 1797 comphelper::getProcessComponentContext()), 1798 css::uno::UNO_QUERY_THROW)->flush(); 1799 } 1800 1801 bool Desktop::InitializeQuickstartMode( const Reference< XComponentContext >& rxContext ) 1802 { 1803 try 1804 { 1805 // the shutdown icon sits in the systray and allows the user to keep 1806 // the office instance running for quicker restart 1807 // this will only be activated if --quickstart was specified on cmdline 1808 1809 bool bQuickstart = shouldLaunchQuickstart(); 1810 1811 // Try to instantiate quickstart service. This service is not mandatory, so 1812 // do nothing if service is not available 1813 1814 // #i105753# the following if was invented for performance 1815 // unfortunately this broke the Mac behavior which is to always run 1816 // in quickstart mode since Mac applications do not usually quit 1817 // when the last document closes. 1818 // Note that this claim that on macOS we "always run in quickstart mode" 1819 // has nothing to do with (quick) *starting* (i.e. starting automatically 1820 // when the user logs in), though, but with not quitting when no documents 1821 // are open. 1822 #ifndef MACOSX 1823 if ( bQuickstart ) 1824 #endif 1825 { 1826 css::office::Quickstart::createStart(rxContext, bQuickstart); 1827 } 1828 return true; 1829 } 1830 catch( const css::uno::Exception& ) 1831 { 1832 return false; 1833 } 1834 } 1835 1836 void Desktop::OverrideSystemSettings( AllSettings& rSettings ) 1837 { 1838 if ( !SvtTabAppearanceCfg::IsInitialized () ) 1839 return; 1840 1841 StyleSettings hStyleSettings = rSettings.GetStyleSettings(); 1842 MouseSettings hMouseSettings = rSettings.GetMouseSettings(); 1843 1844 DragFullOptions nDragFullOptions = hStyleSettings.GetDragFullOptions(); 1845 1846 SvtTabAppearanceCfg aAppearanceCfg; 1847 DragMode nDragMode = aAppearanceCfg.GetDragMode(); 1848 switch ( nDragMode ) 1849 { 1850 case DragMode::FullWindow: 1851 nDragFullOptions |= DragFullOptions::All; 1852 break; 1853 case DragMode::Frame: 1854 nDragFullOptions &= ~DragFullOptions::All; 1855 break; 1856 case DragMode::SystemDep: 1857 default: 1858 break; 1859 } 1860 1861 MouseFollowFlags nFollow = hMouseSettings.GetFollow(); 1862 hMouseSettings.SetFollow( aAppearanceCfg.IsMenuMouseFollow() ? (nFollow|MouseFollowFlags::Menu) : (nFollow&~MouseFollowFlags::Menu)); 1863 rSettings.SetMouseSettings(hMouseSettings); 1864 1865 bool bMenuIcons = officecfg::Office::Common::View::Menu::ShowIconsInMenues::get(); 1866 bool bSystemMenuIcons = officecfg::Office::Common::View::Menu::IsSystemIconsInMenus::get(); 1867 TriState eMenuIcons = bSystemMenuIcons ? TRISTATE_INDET : static_cast<TriState>(bMenuIcons); 1868 hStyleSettings.SetUseImagesInMenus(eMenuIcons); 1869 hStyleSettings.SetContextMenuShortcuts(static_cast<TriState>(officecfg::Office::Common::View::Menu::ShortcutsInContextMenus::get())); 1870 hStyleSettings.SetDragFullOptions( nDragFullOptions ); 1871 rSettings.SetStyleSettings ( hStyleSettings ); 1872 } 1873 1874 namespace { 1875 1876 class ExitTimer : public Timer 1877 { 1878 public: 1879 ExitTimer() : Timer("desktop ExitTimer") 1880 { 1881 SetTimeout(500); 1882 Start(); 1883 } 1884 virtual void Invoke() override 1885 { 1886 _exit(42); 1887 } 1888 }; 1889 1890 } 1891 1892 IMPL_LINK_NOARG(Desktop, OpenClients_Impl, void*, void) 1893 { 1894 // #i114963# 1895 // Enable IPC thread before OpenClients 1896 // 1897 // This is because it is possible for another client to connect during the OpenClients() call. 1898 // This can happen on Windows when document is printed (not opened) and another client wants to print (when printing multiple documents). 1899 // If the IPC thread is enabled after OpenClients, then the client will not be processed because the application will exit after printing. i.e RequestHandler::AreRequestsPending() will always return false 1900 // 1901 // ALSO: 1902 // 1903 // Multiple clients may request simultaneous connections. 1904 // When this server closes down it attempts to recreate the pipe (in RequestHandler::Disable()). 1905 // It's possible that the client has a pending connection request. 1906 // When the IPC thread is not running, this connection locks (because maPipe.accept()) is never called 1907 RequestHandler::SetReady(true); 1908 OpenClients(); 1909 1910 CloseSplashScreen(); 1911 CheckFirstRun( ); 1912 #ifdef _WIN32 1913 bool bDontShowDialogs 1914 = Application::IsHeadlessModeEnabled(); // uitest.uicheck fails when the dialog is open 1915 for (sal_uInt16 i = 0; !bDontShowDialogs && i < Application::GetCommandLineParamCount(); i++) 1916 { 1917 if (Application::GetCommandLineParam(i) == "--nologo") 1918 bDontShowDialogs = true; 1919 } 1920 if (!bDontShowDialogs) 1921 vcl::fileregistration::CheckFileExtRegistration(SfxGetpApp()->GetTopWindow()); 1922 // Registers a COM class factory of the service manager with the windows operating system. 1923 Reference< XMultiServiceFactory > xSMgr= comphelper::getProcessServiceFactory(); 1924 xSMgr->createInstance("com.sun.star.bridge.OleApplicationRegistration"); 1925 xSMgr->createInstance("com.sun.star.comp.ole.EmbedServer"); 1926 #endif 1927 const char *pExitPostStartup = getenv ("OOO_EXIT_POST_STARTUP"); 1928 if (pExitPostStartup && *pExitPostStartup) 1929 new ExitTimer(); 1930 } 1931 1932 void Desktop::OpenClients() 1933 { 1934 1935 const CommandLineArgs& rArgs = GetCommandLineArgs(); 1936 1937 if (!rArgs.IsQuickstart()) 1938 { 1939 OUString aHelpModule; 1940 if (rArgs.IsHelpWriter()) { 1941 aHelpModule = "swriter"; 1942 } else if (rArgs.IsHelpCalc()) { 1943 aHelpModule = "scalc"; 1944 } else if (rArgs.IsHelpDraw()) { 1945 aHelpModule = "sdraw"; 1946 } else if (rArgs.IsHelpImpress()) { 1947 aHelpModule = "simpress"; 1948 } else if (rArgs.IsHelpBase()) { 1949 aHelpModule = "sdatabase"; 1950 } else if (rArgs.IsHelpBasic()) { 1951 aHelpModule = "sbasic"; 1952 } else if (rArgs.IsHelpMath()) { 1953 aHelpModule = "smath"; 1954 } 1955 if (!aHelpModule.isEmpty()) { 1956 OUString aHelpURL = "vnd.sun.star.help://" 1957 + aHelpModule 1958 + "/start?Language=" 1959 + utl::ConfigManager::getUILocale(); 1960 #if defined UNX 1961 aHelpURL += "&System=UNX"; 1962 #elif defined _WIN32 1963 aHelpURL += "&System=WIN"; 1964 #endif 1965 Application::GetHelp()->Start(aHelpURL); 1966 return; 1967 } 1968 } 1969 1970 // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line. 1971 // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data. 1972 // But the require that all documents, which are saved as backup should exists inside 1973 // memory. May be this mechanism will be inconsistent if the configuration exists... 1974 // but no document inside memory corresponds to this data. 1975 // Further it's not acceptable to recover such documents without any UI. It can 1976 // need some time, where the user won't see any results and wait for finishing the office startup... 1977 bool bAllowRecoveryAndSessionManagement = ( !rArgs.IsNoRestore() ) && ( !rArgs.IsHeadless() ); 1978 1979 #if !defined ANDROID 1980 // Enter safe mode if requested 1981 if (Application::IsSafeModeEnabled()) { 1982 handleSafeMode(); 1983 } 1984 #endif 1985 1986 #if HAVE_FEATURE_BREAKPAD 1987 if (officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::crashReportInfoExists()) 1988 handleCrashReport(); 1989 #endif 1990 1991 if ( ! bAllowRecoveryAndSessionManagement ) 1992 { 1993 try 1994 { 1995 Reference< XDispatch > xRecovery = css::frame::theAutoRecovery::get( ::comphelper::getProcessComponentContext() ); 1996 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() ); 1997 1998 css::util::URL aCmd; 1999 aCmd.Complete = "vnd.sun.star.autorecovery:/disableRecovery"; 2000 xParser->parseStrict(aCmd); 2001 2002 xRecovery->dispatch(aCmd, css::uno::Sequence< css::beans::PropertyValue >()); 2003 } 2004 catch(const css::uno::Exception&) 2005 { 2006 TOOLS_WARN_EXCEPTION( "desktop.app", "Could not disable AutoRecovery."); 2007 } 2008 } 2009 else 2010 { 2011 bool bCrashed = false; 2012 bool bExistsRecoveryData = false; 2013 bool bExistsSessionData = false; 2014 bool const bDisableRecovery 2015 = getenv("OOO_DISABLE_RECOVERY") != nullptr 2016 || !officecfg::Office::Recovery::RecoveryInfo::Enabled::get(); 2017 2018 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData); 2019 2020 if ( !bDisableRecovery && 2021 ( 2022 bExistsRecoveryData || // => crash with files => recovery 2023 bCrashed // => crash without files => error report 2024 ) 2025 ) 2026 { 2027 try 2028 { 2029 impl_callRecoveryUI( 2030 false , // false => force recovery instead of emergency save 2031 bExistsRecoveryData); 2032 } 2033 catch(const css::uno::Exception&) 2034 { 2035 TOOLS_WARN_EXCEPTION( "desktop.app", "Error during recovery"); 2036 } 2037 } 2038 2039 Reference< XSessionManagerListener2 > xSessionListener; 2040 try 2041 { 2042 // specifies whether the UI-interaction on Session shutdown is allowed 2043 bool bUIOnSessionShutdownAllowed = officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled::get(); 2044 xSessionListener = SessionListener::createWithOnQuitFlag( 2045 ::comphelper::getProcessComponentContext(), bUIOnSessionShutdownAllowed); 2046 } 2047 catch(const css::uno::Exception&) 2048 { 2049 TOOLS_WARN_EXCEPTION( "desktop.app", "Registration of session listener failed"); 2050 } 2051 2052 if ( !bExistsRecoveryData && xSessionListener.is() ) 2053 { 2054 // session management 2055 try 2056 { 2057 xSessionListener->doRestore(); 2058 } 2059 catch(const css::uno::Exception&) 2060 { 2061 TOOLS_WARN_EXCEPTION( "desktop.app", "Error in session management"); 2062 } 2063 } 2064 } 2065 2066 // write this information here to avoid depending on vcl in the crash reporter lib 2067 CrashReporter::addKeyValue("Language", Application::GetSettings().GetLanguageTag().getBcp47(), CrashReporter::Create); 2068 2069 RequestHandler::EnableRequests(); 2070 2071 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl()); 2072 aRequest.aOpenList = rArgs.GetOpenList(); 2073 aRequest.aViewList = rArgs.GetViewList(); 2074 aRequest.aStartList = rArgs.GetStartList(); 2075 aRequest.aPrintList = rArgs.GetPrintList(); 2076 aRequest.aPrintToList = rArgs.GetPrintToList(); 2077 aRequest.aPrinterName = rArgs.GetPrinterName(); 2078 aRequest.aForceOpenList = rArgs.GetForceOpenList(); 2079 aRequest.aForceNewList = rArgs.GetForceNewList(); 2080 aRequest.aConversionList = rArgs.GetConversionList(); 2081 aRequest.aConversionParams = rArgs.GetConversionParams(); 2082 aRequest.aConversionOut = rArgs.GetConversionOut(); 2083 aRequest.aImageConversionType = rArgs.GetImageConversionType(); 2084 aRequest.aInFilter = rArgs.GetInFilter(); 2085 aRequest.bTextCat = rArgs.IsTextCat(); 2086 aRequest.bScriptCat = rArgs.IsScriptCat(); 2087 2088 if ( !aRequest.aOpenList.empty() || 2089 !aRequest.aViewList.empty() || 2090 !aRequest.aStartList.empty() || 2091 !aRequest.aPrintList.empty() || 2092 !aRequest.aForceOpenList.empty() || 2093 !aRequest.aForceNewList.empty() || 2094 ( !aRequest.aPrintToList.empty() && !aRequest.aPrinterName.isEmpty() ) || 2095 !aRequest.aConversionList.empty() ) 2096 { 2097 if ( rArgs.HasModuleParam() ) 2098 { 2099 SvtModuleOptions aOpt; 2100 2101 // Support command line parameters to start a module (as preselection) 2102 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) 2103 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::WRITER ); 2104 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) ) 2105 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::CALC ); 2106 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) ) 2107 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::IMPRESS ); 2108 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) ) 2109 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::DRAW ); 2110 } 2111 2112 // check for printing disabled 2113 if( ( !(aRequest.aPrintList.empty() && aRequest.aPrintToList.empty()) ) 2114 && Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) 2115 { 2116 aRequest.aPrintList.clear(); 2117 aRequest.aPrintToList.clear(); 2118 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr, 2119 VclMessageType::Warning, VclButtonsType::Ok, 2120 DpResId(STR_ERR_PRINTDISABLED))); 2121 xBox->run(); 2122 } 2123 2124 // Process request 2125 if ( RequestHandler::ExecuteCmdLineRequests(aRequest, false) ) 2126 { 2127 // Don't do anything if we have successfully called terminate at desktop: 2128 return; 2129 } 2130 } 2131 2132 // no default document if a document was loaded by recovery or by command line or if soffice is used as server 2133 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); 2134 Reference< XElementAccess > xList( xDesktop->getFrames(), UNO_QUERY_THROW ); 2135 if ( xList->hasElements() ) 2136 return; 2137 2138 if ( rArgs.IsQuickstart() || rArgs.IsInvisible() || Application::AnyInput( VclInputFlags::APPEVENT ) ) 2139 // soffice was started as tray icon ... 2140 return; 2141 2142 OpenDefault(); 2143 } 2144 2145 void Desktop::OpenDefault() 2146 { 2147 OUString aName; 2148 SvtModuleOptions aOpt; 2149 2150 const CommandLineArgs& rArgs = GetCommandLineArgs(); 2151 if ( rArgs.IsNoDefault() ) return; 2152 if ( rArgs.HasModuleParam() ) 2153 { 2154 // Support new command line parameters to start a module 2155 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) 2156 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER ); 2157 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) ) 2158 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC ); 2159 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) ) 2160 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS ); 2161 else if ( rArgs.IsBase() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ) 2162 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE ); 2163 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) ) 2164 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW ); 2165 else if ( rArgs.IsMath() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::MATH ) ) 2166 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::MATH ); 2167 else if ( rArgs.IsGlobal() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) 2168 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERGLOBAL ); 2169 else if ( rArgs.IsWeb() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) 2170 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERWEB ); 2171 } 2172 2173 if ( aName.isEmpty() ) 2174 { 2175 if (aOpt.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE)) 2176 { 2177 ShowBackingComponent(nullptr); 2178 return; 2179 } 2180 2181 // Old way to create a default document 2182 if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) 2183 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER ); 2184 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) ) 2185 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC ); 2186 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) ) 2187 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS ); 2188 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ) 2189 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE ); 2190 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) ) 2191 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW ); 2192 else 2193 return; 2194 } 2195 2196 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl()); 2197 aRequest.aOpenList.push_back(aName); 2198 RequestHandler::ExecuteCmdLineRequests(aRequest, false); 2199 } 2200 2201 2202 OUString GetURL_Impl( 2203 const OUString& rName, std::optional< OUString > const & cwdUrl ) 2204 { 2205 // if rName is a vnd.sun.star.script URL do not attempt to parse it 2206 // as INetURLObj does not handle URLs there 2207 if (rName.startsWith("vnd.sun.star.script")) 2208 { 2209 return rName; 2210 } 2211 2212 // don't touch file urls, those should already be in internal form 2213 // they won't get better here (#112849#) 2214 if (comphelper::isFileUrl(rName)) 2215 { 2216 return rName; 2217 } 2218 2219 if ( rName.startsWith("service:")) 2220 { 2221 return rName; 2222 } 2223 2224 // Add path separator to these directory and make given URL (rName) absolute by using of current working directory 2225 // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!! 2226 // Otherwise last part will be ignored and wrong result will be returned!!! 2227 // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ... 2228 // But if we add a separator - he doesn't do it anymore. 2229 INetURLObject aObj; 2230 if (cwdUrl) { 2231 aObj.SetURL(*cwdUrl); 2232 aObj.setFinalSlash(); 2233 } 2234 2235 // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths. 2236 // Otherwise this char won't get encoded and we are not able to load such files later, 2237 bool bWasAbsolute; 2238 INetURLObject aURL = aObj.smartRel2Abs( rName, bWasAbsolute, false, INetURLObject::EncodeMechanism::WasEncoded, 2239 RTL_TEXTENCODING_UTF8, true ); 2240 OUString aFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); 2241 2242 ::osl::FileStatus aStatus( osl_FileStatus_Mask_FileURL ); 2243 ::osl::DirectoryItem aItem; 2244 if( ::osl::FileBase::E_None == ::osl::DirectoryItem::get( aFileURL, aItem ) && 2245 ::osl::FileBase::E_None == aItem.getFileStatus( aStatus ) ) 2246 aFileURL = aStatus.getFileURL(); 2247 2248 return aFileURL; 2249 } 2250 2251 void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent ) 2252 { 2253 switch ( rAppEvent.GetEvent() ) 2254 { 2255 case ApplicationEvent::Type::Accept: 2256 // every time an accept parameter is used we create an acceptor 2257 // with the corresponding accept-string 2258 createAcceptor(rAppEvent.GetStringData()); 2259 break; 2260 case ApplicationEvent::Type::Appear: 2261 if ( !GetCommandLineArgs().IsInvisible() && !impl_bringToFrontRecoveryUI() ) 2262 { 2263 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 2264 2265 // find active task - the active task is always a visible task 2266 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext ); 2267 Reference< css::frame::XFrame > xTask = xDesktop->getActiveFrame(); 2268 if ( !xTask.is() ) 2269 { 2270 // get any task if there is no active one 2271 Reference< css::container::XIndexAccess > xList = xDesktop->getFrames(); 2272 if ( xList->getCount() > 0 ) 2273 xList->getByIndex(0) >>= xTask; 2274 } 2275 2276 if ( xTask.is() ) 2277 { 2278 Reference< css::awt::XTopWindow > xTop( xTask->getContainerWindow(), UNO_QUERY ); 2279 xTop->toFront(); 2280 } 2281 else 2282 { 2283 // no visible task that could be activated found 2284 Reference< css::awt::XWindow > xContainerWindow; 2285 Reference< XFrame > xBackingFrame = xDesktop->findFrame( "_blank", 0); 2286 if (xBackingFrame.is()) 2287 xContainerWindow = xBackingFrame->getContainerWindow(); 2288 if (xContainerWindow.is()) 2289 { 2290 Reference< XController > xStartModule = StartModule::createWithParentWindow(xContext, xContainerWindow); 2291 Reference< css::awt::XWindow > xBackingWin(xStartModule, UNO_QUERY); 2292 // Attention: You MUST(!) call setComponent() before you call attachFrame(). 2293 // Because the backing component set the property "IsBackingMode" of the frame 2294 // to true inside attachFrame(). But setComponent() reset this state every time ... 2295 xBackingFrame->setComponent(xBackingWin, xStartModule); 2296 xStartModule->attachFrame(xBackingFrame); 2297 xContainerWindow->setVisible(true); 2298 2299 VclPtr<vcl::Window> pCompWindow = VCLUnoHelper::GetWindow(xBackingFrame->getComponentWindow()); 2300 if (pCompWindow) 2301 pCompWindow->PaintImmediately(); 2302 } 2303 } 2304 } 2305 break; 2306 case ApplicationEvent::Type::Open: 2307 { 2308 const CommandLineArgs& rCmdLine = GetCommandLineArgs(); 2309 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() ) 2310 { 2311 ProcessDocumentsRequest docsRequest(rCmdLine.getCwdUrl()); 2312 std::vector<OUString> const & data(rAppEvent.GetStringsData()); 2313 docsRequest.aOpenList.insert( 2314 docsRequest.aOpenList.end(), data.begin(), data.end()); 2315 RequestHandler::ExecuteCmdLineRequests(docsRequest, false); 2316 } 2317 } 2318 break; 2319 case ApplicationEvent::Type::OpenHelpUrl: 2320 // start help for a specific URL 2321 Application::GetHelp()->Start(rAppEvent.GetStringData()); 2322 break; 2323 case ApplicationEvent::Type::Print: 2324 { 2325 const CommandLineArgs& rCmdLine = GetCommandLineArgs(); 2326 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() ) 2327 { 2328 ProcessDocumentsRequest docsRequest(rCmdLine.getCwdUrl()); 2329 std::vector<OUString> const & data(rAppEvent.GetStringsData()); 2330 docsRequest.aPrintList.insert( 2331 docsRequest.aPrintList.end(), data.begin(), data.end()); 2332 RequestHandler::ExecuteCmdLineRequests(docsRequest, false); 2333 } 2334 } 2335 break; 2336 case ApplicationEvent::Type::PrivateDoShutdown: 2337 { 2338 Desktop* pD = dynamic_cast<Desktop*>(GetpApp()); 2339 OSL_ENSURE( pD, "no desktop ?!?" ); 2340 if( pD ) 2341 pD->doShutdown(); 2342 } 2343 break; 2344 case ApplicationEvent::Type::QuickStart: 2345 if ( !GetCommandLineArgs().IsInvisible() ) 2346 { 2347 // If the office has been started the second time its command line arguments are sent through a pipe 2348 // connection to the first office. We want to reuse the quickstart option for the first office. 2349 // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the 2350 // application events to do this (they are executed inside main thread)!!! 2351 // Don't start quickstart service if the user specified "--invisible" on the command line! 2352 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 2353 css::office::Quickstart::createStart(xContext, true/*Quickstart*/); 2354 } 2355 break; 2356 case ApplicationEvent::Type::ShowDialog: 2357 // This is only used on macOS, and only for About or Preferences. 2358 // Ignore all errors here. It's clicking a menu entry only ... 2359 // The user will try it again, in case nothing happens .-) 2360 try 2361 { 2362 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 2363 2364 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext ); 2365 2366 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext); 2367 css::util::URL aCommand; 2368 if( rAppEvent.GetStringData() == "PREFERENCES" ) 2369 aCommand.Complete = ".uno:OptionsTreeDialog"; 2370 else if( rAppEvent.GetStringData() == "ABOUT" ) 2371 aCommand.Complete = ".uno:About"; 2372 if( !aCommand.Complete.isEmpty() ) 2373 { 2374 xParser->parseStrict(aCommand); 2375 2376 css::uno::Reference< css::frame::XDispatch > xDispatch = xDesktop->queryDispatch(aCommand, OUString(), 0); 2377 if (xDispatch.is()) 2378 xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >()); 2379 } 2380 } 2381 catch(const css::uno::Exception&) 2382 { 2383 TOOLS_WARN_EXCEPTION("desktop.app", "exception thrown by dialog"); 2384 } 2385 break; 2386 case ApplicationEvent::Type::Unaccept: 2387 // try to remove corresponding acceptor 2388 destroyAcceptor(rAppEvent.GetStringData()); 2389 break; 2390 default: 2391 SAL_WARN( "desktop.app", "this cannot happen"); 2392 break; 2393 } 2394 } 2395 2396 void Desktop::OpenSplashScreen() 2397 { 2398 const CommandLineArgs &rCmdLine = GetCommandLineArgs(); 2399 // Show intro only if this is normal start (e.g. no server, no quickstart, no printing ) 2400 if ( !(!rCmdLine.IsInvisible() && 2401 !rCmdLine.IsHeadless() && 2402 !rCmdLine.IsQuickstart() && 2403 !rCmdLine.IsMinimized() && 2404 !rCmdLine.IsNoLogo() && 2405 !rCmdLine.IsTerminateAfterInit() && 2406 rCmdLine.GetPrintList().empty() && 2407 rCmdLine.GetPrintToList().empty() && 2408 rCmdLine.GetConversionList().empty()) ) 2409 return; 2410 2411 // Determine application name from command line parameters 2412 OUString aAppName; 2413 if ( rCmdLine.IsWriter() ) 2414 aAppName = "writer"; 2415 else if ( rCmdLine.IsCalc() ) 2416 aAppName = "calc"; 2417 else if ( rCmdLine.IsDraw() ) 2418 aAppName = "draw"; 2419 else if ( rCmdLine.IsImpress() ) 2420 aAppName = "impress"; 2421 else if ( rCmdLine.IsBase() ) 2422 aAppName = "base"; 2423 else if ( rCmdLine.IsGlobal() ) 2424 aAppName = "global"; 2425 else if ( rCmdLine.IsMath() ) 2426 aAppName = "math"; 2427 else if ( rCmdLine.IsWeb() ) 2428 aAppName = "web"; 2429 2430 // Which splash to use 2431 OUString aSplashService( "com.sun.star.office.SplashScreen" ); 2432 if ( rCmdLine.HasSplashPipe() ) 2433 aSplashService = "com.sun.star.office.PipeSplashScreen"; 2434 2435 Sequence< Any > aSeq{ Any(true) /* bVisible */, Any(aAppName) }; 2436 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 2437 m_rSplashScreen.set( 2438 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService, aSeq, xContext), 2439 UNO_QUERY); 2440 2441 if(m_rSplashScreen.is()) 2442 m_rSplashScreen->start("SplashScreen", 100); 2443 2444 } 2445 2446 void Desktop::SetSplashScreenProgress(sal_Int32 iProgress) 2447 { 2448 if(m_rSplashScreen.is()) 2449 { 2450 m_rSplashScreen->setValue(iProgress); 2451 } 2452 } 2453 2454 void Desktop::SetSplashScreenText( const OUString& rText ) 2455 { 2456 if( m_rSplashScreen.is() ) 2457 { 2458 m_rSplashScreen->setText( rText ); 2459 } 2460 } 2461 2462 void Desktop::CloseSplashScreen() 2463 { 2464 if(m_rSplashScreen.is()) 2465 { 2466 SolarMutexGuard ensureSolarMutex; 2467 m_rSplashScreen->end(); 2468 m_rSplashScreen = nullptr; 2469 } 2470 } 2471 2472 2473 IMPL_STATIC_LINK_NOARG(Desktop, AsyncInitFirstRun, Timer *, void) 2474 { 2475 // does initializations which are necessary for the first run of the office 2476 try 2477 { 2478 Reference< XJobExecutor > xExecutor = theJobExecutor::get( ::comphelper::getProcessComponentContext() ); 2479 xExecutor->trigger( "onFirstRunInitialization" ); 2480 } 2481 catch(const css::uno::Exception&) 2482 { 2483 TOOLS_WARN_EXCEPTION( "desktop.app", "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor" ); 2484 } 2485 } 2486 2487 void Desktop::ShowBackingComponent(Desktop * progress) 2488 { 2489 if (GetCommandLineArgs().IsNoDefault()) 2490 { 2491 return; 2492 } 2493 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); 2494 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xContext); 2495 if (progress != nullptr) 2496 { 2497 progress->SetSplashScreenProgress(60); 2498 } 2499 Reference< XFrame > xBackingFrame = xDesktop->findFrame( "_blank", 0); 2500 Reference< css::awt::XWindow > xContainerWindow; 2501 2502 if (xBackingFrame.is()) 2503 xContainerWindow = xBackingFrame->getContainerWindow(); 2504 if (!xContainerWindow.is()) 2505 return; 2506 2507 // set the WindowExtendedStyle::Document style. Normally, this is done by the TaskCreator service when a "_blank" 2508 // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior, 2509 // otherwise documents loaded into this frame will later on miss functionality depending on the style. 2510 VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow ); 2511 SAL_WARN_IF( !pContainerWindow, "desktop.app", "Desktop::Main: no implementation access to the frame's container window!" ); 2512 pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document ); 2513 if (progress != nullptr) 2514 { 2515 progress->SetSplashScreenProgress(75); 2516 } 2517 2518 Reference< XController > xStartModule = StartModule::createWithParentWindow( xContext, xContainerWindow); 2519 // Attention: You MUST(!) call setComponent() before you call attachFrame(). 2520 // Because the backing component set the property "IsBackingMode" of the frame 2521 // to true inside attachFrame(). But setComponent() reset this state everytimes ... 2522 xBackingFrame->setComponent(Reference< XWindow >(xStartModule, UNO_QUERY), xStartModule); 2523 if (progress != nullptr) 2524 { 2525 progress->SetSplashScreenProgress(100); 2526 } 2527 xStartModule->attachFrame(xBackingFrame); 2528 if (progress != nullptr) 2529 { 2530 progress->CloseSplashScreen(); 2531 } 2532 xContainerWindow->setVisible(true); 2533 } 2534 2535 2536 void Desktop::CheckFirstRun( ) 2537 { 2538 if (!officecfg::Office::Common::Misc::FirstRun::get()) 2539 return; 2540 2541 // use VCL timer, which won't trigger during shutdown if the 2542 // application exits before timeout 2543 m_firstRunTimer.Start(); 2544 2545 #ifdef _WIN32 2546 // Check if Quickstarter should be started (on Windows only) 2547 OUString sRootKey = ReplaceStringHookProc("Software\\%OOOVENDOR\\%PRODUCTNAME\\%PRODUCTVERSION"); 2548 WCHAR szValue[8192]; 2549 DWORD nValueSize = sizeof(szValue); 2550 HKEY hKey; 2551 if (ERROR_SUCCESS == RegOpenKeyW(HKEY_LOCAL_MACHINE, o3tl::toW(sRootKey.getStr()), &hKey)) 2552 { 2553 if ( ERROR_SUCCESS == RegQueryValueExW( hKey, L"RunQuickstartAtFirstStart", nullptr, nullptr, reinterpret_cast<LPBYTE>(szValue), &nValueSize ) ) 2554 { 2555 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 2556 css::office::Quickstart::createAutoStart(xContext, true/*Quickstart*/, true/*bAutostart*/); 2557 RegCloseKey( hKey ); 2558 } 2559 } 2560 #endif 2561 2562 std::shared_ptr< comphelper::ConfigurationChanges > batch( 2563 comphelper::ConfigurationChanges::create()); 2564 officecfg::Office::Common::Misc::FirstRun::set(false, batch); 2565 batch->commit(); 2566 } 2567 2568 } 2569 2570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2571
