Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / desktop / source / app / app.cxx
blobc0b30c2ae2fde29d186c5319bafbde2de91d65a4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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 #include <config_wasm_strip.h>
29 #include <sal/config.h>
31 #include <cstdlib>
32 #include <iostream>
33 #include <string_view>
35 #include <app.hxx>
36 #include <dp_shared.hxx>
37 #include <strings.hrc>
38 #include "cmdlineargs.hxx"
39 #include <lockfile.hxx>
40 #include "userinstall.hxx"
41 #include "desktopcontext.hxx"
42 #include <migration.hxx>
43 #include "officeipcthread.hxx"
44 #if HAVE_FEATURE_UPDATE_MAR
45 #include "updater.hxx"
46 #endif
48 #include <framework/desktop.hxx>
49 #include <i18nlangtag/languagetag.hxx>
50 #include <o3tl/char16_t2wchar_t.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>
82 #include <desktop/exithelper.h>
83 #include <sal/log.hxx>
84 #include <toolkit/helper/vclunohelper.hxx>
85 #include <comphelper/lok.hxx>
86 #include <comphelper/configuration.hxx>
87 #include <comphelper/fileurl.hxx>
88 #include <comphelper/threadpool.hxx>
89 #include <comphelper/processfactory.hxx>
90 #include <comphelper/backupfilehelper.hxx>
91 #include <uno/current_context.hxx>
92 #include <unotools/bootstrap.hxx>
93 #include <unotools/configmgr.hxx>
94 #include <unotools/moduleoptions.hxx>
95 #include <unotools/localfilehelper.hxx>
96 #include <unotools/ucbhelper.hxx>
97 #include <officecfg/Office/Common.hxx>
98 #include <officecfg/Office/Recovery.hxx>
99 #include <officecfg/Office/Update.hxx>
100 #include <officecfg/Setup.hxx>
101 #include <osl/file.hxx>
102 #include <osl/process.h>
103 #include <rtl/byteseq.hxx>
104 #include <unotools/pathoptions.hxx>
105 #if !ENABLE_WASM_STRIP_PINGUSER
106 #include <unotools/VersionConfig.hxx>
107 #endif
108 #include <rtl/bootstrap.hxx>
109 #include <vcl/test/GraphicsRenderTests.hxx>
110 #include <vcl/help.hxx>
111 #include <vcl/weld.hxx>
112 #include <vcl/settings.hxx>
113 #include <sfx2/flatpak.hxx>
114 #include <sfx2/sfxsids.hrc>
115 #include <sfx2/app.hxx>
116 #include <sfx2/safemode.hxx>
117 #include <svl/itemset.hxx>
118 #include <svl/eitem.hxx>
119 #include <basic/sbstar.hxx>
120 #include <desktop/crashreport.hxx>
121 #include <tools/urlobj.hxx>
122 #include <comphelper/diagnose_ex.hxx>
123 #include <svtools/fontsubstconfig.hxx>
124 #include <svtools/accessibilityoptions.hxx>
125 #include <svtools/apearcfg.hxx>
126 #include <vcl/graphicfilter.hxx>
127 #include <vcl/window.hxx>
128 #include "langselect.hxx"
129 #include <salhelper/thread.hxx>
131 #if defined MACOSX
132 #include <errno.h>
133 #include <sys/wait.h>
134 #endif
136 #ifdef _WIN32
137 #define WIN32_LEAN_AND_MEAN
138 #include <windows.h>
139 #include <vcl/fileregistration.hxx>
140 #endif
142 #if defined(_WIN32)
143 #include <process.h>
144 #define GETPID _getpid
145 #else
146 #include <unistd.h>
147 #define GETPID getpid
148 #endif
150 #include <strings.hxx>
152 using namespace ::com::sun::star::awt;
153 using namespace ::com::sun::star::uno;
154 using namespace ::com::sun::star::util;
155 using namespace ::com::sun::star::lang;
156 using namespace ::com::sun::star::beans;
157 using namespace ::com::sun::star::frame;
158 using namespace ::com::sun::star::document;
159 using namespace ::com::sun::star::view;
160 using namespace ::com::sun::star::task;
161 using namespace ::com::sun::star::system;
162 using namespace ::com::sun::star::ui;
163 using namespace ::com::sun::star::ui::dialogs;
164 using namespace ::com::sun::star::container;
166 namespace desktop
169 static oslSignalHandler pSignalHandler = nullptr;
171 namespace {
173 #if HAVE_FEATURE_EXTENSIONS
175 // Remove any existing UserInstallation's extensions cache data remaining from
176 // old installations. This addresses at least two problems:
178 // For one, apparently due to the old share/prereg/bundled mechanism (disabled
179 // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying
180 // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled
181 // cache could contain corrupted information (like a UNO component registered
182 // twice, which got changed from active to passive registration in one LO
183 // version, but the version of the corresponding bundled extension only
184 // incremented in a later LO version).
186 // For another, UserInstallations have been seen in the wild where no extensions
187 // were installed per-user (any longer), but user/uno_packages/cache/registry/
188 // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files
189 // contained data nevertheless.
191 // When a LO upgrade is detected (i.e., no user/extensions/buildid or one
192 // containing an old build ID), then user/extensions and
193 // user/uno_packages/cache/registry/
194 // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are
195 // removed. That should prevent any problems starting the service manager due
196 // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the
197 // removed cache data is recreated.
199 // Multiple instances of soffice.bin can execute this code in parallel for a
200 // single UserInstallation, as it is called before RequestHandler is set up.
201 // Therefore, any errors here only lead to SAL_WARNs.
203 // At least in theory, this function could be removed again once no
204 // UserInstallation can be poisoned by old junk any more.
205 bool cleanExtensionCache() {
206 OUString buildId(
207 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}");
208 rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure
209 OUString extDir(
210 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
211 ":UserInstallation}/user/extensions");
212 rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure
213 OUString buildIdFile(extDir + "/buildid");
214 osl::File fr(buildIdFile);
215 osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read);
216 switch (rc) {
217 case osl::FileBase::E_None:
219 rtl::ByteSequence s1;
220 rc = fr.readLine(s1);
221 osl::FileBase::RC rc2 = fr.close();
222 SAL_WARN_IF(
223 rc2 != osl::FileBase::E_None, "desktop.app",
224 "cannot close " << fr.getURL() << " after reading: " << +rc2);
225 // readLine returns E_AGAIN for a zero-size file:
226 if (rc != osl::FileBase::E_None && rc != osl::FileBase::E_AGAIN) {
227 SAL_WARN( "desktop.app", "cannot read from " << fr.getURL() << ": " << +rc);
228 break;
230 OUString s2(
231 reinterpret_cast< char const * >(s1.getConstArray()),
232 s1.getLength(), RTL_TEXTENCODING_ISO_8859_1);
233 // using ISO 8859-1 avoids any and all conversion errors; the
234 // content should only be a subset of ASCII, anyway
235 if (s2 == buildId) {
236 return false;
238 break;
240 case osl::FileBase::E_NOENT:
241 break;
242 default:
243 SAL_WARN( "desktop.app", "cannot open " << fr.getURL() << " for reading: " << +rc);
244 break;
246 utl::removeTree(extDir);
247 OUString userRcFile(
248 "$UNO_USER_PACKAGES_CACHE/registry/"
249 "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc");
250 rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure
251 rc = osl::File::remove(userRcFile);
252 SAL_WARN_IF(
253 rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop.app",
254 "cannot remove file " << userRcFile << ": " << +rc);
255 rc = osl::Directory::createPath(extDir);
256 SAL_WARN_IF(
257 rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop.app",
258 "cannot create path " << extDir << ": " << +rc);
259 osl::File fw(buildIdFile);
260 rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
261 if (rc != osl::FileBase::E_None) {
262 SAL_WARN( "desktop.app", "cannot open " << fw.getURL() << " for writing: " << +rc);
263 return true;
265 OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8));
266 // using UTF-8 avoids almost all conversion errors (and buildid
267 // containing single surrogate halves should never happen, anyway); the
268 // content should only be a subset of ASCII, anyway
269 sal_uInt64 n = 0;
270 rc = fw.write(buf.getStr(), buf.getLength(), n);
271 SAL_WARN_IF(
272 (rc != osl::FileBase::E_None
273 || n != static_cast< sal_uInt32 >(buf.getLength())),
274 "desktop.app",
275 "cannot write to " << fw.getURL() << ": " << +rc << ", " << n);
276 rc = fw.close();
277 SAL_WARN_IF(
278 rc != osl::FileBase::E_None, "desktop.app",
279 "cannot close " << fw.getURL() << " after writing: " << +rc);
280 return true;
283 #endif
285 bool shouldLaunchQuickstart()
287 bool bQuickstart = Desktop::GetCommandLineArgs().IsQuickstart();
288 if (!bQuickstart)
290 SfxItemSetFixed<SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER> aQLSet(SfxGetpApp()->GetPool());
291 SfxApplication::GetOptions(aQLSet);
292 const SfxBoolItem* pLauncherItem = aQLSet.GetItemIfSet(SID_ATTR_QUICKLAUNCHER, false);
293 if (pLauncherItem)
294 bQuickstart = pLauncherItem->GetValue();
296 return bQuickstart;
299 void SetRestartState() {
300 try {
301 std::shared_ptr< comphelper::ConfigurationChanges > batch(
302 comphelper::ConfigurationChanges::create());
303 officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch);
304 batch->commit();
305 } catch (css::uno::Exception) {
306 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring");
310 void DoRestartActionsIfNecessary(bool quickstart) {
311 if (!quickstart)
312 return;
314 try {
315 if (officecfg::Setup::Office::OfficeRestartInProgress::get()) {
316 std::shared_ptr< comphelper::ConfigurationChanges > batch(
317 comphelper::ConfigurationChanges::create());
318 officecfg::Setup::Office::OfficeRestartInProgress::set(
319 false, batch);
320 batch->commit();
321 css::office::Quickstart::createStart(
322 comphelper::getProcessComponentContext(),
323 shouldLaunchQuickstart());
325 } catch (css::uno::Exception &) {
326 TOOLS_WARN_EXCEPTION("desktop.app", "ignoring");
330 void RemoveIconCacheDirectory()
332 // See getIconCacheUrl in vcl/source/image/ImplImageTree.cxx
333 OUString sUrl = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
334 "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache";
335 rtl::Bootstrap::expandMacros(sUrl);
336 utl::UCBContentHelper::Kill(sUrl);
341 namespace {
343 void runGraphicsRenderTests()
345 if (comphelper::LibreOfficeKit::isActive())
346 return;
347 #if !ENABLE_WASM_STRIP_PINGUSER
348 if (!utl::isProductVersionUpgraded(false))
350 return;
352 #endif
353 GraphicsRenderTests TestObject;
354 TestObject.run();
358 OUString MakeStartupErrorMessage(std::u16string_view aErrorMessage)
360 return DpResId(STR_BOOTSTRAP_ERR_CANNOT_START) + "\n" + aErrorMessage;
364 // shows a simple error box with the given message ... but exits from these process !
365 // Fatal errors can't be solved by the process ... nor any recovery can help.
366 // Mostly the installation was damaged and must be repaired manually .. or by calling
367 // setup again.
368 // On the other side we must make sure that no further actions will be possible within
369 // the current office process ! No pipe requests, no menu/toolbar/shortcut actions
370 // are allowed. Otherwise we will force a "crash inside a crash".
371 // That's why we have to use a special native message box here which does not use yield :-)
373 void FatalError(const OUString& sMessage)
375 OUString sProductKey = ::utl::Bootstrap::getProductKey();
376 if ( sProductKey.isEmpty())
378 osl_getExecutableFile( &sProductKey.pData );
380 ::sal_uInt32 nLastIndex = sProductKey.lastIndexOf('/');
381 if ( nLastIndex > 0 )
382 sProductKey = sProductKey.copy( nLastIndex+1 );
385 OUString sTitle = sProductKey + " - Fatal Error";
386 Application::ShowNativeErrorBox (sTitle, sMessage);
387 std::cerr << sTitle << ": " << sMessage << std::endl;
388 _exit(EXITHELPER_FATAL_ERROR);
393 CommandLineArgs& Desktop::GetCommandLineArgs()
395 static CommandLineArgs theCommandLineArgs;
396 return theCommandLineArgs;
399 OUString ReplaceStringHookProc( const OUString& rStr )
401 const static OUString sBuildId(utl::Bootstrap::getBuildIdData("development")),
402 sBrandName(utl::ConfigManager::getProductName()),
403 sVersion(utl::ConfigManager::getProductVersion()),
404 sAboutBoxVersion(utl::ConfigManager::getAboutBoxProductVersion()),
405 sAboutBoxVersionSuffix(utl::ConfigManager::getAboutBoxProductVersionSuffix()),
406 sExtension(utl::ConfigManager::getProductExtension());
408 OUString sRet(rStr);
409 if (sRet.indexOf("%PRODUCT") != -1 || sRet.indexOf("%ABOUTBOX") != -1)
411 sRet = sRet.replaceAll( "%PRODUCTNAME", sBrandName );
412 sRet = sRet.replaceAll( "%PRODUCTVERSION", sVersion );
413 sRet = sRet.replaceAll( "%BUILDID", sBuildId );
414 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", sAboutBoxVersionSuffix );
415 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion );
416 sRet = sRet.replaceAll( "%PRODUCTEXTENSION", sExtension );
419 if ( sRet.indexOf( "%OOOVENDOR" ) != -1 )
421 const static OUString sOOOVendor = utl::ConfigManager::getVendor();
422 sRet = sRet.replaceAll( "%OOOVENDOR", sOOOVendor );
425 return sRet;
428 Desktop::Desktop()
429 : m_bCleanedExtensionCache(false)
430 , m_bServicesRegistered(false)
431 , m_aBootstrapError(BE_OK)
432 , m_aBootstrapStatus(BS_OK)
433 , m_firstRunTimer( "desktop::Desktop m_firstRunTimer" )
435 m_firstRunTimer.SetTimeout(3000); // 3 sec.
436 m_firstRunTimer.SetInvokeHandler(LINK(this, Desktop, AsyncInitFirstRun));
439 Desktop::~Desktop()
443 void Desktop::Init()
445 SetBootstrapStatus(BS_OK);
447 #if HAVE_FEATURE_EXTENSIONS
448 m_bCleanedExtensionCache = cleanExtensionCache();
449 #endif
451 // We need to have service factory before going further, but see fdo#37195.
452 // Doing this will mmap common.rdb, making it not overwritable on windows,
453 // so this can't happen before the synchronization above. Lets rework this
454 // so that the above is called *from* CreateApplicationServiceManager or
455 // something to enforce this gotcha
458 InitApplicationServiceManager();
460 catch (css::uno::Exception & e)
462 HandleBootstrapErrors( BE_UNO_SERVICEMANAGER, e.Message );
463 std::abort();
466 // Check whether safe mode is enabled
467 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
468 // Check if we are restarting from safe mode - in that case we don't want to enter it again
469 if (sfx2::SafeMode::hasRestartFlag())
470 sfx2::SafeMode::removeRestartFlag();
471 else if (rCmdLineArgs.IsSafeMode() || sfx2::SafeMode::hasFlag())
472 Application::EnableSafeMode();
474 // When we are in SafeMode we need to do changes before the configuration
475 // gets read (langselect::prepareLocale() by UNO API -> Components::Components)
476 // This may prepare SafeMode or restore from it by moving data in
477 // the UserConfiguration directory
478 comphelper::BackupFileHelper::reactOnSafeMode(Application::IsSafeModeEnabled());
482 if (!langselect::prepareLocale())
484 SetBootstrapError( BE_LANGUAGE_MISSING, OUString() );
487 catch (css::uno::Exception & e)
489 SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message );
492 // test code for ProfileSafeMode to allow testing the fail
493 // of loading the office configuration initially. To use,
494 // either set to true and compile, or set a breakpoint
495 // in debugger and change the local bool
496 static bool bTryHardOfficeconfigBroken(false); // loplugin:constvars:ignore
498 if (bTryHardOfficeconfigBroken)
500 SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString());
503 // start ipc thread only for non-remote offices
504 RequestHandler::Status aStatus = RequestHandler::Enable(true);
505 if ( aStatus == RequestHandler::IPC_STATUS_PIPE_ERROR )
507 #if defined(ANDROID) || defined(EMSCRIPTEN)
508 // Ignore crack pipe errors on Android
509 #else
510 // Keep using this oddly named BE_PATHINFO_MISSING value
511 // for pipe-related errors on other platforms. Of course
512 // this crack with two (if not more) levels of our own
513 // error codes hiding the actual system error code is
514 // broken, but that is done all over the code, let's leave
515 // reengineering that to another year.
516 SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
517 #endif
519 else if ( aStatus == RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR )
521 SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
523 else if ( aStatus == RequestHandler::IPC_STATUS_2ND_OFFICE )
525 // 2nd office startup should terminate after sending cmdlineargs through pipe
526 SetBootstrapStatus(BS_TERMINATE);
528 else if ( !rCmdLineArgs.GetUnknown().isEmpty()
529 || rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() )
531 // disable IPC thread in an instance that is just showing a help message
532 RequestHandler::Disable();
534 pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, nullptr);
537 void Desktop::InitFinished()
539 CloseSplashScreen();
542 void Desktop::DeInit()
544 try {
545 // instead of removing of the configManager just let it commit all the changes
546 utl::ConfigManager::storeConfigItems();
547 FlushConfiguration();
549 // close splashscreen if it's still open
550 CloseSplashScreen();
551 Reference< XComponent >(
552 comphelper::getProcessComponentContext(), UNO_QUERY_THROW )->
553 dispose();
554 // nobody should get a destroyed service factory...
555 ::comphelper::setProcessServiceFactory( nullptr );
557 // clear lockfile
558 m_xLockfile.reset();
560 RequestHandler::Disable();
561 if( pSignalHandler )
562 osl_removeSignalHandler( pSignalHandler );
563 } catch (const RuntimeException&) {
564 // someone threw an exception during shutdown
565 // this will leave some garbage behind...
566 TOOLS_WARN_EXCEPTION("desktop.app", "exception throwing during shutdown, will leave some garbage behind");
570 bool Desktop::QueryExit()
574 utl::ConfigManager::storeConfigItems();
576 catch ( const RuntimeException& )
580 static constexpr OUStringLiteral SUSPEND_QUICKSTARTVETO = u"SuspendQuickstartVeto";
582 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
583 Reference< XPropertySet > xPropertySet(xDesktop, UNO_QUERY_THROW);
584 xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(true) );
586 bool bExit = xDesktop->terminate();
588 if ( !bExit )
590 xPropertySet->setPropertyValue( SUSPEND_QUICKSTARTVETO, Any(false) );
592 else
594 FlushConfiguration();
597 // it is no problem to call RequestHandler::Disable() more than once
598 // it also looks to be threadsafe
599 RequestHandler::Disable();
601 catch ( const RuntimeException& )
605 m_xLockfile.reset();
609 return bExit;
612 void Desktop::Shutdown()
614 framework::getDesktop(::comphelper::getProcessComponentContext())->shutdown();
617 void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus, std::u16string_view aDiagnosticMessage )
619 if ( aBootstrapStatus == ::utl::Bootstrap::DATA_OK )
620 return;
622 OUString aProductKey;
623 OUString aTemp;
625 osl_getExecutableFile( &aProductKey.pData );
626 sal_uInt32 lastIndex = aProductKey.lastIndexOf('/');
627 if ( lastIndex > 0 )
628 aProductKey = aProductKey.copy( lastIndex+1 );
630 aTemp = ::utl::Bootstrap::getProductKey( aProductKey );
631 if ( !aTemp.isEmpty() )
632 aProductKey = aTemp;
634 OUString const aMessage(OUString::Concat(aDiagnosticMessage) + "\n");
636 std::unique_ptr<weld::MessageDialog> xBootstrapFailedBox(Application::CreateMessageDialog(nullptr,
637 VclMessageType::Warning, VclButtonsType::Ok, aMessage));
638 xBootstrapFailedBox->set_title(aProductKey);
639 xBootstrapFailedBox->run();
642 // Create an error message depending on bootstrap failure code and an optional file url
643 OUString Desktop::CreateErrorMsgString(
644 utl::Bootstrap::FailureCode nFailureCode,
645 const OUString& aFileURL )
647 OUString aMsg;
648 bool bFileInfo = true;
650 switch ( nFailureCode )
652 /// the shared installation directory could not be located
653 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
655 aMsg = DpResId(STR_BOOTSTRAP_ERR_PATH_INVALID);
656 bFileInfo = false;
658 break;
660 /// the bootstrap INI file could not be found or read
661 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
663 aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING);
665 break;
667 /// the bootstrap INI is missing a required entry
668 /// the bootstrap INI contains invalid data
669 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
670 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
672 aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_CORRUPT);
674 break;
676 /// the version locator INI file could not be found or read
677 case ::utl::Bootstrap::MISSING_VERSION_FILE:
679 aMsg = DpResId(STR_BOOTSTRAP_ERR_FILE_MISSING);
681 break;
683 /// the version locator INI has no entry for this version
684 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
686 aMsg = DpResId(STR_BOOTSTRAP_ERR_NO_SUPPORT);
688 break;
690 /// the user installation directory does not exist
691 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
693 aMsg = DpResId(STR_BOOTSTRAP_ERR_DIR_MISSING);
695 break;
697 /// some bootstrap data was invalid in unexpected ways
698 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
700 aMsg = DpResId(STR_BOOTSTRAP_ERR_INTERNAL);
701 bFileInfo = false;
703 break;
705 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
707 // This needs to be improved, see #i67575#:
708 aMsg = "Invalid version file entry";
709 bFileInfo = false;
711 break;
713 case ::utl::Bootstrap::NO_FAILURE:
715 OSL_ASSERT(false);
717 break;
720 if ( bFileInfo )
722 OUString aMsgString( aMsg );
723 OUString aFilePath;
725 osl::File::getSystemPathFromFileURL( aFileURL, aFilePath );
727 aMsgString = aMsgString.replaceFirst( "$1", aFilePath );
728 aMsg = aMsgString;
731 return MakeStartupErrorMessage( aMsg );
734 void Desktop::HandleBootstrapErrors(
735 BootstrapError aBootstrapError, OUString const & aErrorMessage )
737 if ( aBootstrapError == BE_PATHINFO_MISSING )
739 OUString aErrorMsg;
740 OUString aBuffer;
741 utl::Bootstrap::Status aBootstrapStatus;
742 utl::Bootstrap::FailureCode nFailureCode;
744 aBootstrapStatus = ::utl::Bootstrap::checkBootstrapStatus( aBuffer, nFailureCode );
745 if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
747 switch ( nFailureCode )
749 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
750 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
752 aErrorMsg = CreateErrorMsgString( nFailureCode, OUString() );
754 break;
756 /// the bootstrap INI file could not be found or read
757 /// the bootstrap INI is missing a required entry
758 /// the bootstrap INI contains invalid data
759 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
760 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
761 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
763 OUString aBootstrapFileURL;
765 utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL );
766 aErrorMsg = CreateErrorMsgString( nFailureCode, aBootstrapFileURL );
768 break;
770 /// the version locator INI file could not be found or read
771 /// the version locator INI has no entry for this version
772 /// the version locator INI entry is not a valid directory URL
773 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
774 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
775 case ::utl::Bootstrap::MISSING_VERSION_FILE:
777 OUString aVersionFileURL;
779 utl::Bootstrap::locateVersionFile( aVersionFileURL );
780 aErrorMsg = CreateErrorMsgString( nFailureCode, aVersionFileURL );
782 break;
784 /// the user installation directory does not exist
785 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
787 OUString aUserInstallationURL;
789 utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
790 aErrorMsg = CreateErrorMsgString( nFailureCode, aUserInstallationURL );
792 break;
794 case ::utl::Bootstrap::NO_FAILURE:
796 OSL_ASSERT(false);
798 break;
801 HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg );
804 else if ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING )
806 // UNO service manager is not available. VCL needs a UNO service manager to display a message box!!!
807 // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
809 // When UNO is not properly initialized, all kinds of things can fail
810 // and cause the process to crash. To give the user a hint even if
811 // generating and displaying a message box below crashes, print a
812 // hard-coded message on stderr first:
813 std::cerr
814 << "The application cannot be started.\n"
815 // STR_BOOTSTRAP_ERR_CANNOT_START
816 << (aBootstrapError == BE_UNO_SERVICEMANAGER
817 ? "The component manager is not available.\n"
818 // STR_BOOTSTRAP_ERR_NO_SERVICE
819 : "The configuration service is not available.\n");
820 // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
821 if ( !aErrorMessage.isEmpty() )
823 std::cerr << "(\"" << aErrorMessage << "\")\n";
826 // First sentence. We cannot bootstrap office further!
827 OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NO_CFG_SERVICE) + "\n";
828 if ( !aErrorMessage.isEmpty() )
830 aDiagnosticMessage += "(\"" + aErrorMessage + "\")\n";
833 // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to
834 // repair the installation with the setup executable besides the office executable. Now
835 // we have to ask the user to start the setup on CD/installation directory manually!!
836 aDiagnosticMessage += DpResId(STR_ASK_START_SETUP_MANUALLY);
838 FatalError(MakeStartupErrorMessage(aDiagnosticMessage));
840 else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
842 // set flag at BackupFileHelper to be able to know if _exit was called and
843 // actions are executed after this. This method we are in will not return,
844 // but end up in a _exit() call
845 comphelper::BackupFileHelper::setExitWasCalled();
847 // enter safe mode, too
848 sfx2::SafeMode::putFlag();
850 OUString msg(DpResId(STR_CONFIG_ERR_ACCESS_GENERAL));
851 if (!aErrorMessage.isEmpty()) {
852 msg += "\n(\"" + aErrorMessage + "\")";
854 FatalError(MakeStartupErrorMessage(msg));
856 else if ( aBootstrapError == BE_USERINSTALL_FAILED )
858 OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_USERINSTALL_FAILED);
859 FatalError(MakeStartupErrorMessage(aDiagnosticMessage));
861 else if ( aBootstrapError == BE_LANGUAGE_MISSING )
863 OUString aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_LANGUAGE_MISSING);
864 FatalError(MakeStartupErrorMessage(aDiagnosticMessage));
866 else if (( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) ||
867 ( aBootstrapError == BE_USERINSTALL_NOWRITEACCESS ))
869 OUString aUserInstallationURL;
870 OUString aUserInstallationPath;
871 utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
872 osl::File::getSystemPathFromFileURL( aUserInstallationURL, aUserInstallationPath );
874 OUString aDiagnosticMessage;
875 if ( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE )
876 aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NOTENOUGHDISKSPACE);
877 else
878 aDiagnosticMessage = DpResId(STR_BOOTSTRAP_ERR_NOACCESSRIGHTS);
879 aDiagnosticMessage += aUserInstallationPath;
881 FatalError(MakeStartupErrorMessage(aDiagnosticMessage));
886 namespace {
889 #if HAVE_FEATURE_BREAKPAD
890 void handleCrashReport()
892 static constexpr OUStringLiteral SERVICENAME_CRASHREPORT = u"com.sun.star.comp.svx.CrashReportUI";
894 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
896 Reference< css::frame::XSynchronousDispatch > xRecoveryUI(
897 xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_CRASHREPORT, xContext),
898 css::uno::UNO_QUERY_THROW);
900 Reference< css::util::XURLTransformer > xURLParser =
901 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
903 css::util::URL aURL;
904 css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >());
905 bool bRet = false;
906 aRet >>= bRet;
908 #endif
910 #if !defined ANDROID
911 void handleSafeMode()
913 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
915 Reference< css::frame::XSynchronousDispatch > xSafeModeUI(
916 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.SafeModeUI", xContext),
917 css::uno::UNO_QUERY_THROW);
919 css::util::URL aURL;
920 css::uno::Any aRet = xSafeModeUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >());
921 bool bRet = false;
922 aRet >>= bRet;
924 #endif
926 /** @short check if recovery must be started or not.
928 @param bCrashed [boolean ... out!]
929 the office crashed last times.
930 But may be there are no recovery data.
931 Useful to trigger the error report tool without
932 showing the recovery UI.
934 @param bRecoveryDataExists [boolean ... out!]
935 there exists some recovery data.
937 @param bSessionDataExists [boolean ... out!]
938 there exists some session data.
939 Because the user may be logged out last time from its
940 unix session...
942 void impl_checkRecoveryState(bool& bCrashed ,
943 bool& bRecoveryDataExists,
944 bool& bSessionDataExists )
946 bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get()
947 #if HAVE_FEATURE_BREAKPAD
948 || CrashReporter::crashReportInfoExists();
949 #else
951 #endif
952 bool elements = officecfg::Office::Recovery::RecoveryList::get()->
953 hasElements();
954 bool session
955 = officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
956 bRecoveryDataExists = elements && !session;
957 bSessionDataExists = elements && session;
960 Reference< css::frame::XSynchronousDispatch > g_xRecoveryUI;
962 template <class Ref>
963 struct RefClearGuard
965 Ref& m_Ref;
966 RefClearGuard(Ref& ref) : m_Ref(ref) {}
967 ~RefClearGuard() { m_Ref.clear(); }
970 /* @short start the recovery wizard.
972 @param bEmergencySave
973 differs between EMERGENCY_SAVE and RECOVERY
975 #if !ENABLE_WASM_STRIP_RECOVERYUI
976 bool impl_callRecoveryUI(bool bEmergencySave ,
977 bool bExistsRecoveryData)
979 constexpr OUStringLiteral COMMAND_EMERGENCYSAVE = u"vnd.sun.star.autorecovery:/doEmergencySave";
980 constexpr OUStringLiteral COMMAND_RECOVERY = u"vnd.sun.star.autorecovery:/doAutoRecovery";
982 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
984 g_xRecoveryUI.set(
985 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.svx.RecoveryUI", xContext),
986 css::uno::UNO_QUERY_THROW);
987 RefClearGuard<Reference< css::frame::XSynchronousDispatch >> refClearGuard(g_xRecoveryUI);
989 Reference< css::util::XURLTransformer > xURLParser =
990 css::util::URLTransformer::create(xContext);
992 css::util::URL aURL;
993 if (bEmergencySave)
994 aURL.Complete = COMMAND_EMERGENCYSAVE;
995 else if (bExistsRecoveryData)
996 aURL.Complete = COMMAND_RECOVERY;
997 else
998 return false;
1000 xURLParser->parseStrict(aURL);
1002 css::uno::Any aRet = g_xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >());
1003 bool bRet = false;
1004 aRet >>= bRet;
1005 return bRet;
1007 #endif
1009 bool impl_bringToFrontRecoveryUI()
1011 Reference< css::frame::XSynchronousDispatch > xRecoveryUI(g_xRecoveryUI);
1012 if (!xRecoveryUI.is())
1013 return false;
1015 css::util::URL aURL;
1016 aURL.Complete = "vnd.sun.star.autorecovery:/doBringToFront";
1017 Reference< css::util::XURLTransformer > xURLParser =
1018 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
1019 xURLParser->parseStrict(aURL);
1021 css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >());
1022 bool bRet = false;
1023 aRet >>= bRet;
1024 return bRet;
1029 namespace {
1031 void restartOnMac(bool passArguments) {
1032 #if defined MACOSX
1033 RequestHandler::Disable();
1034 #if HAVE_FEATURE_MACOSX_SANDBOX
1035 (void) passArguments; // avoid warnings
1036 OUString aMessage = DpResId(STR_LO_MUST_BE_RESTARTED);
1038 std::unique_ptr<weld::MessageDialog> xRestartBox(Application::CreateMessageDialog(nullptr,
1039 VclMessageType::Warning, VclButtonsType::Ok, aMessage));
1040 xRestartBox->run();
1041 #else
1042 OUString execUrl;
1043 OSL_VERIFY(osl_getExecutableFile(&execUrl.pData) == osl_Process_E_None);
1044 OUString execPath;
1045 OString execPath8;
1046 if ((osl::FileBase::getSystemPathFromFileURL(execUrl, execPath)
1047 != osl::FileBase::E_None) ||
1048 !execPath.convertToString(
1049 &execPath8, osl_getThreadTextEncoding(),
1050 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1051 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1053 std::abort();
1055 std::vector< OString > args { execPath8 };
1056 bool wait = false;
1057 if (passArguments) {
1058 sal_uInt32 n = osl_getCommandArgCount();
1059 for (sal_uInt32 i = 0; i < n; ++i) {
1060 OUString arg;
1061 osl_getCommandArg(i, &arg.pData);
1062 if (arg.match("--accept=")) {
1063 wait = true;
1065 OString arg8;
1066 if (!arg.convertToString(
1067 &arg8, osl_getThreadTextEncoding(),
1068 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1069 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1071 std::abort();
1073 args.push_back(arg8);
1076 std::vector< char const * > argPtrs;
1077 for (auto const& elem : args)
1079 argPtrs.push_back(elem.getStr());
1081 argPtrs.push_back(nullptr);
1082 execv(execPath8.getStr(), const_cast< char ** >(argPtrs.data()));
1083 if (errno == ENOTSUP) { // happens when multithreaded on macOS < 10.6
1084 pid_t pid = fork();
1085 if (pid == 0) {
1086 execv(execPath8.getStr(), const_cast< char ** >(argPtrs.data()));
1087 } else if (pid > 0) {
1088 // Two simultaneously running soffice processes lead to two dock
1089 // icons, so avoid waiting here unless it must be assumed that the
1090 // process invoking soffice itself wants to wait for soffice to
1091 // finish:
1092 if (!wait) {
1093 return;
1095 int stat;
1096 if (waitpid(pid, &stat, 0) == pid && WIFEXITED(stat)) {
1097 _exit(WEXITSTATUS(stat));
1101 std::abort();
1102 #endif
1103 #else
1104 (void) passArguments; // avoid warnings
1105 #endif
1108 #if HAVE_FEATURE_UPDATE_MAR
1109 bool isTimeForUpdateCheck()
1111 sal_uInt64 nLastUpdate = officecfg::Office::Update::Update::LastUpdateTime::get();
1112 sal_uInt64 nNow = tools::Time::GetSystemTicks();
1114 sal_uInt64 n7DayInMS = 1000 * 60 * 60 * 12 * 1; // 12 hours in ms
1115 if (nNow - n7DayInMS >= nLastUpdate)
1116 return true;
1118 return false;
1120 #endif
1124 void Desktop::Exception(ExceptionCategory nCategory)
1126 // protect against recursive calls
1127 static bool bInException = false;
1129 #if HAVE_FEATURE_BREAKPAD
1130 CrashReporter::removeExceptionHandler(); // disallow re-entry
1131 #endif
1133 SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
1134 Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
1135 if ( bInException )
1137 Application::Abort( OUString() );
1140 bInException = true;
1141 const CommandLineArgs& rArgs = GetCommandLineArgs();
1143 // save all modified documents ... if it's allowed doing so.
1144 bool bRestart = false;
1145 bool bAllowRecoveryAndSessionManagement = (
1146 ( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery
1147 ( !rArgs.IsHeadless() ) &&
1148 ( nCategory != ExceptionCategory::UserInterface ) && // recovery can't work without UI ... but UI layer seems to be the reason for this crash
1149 ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicate a corrupted installation...)
1151 if ( bAllowRecoveryAndSessionManagement )
1153 // Save all open documents so they will be reopened
1154 // the next time the application is started
1155 // returns true if at least one document could be saved...
1156 #if !ENABLE_WASM_STRIP_RECOVERYUI
1157 bRestart = impl_callRecoveryUI(
1158 true , // force emergency save
1159 false);
1160 #endif
1163 FlushConfiguration();
1165 m_xLockfile.reset();
1167 if( bRestart )
1169 RequestHandler::Disable();
1170 if( pSignalHandler )
1171 osl_removeSignalHandler( pSignalHandler );
1173 restartOnMac(false);
1174 #if !ENABLE_WASM_STRIP_SPLASH
1175 if ( m_rSplashScreen.is() )
1176 m_rSplashScreen->reset();
1177 #endif
1179 _exit( EXITHELPER_CRASH_WITH_RESTART );
1181 else
1183 Application::Abort( OUString() );
1186 OSL_ASSERT(false); // unreachable
1189 void Desktop::AppEvent( const ApplicationEvent& rAppEvent )
1191 HandleAppEvent( rAppEvent );
1194 namespace {
1196 class JVMloadThread : public salhelper::Thread {
1197 public:
1198 JVMloadThread() : salhelper::Thread("Preload JVM thread")
1202 private:
1203 virtual void execute() override final
1205 Reference< XMultiServiceFactory > xSMgr = comphelper::getProcessServiceFactory();
1207 Reference< css::loader::XImplementationLoader > xJavaComponentLoader(
1208 xSMgr->createInstance("com.sun.star.comp.stoc.JavaComponentLoader"),
1209 css::uno::UNO_QUERY_THROW);
1211 if (xJavaComponentLoader.is())
1213 const css::uno::Reference< ::com::sun::star::registry::XRegistryKey > xRegistryKey;
1216 xJavaComponentLoader->activate("", "", "", xRegistryKey);
1218 catch (...)
1220 SAL_WARN("desktop.app", "Cannot activate factory during JVM preloading");
1226 struct ExecuteGlobals
1228 Reference < css::document::XDocumentEventListener > xGlobalBroadcaster;
1229 bool bRestartRequested;
1230 std::unique_ptr<SvtCTLOptions> pCTLLanguageOptions;
1231 std::unique_ptr<SvtPathOptions> pPathOptions;
1232 rtl::Reference< JVMloadThread > xJVMloadThread;
1234 ExecuteGlobals()
1235 : bRestartRequested( false )
1241 static ExecuteGlobals* pExecGlobals = nullptr;
1243 int Desktop::Main()
1245 pExecGlobals = new ExecuteGlobals();
1247 // Remember current context object
1248 css::uno::ContextLayer layer( css::uno::getCurrentContext() );
1250 if ( m_aBootstrapError != BE_OK )
1252 HandleBootstrapErrors( m_aBootstrapError, m_aBootstrapErrorMessage );
1253 return EXIT_FAILURE;
1256 BootstrapStatus eStatus = GetBootstrapStatus();
1257 if (eStatus == BS_TERMINATE) {
1258 return EXIT_SUCCESS;
1261 // Detect desktop environment - need to do this as early as possible
1262 css::uno::setCurrentContext( new DesktopContext( css::uno::getCurrentContext() ) );
1264 if (officecfg::Office::Common::Misc::PreloadJVM::get() && pExecGlobals)
1266 SAL_INFO("desktop.app", "Preload JVM");
1268 // pre-load JVM
1269 pExecGlobals->xJVMloadThread = new JVMloadThread();
1270 pExecGlobals->xJVMloadThread->launch();
1273 CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
1275 Translate::SetReadStringHook(ReplaceStringHookProc);
1277 // Startup screen
1278 #if !ENABLE_WASM_STRIP_SPLASH
1279 OpenSplashScreen();
1280 #endif
1282 SetSplashScreenProgress(10);
1284 userinstall::Status inst_fin = userinstall::finalize();
1285 if (inst_fin != userinstall::EXISTED && inst_fin != userinstall::CREATED)
1287 SAL_WARN( "desktop.app", "userinstall failed: " << inst_fin);
1288 if ( inst_fin == userinstall::ERROR_NO_SPACE )
1289 HandleBootstrapErrors(
1290 BE_USERINSTALL_NOTENOUGHDISKSPACE, OUString() );
1291 else if ( inst_fin == userinstall::ERROR_CANT_WRITE )
1292 HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS, OUString() );
1293 else
1294 HandleBootstrapErrors( BE_USERINSTALL_FAILED, OUString() );
1295 return EXIT_FAILURE;
1297 // refresh path information
1298 utl::Bootstrap::reloadData();
1299 SetSplashScreenProgress(20);
1301 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1303 Reference< XRestartManager > xRestartManager( OfficeRestartManager::get(xContext) );
1305 Reference< XDesktop2 > xDesktop;
1307 RegisterServices();
1309 SetSplashScreenProgress(25);
1311 #if HAVE_FEATURE_DESKTOP && !defined(EMSCRIPTEN)
1312 // check user installation directory for lockfile so we can be sure
1313 // there is no other instance using our data files from a remote host
1315 bool bMustLockProfile = ( getenv( "SAL_NOLOCK_PROFILE" ) == nullptr );
1316 if ( bMustLockProfile )
1318 m_xLockfile.reset(new Lockfile);
1320 if ( !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsInvisible() &&
1321 !rCmdLineArgs.IsNoLockcheck() && !m_xLockfile->check( Lockfile_execWarning ))
1323 // Lockfile exists, and user clicked 'no'
1324 return EXIT_FAILURE;
1328 // check if accessibility is enabled but not working and allow to quit
1329 if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() )
1331 if( !InitAccessBridge() )
1332 return EXIT_FAILURE;
1334 #endif
1336 // terminate if requested...
1337 if( rCmdLineArgs.IsTerminateAfterInit() )
1338 return EXIT_SUCCESS;
1340 // Read the common configuration items for optimization purpose
1341 if ( !InitializeConfiguration() )
1342 return EXIT_FAILURE;
1344 #if HAVE_FEATURE_UPDATE_MAR
1345 const char* pUpdaterTestEnable = std::getenv("LIBO_UPDATER_TEST_ENABLE");
1346 if (pUpdaterTestEnable || officecfg::Office::Update::Update::Enabled::get())
1348 // check if we just updated
1349 const char* pUpdaterRunning = std::getenv("LIBO_UPDATER_TEST_RUNNING");
1350 bool bUpdateRunning = officecfg::Office::Update::Update::UpdateRunning::get() || pUpdaterRunning;
1351 if (bUpdateRunning)
1353 OUString aSeeAlso = officecfg::Office::Update::Update::SeeAlso::get();
1354 OUString aOldBuildID = officecfg::Office::Update::Update::OldBuildID::get();
1356 OUString aBuildID = Updater::getBuildID();
1357 if (aOldBuildID == aBuildID)
1359 Updater::log("Old and new Build ID are the same. No Updating took place.");
1361 else
1363 if (!aSeeAlso.isEmpty())
1365 SAL_INFO("desktop.updater", "See also: " << aSeeAlso);
1366 Reference< css::system::XSystemShellExecute > xSystemShell(
1367 SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
1369 xSystemShell->execute( aSeeAlso, OUString(), SystemShellExecuteFlags::URIS_ONLY );
1373 // reset all the configuration values,
1374 // all values need to be read before this code
1375 std::shared_ptr< comphelper::ConfigurationChanges > batch(
1376 comphelper::ConfigurationChanges::create());
1377 officecfg::Office::Update::Update::UpdateRunning::set(false, batch);
1378 officecfg::Office::Update::Update::SeeAlso::set(OUString(), batch);
1379 officecfg::Office::Update::Update::OldBuildID::set(OUString(), batch);
1380 batch->commit();
1382 Updater::removeUpdateFiles();
1385 osl::DirectoryItem aUpdateFile;
1386 osl::DirectoryItem::get(Updater::getUpdateFileURL(), aUpdateFile);
1388 const char* pUpdaterTestUpdate = std::getenv("LIBO_UPDATER_TEST_UPDATE");
1389 const char* pForcedUpdateCheck = std::getenv("LIBO_UPDATER_TEST_UPDATE_CHECK");
1390 if (pUpdaterTestUpdate || aUpdateFile.is())
1392 OUString aBuildID("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}");
1393 rtl::Bootstrap::expandMacros(aBuildID);
1394 std::shared_ptr< comphelper::ConfigurationChanges > batch(
1395 comphelper::ConfigurationChanges::create());
1396 officecfg::Office::Update::Update::OldBuildID::set(aBuildID, batch);
1397 officecfg::Office::Update::Update::UpdateRunning::set(true, batch);
1398 batch->commit();
1400 // make sure the change is written to the configuration before we start the update
1401 css::uno::Reference<css::util::XFlushable> xFlushable(css::configuration::theDefaultProvider::get(xContext), UNO_QUERY);
1402 xFlushable->flush();
1403 // avoid the old oosplash staying around
1404 CloseSplashScreen();
1405 bool bSuccess = update();
1406 if (bSuccess)
1407 return EXIT_SUCCESS;
1409 else if (isTimeForUpdateCheck() || pForcedUpdateCheck)
1411 sal_uInt64 nNow = tools::Time::GetSystemTicks();
1412 Updater::log("Update Check Time: " + OUString::number(nNow));
1413 std::shared_ptr< comphelper::ConfigurationChanges > batch(
1414 comphelper::ConfigurationChanges::create());
1415 officecfg::Office::Update::Update::LastUpdateTime::set(nNow, batch);
1416 batch->commit();
1417 m_aUpdateThread = std::thread(update_checker);
1420 #endif
1422 SetSplashScreenProgress(30);
1424 // create title string
1425 OUString aTitle(ReplaceStringHookProc(RID_APPTITLE));
1426 #ifdef DBG_UTIL
1427 //include buildid in non product builds
1428 aTitle += " [" + utl::Bootstrap::getBuildIdData("development") + "]";
1429 #endif
1431 SetDisplayName( aTitle );
1432 SetSplashScreenProgress(35);
1433 pExecGlobals->pPathOptions.reset( new SvtPathOptions);
1434 SetSplashScreenProgress(40);
1436 xDesktop = css::frame::Desktop::create( xContext );
1438 // create service for loading SFX (still needed in startup)
1439 pExecGlobals->xGlobalBroadcaster = Reference < css::document::XDocumentEventListener >
1440 ( css::frame::theGlobalEventBroadcaster::get(xContext), UNO_SET_THROW );
1442 /* ensure existence of a default window that messages can be dispatched to
1443 This is for the benefit of testtool which uses PostUserEvent extensively
1444 and else can deadlock while creating this window from another thread while
1445 the main thread is not yet in the event loop.
1447 Application::GetDefaultDevice();
1449 #if HAVE_FEATURE_EXTENSIONS
1450 // Check if bundled or shared extensions were added /removed
1451 // and process those extensions (has to be done before checking
1452 // the extension dependencies!
1453 SynchronizeExtensionRepositories(m_bCleanedExtensionCache, this);
1454 bool bAbort = CheckExtensionDependencies();
1455 if ( bAbort )
1456 return EXIT_FAILURE;
1458 if (inst_fin == userinstall::CREATED)
1460 Migration::migrateSettingsIfNecessary();
1462 #endif
1464 // keep a language options instance...
1465 pExecGlobals->pCTLLanguageOptions.reset( new SvtCTLOptions(true));
1467 css::document::DocumentEvent aEvent;
1468 aEvent.EventName = "OnStartApp";
1469 pExecGlobals->xGlobalBroadcaster->documentEventOccured(aEvent);
1471 SetSplashScreenProgress(50);
1473 // Backing Component
1474 bool bCrashed = false;
1475 bool bExistsRecoveryData = false;
1476 bool bExistsSessionData = false;
1478 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData);
1480 OUString pidfileName = rCmdLineArgs.GetPidfileName();
1481 if ( !pidfileName.isEmpty() )
1483 OUString pidfileURL;
1485 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None )
1487 osl::File pidfile( pidfileURL );
1488 osl::FileBase::RC rc;
1490 osl::File::remove( pidfileURL );
1491 if ( (rc = pidfile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ) ) == osl::File::E_None )
1493 OString pid( OString::number( GETPID() ) );
1494 sal_uInt64 written = 0;
1495 if ( pidfile.write(pid.getStr(), pid.getLength(), written) != osl::File::E_None )
1497 SAL_WARN("desktop.app", "cannot write pidfile " << pidfile.getURL());
1499 pidfile.close();
1501 else
1503 SAL_WARN("desktop.app", "cannot open pidfile " << pidfile.getURL() << rc);
1506 else
1508 SAL_WARN("desktop.app", "cannot get pidfile URL from path" << pidfileName);
1512 pExecGlobals->bRestartRequested = xRestartManager->isRestartRequested(true);
1513 if ( !pExecGlobals->bRestartRequested )
1515 if ((!rCmdLineArgs.WantsToLoadDocument() && !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsQuickstart()) &&
1516 (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE)) &&
1517 (!bExistsRecoveryData ) &&
1518 (!bExistsSessionData ) &&
1519 (!Application::AnyInput( VclInputFlags::APPEVENT ) ))
1521 ShowBackingComponent(this);
1525 SetSplashScreenProgress(55);
1527 svtools::ApplyFontSubstitutionsToVcl();
1529 SvtTabAppearanceCfg::SetInitialized();
1530 SvtTabAppearanceCfg::SetApplicationDefaults( this );
1531 SvtAccessibilityOptions::SetVCLSettings();
1532 SetSplashScreenProgress(60);
1534 if ( !pExecGlobals->bRestartRequested )
1536 Application::SetFilterHdl( LINK( this, Desktop, ImplInitFilterHdl ) );
1538 // Preload function depends on an initialized sfx application!
1539 SetSplashScreenProgress(75);
1541 // use system window dialogs
1542 Application::SetSystemWindowMode( SystemWindowFlags::DIALOG );
1544 SetSplashScreenProgress(80);
1546 if ( !rCmdLineArgs.IsInvisible() &&
1547 !rCmdLineArgs.IsNoQuickstart() )
1548 InitializeQuickstartMode( xContext );
1550 if ( xDesktop.is() )
1551 xDesktop->addTerminateListener( new RequestHandlerController );
1552 SetSplashScreenProgress(100);
1554 // FIXME: move this somewhere sensible.
1555 #if HAVE_FEATURE_OPENCL
1556 CheckOpenCLCompute(xDesktop);
1557 #endif
1559 #if !defined(EMSCRIPTEN)
1560 //Running the VCL graphics rendering tests
1561 const char * pDisplay = std::getenv("DISPLAY");
1562 if (!pDisplay || pDisplay[0] == ':')
1564 runGraphicsRenderTests();
1566 #endif
1568 // Post user event to startup first application component window
1569 // We have to send this OpenClients message short before execute() to
1570 // minimize the risk that this message overtakes type detection construction!!
1571 Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) );
1573 // Post event to enable acceptors
1574 Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) );
1576 // call Application::Execute to process messages in vcl message loop
1577 #if HAVE_FEATURE_JAVA
1578 // The JavaContext contains an interaction handler which is used when
1579 // the creation of a Java Virtual Machine fails
1580 css::uno::ContextLayer layer2(
1581 new svt::JavaContext( css::uno::getCurrentContext() ) );
1582 #endif
1583 // check whether the shutdown is caused by restart just before entering the Execute
1584 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
1585 xRestartManager->isRestartRequested(true);
1587 if ( !pExecGlobals->bRestartRequested )
1589 // if this run of the office is triggered by restart, some additional actions should be done
1590 DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() );
1592 Execute();
1595 else
1597 if (xDesktop.is())
1598 xDesktop->terminate();
1600 // CAUTION: you do not necessarily get here e.g. on the Mac.
1601 // please put all deinitialization code into doShutdown
1602 return doShutdown();
1605 int Desktop::doShutdown()
1607 if( ! pExecGlobals )
1608 return EXIT_SUCCESS;
1610 if (m_aUpdateThread.joinable())
1611 m_aUpdateThread.join();
1613 if (pExecGlobals->xJVMloadThread.is())
1615 pExecGlobals->xJVMloadThread->join();
1616 pExecGlobals->xJVMloadThread.clear();
1619 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
1620 OfficeRestartManager::get(comphelper::getProcessComponentContext())->
1621 isRestartRequested(true);
1622 if ( pExecGlobals->bRestartRequested )
1623 SetRestartState();
1625 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
1626 OUString pidfileName = rCmdLineArgs.GetPidfileName();
1627 if ( !pidfileName.isEmpty() )
1629 OUString pidfileURL;
1631 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None )
1633 if ( osl::File::remove( pidfileURL ) != osl::FileBase::E_None )
1635 SAL_WARN("desktop.app", "shutdown: cannot remove pidfile " << pidfileURL);
1638 else
1640 SAL_WARN("desktop.app", "shutdown: cannot get pidfile URL from path" << pidfileName);
1644 // remove temp directory
1645 RemoveTemporaryDirectory();
1646 flatpak::removeTemporaryHtmlDirectory();
1648 // flush evtl. configuration changes so that all config files in user
1649 // dir are written
1650 FlushConfiguration();
1652 if (pExecGlobals->bRestartRequested)
1654 // tdf#128523
1655 RemoveIconCacheDirectory();
1657 // a restart is already requested, usually due to a configuration change
1658 // that needs a restart to get active. If this is the case, do not try
1659 // to use SecureUserConfig to safe this still untested new configuration
1661 else
1663 // Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown
1664 // is in progress and the currently used configuration was working. Try to secure this
1665 // working configuration for later eventually necessary restores
1666 comphelper::BackupFileHelper aBackupFileHelper;
1668 aBackupFileHelper.tryPush();
1669 aBackupFileHelper.tryPushExtensionInfo();
1672 // The acceptors in the AcceptorMap must be released (in DeregisterServices)
1673 // with the solar mutex unlocked, to avoid deadlock:
1675 SolarMutexReleaser aReleaser;
1676 DeregisterServices();
1677 #if HAVE_FEATURE_SCRIPTING
1678 StarBASIC::DetachAllDocBasicItems();
1679 #endif
1682 // be sure that path/language options gets destroyed before
1683 // UCB is deinitialized
1684 pExecGlobals->pCTLLanguageOptions.reset();
1685 pExecGlobals->pPathOptions.reset();
1687 comphelper::ThreadPool::getSharedOptimalPool().shutdown();
1689 bool bRR = pExecGlobals->bRestartRequested;
1690 delete pExecGlobals;
1691 pExecGlobals = nullptr;
1693 if ( bRR )
1695 restartOnMac(true);
1696 #if !ENABLE_WASM_STRIP_SPLASH
1697 if ( m_rSplashScreen.is() )
1698 m_rSplashScreen->reset();
1699 #endif
1701 return EXITHELPER_NORMAL_RESTART;
1703 return EXIT_SUCCESS;
1706 IMPL_STATIC_LINK( Desktop, ImplInitFilterHdl, ::ConvertData&, rData, bool )
1708 return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( rData );
1711 bool Desktop::InitializeConfiguration()
1715 css::configuration::theDefaultProvider::get(
1716 comphelper::getProcessComponentContext() );
1717 return true;
1719 catch( css::lang::ServiceNotRegisteredException & e )
1721 HandleBootstrapErrors(
1722 Desktop::BE_UNO_SERVICE_CONFIG_MISSING, e.Message );
1724 catch( const css::configuration::MissingBootstrapFileException& e )
1726 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE,
1727 e.BootstrapFileURL ));
1728 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL, aMsg );
1730 catch( const css::configuration::InvalidBootstrapFileException& e )
1732 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY,
1733 e.BootstrapFileURL ));
1734 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1736 catch( const css::configuration::InstallationIncompleteException& )
1738 OUString aVersionFileURL;
1739 OUString aMsg;
1740 utl::Bootstrap::PathStatus aPathStatus = utl::Bootstrap::locateVersionFile( aVersionFileURL );
1741 if ( aPathStatus == utl::Bootstrap::PATH_EXISTS )
1742 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY, aVersionFileURL );
1743 else
1744 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE, aVersionFileURL );
1746 HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL, aMsg );
1748 catch ( const css::configuration::backend::BackendAccessException& exception)
1750 // [cm122549] It is assumed in this case that the message
1751 // coming from InitConfiguration (in fact CreateApplicationConf...)
1752 // is suitable for display directly.
1753 FatalError( MakeStartupErrorMessage( exception.Message ) );
1755 catch ( const css::configuration::backend::BackendSetupException& exception)
1757 // [cm122549] It is assumed in this case that the message
1758 // coming from InitConfiguration (in fact CreateApplicationConf...)
1759 // is suitable for display directly.
1760 FatalError( MakeStartupErrorMessage( exception.Message ) );
1762 catch ( const css::configuration::CannotLoadConfigurationException& )
1764 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA,
1765 OUString() ));
1766 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1768 catch( const css::uno::Exception& )
1770 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA,
1771 OUString() ));
1772 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1774 return false;
1777 void Desktop::FlushConfiguration()
1779 css::uno::Reference< css::util::XFlushable >(
1780 css::configuration::theDefaultProvider::get(
1781 comphelper::getProcessComponentContext()),
1782 css::uno::UNO_QUERY_THROW)->flush();
1785 bool Desktop::InitializeQuickstartMode( const Reference< XComponentContext >& rxContext )
1789 // the shutdown icon sits in the systray and allows the user to keep
1790 // the office instance running for quicker restart
1791 // this will only be activated if --quickstart was specified on cmdline
1793 bool bQuickstart = shouldLaunchQuickstart();
1795 // Try to instantiate quickstart service. This service is not mandatory, so
1796 // do nothing if service is not available
1798 // #i105753# the following if was invented for performance
1799 // unfortunately this broke the Mac behavior which is to always run
1800 // in quickstart mode since Mac applications do not usually quit
1801 // when the last document closes.
1802 // Note that this claim that on macOS we "always run in quickstart mode"
1803 // has nothing to do with (quick) *starting* (i.e. starting automatically
1804 // when the user logs in), though, but with not quitting when no documents
1805 // are open.
1806 #ifndef MACOSX
1807 if ( bQuickstart )
1808 #endif
1810 css::office::Quickstart::createStart(rxContext, bQuickstart);
1812 return true;
1814 catch( const css::uno::Exception& )
1816 return false;
1820 void Desktop::OverrideSystemSettings( AllSettings& rSettings )
1822 if ( !SvtTabAppearanceCfg::IsInitialized () )
1823 return;
1825 StyleSettings hStyleSettings = rSettings.GetStyleSettings();
1826 MouseSettings hMouseSettings = rSettings.GetMouseSettings();
1828 DragFullOptions nDragFullOptions = hStyleSettings.GetDragFullOptions();
1830 DragMode nDragMode = static_cast<DragMode>(officecfg::Office::Common::View::Window::Drag::get());
1831 switch ( nDragMode )
1833 case DragMode::FullWindow:
1834 nDragFullOptions |= DragFullOptions::All;
1835 break;
1836 case DragMode::Frame:
1837 nDragFullOptions &= ~DragFullOptions::All;
1838 break;
1839 case DragMode::SystemDep:
1840 default:
1841 break;
1844 MouseFollowFlags nFollow = hMouseSettings.GetFollow();
1845 bool bMenuFollowMouse = officecfg::Office::Common::View::Menu::FollowMouse::get();
1846 hMouseSettings.SetFollow( bMenuFollowMouse ? (nFollow|MouseFollowFlags::Menu) : (nFollow&~MouseFollowFlags::Menu));
1847 rSettings.SetMouseSettings(hMouseSettings);
1849 bool bMenuIcons = officecfg::Office::Common::View::Menu::ShowIconsInMenues::get();
1850 bool bSystemMenuIcons = officecfg::Office::Common::View::Menu::IsSystemIconsInMenus::get();
1851 TriState eMenuIcons = bSystemMenuIcons ? TRISTATE_INDET : static_cast<TriState>(bMenuIcons);
1852 hStyleSettings.SetUseImagesInMenus(eMenuIcons);
1853 hStyleSettings.SetContextMenuShortcuts(static_cast<TriState>(officecfg::Office::Common::View::Menu::ShortcutsInContextMenus::get()));
1854 hStyleSettings.SetDragFullOptions( nDragFullOptions );
1855 rSettings.SetStyleSettings ( hStyleSettings );
1858 namespace {
1860 class ExitTimer : public Timer
1862 public:
1863 ExitTimer() : Timer("desktop ExitTimer")
1865 SetTimeout(500);
1866 Start();
1868 virtual void Invoke() override
1870 _exit(42);
1876 IMPL_LINK_NOARG(Desktop, OpenClients_Impl, void*, void)
1878 // #i114963#
1879 // Enable IPC thread before OpenClients
1881 // This is because it is possible for another client to connect during the OpenClients() call.
1882 // This can happen on Windows when document is printed (not opened) and another client wants to print (when printing multiple documents).
1883 // 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
1885 // ALSO:
1887 // Multiple clients may request simultaneous connections.
1888 // When this server closes down it attempts to recreate the pipe (in RequestHandler::Disable()).
1889 // It's possible that the client has a pending connection request.
1890 // When the IPC thread is not running, this connection locks (because maPipe.accept()) is never called
1891 RequestHandler::SetReady(true);
1892 OpenClients();
1894 CloseSplashScreen();
1895 CheckFirstRun( );
1896 #ifdef _WIN32
1897 bool bDontShowDialogs
1898 = Application::IsHeadlessModeEnabled(); // uitest.uicheck fails when the dialog is open
1899 for (sal_uInt16 i = 0; !bDontShowDialogs && i < Application::GetCommandLineParamCount(); i++)
1901 if (Application::GetCommandLineParam(i) == "--nologo")
1902 bDontShowDialogs = true;
1904 if (!bDontShowDialogs)
1905 vcl::fileregistration::CheckFileExtRegistration(SfxGetpApp()->GetTopWindow());
1906 // Registers a COM class factory of the service manager with the windows operating system.
1907 Reference< XMultiServiceFactory > xSMgr= comphelper::getProcessServiceFactory();
1908 xSMgr->createInstance("com.sun.star.bridge.OleApplicationRegistration");
1909 xSMgr->createInstance("com.sun.star.comp.ole.EmbedServer");
1910 #endif
1911 const char *pExitPostStartup = getenv ("OOO_EXIT_POST_STARTUP");
1912 if (pExitPostStartup && *pExitPostStartup)
1913 new ExitTimer();
1916 void Desktop::OpenClients()
1919 const CommandLineArgs& rArgs = GetCommandLineArgs();
1921 if (!rArgs.IsQuickstart())
1923 OUString aHelpModule;
1924 if (rArgs.IsHelpWriter()) {
1925 aHelpModule = "swriter";
1926 } else if (rArgs.IsHelpCalc()) {
1927 aHelpModule = "scalc";
1928 } else if (rArgs.IsHelpDraw()) {
1929 aHelpModule = "sdraw";
1930 } else if (rArgs.IsHelpImpress()) {
1931 aHelpModule = "simpress";
1932 } else if (rArgs.IsHelpBase()) {
1933 aHelpModule = "sdatabase";
1934 } else if (rArgs.IsHelpBasic()) {
1935 aHelpModule = "sbasic";
1936 } else if (rArgs.IsHelpMath()) {
1937 aHelpModule = "smath";
1939 if (!aHelpModule.isEmpty()) {
1940 OUString aHelpURL = "vnd.sun.star.help://"
1941 + aHelpModule
1942 + "/start?Language="
1943 + utl::ConfigManager::getUILocale();
1944 #if defined UNX
1945 aHelpURL += "&System=UNX";
1946 #elif defined _WIN32
1947 aHelpURL += "&System=WIN";
1948 #endif
1949 Application::GetHelp()->Start(aHelpURL);
1950 return;
1954 // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line.
1955 // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data.
1956 // But the require that all documents, which are saved as backup should exists inside
1957 // memory. May be this mechanism will be inconsistent if the configuration exists...
1958 // but no document inside memory corresponds to this data.
1959 // Further it's not acceptable to recover such documents without any UI. It can
1960 // need some time, where the user won't see any results and wait for finishing the office startup...
1961 bool bAllowRecoveryAndSessionManagement = ( !rArgs.IsNoRestore() ) && ( !rArgs.IsHeadless() );
1963 #if !defined ANDROID
1964 // Enter safe mode if requested
1965 if (Application::IsSafeModeEnabled()) {
1966 handleSafeMode();
1968 #endif
1970 #if HAVE_FEATURE_BREAKPAD
1971 if (officecfg::Office::Common::Misc::CrashReport::get() && CrashReporter::crashReportInfoExists())
1972 handleCrashReport();
1973 #endif
1975 if ( ! bAllowRecoveryAndSessionManagement )
1979 Reference< XDispatch > xRecovery = css::frame::theAutoRecovery::get( ::comphelper::getProcessComponentContext() );
1980 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() );
1982 css::util::URL aCmd;
1983 aCmd.Complete = "vnd.sun.star.autorecovery:/disableRecovery";
1984 xParser->parseStrict(aCmd);
1986 xRecovery->dispatch(aCmd, css::uno::Sequence< css::beans::PropertyValue >());
1988 catch(const css::uno::Exception&)
1990 TOOLS_WARN_EXCEPTION( "desktop.app", "Could not disable AutoRecovery.");
1993 else
1995 bool bExistsRecoveryData = false;
1996 #if !ENABLE_WASM_STRIP_RECOVERYUI
1997 bool bCrashed = false;
1998 bool bExistsSessionData = false;
1999 bool const bDisableRecovery
2000 = getenv("OOO_DISABLE_RECOVERY") != nullptr
2001 || IsOnSystemEventLoop()
2002 || !officecfg::Office::Recovery::RecoveryInfo::Enabled::get();
2004 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData);
2006 if ( !bDisableRecovery &&
2008 bExistsRecoveryData || // => crash with files => recovery
2009 bCrashed // => crash without files => error report
2015 impl_callRecoveryUI(
2016 false , // false => force recovery instead of emergency save
2017 bExistsRecoveryData);
2019 catch(const css::uno::Exception&)
2021 TOOLS_WARN_EXCEPTION( "desktop.app", "Error during recovery");
2024 #endif
2026 Reference< XSessionManagerListener2 > xSessionListener;
2029 // specifies whether the UI-interaction on Session shutdown is allowed
2030 bool bUIOnSessionShutdownAllowed = officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled::get();
2031 xSessionListener = SessionListener::createWithOnQuitFlag(
2032 ::comphelper::getProcessComponentContext(), bUIOnSessionShutdownAllowed);
2034 catch(const css::uno::Exception&)
2036 TOOLS_WARN_EXCEPTION( "desktop.app", "Registration of session listener failed");
2039 if ( !bExistsRecoveryData && xSessionListener.is() )
2041 // session management
2044 xSessionListener->doRestore();
2046 catch(const css::uno::Exception&)
2048 TOOLS_WARN_EXCEPTION( "desktop.app", "Error in session management");
2053 // write this information here to avoid depending on vcl in the crash reporter lib
2054 CrashReporter::addKeyValue("Language", Application::GetSettings().GetLanguageTag().getBcp47(), CrashReporter::Create);
2056 RequestHandler::EnableRequests();
2058 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl());
2059 aRequest.aOpenList = rArgs.GetOpenList();
2060 aRequest.aViewList = rArgs.GetViewList();
2061 aRequest.aStartList = rArgs.GetStartList();
2062 aRequest.aPrintList = rArgs.GetPrintList();
2063 aRequest.aPrintToList = rArgs.GetPrintToList();
2064 aRequest.aPrinterName = rArgs.GetPrinterName();
2065 aRequest.aForceOpenList = rArgs.GetForceOpenList();
2066 aRequest.aForceNewList = rArgs.GetForceNewList();
2067 aRequest.aConversionList = rArgs.GetConversionList();
2068 aRequest.aConversionParams = rArgs.GetConversionParams();
2069 aRequest.aConversionOut = rArgs.GetConversionOut();
2070 aRequest.aImageConversionType = rArgs.GetImageConversionType();
2071 aRequest.aInFilter = rArgs.GetInFilter();
2072 aRequest.bTextCat = rArgs.IsTextCat();
2073 aRequest.bScriptCat = rArgs.IsScriptCat();
2075 if ( !aRequest.aOpenList.empty() ||
2076 !aRequest.aViewList.empty() ||
2077 !aRequest.aStartList.empty() ||
2078 !aRequest.aPrintList.empty() ||
2079 !aRequest.aForceOpenList.empty() ||
2080 !aRequest.aForceNewList.empty() ||
2081 ( !aRequest.aPrintToList.empty() && !aRequest.aPrinterName.isEmpty() ) ||
2082 !aRequest.aConversionList.empty() )
2084 if ( rArgs.HasModuleParam() )
2086 SvtModuleOptions aOpt;
2088 // Support command line parameters to start a module (as preselection)
2089 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
2090 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::WRITER );
2091 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) )
2092 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::CALC );
2093 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) )
2094 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::IMPRESS );
2095 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) )
2096 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::DRAW );
2099 // check for printing disabled
2100 if( ( !(aRequest.aPrintList.empty() && aRequest.aPrintToList.empty()) )
2101 && Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
2103 aRequest.aPrintList.clear();
2104 aRequest.aPrintToList.clear();
2105 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
2106 VclMessageType::Warning, VclButtonsType::Ok,
2107 DpResId(STR_ERR_PRINTDISABLED)));
2108 xBox->run();
2111 // Process request
2112 if ( RequestHandler::ExecuteCmdLineRequests(aRequest, false) )
2114 // Don't do anything if we have successfully called terminate at desktop:
2115 return;
2119 // no default document if a document was loaded by recovery or by command line or if soffice is used as server
2120 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2121 Reference< XElementAccess > xList( xDesktop->getFrames(), UNO_QUERY_THROW );
2122 if ( xList->hasElements() )
2123 return;
2125 if ( rArgs.IsQuickstart() || rArgs.IsInvisible() || Application::AnyInput( VclInputFlags::APPEVENT ) )
2126 // soffice was started as tray icon ...
2127 return;
2129 OpenDefault();
2132 void Desktop::OpenDefault()
2134 OUString aName;
2135 SvtModuleOptions aOpt;
2137 const CommandLineArgs& rArgs = GetCommandLineArgs();
2138 if ( rArgs.IsNoDefault() ) return;
2139 if ( rArgs.HasModuleParam() )
2141 // Support new command line parameters to start a module
2142 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
2143 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER );
2144 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) )
2145 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC );
2146 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) )
2147 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS );
2148 else if ( rArgs.IsBase() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
2149 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE );
2150 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) )
2151 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW );
2152 else if ( rArgs.IsMath() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::MATH ) )
2153 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::MATH );
2154 else if ( rArgs.IsGlobal() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
2155 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERGLOBAL );
2156 else if ( rArgs.IsWeb() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
2157 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITERWEB );
2160 if ( aName.isEmpty() )
2162 if (aOpt.IsModuleInstalled(SvtModuleOptions::EModule::STARTMODULE))
2164 ShowBackingComponent(nullptr);
2165 return;
2168 // Old way to create a default document
2169 if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
2170 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::WRITER );
2171 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) )
2172 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::CALC );
2173 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) )
2174 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::IMPRESS );
2175 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
2176 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DATABASE );
2177 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) )
2178 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::EFactory::DRAW );
2179 else
2180 return;
2183 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl());
2184 aRequest.aOpenList.push_back(aName);
2185 RequestHandler::ExecuteCmdLineRequests(aRequest, false);
2189 OUString GetURL_Impl(
2190 const OUString& rName, std::optional< OUString > const & cwdUrl )
2192 // if rName is a vnd.sun.star.script URL do not attempt to parse it
2193 // as INetURLObj does not handle URLs there
2194 if (rName.startsWith("vnd.sun.star.script"))
2196 return rName;
2199 // don't touch file urls, those should already be in internal form
2200 // they won't get better here (#112849#)
2201 if (comphelper::isFileUrl(rName))
2203 return rName;
2206 if ( rName.startsWith("service:"))
2208 return rName;
2211 // Add path separator to these directory and make given URL (rName) absolute by using of current working directory
2212 // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!!
2213 // Otherwise last part will be ignored and wrong result will be returned!!!
2214 // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ...
2215 // But if we add a separator - he doesn't do it anymore.
2216 INetURLObject aObj;
2217 if (cwdUrl) {
2218 aObj.SetURL(*cwdUrl);
2219 aObj.setFinalSlash();
2222 // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths.
2223 // Otherwise this char won't get encoded and we are not able to load such files later,
2224 bool bWasAbsolute;
2225 INetURLObject aURL = aObj.smartRel2Abs( rName, bWasAbsolute, false, INetURLObject::EncodeMechanism::WasEncoded,
2226 RTL_TEXTENCODING_UTF8, true );
2227 OUString aFileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2229 ::osl::FileStatus aStatus( osl_FileStatus_Mask_FileURL );
2230 ::osl::DirectoryItem aItem;
2231 if( ::osl::FileBase::E_None == ::osl::DirectoryItem::get( aFileURL, aItem ) &&
2232 ::osl::FileBase::E_None == aItem.getFileStatus( aStatus ) )
2233 aFileURL = aStatus.getFileURL();
2235 return aFileURL;
2238 void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent )
2240 switch ( rAppEvent.GetEvent() )
2242 case ApplicationEvent::Type::Accept:
2243 // every time an accept parameter is used we create an acceptor
2244 // with the corresponding accept-string
2245 createAcceptor(rAppEvent.GetStringData());
2246 break;
2247 case ApplicationEvent::Type::Appear:
2248 if ( !GetCommandLineArgs().IsInvisible() && !impl_bringToFrontRecoveryUI() )
2250 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2252 // find active task - the active task is always a visible task
2253 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
2254 Reference< css::frame::XFrame > xTask = xDesktop->getActiveFrame();
2255 if ( !xTask.is() )
2257 // get any task if there is no active one
2258 Reference< css::container::XIndexAccess > xList = xDesktop->getFrames();
2259 if ( xList->getCount() > 0 )
2260 xList->getByIndex(0) >>= xTask;
2263 if ( xTask.is() )
2265 Reference< css::awt::XTopWindow > xTop( xTask->getContainerWindow(), UNO_QUERY );
2266 xTop->toFront();
2268 else
2270 // no visible task that could be activated found
2271 Reference< css::awt::XWindow > xContainerWindow;
2272 Reference< XFrame > xBackingFrame = xDesktop->findFrame( "_blank", 0);
2273 if (xBackingFrame.is())
2274 xContainerWindow = xBackingFrame->getContainerWindow();
2275 if (xContainerWindow.is())
2277 Reference< XController > xStartModule = StartModule::createWithParentWindow(xContext, xContainerWindow);
2278 Reference< css::awt::XWindow > xBackingWin(xStartModule, UNO_QUERY);
2279 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2280 // Because the backing component set the property "IsBackingMode" of the frame
2281 // to true inside attachFrame(). But setComponent() reset this state every time ...
2282 xBackingFrame->setComponent(xBackingWin, xStartModule);
2283 xStartModule->attachFrame(xBackingFrame);
2284 xContainerWindow->setVisible(true);
2286 VclPtr<vcl::Window> pCompWindow = VCLUnoHelper::GetWindow(xBackingFrame->getComponentWindow());
2287 if (pCompWindow)
2288 pCompWindow->PaintImmediately();
2292 break;
2293 case ApplicationEvent::Type::Open:
2295 const CommandLineArgs& rCmdLine = GetCommandLineArgs();
2296 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
2298 ProcessDocumentsRequest docsRequest(rCmdLine.getCwdUrl());
2299 std::vector<OUString> const & data(rAppEvent.GetStringsData());
2300 docsRequest.aOpenList.insert(
2301 docsRequest.aOpenList.end(), data.begin(), data.end());
2302 RequestHandler::ExecuteCmdLineRequests(docsRequest, false);
2305 break;
2306 case ApplicationEvent::Type::OpenHelpUrl:
2307 // start help for a specific URL
2308 Application::GetHelp()->Start(rAppEvent.GetStringData());
2309 break;
2310 case ApplicationEvent::Type::Print:
2312 const CommandLineArgs& rCmdLine = GetCommandLineArgs();
2313 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
2315 ProcessDocumentsRequest docsRequest(rCmdLine.getCwdUrl());
2316 std::vector<OUString> const & data(rAppEvent.GetStringsData());
2317 docsRequest.aPrintList.insert(
2318 docsRequest.aPrintList.end(), data.begin(), data.end());
2319 RequestHandler::ExecuteCmdLineRequests(docsRequest, false);
2322 break;
2323 case ApplicationEvent::Type::PrivateDoShutdown:
2325 Desktop* pD = dynamic_cast<Desktop*>(GetpApp());
2326 OSL_ENSURE( pD, "no desktop ?!?" );
2327 if( pD )
2328 pD->doShutdown();
2330 break;
2331 case ApplicationEvent::Type::QuickStart:
2332 if ( !GetCommandLineArgs().IsInvisible() )
2334 // If the office has been started the second time its command line arguments are sent through a pipe
2335 // connection to the first office. We want to reuse the quickstart option for the first office.
2336 // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the
2337 // application events to do this (they are executed inside main thread)!!!
2338 // Don't start quickstart service if the user specified "--invisible" on the command line!
2339 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2340 css::office::Quickstart::createStart(xContext, true/*Quickstart*/);
2342 break;
2343 case ApplicationEvent::Type::ShowDialog:
2344 // This is only used on macOS, and only for About or Preferences.
2345 // Ignore all errors here. It's clicking a menu entry only ...
2346 // The user will try it again, in case nothing happens .-)
2349 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2351 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
2353 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext);
2354 css::util::URL aCommand;
2355 if( rAppEvent.GetStringData() == "PREFERENCES" )
2356 aCommand.Complete = ".uno:OptionsTreeDialog";
2357 else if( rAppEvent.GetStringData() == "ABOUT" )
2358 aCommand.Complete = ".uno:About";
2359 if( !aCommand.Complete.isEmpty() )
2361 xParser->parseStrict(aCommand);
2363 css::uno::Reference< css::frame::XDispatch > xDispatch = xDesktop->queryDispatch(aCommand, OUString(), 0);
2364 if (xDispatch.is())
2365 xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >());
2368 catch(const css::uno::Exception&)
2370 TOOLS_WARN_EXCEPTION("desktop.app", "exception thrown by dialog");
2372 break;
2373 case ApplicationEvent::Type::Unaccept:
2374 // try to remove corresponding acceptor
2375 destroyAcceptor(rAppEvent.GetStringData());
2376 break;
2377 default:
2378 SAL_WARN( "desktop.app", "this cannot happen");
2379 break;
2383 #if !ENABLE_WASM_STRIP_SPLASH
2384 void Desktop::OpenSplashScreen()
2386 const CommandLineArgs &rCmdLine = GetCommandLineArgs();
2387 // Show intro only if this is normal start (e.g. no server, no quickstart, no printing )
2388 if ( !(!rCmdLine.IsInvisible() &&
2389 !rCmdLine.IsHeadless() &&
2390 !rCmdLine.IsQuickstart() &&
2391 !rCmdLine.IsMinimized() &&
2392 !rCmdLine.IsNoLogo() &&
2393 !rCmdLine.IsTerminateAfterInit() &&
2394 rCmdLine.GetPrintList().empty() &&
2395 rCmdLine.GetPrintToList().empty() &&
2396 rCmdLine.GetConversionList().empty()) )
2397 return;
2399 // Determine application name from command line parameters
2400 OUString aAppName;
2401 if ( rCmdLine.IsWriter() )
2402 aAppName = "writer";
2403 else if ( rCmdLine.IsCalc() )
2404 aAppName = "calc";
2405 else if ( rCmdLine.IsDraw() )
2406 aAppName = "draw";
2407 else if ( rCmdLine.IsImpress() )
2408 aAppName = "impress";
2409 else if ( rCmdLine.IsBase() )
2410 aAppName = "base";
2411 else if ( rCmdLine.IsGlobal() )
2412 aAppName = "global";
2413 else if ( rCmdLine.IsMath() )
2414 aAppName = "math";
2415 else if ( rCmdLine.IsWeb() )
2416 aAppName = "web";
2418 // Which splash to use
2419 OUString aSplashService( "com.sun.star.office.SplashScreen" );
2420 if ( rCmdLine.HasSplashPipe() )
2421 aSplashService = "com.sun.star.office.PipeSplashScreen";
2423 Sequence< Any > aSeq{ Any(true) /* bVisible */, Any(aAppName) };
2424 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2425 m_rSplashScreen.set(
2426 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService, aSeq, xContext),
2427 UNO_QUERY);
2429 if(m_rSplashScreen.is())
2430 m_rSplashScreen->start("SplashScreen", 100);
2433 #endif
2435 void Desktop::SetSplashScreenProgress(sal_Int32 iProgress)
2437 #if ENABLE_WASM_STRIP_SPLASH
2438 (void) iProgress;
2439 #else
2440 if(m_rSplashScreen.is())
2442 m_rSplashScreen->setValue(iProgress);
2444 #endif
2447 void Desktop::SetSplashScreenText( const OUString& rText )
2449 #if ENABLE_WASM_STRIP_SPLASH
2450 (void) rText;
2451 #else
2452 if( m_rSplashScreen.is() )
2454 m_rSplashScreen->setText( rText );
2456 #endif
2459 void Desktop::CloseSplashScreen()
2461 #if !ENABLE_WASM_STRIP_SPLASH
2462 if(m_rSplashScreen.is())
2464 SolarMutexGuard ensureSolarMutex;
2465 m_rSplashScreen->end();
2466 m_rSplashScreen = nullptr;
2468 #endif
2472 IMPL_STATIC_LINK_NOARG(Desktop, AsyncInitFirstRun, Timer *, void)
2474 // does initializations which are necessary for the first run of the office
2477 Reference< XJobExecutor > xExecutor = theJobExecutor::get( ::comphelper::getProcessComponentContext() );
2478 xExecutor->trigger( "onFirstRunInitialization" );
2480 catch(const css::uno::Exception&)
2482 TOOLS_WARN_EXCEPTION( "desktop.app", "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor" );
2486 void Desktop::ShowBackingComponent(Desktop * progress)
2488 if (GetCommandLineArgs().IsNoDefault())
2490 return;
2492 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
2493 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xContext);
2494 if (progress != nullptr)
2496 progress->SetSplashScreenProgress(60);
2498 Reference< XFrame > xBackingFrame = xDesktop->findFrame( "_blank", 0);
2499 Reference< css::awt::XWindow > xContainerWindow;
2501 if (xBackingFrame.is())
2502 xContainerWindow = xBackingFrame->getContainerWindow();
2503 if (!xContainerWindow.is())
2504 return;
2506 // set the WindowExtendedStyle::Document style. Normally, this is done by the TaskCreator service when a "_blank"
2507 // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior,
2508 // otherwise documents loaded into this frame will later on miss functionality depending on the style.
2509 VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
2510 SAL_WARN_IF( !pContainerWindow, "desktop.app", "Desktop::Main: no implementation access to the frame's container window!" );
2511 pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document );
2512 if (progress != nullptr)
2514 progress->SetSplashScreenProgress(75);
2517 Reference< XController > xStartModule = StartModule::createWithParentWindow( xContext, xContainerWindow);
2518 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2519 // Because the backing component set the property "IsBackingMode" of the frame
2520 // to true inside attachFrame(). But setComponent() reset this state everytimes ...
2521 xBackingFrame->setComponent(Reference< XWindow >(xStartModule, UNO_QUERY), xStartModule);
2522 if (progress != nullptr)
2524 progress->SetSplashScreenProgress(100);
2526 xStartModule->attachFrame(xBackingFrame);
2527 if (progress != nullptr)
2529 progress->CloseSplashScreen();
2531 xContainerWindow->setVisible(true);
2535 void Desktop::CheckFirstRun( )
2537 if (!officecfg::Office::Common::Misc::FirstRun::get())
2538 return;
2540 // use VCL timer, which won't trigger during shutdown if the
2541 // application exits before timeout
2542 m_firstRunTimer.Start();
2544 #ifdef _WIN32
2545 // Check if Quickstarter should be started (on Windows only)
2546 OUString sRootKey = ReplaceStringHookProc("Software\\%OOOVENDOR\\%PRODUCTNAME\\%PRODUCTVERSION");
2547 WCHAR szValue[8192];
2548 DWORD nValueSize = sizeof(szValue);
2549 HKEY hKey;
2550 if (ERROR_SUCCESS == RegOpenKeyW(HKEY_LOCAL_MACHINE, o3tl::toW(sRootKey.getStr()), &hKey))
2552 if ( ERROR_SUCCESS == RegQueryValueExW( hKey, L"RunQuickstartAtFirstStart", nullptr, nullptr, reinterpret_cast<LPBYTE>(szValue), &nValueSize ) )
2554 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2555 css::office::Quickstart::createAutoStart(xContext, true/*Quickstart*/, true/*bAutostart*/);
2556 RegCloseKey( hKey );
2559 #endif
2561 std::shared_ptr< comphelper::ConfigurationChanges > batch(
2562 comphelper::ConfigurationChanges::create());
2563 officecfg::Office::Common::Misc::FirstRun::set(false, batch);
2564 batch->commit();
2569 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */