bump product version to 4.1.6.2
[LibreOffice.git] / desktop / source / app / app.cxx
blob5bda37326bff66b012c6ec41c7dce18694687c2b
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 <config_features.h>
22 #include "sal/config.h"
24 #include <iostream>
26 #include "app.hxx"
27 #include "desktop.hrc"
28 #include "cmdlineargs.hxx"
29 #include "cmdlinehelp.hxx"
30 #include "dispatchwatcher.hxx"
31 #include "configinit.hxx"
32 #include "lockfile.hxx"
33 #include "userinstall.hxx"
34 #include "desktopcontext.hxx"
35 #include "exithelper.h"
36 #include "migration.hxx"
38 #include <svtools/javacontext.hxx>
39 #include <com/sun/star/frame/AutoRecovery.hpp>
40 #include <com/sun/star/frame/GlobalEventBroadcaster.hpp>
41 #include <com/sun/star/frame/SessionListener.hpp>
42 #include <com/sun/star/frame/XSessionManagerListener.hpp>
43 #include <com/sun/star/frame/XSynchronousDispatch.hpp>
44 #include <com/sun/star/document/CorruptedFilterConfigurationException.hpp>
45 #include <com/sun/star/configuration/CorruptedConfigurationException.hpp>
46 #include <com/sun/star/configuration/theDefaultProvider.hpp>
47 #include <com/sun/star/util/XFlushable.hpp>
48 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
49 #include <com/sun/star/frame/Desktop.hpp>
50 #include <com/sun/star/frame/StartModule.hpp>
51 #include <com/sun/star/frame/XComponentLoader.hpp>
52 #include <com/sun/star/view/XPrintable.hpp>
53 #include <com/sun/star/awt/XTopWindow.hpp>
54 #include "com/sun/star/util/URLTransformer.hpp"
55 #include <com/sun/star/util/XURLTransformer.hpp>
56 #include <com/sun/star/util/XCloseable.hpp>
57 #include <com/sun/star/frame/XDispatchProvider.hpp>
58 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
59 #include <com/sun/star/configuration/MissingBootstrapFileException.hpp>
60 #include <com/sun/star/configuration/InvalidBootstrapFileException.hpp>
61 #include <com/sun/star/configuration/InstallationIncompleteException.hpp>
62 #include <com/sun/star/configuration/backend/BackendSetupException.hpp>
63 #include <com/sun/star/configuration/backend/BackendAccessException.hpp>
64 #include <com/sun/star/task/JobExecutor.hpp>
65 #include <com/sun/star/task/OfficeRestartManager.hpp>
66 #include <com/sun/star/task/XRestartManager.hpp>
67 #include <com/sun/star/document/XEventListener.hpp>
68 #include <com/sun/star/frame/UICommandDescription.hpp>
69 #include <com/sun/star/ui/UIElementFactoryManager.hpp>
70 #include <com/sun/star/ui/WindowStateConfiguration.hpp>
71 #include <com/sun/star/frame/XUIControllerRegistration.hpp>
72 #include <com/sun/star/frame/ToolbarControllerFactory.hpp>
73 #include <com/sun/star/frame/PopupMenuControllerFactory.hpp>
75 #include <toolkit/unohlp.hxx>
76 #include <comphelper/configuration.hxx>
77 #include <comphelper/processfactory.hxx>
78 #include <unotools/bootstrap.hxx>
79 #include <unotools/configmgr.hxx>
80 #include <unotools/moduleoptions.hxx>
81 #include <officecfg/Office/Common.hxx>
82 #include <officecfg/Office/Recovery.hxx>
83 #include <osl/file.hxx>
84 #include <osl/process.h>
85 #include <rtl/uri.hxx>
86 #include <unotools/pathoptions.hxx>
87 #include <svtools/miscopt.hxx>
88 #include <svtools/menuoptions.hxx>
89 #include <rtl/logfile.hxx>
90 #include <rtl/bootstrap.hxx>
91 #include <vcl/help.hxx>
92 #include <vcl/msgbox.hxx>
93 #include <sfx2/sfx.hrc>
94 #include <sfx2/app.hxx>
95 #include <svl/itemset.hxx>
96 #include <svl/eitem.hxx>
98 #include <svtools/fontsubstconfig.hxx>
99 #include <svtools/accessibilityoptions.hxx>
100 #include <svtools/apearcfg.hxx>
101 #include <vcl/graphicfilter.hxx>
103 #include "langselect.hxx"
105 #include <config_telepathy.h>
107 #if ENABLE_TELEPATHY
108 #include <tubes/manager.hxx>
109 #endif
111 #if defined MACOSX
112 #include <errno.h>
113 #include <sys/wait.h>
114 #endif
116 #ifdef WNT
117 #ifdef _MSC_VER
118 #pragma warning(push, 1) /* disable warnings within system headers */
119 #pragma warning (disable: 4005)
120 #endif
121 #define WIN32_LEAN_AND_MEAN
122 #include <windows.h>
123 #ifdef _MSC_VER
124 #pragma warning(pop)
125 #endif
126 #endif //WNT
128 #if defined WNT
129 #include <process.h>
130 #define GETPID _getpid
131 #else
132 #include <unistd.h>
133 #define GETPID getpid
134 #endif
136 using namespace ::com::sun::star::awt;
137 using namespace ::com::sun::star::uno;
138 using namespace ::com::sun::star::util;
139 using namespace ::com::sun::star::lang;
140 using namespace ::com::sun::star::beans;
141 using namespace ::com::sun::star::frame;
142 using namespace ::com::sun::star::document;
143 using namespace ::com::sun::star::view;
144 using namespace ::com::sun::star::task;
145 using namespace ::com::sun::star::system;
146 using namespace ::com::sun::star::ui;
147 using namespace ::com::sun::star::ui::dialogs;
148 using namespace ::com::sun::star::container;
150 ResMgr* desktop::Desktop::pResMgr = 0;
152 namespace desktop
155 static oslSignalHandler pSignalHandler = 0;
156 static sal_Bool _bCrashReporterEnabled = sal_True;
158 namespace {
160 void removeTree(OUString const & url) {
161 osl::Directory dir(url);
162 osl::FileBase::RC rc = dir.open();
163 switch (rc) {
164 case osl::FileBase::E_None:
165 break;
166 case osl::FileBase::E_NOENT:
167 return; //TODO: SAL_WARN if recursive
168 default:
169 SAL_WARN(
170 "desktop", "cannot open directory " << dir.getURL() << ": " << +rc);
171 return;
173 for (;;) {
174 osl::DirectoryItem i;
175 rc = dir.getNextItem(i, SAL_MAX_UINT32);
176 if (rc == osl::FileBase::E_NOENT) {
177 break;
179 if (rc != osl::FileBase::E_None) {
180 SAL_WARN(
181 "desktop",
182 "cannot iterate directory " << dir.getURL() << ": " << +rc);
183 break;
185 osl::FileStatus stat(
186 osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
187 osl_FileStatus_Mask_FileURL);
188 rc = i.getFileStatus(stat);
189 if (rc != osl::FileBase::E_None) {
190 SAL_WARN(
191 "desktop",
192 "cannot stat in directory " << dir.getURL() << ": " << +rc);
193 continue;
195 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
196 removeTree(stat.getFileURL());
197 } else {
198 rc = osl::File::remove(stat.getFileURL());
199 SAL_WARN_IF(
200 rc != osl::FileBase::E_None, "desktop",
201 "cannot remove file " << stat.getFileURL() << ": " << +rc);
204 if (dir.isOpen()) {
205 rc = dir.close();
206 SAL_WARN_IF(
207 rc != osl::FileBase::E_None, "desktop",
208 "cannot close directory " << dir.getURL() << ": " << +rc);
210 rc = osl::Directory::remove(url);
211 SAL_WARN_IF(
212 rc != osl::FileBase::E_None, "desktop",
213 "cannot remove directory " << url << ": " << +rc);
216 // Remove any existing UserInstallation's extensions cache data remaining from
217 // old installations. This addresses at least two problems:
219 // For one, apparently due to the old share/prereg/bundled mechanism (disabled
220 // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying
221 // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled
222 // cache could contain corrupted information (like a UNO component registered
223 // twice, which got changed from active to passive registration in one LO
224 // version, but the version of the corresponding bundled extension only
225 // incremented in a later LO version).
227 // For another, UserInstallations have been seen in the wild where no extensions
228 // were installed per-user (any longer), but user/uno_packages/cache/registry/
229 // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files
230 // contained data nevertheless.
232 // When a LO upgrade is detected (i.e., no user/extensions/buildid or one
233 // containing an old build ID), then user/extensions and
234 // user/uno_packages/cache/registry/
235 // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are
236 // removed. That should prevent any problems starting the service manager due
237 // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the
238 // removed cache data is recreated.
240 // Multiple instances of soffice.bin can execute this code in parallel for a
241 // single UserInstallation, as it is called before OfficeIPCThread is set up.
242 // Therefore, any errors here only lead to SAL_WARNs.
244 // At least in theory, this function could be removed again once no
245 // UserInstallation can be poisoned by old junk any more.
246 bool cleanExtensionCache() {
247 OUString buildId(
248 "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}");
249 rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure
250 OUString extDir(
251 "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
252 ":UserInstallation}/user/extensions");
253 rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure
254 OUString buildIdFile(extDir + "/buildid");
255 osl::File fr(buildIdFile);
256 osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read);
257 switch (rc) {
258 case osl::FileBase::E_None:
260 rtl::ByteSequence s1;
261 rc = fr.readLine(s1);
262 osl::FileBase::RC rc2 = fr.close();
263 SAL_WARN_IF(
264 rc2 != osl::FileBase::E_None, "desktop",
265 "cannot close " << fr.getURL() << " after reading: " << +rc2);
266 if (rc != osl::FileBase::E_None) {
267 SAL_WARN(
268 "desktop",
269 "cannot read from " << fr.getURL() << ": " << +rc);
270 break;
272 OUString s2(
273 reinterpret_cast< char const * >(s1.getConstArray()),
274 s1.getLength(), RTL_TEXTENCODING_ISO_8859_1);
275 // using ISO 8859-1 avoids any and all conversion errors; the
276 // content should only be a subset of ASCII, anyway
277 if (s2 == buildId) {
278 return false;
280 break;
282 case osl::FileBase::E_NOENT:
283 break;
284 default:
285 SAL_WARN(
286 "desktop",
287 "cannot open " << fr.getURL() << " for reading: " << +rc);
288 break;
290 removeTree(extDir);
291 OUString userRcFile(
292 "$UNO_USER_PACKAGES_CACHE/registry/"
293 "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc");
294 rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure
295 rc = osl::File::remove(userRcFile);
296 SAL_WARN_IF(
297 rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop",
298 "cannot remove file " << userRcFile << ": " << +rc);
299 rc = osl::Directory::createPath(extDir);
300 SAL_WARN_IF(
301 rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop",
302 "cannot create path " << extDir << ": " << +rc);
303 osl::File fw(buildIdFile);
304 rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
305 if (rc != osl::FileBase::E_None) {
306 SAL_WARN(
307 "desktop",
308 "cannot open " << fw.getURL() << " for writing: " << +rc);
309 return true;
311 OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8));
312 // using UTF-8 avoids almost all conversion errors (and buildid
313 // containing single surrogate halves should never happen, anyway); the
314 // content should only be a subset of ASCII, anyway
315 sal_uInt64 n = 0;
316 rc = fw.write(buf.getStr(), buf.getLength(), n);
317 SAL_WARN_IF(
318 (rc != osl::FileBase::E_None
319 || n != static_cast< sal_uInt32 >(buf.getLength())),
320 "desktop",
321 "cannot write to " << fw.getURL() << ": " << +rc << ", " << n);
322 rc = fw.close();
323 SAL_WARN_IF(
324 rc != osl::FileBase::E_None, "desktop",
325 "cannot close " << fw.getURL() << " after writing: " << +rc);
326 return true;
331 // ----------------------------------------------------------------------------
333 ResMgr* Desktop::GetDesktopResManager()
335 if ( !Desktop::pResMgr )
337 // Create desktop resource manager and bootstrap process
338 // was successful. Use default way to get language specific message.
339 if ( Application::IsInExecute() )
340 Desktop::pResMgr = ResMgr::CreateResMgr("dkt");
342 if ( !Desktop::pResMgr )
344 // Use VCL to get the correct language specific message as we
345 // are in the bootstrap process and not able to get the installed
346 // language!!
347 OUString aUILocaleString = LanguageSelection::getLanguageString();
348 LanguageTag aLanguageTag( aUILocaleString);
349 //! ResMgr may modify the Locale for fallback!
350 Desktop::pResMgr = ResMgr::SearchCreateResMgr( "dkt", aLanguageTag);
351 AllSettings as = GetSettings();
352 as.SetUILanguageTag(aLanguageTag);
353 SetSettings(as);
357 return Desktop::pResMgr;
360 namespace {
362 // ----------------------------------------------------------------------------
363 // Get a message string securely. There is a fallback string if the resource
364 // is not available.
366 OUString GetMsgString(
367 sal_uInt16 nId, const OUString& aFallbackMsg,
368 bool bAlwaysUseFallbackMsg = false )
370 if ( !bAlwaysUseFallbackMsg )
372 ResMgr* resMgr = Desktop::GetDesktopResManager();
373 if ( resMgr )
374 return OUString( String( ResId( nId, *resMgr )));
376 return aFallbackMsg;
379 OUString MakeStartupErrorMessage(
380 OUString const & aErrorMessage, bool bAlwaysUseFallbackMsg = false )
382 OUStringBuffer aDiagnosticMessage( 100 );
384 aDiagnosticMessage.append(
385 GetMsgString(
386 STR_BOOTSTRAP_ERR_CANNOT_START, "The program cannot be started.",
387 bAlwaysUseFallbackMsg ) );
389 aDiagnosticMessage.appendAscii( "\n" );
391 aDiagnosticMessage.append( aErrorMessage );
393 return aDiagnosticMessage.makeStringAndClear();
396 OUString MakeStartupConfigAccessErrorMessage( OUString const & aInternalErrMsg )
398 OUStringBuffer aDiagnosticMessage( 200 );
400 ResMgr* pResMgr = Desktop::GetDesktopResManager();
401 if ( pResMgr )
402 aDiagnosticMessage.append( OUString(String(ResId(STR_BOOTSTRAP_ERR_CFG_DATAACCESS, *pResMgr ))) );
403 else
404 aDiagnosticMessage.appendAscii( "The program cannot be started." );
406 if ( !aInternalErrMsg.isEmpty() )
408 aDiagnosticMessage.appendAscii( "\n\n" );
409 if ( pResMgr )
410 aDiagnosticMessage.append( OUString(String(ResId(STR_INTERNAL_ERRMSG, *pResMgr ))) );
411 else
412 aDiagnosticMessage.appendAscii( "The following internal error has occurred:\n\n" );
413 aDiagnosticMessage.append( aInternalErrMsg );
416 return aDiagnosticMessage.makeStringAndClear();
419 //=============================================================================
420 // shows a simple error box with the given message ... but exits from these process !
421 // Fatal errors cant be solved by the process ... nor any recovery can help.
422 // Mostly the installation was damaged and must be repaired manually .. or by calling
423 // setup again.
424 // On the other side we must make sure that no further actions will be possible within
425 // the current office process ! No pipe requests, no menu/toolbar/shortuct actions
426 // are allowed. Otherwise we will force a "crash inside a crash".
427 // Thats why we have to use a special native message box here which does not use yield :-)
428 //=============================================================================
429 void FatalError(const OUString& sMessage)
431 OUString sProductKey = ::utl::Bootstrap::getProductKey();
432 if ( sProductKey.isEmpty())
434 osl_getExecutableFile( &sProductKey.pData );
436 ::sal_uInt32 nLastIndex = sProductKey.lastIndexOf('/');
437 if ( nLastIndex > 0 )
438 sProductKey = sProductKey.copy( nLastIndex+1 );
441 OUStringBuffer sTitle (128);
442 sTitle.append (sProductKey );
443 sTitle.appendAscii (" - Fatal Error");
445 Application::ShowNativeErrorBox (sTitle.makeStringAndClear (), sMessage);
446 _exit(EXITHELPER_FATAL_ERROR);
449 static bool ShouldSuppressUI(const CommandLineArgs& rCmdLine)
451 return rCmdLine.IsInvisible() ||
452 rCmdLine.IsHeadless() ||
453 rCmdLine.IsQuickstart();
456 struct theCommandLineArgs : public rtl::Static< CommandLineArgs, theCommandLineArgs > {};
460 CommandLineArgs& Desktop::GetCommandLineArgs()
462 return theCommandLineArgs::get();
465 namespace
467 struct BrandName
468 : public rtl::Static< String, BrandName > {};
469 struct Version
470 : public rtl::Static< String, Version > {};
471 struct AboutBoxVersion
472 : public rtl::Static< String, AboutBoxVersion > {};
473 struct AboutBoxVersionSuffix
474 : public rtl::Static< String, AboutBoxVersionSuffix > {};
475 struct OOOVendor
476 : public rtl::Static< String, OOOVendor > {};
477 struct Extension
478 : public rtl::Static< String, Extension > {};
479 struct XMLFileFormatName
480 : public rtl::Static< String, XMLFileFormatName > {};
481 struct XMLFileFormatVersion
482 : public rtl::Static< String, XMLFileFormatVersion > {};
483 struct WriterCompatibilityVersionOOo11
484 : public rtl::Static< String, WriterCompatibilityVersionOOo11 > {};
487 OUString ReplaceStringHookProc( const OUString& rStr )
489 OUString sRet(rStr);
491 if (sRet.indexOf("%PRODUCT") != -1 || sRet.indexOf("%ABOUTBOX") != -1)
493 OUString sBrandName = BrandName::get();
494 OUString sVersion = Version::get();
495 OUString sBuildId = utl::Bootstrap::getBuildIdData("development");
496 OUString sAboutBoxVersion = AboutBoxVersion::get();
497 OUString sAboutBoxVersionSuffix = AboutBoxVersionSuffix::get();
498 OUString sExtension = Extension::get();
499 OUString sXMLFileFormatName = XMLFileFormatName::get();
500 OUString sXMLFileFormatVersion = XMLFileFormatVersion::get();
502 if ( sBrandName.isEmpty() )
504 sBrandName = utl::ConfigManager::getProductName();
505 sXMLFileFormatName = utl::ConfigManager::getProductXmlFileFormat();
506 sXMLFileFormatVersion =
507 utl::ConfigManager::getProductXmlFileFormatVersion();
508 sVersion = utl::ConfigManager::getProductVersion();
509 sAboutBoxVersion = utl::ConfigManager::getAboutBoxProductVersion();
510 sAboutBoxVersionSuffix = utl::ConfigManager::getAboutBoxProductVersionSuffix();
511 if ( sExtension.isEmpty() )
513 sExtension = utl::ConfigManager::getProductExtension();
517 sRet = sRet.replaceAll( "%PRODUCTNAME", sBrandName );
518 sRet = sRet.replaceAll( "%PRODUCTVERSION", sVersion );
519 sRet = sRet.replaceAll( "%BUILDID", sBuildId );
520 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX", sAboutBoxVersionSuffix );
521 sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSION", sAboutBoxVersion );
522 sRet = sRet.replaceAll( "%PRODUCTEXTENSION", sExtension );
523 sRet = sRet.replaceAll( "%PRODUCTXMLFILEFORMATNAME", sXMLFileFormatName );
524 sRet = sRet.replaceAll( "%PRODUCTXMLFILEFORMATVERSION", sXMLFileFormatVersion );
527 if ( sRet.indexOf( "%OOOVENDOR" ) != -1 )
529 OUString sOOOVendor = OOOVendor::get();
531 if ( sOOOVendor.isEmpty() )
533 sOOOVendor = utl::ConfigManager::getVendor();
536 sRet = sRet.replaceAll( "%OOOVENDOR", sOOOVendor );
539 if ( sRet.indexOf( "%WRITERCOMPATIBILITYVERSIONOOO11" ) != -1 )
541 OUString sWriterCompatibilityVersionOOo11 = WriterCompatibilityVersionOOo11::get();
542 if ( sWriterCompatibilityVersionOOo11.isEmpty() )
544 sWriterCompatibilityVersionOOo11 =
545 utl::ConfigManager::getWriterCompatibilityVersionOOo_1_1();
548 sRet = sRet.replaceAll( "%WRITERCOMPATIBILITYVERSIONOOO11",
549 sWriterCompatibilityVersionOOo11 );
552 return sRet;
555 Desktop::Desktop()
556 : m_bCleanedExtensionCache( false )
557 , m_bServicesRegistered( false )
558 , m_aBootstrapError( BE_OK )
560 RTL_LOGFILE_TRACE( "desktop (cd100003) ::Desktop::Desktop" );
563 Desktop::~Desktop()
565 #if ENABLE_TELEPATHY
566 TeleManager::finalize();
567 #endif
570 void Desktop::Init()
572 RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::Init" );
573 SetBootstrapStatus(BS_OK);
575 m_bCleanedExtensionCache = cleanExtensionCache();
577 // We need to have service factory before going further, but see fdo#37195.
578 // Doing this will mmap common.rdb, making it not overwritable on windows,
579 // so this can't happen before the synchronization above. Lets rework this
580 // so that the above is called *from* CreateApplicationServiceManager or
581 // something to enforce this gotcha
584 InitApplicationServiceManager();
586 catch (css::uno::Exception & e)
588 SetBootstrapError( BE_UNO_SERVICEMANAGER, e.Message );
591 if ( m_aBootstrapError == BE_OK )
593 // prepare language
594 if ( !LanguageSelection::prepareLanguage() )
596 if ( LanguageSelection::getStatus() == LanguageSelection::LS_STATUS_CANNOT_DETERMINE_LANGUAGE )
597 SetBootstrapError( BE_LANGUAGE_MISSING, OUString() );
598 else
599 SetBootstrapError( BE_OFFICECONFIG_BROKEN, OUString() );
603 if ( 1 )
605 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
607 // start ipc thread only for non-remote offices
608 RTL_LOGFILE_CONTEXT( aLog2, "desktop (cd100003) ::OfficeIPCThread::EnableOfficeIPCThread" );
609 OfficeIPCThread::Status aStatus = OfficeIPCThread::EnableOfficeIPCThread();
610 if ( aStatus == OfficeIPCThread::IPC_STATUS_PIPE_ERROR )
612 #ifdef MACOSX
613 // In a sandboxed LO, on 10.8.2 at least, creating the
614 // Unix domain socket fails. Ignore that as hopefully
615 // people running a sandboxed LO won't attempt starting it
616 // from the command-line or otherwise in tricky ways, so
617 // the normal OS X mechanism that prevents multiple
618 // instances of an app from being started should work
619 // fine. I hope.
620 #elif defined ANDROID
621 // Ignore crack pipe errors on Android, too
622 #else
623 // Keep using this oddly named BE_PATHINFO_MISSING value
624 // for pipe-related errors on other platforms. Of course
625 // this crack with two (if not more) levels of our own
626 // error codes hiding the actual system error code is
627 // broken, but that is done all over the code, let's leave
628 // re-enginering that to another year.
629 SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
630 #endif
632 else if ( aStatus == OfficeIPCThread::IPC_STATUS_BOOTSTRAP_ERROR )
634 SetBootstrapError( BE_PATHINFO_MISSING, OUString() );
636 else if ( aStatus == OfficeIPCThread::IPC_STATUS_2ND_OFFICE )
638 // 2nd office startup should terminate after sending cmdlineargs through pipe
639 SetBootstrapStatus(BS_TERMINATE);
641 else if ( !rCmdLineArgs.GetUnknown().isEmpty()
642 || rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() )
644 // disable IPC thread in an instance that is just showing a help message
645 OfficeIPCThread::DisableOfficeIPCThread();
647 pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, NULL);
651 void Desktop::InitFinished()
653 RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::InitFinished" );
655 CloseSplashScreen();
658 void Desktop::DeInit()
660 RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::DeInit" );
662 try {
663 // instead of removing of the configManager just let it commit all the changes
664 RTL_LOGFILE_CONTEXT_TRACE( aLog, "<- store config items" );
665 utl::ConfigManager::storeConfigItems();
666 FlushConfiguration();
667 RTL_LOGFILE_CONTEXT_TRACE( aLog, "<- store config items" );
669 // close splashscreen if it's still open
670 CloseSplashScreen();
671 Reference< XComponent >(
672 comphelper::getProcessComponentContext(), UNO_QUERY_THROW )->
673 dispose();
674 // nobody should get a destroyed service factory...
675 ::comphelper::setProcessServiceFactory( NULL );
677 // clear lockfile
678 m_xLockfile.reset();
680 OfficeIPCThread::DisableOfficeIPCThread();
681 if( pSignalHandler )
682 osl_removeSignalHandler( pSignalHandler );
683 } catch (const RuntimeException&) {
684 // someone threw an exception during shutdown
685 // this will leave some garbage behind..
688 RTL_LOGFILE_CONTEXT_TRACE( aLog, "FINISHED WITH Destop::DeInit" );
691 sal_Bool Desktop::QueryExit()
695 RTL_LOGFILE_CONTEXT_TRACE( aLog, "<- store config items" );
696 utl::ConfigManager::storeConfigItems();
697 RTL_LOGFILE_CONTEXT_TRACE( aLog, "<- store config items" );
699 catch ( const RuntimeException& )
703 const sal_Char SUSPEND_QUICKSTARTVETO[] = "SuspendQuickstartVeto";
705 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
706 Reference< XPropertySet > xPropertySet(xDesktop, UNO_QUERY_THROW);
707 xPropertySet->setPropertyValue( OUString(SUSPEND_QUICKSTARTVETO ), Any((sal_Bool)sal_True) );
709 sal_Bool bExit = xDesktop->terminate();
711 if ( !bExit )
713 xPropertySet->setPropertyValue( OUString(SUSPEND_QUICKSTARTVETO ), Any((sal_Bool)sal_False) );
715 else
717 FlushConfiguration();
720 // it is no problem to call DisableOfficeIPCThread() more than once
721 // it also looks to be threadsafe
722 OfficeIPCThread::DisableOfficeIPCThread();
724 catch ( const RuntimeException& )
728 m_xLockfile.reset();
732 return bExit;
735 void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus, const OUString& aDiagnosticMessage )
737 if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
739 OUString aProductKey;
740 OUString aTemp;
742 osl_getExecutableFile( &aProductKey.pData );
743 sal_uInt32 lastIndex = aProductKey.lastIndexOf('/');
744 if ( lastIndex > 0 )
745 aProductKey = aProductKey.copy( lastIndex+1 );
747 aTemp = ::utl::Bootstrap::getProductKey( aProductKey );
748 if ( !aTemp.isEmpty() )
749 aProductKey = aTemp;
751 OUString const aMessage(aDiagnosticMessage + "\n");
753 ErrorBox aBootstrapFailedBox( NULL, WB_OK, aMessage );
754 aBootstrapFailedBox.SetText( aProductKey );
755 aBootstrapFailedBox.Execute();
759 // Create a error message depending on bootstrap failure code and an optional file url
760 OUString Desktop::CreateErrorMsgString(
761 utl::Bootstrap::FailureCode nFailureCode,
762 const OUString& aFileURL )
764 OUString aMsg;
765 OUString aFilePath;
766 sal_Bool bFileInfo = sal_True;
768 switch ( nFailureCode )
770 /// the shared installation directory could not be located
771 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
773 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_PATH_INVALID,
774 OUString( "The installation path is not available." ) );
775 bFileInfo = sal_False;
777 break;
779 /// the bootstrap INI file could not be found or read
780 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
782 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING,
783 OUString( "The configuration file \"$1\" is missing." ) );
785 break;
787 /// the bootstrap INI is missing a required entry
788 /// the bootstrap INI contains invalid data
789 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
790 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
792 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_CORRUPT,
793 OUString( "The configuration file \"$1\" is corrupt." ) );
795 break;
797 /// the version locator INI file could not be found or read
798 case ::utl::Bootstrap::MISSING_VERSION_FILE:
800 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING,
801 OUString( "The configuration file \"$1\" is missing." ) );
803 break;
805 /// the version locator INI has no entry for this version
806 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
808 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_SUPPORT,
809 OUString( "The main configuration file \"$1\" does not support the current version." ) );
811 break;
813 /// the user installation directory does not exist
814 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
816 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_DIR_MISSING,
817 OUString( "The configuration directory \"$1\" is missing." ) );
819 break;
821 /// some bootstrap data was invalid in unexpected ways
822 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
824 aMsg = GetMsgString( STR_BOOTSTRAP_ERR_INTERNAL,
825 OUString( "An internal failure occurred." ) );
826 bFileInfo = sal_False;
828 break;
830 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
832 // This needs to be improved, see #i67575#:
833 aMsg = OUString(
834 "Invalid version file entry" );
835 bFileInfo = sal_False;
837 break;
839 case ::utl::Bootstrap::NO_FAILURE:
841 OSL_ASSERT(false);
843 break;
846 if ( bFileInfo )
848 String aMsgString( aMsg );
850 osl::File::getSystemPathFromFileURL( aFileURL, aFilePath );
852 aMsgString.SearchAndReplaceAscii( "$1", aFilePath );
853 aMsg = aMsgString;
856 return MakeStartupErrorMessage( aMsg );
859 void Desktop::HandleBootstrapErrors(
860 BootstrapError aBootstrapError, OUString const & aErrorMessage )
862 if ( aBootstrapError == BE_PATHINFO_MISSING )
864 OUString aErrorMsg;
865 OUString aBuffer;
866 utl::Bootstrap::Status aBootstrapStatus;
867 utl::Bootstrap::FailureCode nFailureCode;
869 aBootstrapStatus = ::utl::Bootstrap::checkBootstrapStatus( aBuffer, nFailureCode );
870 if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK )
872 switch ( nFailureCode )
874 case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY:
875 case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA:
877 aErrorMsg = CreateErrorMsgString( nFailureCode, OUString() );
879 break;
881 /// the bootstrap INI file could not be found or read
882 /// the bootstrap INI is missing a required entry
883 /// the bootstrap INI contains invalid data
884 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY:
885 case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY:
886 case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE:
888 OUString aBootstrapFileURL;
890 utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL );
891 aErrorMsg = CreateErrorMsgString( nFailureCode, aBootstrapFileURL );
893 break;
895 /// the version locator INI file could not be found or read
896 /// the version locator INI has no entry for this version
897 /// the version locator INI entry is not a valid directory URL
898 case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY:
899 case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY:
900 case ::utl::Bootstrap::MISSING_VERSION_FILE:
902 OUString aVersionFileURL;
904 utl::Bootstrap::locateVersionFile( aVersionFileURL );
905 aErrorMsg = CreateErrorMsgString( nFailureCode, aVersionFileURL );
907 break;
909 /// the user installation directory does not exist
910 case ::utl::Bootstrap::MISSING_USER_DIRECTORY:
912 OUString aUserInstallationURL;
914 utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
915 aErrorMsg = CreateErrorMsgString( nFailureCode, aUserInstallationURL );
917 break;
919 case ::utl::Bootstrap::NO_FAILURE:
921 OSL_ASSERT(false);
923 break;
926 HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg );
929 else if ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING )
931 // Uno service manager is not available. VCL needs a uno service manager to display a message box!!!
932 // Currently we are not able to display a message box with a service manager due to this limitations inside VCL.
934 // When UNO is not properly initialized, all kinds of things can fail
935 // and cause the process to crash (e.g., a call to GetMsgString may
936 // crash when somewhere deep within that call Any::operator <= is used
937 // with a PropertyValue, and no binary UNO type description for
938 // PropertyValue is available). To give the user a hint even if
939 // generating and displaying a message box below crashes, print a
940 // hard-coded message on stderr first:
941 std::cerr
942 << "The application cannot be started.\n"
943 // STR_BOOTSTRAP_ERR_CANNOT_START
944 << (aBootstrapError == BE_UNO_SERVICEMANAGER
945 ? "The component manager is not available.\n"
946 // STR_BOOTSTRAP_ERR_NO_SERVICE
947 : "The configuration service is not available.\n");
948 // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE
949 if ( !aErrorMessage.isEmpty() )
951 std::cerr << "(\"" << aErrorMessage << "\")\n";
954 // First sentence. We cannot bootstrap office further!
955 OUString aMessage;
956 OUStringBuffer aDiagnosticMessage( 100 );
958 OUString aErrorMsg;
960 if ( aBootstrapError == BE_UNO_SERVICEMANAGER )
961 aErrorMsg = "The service manager is not available.";
962 else
963 aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_CFG_SERVICE,
964 OUString( "The configuration service is not available." ) );
966 aDiagnosticMessage.append( aErrorMsg );
967 aDiagnosticMessage.appendAscii( "\n" );
968 if ( !aErrorMessage.isEmpty() )
970 aDiagnosticMessage.appendAscii( "(\"" );
971 aDiagnosticMessage.append( aErrorMessage );
972 aDiagnosticMessage.appendAscii( "\")\n" );
975 // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to
976 // repair the installation with the setup executable besides the office executable. Now
977 // we have to ask the user to start the setup on CD/installation directory manually!!
978 OUString aStartSetupManually( GetMsgString(
979 STR_ASK_START_SETUP_MANUALLY,
980 OUString( "Start setup application to repair the installation from CD, or the folder containing the installation packages." ),
981 aBootstrapError == BE_UNO_SERVICEMANAGER ) );
983 aDiagnosticMessage.append( aStartSetupManually );
984 aMessage = MakeStartupErrorMessage(
985 aDiagnosticMessage.makeStringAndClear(),
986 aBootstrapError == BE_UNO_SERVICEMANAGER );
988 FatalError( aMessage);
990 else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
992 OUString aMessage;
993 OUStringBuffer aDiagnosticMessage( 100 );
994 OUString aErrorMsg;
995 aErrorMsg = GetMsgString( STR_CONFIG_ERR_ACCESS_GENERAL,
996 OUString( "A general error occurred while accessing your central configuration." ) );
997 aDiagnosticMessage.append( aErrorMsg );
998 aMessage = MakeStartupErrorMessage( aDiagnosticMessage.makeStringAndClear() );
999 FatalError(aMessage);
1001 else if ( aBootstrapError == BE_USERINSTALL_FAILED )
1003 OUString aMessage;
1004 OUStringBuffer aDiagnosticMessage( 100 );
1005 OUString aErrorMsg;
1006 aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_USERINSTALL_FAILED,
1007 OUString( "User installation could not be completed" ) );
1008 aDiagnosticMessage.append( aErrorMsg );
1009 aMessage = MakeStartupErrorMessage( aDiagnosticMessage.makeStringAndClear() );
1010 FatalError(aMessage);
1012 else if ( aBootstrapError == BE_LANGUAGE_MISSING )
1014 OUString aMessage;
1015 OUStringBuffer aDiagnosticMessage( 100 );
1016 OUString aErrorMsg;
1017 aErrorMsg = GetMsgString(
1018 //@@@ FIXME: should use an own resource string => #i36213#
1019 STR_BOOTSTRAP_ERR_LANGUAGE_MISSING,
1020 OUString( "Language could not be determined." ) );
1021 aDiagnosticMessage.append( aErrorMsg );
1022 aMessage = MakeStartupErrorMessage(
1023 aDiagnosticMessage.makeStringAndClear() );
1024 FatalError(aMessage);
1026 else if (( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) ||
1027 ( aBootstrapError == BE_USERINSTALL_NOWRITEACCESS ))
1029 OUString aUserInstallationURL;
1030 OUString aUserInstallationPath;
1031 OUString aMessage;
1032 OUString aErrorMsg;
1033 OUStringBuffer aDiagnosticMessage( 100 );
1035 utl::Bootstrap::locateUserInstallation( aUserInstallationURL );
1037 if ( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE )
1038 aErrorMsg = GetMsgString(
1039 STR_BOOSTRAP_ERR_NOTENOUGHDISKSPACE,
1040 OUString( "User installation could not be completed due to insufficient free disk space." ) );
1041 else
1042 aErrorMsg = GetMsgString(
1043 STR_BOOSTRAP_ERR_NOACCESSRIGHTS,
1044 OUString( "User installation could not be processed due to missing access rights." ) );
1046 osl::File::getSystemPathFromFileURL( aUserInstallationURL, aUserInstallationPath );
1048 aDiagnosticMessage.append( aErrorMsg );
1049 aDiagnosticMessage.append( aUserInstallationPath );
1050 aMessage = MakeStartupErrorMessage(
1051 aDiagnosticMessage.makeStringAndClear() );
1052 FatalError(aMessage);
1055 return;
1059 void Desktop::retrieveCrashReporterState()
1061 _bCrashReporterEnabled
1062 = officecfg::Office::Recovery::CrashReporter::Enabled::get();
1065 sal_Bool Desktop::isUIOnSessionShutdownAllowed()
1067 return officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled
1068 ::get();
1071 //-----------------------------------------------
1072 /** @short check if crash reporter feature is enabled or
1073 disabled.
1075 sal_Bool Desktop::isCrashReporterEnabled()
1077 return _bCrashReporterEnabled;
1080 //-----------------------------------------------
1081 /** @short check if recovery must be started or not.
1083 @param bCrashed [boolean ... out!]
1084 the office crashed last times.
1085 But may be there are no recovery data.
1086 Useful to trigger the error report tool without
1087 showing the recovery UI.
1089 @param bRecoveryDataExists [boolean ... out!]
1090 there exists some recovery data.
1092 @param bSessionDataExists [boolean ... out!]
1093 there exists some session data.
1094 Because the user may be logged out last time from it's
1095 unix session...
1097 void impl_checkRecoveryState(sal_Bool& bCrashed ,
1098 sal_Bool& bRecoveryDataExists,
1099 sal_Bool& bSessionDataExists )
1101 bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get();
1102 bool elements = officecfg::Office::Recovery::RecoveryList::get()->
1103 hasElements();
1104 bool session
1105 = officecfg::Office::Recovery::RecoveryInfo::SessionData::get();
1106 bRecoveryDataExists = elements && !session;
1107 bSessionDataExists = elements && session;
1110 //-----------------------------------------------
1111 /* @short start the recovery wizard.
1113 @param bEmergencySave
1114 differs between EMERGENCY_SAVE and RECOVERY
1116 sal_Bool impl_callRecoveryUI(sal_Bool bEmergencySave ,
1117 sal_Bool bCrashed ,
1118 sal_Bool bExistsRecoveryData)
1120 static OUString SERVICENAME_RECOVERYUI("com.sun.star.comp.svx.RecoveryUI");
1121 static OUString COMMAND_EMERGENCYSAVE("vnd.sun.star.autorecovery:/doEmergencySave");
1122 static OUString COMMAND_RECOVERY("vnd.sun.star.autorecovery:/doAutoRecovery");
1123 static OUString COMMAND_CRASHREPORT("vnd.sun.star.autorecovery:/doCrashReport");
1125 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1127 Reference< css::frame::XSynchronousDispatch > xRecoveryUI(
1128 xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_RECOVERYUI, xContext),
1129 css::uno::UNO_QUERY_THROW);
1131 Reference< css::util::XURLTransformer > xURLParser =
1132 css::util::URLTransformer::create(::comphelper::getProcessComponentContext());
1134 css::util::URL aURL;
1135 if (bEmergencySave)
1136 aURL.Complete = COMMAND_EMERGENCYSAVE;
1137 else if (bExistsRecoveryData)
1138 aURL.Complete = COMMAND_RECOVERY;
1139 else if (bCrashed && Desktop::isCrashReporterEnabled() )
1140 aURL.Complete = COMMAND_CRASHREPORT;
1141 else
1142 return false;
1144 xURLParser->parseStrict(aURL);
1146 css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >());
1147 sal_Bool bRet = sal_False;
1148 aRet >>= bRet;
1149 return !bEmergencySave || bRet;
1153 * Save all open documents so they will be reopened
1154 * the next time the application ist started
1156 * returns sal_True if at least one document could be saved...
1160 sal_Bool Desktop::SaveTasks()
1162 return impl_callRecoveryUI(
1163 sal_True , // sal_True => force emergency save
1164 sal_False, // 2. and 3. param not used if 1. = true!
1165 sal_False);
1168 namespace {
1170 void restartOnMac(bool passArguments) {
1171 #if defined MACOSX
1172 OfficeIPCThread::DisableOfficeIPCThread();
1173 #ifdef ENABLE_MACOSX_SANDBOX
1174 (void) passArguments; // avoid warnings
1175 ResMgr *resMgr = Desktop::GetDesktopResManager();
1176 OUString aMessage = OUString( String( ResId( STR_LO_MUST_BE_RESTARTED, *resMgr )));
1178 ErrorBox aRestartBox( NULL, WB_OK, aMessage );
1179 aRestartBox.Execute();
1180 #else
1181 OUString execUrl;
1182 OSL_VERIFY(osl_getExecutableFile(&execUrl.pData) == osl_Process_E_None);
1183 OUString execPath;
1184 OString execPath8;
1185 if ((osl::FileBase::getSystemPathFromFileURL(execUrl, execPath)
1186 != osl::FileBase::E_None) ||
1187 !execPath.convertToString(
1188 &execPath8, osl_getThreadTextEncoding(),
1189 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1190 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1192 std::abort();
1194 std::vector< OString > args;
1195 args.push_back(execPath8);
1196 bool wait = false;
1197 if (passArguments) {
1198 sal_uInt32 n = osl_getCommandArgCount();
1199 for (sal_uInt32 i = 0; i < n; ++i) {
1200 OUString arg;
1201 OSL_VERIFY(osl_getCommandArg(i, &arg.pData) == osl_Process_E_None);
1202 if (arg.match("--accept=")) {
1203 wait = true;
1205 OString arg8;
1206 if (!arg.convertToString(
1207 &arg8, osl_getThreadTextEncoding(),
1208 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1209 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1211 std::abort();
1213 args.push_back(arg8);
1216 std::vector< char const * > argPtrs;
1217 for (std::vector< OString >::iterator i(args.begin()); i != args.end();
1218 ++i)
1220 argPtrs.push_back(i->getStr());
1222 argPtrs.push_back(0);
1223 execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0]));
1224 if (errno == ENOTSUP) { // happens when multithreaded on OS X < 10.6
1225 pid_t pid = fork();
1226 if (pid == 0) {
1227 execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0]));
1228 } else if (pid > 0) {
1229 // Two simultaneously running soffice processes lead to two dock
1230 // icons, so avoid waiting here unless it must be assumed that the
1231 // process invoking soffice itself wants to wait for soffice to
1232 // finish:
1233 if (!wait) {
1234 return;
1236 int stat;
1237 if (waitpid(pid, &stat, 0) == pid && WIFEXITED(stat)) {
1238 _exit(WEXITSTATUS(stat));
1242 std::abort();
1243 #endif
1244 #else
1245 (void) passArguments; // avoid warnings
1246 #endif
1251 sal_uInt16 Desktop::Exception(sal_uInt16 nError)
1253 // protect against recursive calls
1254 static sal_Bool bInException = sal_False;
1256 sal_uInt16 nOldMode = Application::GetSystemWindowMode();
1257 Application::SetSystemWindowMode( nOldMode & ~SYSTEMWINDOW_MODE_NOAUTOMODE );
1258 Application::SetDefDialogParent( NULL );
1260 if ( bInException )
1262 String aDoubleExceptionString;
1263 Application::Abort( aDoubleExceptionString );
1266 bInException = sal_True;
1267 const CommandLineArgs& rArgs = GetCommandLineArgs();
1269 // save all modified documents ... if it's allowed doing so.
1270 sal_Bool bRestart = sal_False;
1271 sal_Bool bAllowRecoveryAndSessionManagement = (
1272 ( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery
1273 ( !rArgs.IsHeadless() ) &&
1274 (( nError & EXC_MAJORTYPE ) != EXC_DISPLAY ) && // recovery cant work without UI ... but UI layer seams to be the reason for this crash
1275 ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicates a corrupt installation ...)
1277 if ( bAllowRecoveryAndSessionManagement )
1278 bRestart = SaveTasks();
1280 FlushConfiguration();
1282 switch( nError & EXC_MAJORTYPE )
1284 case EXC_RSCNOTLOADED:
1286 String aResExceptionString;
1287 Application::Abort( aResExceptionString );
1288 break;
1291 case EXC_SYSOBJNOTCREATED:
1293 String aSysResExceptionString;
1294 Application::Abort( aSysResExceptionString );
1295 break;
1298 default:
1300 m_xLockfile.reset();
1302 if( bRestart )
1304 OfficeIPCThread::DisableOfficeIPCThread();
1305 if( pSignalHandler )
1306 osl_removeSignalHandler( pSignalHandler );
1308 restartOnMac(false);
1309 if ( m_rSplashScreen.is() )
1310 m_rSplashScreen->reset();
1312 _exit( EXITHELPER_CRASH_WITH_RESTART );
1314 else
1316 Application::Abort( String() );
1319 break;
1323 OSL_ASSERT(false); // unreachable
1324 return 0;
1327 void Desktop::AppEvent( const ApplicationEvent& rAppEvent )
1329 HandleAppEvent( rAppEvent );
1332 namespace {
1333 void SetDocumentExtendedStyle( const Reference< ::com::sun::star::awt::XWindow > &xContainerWindow )
1335 // set the WB_EXT_DOCUMENT style. Normally, this is done by the TaskCreator service when a "_blank"
1336 // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior,
1337 // otherwise documents loaded into this frame will later on miss functionality depending on the style.
1338 Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow );
1339 OSL_ENSURE( pContainerWindow, "Desktop::Main: no implementation access to the frame's container window!" );
1340 if (!pContainerWindow) {
1341 fprintf (stderr, "Error: It very much looks as if you have used 'linkoo' (or bin/ooinstall -l)\n"
1342 "but have then forgotten to source 'ooenv' into your shell before running !\n"
1343 "to save a crash, we will exit now with an error - please '. ./ooenv' first.\n");
1344 exit (1);
1346 pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WB_EXT_DOCUMENT );
1350 struct ExecuteGlobals
1352 Reference < css::document::XEventListener > xGlobalBroadcaster;
1353 sal_Bool bRestartRequested;
1354 sal_Bool bUseSystemFileDialog;
1355 std::auto_ptr<SvtLanguageOptions> pLanguageOptions;
1356 std::auto_ptr<SvtPathOptions> pPathOptions;
1358 ExecuteGlobals()
1359 : bRestartRequested( sal_False )
1360 , bUseSystemFileDialog( sal_True )
1364 static ExecuteGlobals* pExecGlobals = NULL;
1366 int Desktop::Main()
1368 pExecGlobals = new ExecuteGlobals();
1370 RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::Main" );
1372 // Remember current context object
1373 com::sun::star::uno::ContextLayer layer(
1374 com::sun::star::uno::getCurrentContext() );
1376 if ( m_aBootstrapError != BE_OK )
1378 HandleBootstrapErrors( m_aBootstrapError, m_aBootstrapErrorMessage );
1379 return EXIT_FAILURE;
1382 BootstrapStatus eStatus = GetBootstrapStatus();
1383 if (eStatus == BS_TERMINATE) {
1384 return EXIT_SUCCESS;
1387 // Detect desktop environment - need to do this as early as possible
1388 com::sun::star::uno::setCurrentContext(
1389 new DesktopContext( com::sun::star::uno::getCurrentContext() ) );
1391 CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
1393 #if HAVE_FEATURE_DESKTOP
1394 OUString aUnknown( rCmdLineArgs.GetUnknown() );
1395 if ( !aUnknown.isEmpty() )
1397 displayCmdlineHelp( aUnknown );
1398 return EXIT_FAILURE;
1400 if ( rCmdLineArgs.IsHelp() )
1402 displayCmdlineHelp( OUString() );
1403 return EXIT_SUCCESS;
1405 if ( rCmdLineArgs.IsVersion() )
1407 displayVersion();
1408 return EXIT_SUCCESS;
1410 #endif
1411 // setup configuration error handling
1412 ConfigurationErrorHandler aConfigErrHandler;
1413 if (!ShouldSuppressUI(rCmdLineArgs))
1414 aConfigErrHandler.activate();
1416 ResMgr::SetReadStringHook( ReplaceStringHookProc );
1418 // Startup screen
1419 RTL_LOGFILE_CONTEXT_TRACE( aLog, "desktop (lo119109) Desktop::Main { OpenSplashScreen" );
1420 OpenSplashScreen();
1421 RTL_LOGFILE_CONTEXT_TRACE( aLog, "desktop (lo119109) Desktop::Main } OpenSplashScreen" );
1423 SetSplashScreenProgress(10);
1425 UserInstall::UserInstallStatus inst_fin = UserInstall::finalize();
1426 if (inst_fin != UserInstall::Ok && inst_fin != UserInstall::Created)
1428 OSL_FAIL("userinstall failed");
1429 if ( inst_fin == UserInstall::E_NoDiskSpace )
1430 HandleBootstrapErrors(
1431 BE_USERINSTALL_NOTENOUGHDISKSPACE, OUString() );
1432 else if ( inst_fin == UserInstall::E_NoWriteAccess )
1433 HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS, OUString() );
1434 else
1435 HandleBootstrapErrors( BE_USERINSTALL_FAILED, OUString() );
1436 return EXIT_FAILURE;
1438 // refresh path information
1439 utl::Bootstrap::reloadData();
1440 SetSplashScreenProgress(20);
1442 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
1444 Reference< XRestartManager > xRestartManager( OfficeRestartManager::get(xContext) );
1446 Reference< XDesktop2 > xDesktop;
1449 RegisterServices(xContext);
1451 SetSplashScreenProgress(25);
1453 // check user installation directory for lockfile so we can be sure
1454 // there is no other instance using our data files from a remote host
1455 RTL_LOGFILE_CONTEXT_TRACE( aLog, "desktop (lo119109) Desktop::Main -> Lockfile" );
1456 m_xLockfile.reset(new Lockfile);
1458 #if HAVE_FEATURE_DESKTOP
1459 if ( !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsInvisible() &&
1460 !rCmdLineArgs.IsNoLockcheck() && !m_xLockfile->check( Lockfile_execWarning ))
1462 // Lockfile exists, and user clicked 'no'
1463 return EXIT_FAILURE;
1465 RTL_LOGFILE_CONTEXT_TRACE( aLog, "desktop (lo119109) Desktop::Main <- Lockfile" );
1467 // check if accessibility is enabled but not working and allow to quit
1468 RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ GetEnableATToolSupport" );
1469 if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() )
1471 bool bQuitApp;
1473 if( !InitAccessBridge( true, bQuitApp ) )
1474 if( bQuitApp )
1475 return EXIT_FAILURE;
1477 RTL_LOGFILE_CONTEXT_TRACE( aLog, "} GetEnableATToolSupport" );
1478 #endif
1480 // terminate if requested...
1481 if( rCmdLineArgs.IsTerminateAfterInit() )
1482 return EXIT_SUCCESS;
1484 // Read the common configuration items for optimization purpose
1485 if ( !InitializeConfiguration() )
1486 return EXIT_FAILURE;
1488 SetSplashScreenProgress(30);
1490 // set static variable to enabled/disable crash reporter
1491 retrieveCrashReporterState();
1492 if ( !isCrashReporterEnabled() )
1494 osl_setErrorReporting( sal_False );
1495 // disable stack trace feature
1498 // create title string
1499 LanguageTag aLocale( LANGUAGE_SYSTEM);
1500 ResMgr* pLabelResMgr = ResMgr::SearchCreateResMgr( "ofa", aLocale );
1501 String aTitle = pLabelResMgr ? String( ResId( RID_APPTITLE, *pLabelResMgr ) ) : String();
1502 delete pLabelResMgr;
1504 #ifdef DBG_UTIL
1505 //include buildid in non product builds
1506 OUString aDefault("development");
1507 aTitle += OUString(" [");
1508 String aVerId( utl::Bootstrap::getBuildIdData(aDefault));
1509 aTitle += aVerId;
1510 aTitle += ']';
1511 #endif
1513 SetDisplayName( aTitle );
1514 SetSplashScreenProgress(35);
1515 RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ create SvtPathOptions and SvtLanguageOptions" );
1516 pExecGlobals->pPathOptions.reset( new SvtPathOptions);
1517 SetSplashScreenProgress(40);
1518 RTL_LOGFILE_CONTEXT_TRACE( aLog, "} create SvtPathOptions and SvtLanguageOptions" );
1520 xDesktop = css::frame::Desktop::create( xContext );
1522 // create service for loadin SFX (still needed in startup)
1523 pExecGlobals->xGlobalBroadcaster = Reference < css::document::XEventListener >
1524 ( css::frame::GlobalEventBroadcaster::create(xContext), UNO_QUERY_THROW );
1526 /* ensure existance of a default window that messages can be dispatched to
1527 This is for the benefit of testtool which uses PostUserEvent extensively
1528 and else can deadlock while creating this window from another tread while
1529 the main thread is not yet in the event loop.
1531 Application::GetDefaultDevice();
1533 #if HAVE_FEATURE_EXTENSIONS
1534 // Check if bundled or shared extensions were added /removed
1535 // and process those extensions (has to be done before checking
1536 // the extension dependencies!
1537 SynchronizeExtensionRepositories();
1538 bool bAbort = CheckExtensionDependencies();
1539 if ( bAbort )
1540 return EXIT_FAILURE;
1542 if (inst_fin == UserInstall::Created)
1544 Migration::migrateSettingsIfNecessary();
1546 #endif
1548 // keep a language options instance...
1549 pExecGlobals->pLanguageOptions.reset( new SvtLanguageOptions(sal_True));
1551 css::document::EventObject aEvent;
1552 aEvent.EventName = OUString("OnStartApp");
1553 pExecGlobals->xGlobalBroadcaster->notifyEvent(aEvent);
1555 SetSplashScreenProgress(50);
1557 // Backing Component
1558 sal_Bool bCrashed = sal_False;
1559 sal_Bool bExistsRecoveryData = sal_False;
1560 sal_Bool bExistsSessionData = sal_False;
1562 RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ impl_checkRecoveryState" );
1563 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData);
1564 RTL_LOGFILE_CONTEXT_TRACE( aLog, "} impl_checkRecoveryState" );
1566 OUString pidfileName = rCmdLineArgs.GetPidfileName();
1567 if ( !pidfileName.isEmpty() )
1569 OUString pidfileURL;
1571 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None )
1573 osl::File pidfile( pidfileURL );
1574 osl::FileBase::RC rc;
1576 osl::File::remove( pidfileURL );
1577 if ( (rc = pidfile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ) ) == osl::File::E_None )
1579 OString pid( OString::valueOf( static_cast<sal_Int32>( GETPID() ) ) );
1580 sal_uInt64 written = 0;
1581 if ( pidfile.write(pid.getStr(), pid.getLength(), written) != osl::File::E_None )
1583 SAL_WARN("desktop", "cannot write pidfile " << pidfile.getURL());
1585 pidfile.close();
1587 else
1589 SAL_WARN("desktop", "cannot open pidfile " << pidfile.getURL() << osl::FileBase::RC(rc));
1592 else
1594 SAL_WARN("desktop", "cannot get pidfile URL from path" << pidfileName);
1598 if ( rCmdLineArgs.IsHeadless() )
1600 // Ensure that we use not the system file dialogs as
1601 // headless mode relies on Application::EnableHeadlessMode()
1602 // which does only work for VCL dialogs!!
1603 SvtMiscOptions aMiscOptions;
1604 pExecGlobals->bUseSystemFileDialog = aMiscOptions.UseSystemFileDialog();
1605 aMiscOptions.SetUseSystemFileDialog( sal_False );
1608 pExecGlobals->bRestartRequested = xRestartManager->isRestartRequested(
1609 true);
1610 if ( !pExecGlobals->bRestartRequested )
1612 if ((!rCmdLineArgs.WantsToLoadDocument() && !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsQuickstart()) &&
1613 (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE)) &&
1614 (!bExistsRecoveryData ) &&
1615 (!bExistsSessionData ) &&
1616 (!Application::AnyInput( VCL_INPUT_APPEVENT ) ))
1618 RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ create BackingComponent" );
1619 ShowBackingComponent(this);
1620 RTL_LOGFILE_CONTEXT_TRACE( aLog, "} create BackingComponent" );
1624 catch ( const com::sun::star::lang::WrappedTargetException& wte )
1626 com::sun::star::uno::Exception te;
1627 wte.TargetException >>= te;
1628 FatalError( MakeStartupConfigAccessErrorMessage(wte.Message + te.Message) );
1629 return EXIT_FAILURE;
1631 catch ( const com::sun::star::uno::Exception& e )
1633 FatalError( MakeStartupErrorMessage(e.Message) );
1634 return EXIT_FAILURE;
1636 SetSplashScreenProgress(55);
1638 SvtFontSubstConfig().Apply();
1640 SvtTabAppearanceCfg aAppearanceCfg;
1641 aAppearanceCfg.SetInitialized();
1642 aAppearanceCfg.SetApplicationDefaults( this );
1643 SvtAccessibilityOptions aOptions;
1644 aOptions.SetVCLSettings();
1645 SetSplashScreenProgress(60);
1647 #if ENABLE_TELEPATHY
1648 bool bListen = rCmdLineArgs.IsInvisible();
1649 TeleManager::init( bListen );
1650 #endif
1652 if ( !pExecGlobals->bRestartRequested )
1654 Application::SetFilterHdl( LINK( this, Desktop, ImplInitFilterHdl ) );
1655 sal_Bool bTerminateRequested = sal_False;
1657 // Preload function depends on an initialized sfx application!
1658 SetSplashScreenProgress(75);
1660 // use system window dialogs
1661 Application::SetSystemWindowMode( SYSTEMWINDOW_MODE_DIALOG );
1663 SetSplashScreenProgress(80);
1665 if ( !bTerminateRequested && !rCmdLineArgs.IsInvisible() &&
1666 !rCmdLineArgs.IsNoQuickstart() )
1667 InitializeQuickstartMode( xContext );
1669 RTL_LOGFILE_CONTEXT( aLog2, "desktop (cd100003) createInstance com.sun.star.frame.Desktop" );
1672 if ( xDesktop.is() )
1673 xDesktop->addTerminateListener( new OfficeIPCThreadController );
1674 SetSplashScreenProgress(100);
1676 catch ( const com::sun::star::uno::Exception& e )
1678 FatalError( MakeStartupErrorMessage(e.Message) );
1679 return EXIT_FAILURE;
1682 // Release solar mutex just before we wait for our client to connect
1683 int nAcquireCount = Application::ReleaseSolarMutex();
1685 // Post user event to startup first application component window
1686 // We have to send this OpenClients message short before execute() to
1687 // minimize the risk that this message overtakes type detection contruction!!
1688 Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) );
1690 // Post event to enable acceptors
1691 Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) );
1693 // The configuration error handler currently is only for startup
1694 aConfigErrHandler.deactivate();
1696 // Acquire solar mutex just before we enter our message loop
1697 if ( nAcquireCount )
1698 Application::AcquireSolarMutex( nAcquireCount );
1700 // call Application::Execute to process messages in vcl message loop
1701 RTL_LOGFILE_PRODUCT_TRACE( "PERFORMANCE - enter Application::Execute()" );
1705 #ifdef SOLAR_JAVA
1706 // The JavaContext contains an interaction handler which is used when
1707 // the creation of a Java Virtual Machine fails
1708 com::sun::star::uno::ContextLayer layer2(
1709 new svt::JavaContext( com::sun::star::uno::getCurrentContext() ) );
1710 #endif
1711 // check whether the shutdown is caused by restart just before entering the Execute
1712 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
1713 xRestartManager->isRestartRequested(true);
1715 if ( !pExecGlobals->bRestartRequested )
1717 // if this run of the office is triggered by restart, some additional actions should be done
1718 DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() );
1720 Execute();
1723 catch(const com::sun::star::document::CorruptedFilterConfigurationException& exFilterCfg)
1725 OfficeIPCThread::SetDowning();
1726 FatalError( MakeStartupErrorMessage(exFilterCfg.Message) );
1728 catch(const com::sun::star::configuration::CorruptedConfigurationException& exAnyCfg)
1730 OfficeIPCThread::SetDowning();
1731 FatalError( MakeStartupErrorMessage(exAnyCfg.Message) );
1734 else
1736 if (xDesktop.is())
1737 xDesktop->terminate();
1739 // CAUTION: you do not necessarily get here e.g. on the Mac.
1740 // please put all deinitialization code into doShutdown
1741 return doShutdown();
1744 int Desktop::doShutdown()
1746 if( ! pExecGlobals )
1747 return EXIT_SUCCESS;
1749 pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested ||
1750 OfficeRestartManager::get(comphelper::getProcessComponentContext())->
1751 isRestartRequested(true);
1752 if ( pExecGlobals->bRestartRequested )
1753 SetRestartState();
1755 if (pExecGlobals->xGlobalBroadcaster.is())
1757 css::document::EventObject aEvent;
1758 aEvent.EventName = OUString("OnCloseApp");
1759 pExecGlobals->xGlobalBroadcaster->notifyEvent(aEvent);
1762 delete pResMgr, pResMgr = NULL;
1763 // Restore old value
1764 const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs();
1765 if ( rCmdLineArgs.IsHeadless() )
1766 SvtMiscOptions().SetUseSystemFileDialog( pExecGlobals->bUseSystemFileDialog );
1768 OUString pidfileName = rCmdLineArgs.GetPidfileName();
1769 if ( !pidfileName.isEmpty() )
1771 OUString pidfileURL;
1773 if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None )
1775 if ( osl::File::remove( pidfileURL ) != osl::FileBase::E_None )
1777 SAL_WARN("desktop", "shutdown: cannot remove pidfile " << pidfileURL);
1780 else
1782 SAL_WARN("desktop", "shutdown: cannot get pidfile URL from path" << pidfileName);
1786 // remove temp directory
1787 RemoveTemporaryDirectory();
1788 FlushConfiguration();
1789 // The acceptors in the AcceptorMap must be released (in DeregisterServices)
1790 // with the solar mutex unlocked, to avoid deadlock:
1791 sal_uLong nAcquireCount = Application::ReleaseSolarMutex();
1792 DeregisterServices();
1793 Application::AcquireSolarMutex(nAcquireCount);
1794 // be sure that path/language options gets destroyed before
1795 // UCB is deinitialized
1796 RTL_LOGFILE_CONTEXT_TRACE( aLog, "-> dispose path/language options" );
1797 pExecGlobals->pLanguageOptions.reset( 0 );
1798 pExecGlobals->pPathOptions.reset( 0 );
1799 RTL_LOGFILE_CONTEXT_TRACE( aLog, "<- dispose path/language options" );
1801 sal_Bool bRR = pExecGlobals->bRestartRequested;
1802 delete pExecGlobals, pExecGlobals = NULL;
1804 RTL_LOGFILE_CONTEXT_TRACE( aLog, "FINISHED WITH Destop::Main" );
1805 if ( bRR )
1807 restartOnMac(true);
1808 if ( m_rSplashScreen.is() )
1809 m_rSplashScreen->reset();
1811 return EXITHELPER_NORMAL_RESTART;
1813 return EXIT_SUCCESS;
1816 IMPL_LINK( Desktop, ImplInitFilterHdl, ConvertData*, pData )
1818 return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( pData );
1821 bool Desktop::InitializeConfiguration()
1823 RTL_LOGFILE_CONTEXT( aLog, "desktop (jb99855) ::InitConfiguration" );
1826 css::configuration::theDefaultProvider::get(
1827 comphelper::getProcessComponentContext() );
1828 return true;
1830 catch( ::com::sun::star::lang::ServiceNotRegisteredException & e )
1832 this->HandleBootstrapErrors(
1833 Desktop::BE_UNO_SERVICE_CONFIG_MISSING, e.Message );
1835 catch( const ::com::sun::star::configuration::MissingBootstrapFileException& e )
1837 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE,
1838 e.BootstrapFileURL ));
1839 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL, aMsg );
1841 catch( const ::com::sun::star::configuration::InvalidBootstrapFileException& e )
1843 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY,
1844 e.BootstrapFileURL ));
1845 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1847 catch( const ::com::sun::star::configuration::InstallationIncompleteException& )
1849 OUString aVersionFileURL;
1850 OUString aMsg;
1851 utl::Bootstrap::PathStatus aPathStatus = utl::Bootstrap::locateVersionFile( aVersionFileURL );
1852 if ( aPathStatus == utl::Bootstrap::PATH_EXISTS )
1853 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY, aVersionFileURL );
1854 else
1855 aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE, aVersionFileURL );
1857 HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL, aMsg );
1859 catch ( const com::sun::star::configuration::backend::BackendAccessException& exception)
1861 // [cm122549] It is assumed in this case that the message
1862 // coming from InitConfiguration (in fact CreateApplicationConf...)
1863 // is suitable for display directly.
1864 FatalError( MakeStartupErrorMessage( exception.Message ) );
1866 catch ( const com::sun::star::configuration::backend::BackendSetupException& exception)
1868 // [cm122549] It is assumed in this case that the message
1869 // coming from InitConfiguration (in fact CreateApplicationConf...)
1870 // is suitable for display directly.
1871 FatalError( MakeStartupErrorMessage( exception.Message ) );
1873 catch ( const ::com::sun::star::configuration::CannotLoadConfigurationException& )
1875 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA,
1876 OUString() ));
1877 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1879 catch( const ::com::sun::star::uno::Exception& )
1881 OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA,
1882 OUString() ));
1883 HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg );
1885 return false;
1888 void Desktop::FlushConfiguration()
1890 css::uno::Reference< css::util::XFlushable >(
1891 css::configuration::theDefaultProvider::get(
1892 comphelper::getProcessComponentContext()),
1893 css::uno::UNO_QUERY_THROW)->flush();
1896 sal_Bool Desktop::shouldLaunchQuickstart()
1898 sal_Bool bQuickstart = GetCommandLineArgs().IsQuickstart();
1899 if (!bQuickstart)
1901 const SfxPoolItem* pItem=0;
1902 SfxItemSet aQLSet(SFX_APP()->GetPool(), SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER);
1903 SFX_APP()->GetOptions(aQLSet);
1904 SfxItemState eState = aQLSet.GetItemState(SID_ATTR_QUICKLAUNCHER, sal_False, &pItem);
1905 if (SFX_ITEM_SET == eState)
1906 bQuickstart = ((SfxBoolItem*)pItem)->GetValue();
1908 return bQuickstart;
1912 sal_Bool Desktop::InitializeQuickstartMode( const Reference< XComponentContext >& rxContext )
1916 // the shutdown icon sits in the systray and allows the user to keep
1917 // the office instance running for quicker restart
1918 // this will only be activated if --quickstart was specified on cmdline
1919 RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) createInstance com.sun.star.office.Quickstart" );
1921 sal_Bool bQuickstart = shouldLaunchQuickstart();
1923 // Try to instantiate quickstart service. This service is not mandatory, so
1924 // do nothing if service is not available
1926 // #i105753# the following if was invented for performance
1927 // unfortunately this broke the Mac behavior which is to always run
1928 // in quickstart mode since Mac applications do not usually quit
1929 // when the last document closes
1930 #ifndef MACOSX
1931 if ( bQuickstart )
1932 #endif
1934 Sequence< Any > aSeq( 1 );
1935 aSeq[0] <<= bQuickstart;
1936 Reference < XComponent > xQuickstart(
1937 rxContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.office.Quickstart", aSeq, rxContext),
1938 UNO_QUERY );
1940 return sal_True;
1942 catch( const ::com::sun::star::uno::Exception& )
1944 return sal_False;
1948 void Desktop::SystemSettingsChanging( AllSettings& rSettings, Window* )
1950 if ( !SvtTabAppearanceCfg::IsInitialized () )
1951 return;
1953 # define DRAGFULL_OPTION_ALL \
1954 ( DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE \
1955 | DRAGFULL_OPTION_OBJECTMOVE | DRAGFULL_OPTION_OBJECTSIZE \
1956 | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT \
1957 | DRAGFULL_OPTION_SCROLL )
1958 # define DRAGFULL_OPTION_NONE ((sal_uInt32)~DRAGFULL_OPTION_ALL)
1960 StyleSettings hStyleSettings = rSettings.GetStyleSettings();
1961 MouseSettings hMouseSettings = rSettings.GetMouseSettings();
1963 sal_uInt32 nDragFullOptions = hStyleSettings.GetDragFullOptions();
1965 SvtTabAppearanceCfg aAppearanceCfg;
1966 sal_uInt16 nGet = aAppearanceCfg.GetDragMode();
1967 switch ( nGet )
1969 case DragFullWindow:
1970 nDragFullOptions |= DRAGFULL_OPTION_ALL;
1971 break;
1972 case DragFrame:
1973 nDragFullOptions &= DRAGFULL_OPTION_NONE;
1974 break;
1975 case DragSystemDep:
1976 default:
1977 break;
1980 sal_uInt32 nFollow = hMouseSettings.GetFollow();
1981 hMouseSettings.SetFollow( aAppearanceCfg.IsMenuMouseFollow() ? (nFollow|MOUSE_FOLLOW_MENU) : (nFollow&~MOUSE_FOLLOW_MENU));
1982 rSettings.SetMouseSettings(hMouseSettings);
1984 SvtMenuOptions aMenuOpt;
1985 hStyleSettings.SetUseImagesInMenus(aMenuOpt.GetMenuIconsState());
1986 hStyleSettings.SetDragFullOptions( nDragFullOptions );
1987 rSettings.SetStyleSettings ( hStyleSettings );
1990 // ========================================================================
1991 IMPL_LINK_NOARG(Desktop, AsyncInitFirstRun)
1993 DoFirstRunInitializations();
1994 return 0L;
1997 // ========================================================================
1999 class ExitTimer : public Timer
2001 public:
2002 ExitTimer()
2004 SetTimeout(500);
2005 Start();
2007 virtual void Timeout()
2009 exit(42);
2013 IMPL_LINK_NOARG(Desktop, OpenClients_Impl)
2015 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE - DesktopOpenClients_Impl()" );
2017 try {
2018 OpenClients();
2020 OfficeIPCThread::SetReady();
2022 CloseSplashScreen();
2023 CheckFirstRun( );
2024 EnableOleAutomation();
2026 if (getenv ("OOO_EXIT_POST_STARTUP"))
2027 new ExitTimer();
2028 } catch (const ::com::sun::star::uno::Exception &e) {
2029 String a( "UNO exception during client open:\n" );
2030 Application::Abort( a + e.Message );
2032 return 0;
2035 // enable acceptos
2036 IMPL_LINK_NOARG(Desktop, EnableAcceptors_Impl)
2038 enableAcceptors();
2039 return 0;
2043 // Registers a COM class factory of the service manager with the windows operating system.
2044 void Desktop::EnableOleAutomation()
2046 RTL_LOGFILE_CONTEXT( aLog, "desktop (jl97489) ::Desktop::EnableOleAutomation" );
2047 #ifdef WNT
2048 Reference< XMultiServiceFactory > xSMgr= comphelper::getProcessServiceFactory();
2049 xSMgr->createInstance(OUString("com.sun.star.bridge.OleApplicationRegistration"));
2050 xSMgr->createInstance(OUString("com.sun.star.comp.ole.EmbedServer"));
2051 #endif
2054 void Desktop::PreloadModuleData( const CommandLineArgs& rArgs )
2056 Sequence < com::sun::star::beans::PropertyValue > args(1);
2057 args[0].Name = OUString("Hidden");
2058 args[0].Value <<= sal_True;
2059 Reference < XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2061 if ( rArgs.IsWriter() )
2065 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/swriter"),
2066 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2067 xDoc->close( sal_False );
2069 catch ( const com::sun::star::uno::Exception& )
2073 if ( rArgs.IsCalc() )
2077 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/scalc"),
2078 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2079 xDoc->close( sal_False );
2081 catch ( const com::sun::star::uno::Exception& )
2085 if ( rArgs.IsDraw() )
2089 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/sdraw"),
2090 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2091 xDoc->close( sal_False );
2093 catch ( const com::sun::star::uno::Exception& )
2097 if ( rArgs.IsImpress() )
2101 Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/simpress"),
2102 OUString("_blank"), 0, args ), UNO_QUERY_THROW );
2103 xDoc->close( sal_False );
2105 catch ( const com::sun::star::uno::Exception& )
2111 void Desktop::PreloadConfigurationData()
2113 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2114 Reference< XNameAccess > xNameAccess = css::frame::UICommandDescription::create(xContext);
2116 OUString aWriterDoc( "com.sun.star.text.TextDocument" );
2117 OUString aCalcDoc( "com.sun.star.sheet.SpreadsheetDocument" );
2118 OUString aDrawDoc( "com.sun.star.drawing.DrawingDocument" );
2119 OUString aImpressDoc( "com.sun.star.presentation.PresentationDocument" );
2121 // preload commands configuration
2122 Any a;
2123 Reference< XNameAccess > xCmdAccess;
2127 a = xNameAccess->getByName( aWriterDoc );
2128 a >>= xCmdAccess;
2129 if ( xCmdAccess.is() )
2131 xCmdAccess->getByName( OUString( ".uno:BasicShapes" ));
2132 xCmdAccess->getByName( OUString( ".uno:EditGlossary" ));
2135 catch ( const ::com::sun::star::uno::Exception& )
2141 a = xNameAccess->getByName( aCalcDoc );
2142 a >>= xCmdAccess;
2143 if ( xCmdAccess.is() )
2144 xCmdAccess->getByName( OUString( ".uno:InsertObjectStarMath" ));
2146 catch ( const ::com::sun::star::uno::Exception& )
2152 // draw and impress share the same configuration file (DrawImpressCommands.xcu)
2153 a = xNameAccess->getByName( aDrawDoc );
2154 a >>= xCmdAccess;
2155 if ( xCmdAccess.is() )
2156 xCmdAccess->getByName( OUString( ".uno:Polygon" ));
2158 catch ( const ::com::sun::star::uno::Exception& )
2162 // preload window state configuration
2163 xNameAccess = WindowStateConfiguration::create( xContext );
2164 Reference< XNameAccess > xWindowAccess;
2167 a = xNameAccess->getByName( aWriterDoc );
2168 a >>= xWindowAccess;
2169 if ( xWindowAccess.is() )
2170 xWindowAccess->getByName( OUString( "private:resource/toolbar/standardbar" ));
2172 catch ( const ::com::sun::star::uno::Exception& )
2177 a = xNameAccess->getByName( aCalcDoc );
2178 a >>= xWindowAccess;
2179 if ( xWindowAccess.is() )
2180 xWindowAccess->getByName( OUString( "private:resource/toolbar/standardbar" ));
2182 catch ( const ::com::sun::star::uno::Exception& )
2187 a = xNameAccess->getByName( aDrawDoc );
2188 a >>= xWindowAccess;
2189 if ( xWindowAccess.is() )
2190 xWindowAccess->getByName( OUString( "private:resource/toolbar/standardbar" ));
2192 catch ( const ::com::sun::star::uno::Exception& )
2197 a = xNameAccess->getByName( aImpressDoc );
2198 a >>= xWindowAccess;
2199 if ( xWindowAccess.is() )
2200 xWindowAccess->getByName( OUString( "private:resource/toolbar/standardbar" ));
2202 catch ( const ::com::sun::star::uno::Exception& )
2206 // preload user interface element factories
2207 Sequence< Sequence< css::beans::PropertyValue > > aSeqSeqPropValue;
2208 Reference< XUIElementFactoryManager > xUIElementFactory = UIElementFactoryManager::create( xContext );
2211 aSeqSeqPropValue = xUIElementFactory->getRegisteredFactories();
2213 catch ( const ::com::sun::star::uno::Exception& )
2217 // preload popup menu controller factories. As all controllers are in the same
2218 // configuration file they also get preloaded!
2220 Reference< css::frame::XUIControllerRegistration > xPopupMenuControllerFactory =
2221 css::frame::PopupMenuControllerFactory::create( xContext );
2224 xPopupMenuControllerFactory->hasController(
2225 OUString( ".uno:CharFontName" ),
2226 OUString() );
2228 catch ( const ::com::sun::star::uno::Exception& )
2232 // preload filter configuration
2233 Sequence< OUString > aSeq;
2234 xNameAccess = Reference< XNameAccess >(
2235 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext),
2236 UNO_QUERY );
2237 if ( xNameAccess.is() )
2241 aSeq = xNameAccess->getElementNames();
2243 catch ( const ::com::sun::star::uno::Exception& )
2248 // preload type detection configuration
2249 xNameAccess = Reference< XNameAccess >(
2250 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext),
2251 UNO_QUERY );
2252 if ( xNameAccess.is() )
2256 aSeq = xNameAccess->getElementNames();
2258 catch ( const ::com::sun::star::uno::Exception& )
2264 void Desktop::OpenClients()
2267 // check if a document has been recovered - if there is one of if a document was loaded by cmdline, no default document
2268 // should be created
2269 Reference < XComponent > xFirst;
2270 bool bRecovery = false;
2272 const CommandLineArgs& rArgs = GetCommandLineArgs();
2274 Reference<XMultiServiceFactory> rFactory = ::comphelper::getProcessServiceFactory();
2276 if (!rArgs.IsQuickstart())
2278 sal_Bool bShowHelp = sal_False;
2279 OUStringBuffer aHelpURLBuffer;
2280 if (rArgs.IsHelpWriter()) {
2281 bShowHelp = sal_True;
2282 aHelpURLBuffer.appendAscii("vnd.sun.star.help://swriter/start");
2283 } else if (rArgs.IsHelpCalc()) {
2284 bShowHelp = sal_True;
2285 aHelpURLBuffer.appendAscii("vnd.sun.star.help://scalc/start");
2286 } else if (rArgs.IsHelpDraw()) {
2287 bShowHelp = sal_True;
2288 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdraw/start");
2289 } else if (rArgs.IsHelpImpress()) {
2290 bShowHelp = sal_True;
2291 aHelpURLBuffer.appendAscii("vnd.sun.star.help://simpress/start");
2292 } else if (rArgs.IsHelpBase()) {
2293 bShowHelp = sal_True;
2294 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdatabase/start");
2295 } else if (rArgs.IsHelpBasic()) {
2296 bShowHelp = sal_True;
2297 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sbasic/start");
2298 } else if (rArgs.IsHelpMath()) {
2299 bShowHelp = sal_True;
2300 aHelpURLBuffer.appendAscii("vnd.sun.star.help://smath/start");
2302 if (bShowHelp) {
2303 aHelpURLBuffer.appendAscii("?Language=");
2304 aHelpURLBuffer.append(utl::ConfigManager::getLocale());
2305 #if defined UNX
2306 aHelpURLBuffer.appendAscii("&System=UNX");
2307 #elif defined WNT
2308 aHelpURLBuffer.appendAscii("&System=WIN");
2309 #endif
2310 Application::GetHelp()->Start(
2311 aHelpURLBuffer.makeStringAndClear(), NULL);
2312 return;
2315 else
2317 OUString aIniName;
2319 osl_getExecutableFile( &aIniName.pData );
2320 sal_uInt32 lastIndex = aIniName.lastIndexOf('/');
2321 if ( lastIndex > 0 )
2323 aIniName = aIniName.copy( 0, lastIndex+1 );
2324 aIniName += "perftune";
2325 #if defined(WNT)
2326 aIniName += ".ini";
2327 #else
2328 aIniName += "rc";
2329 #endif
2332 rtl::Bootstrap aPerfTuneIniFile( aIniName );
2334 OUString aDefault( "0" );
2335 OUString aPreloadData;
2337 aPerfTuneIniFile.getFrom( OUString( "QuickstartPreloadConfiguration" ), aPreloadData, aDefault );
2338 if ( aPreloadData == "1" )
2340 if ( rArgs.IsWriter() ||
2341 rArgs.IsCalc() ||
2342 rArgs.IsDraw() ||
2343 rArgs.IsImpress() )
2345 PreloadModuleData( rArgs );
2348 PreloadConfigurationData();
2352 // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line.
2353 // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data.
2354 // But the require that all documents, which are saved as backup should exists inside
2355 // memory. May be this mechanism will be inconsistent if the configuration exists ...
2356 // but no document inside memory corrspond to this data.
2357 // Furter it's not acceptable to recover such documents without any UI. It can
2358 // need some time, where the user wont see any results and wait for finishing the office startup ...
2359 sal_Bool bAllowRecoveryAndSessionManagement = (
2360 ( !rArgs.IsNoRestore() ) &&
2361 ( !rArgs.IsHeadless() )
2364 if ( ! bAllowRecoveryAndSessionManagement )
2368 Reference< XDispatch > xRecovery = css::frame::AutoRecovery::create( ::comphelper::getProcessComponentContext() );
2369 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() );
2371 css::util::URL aCmd;
2372 aCmd.Complete = OUString("vnd.sun.star.autorecovery:/disableRecovery");
2373 xParser->parseStrict(aCmd);
2375 xRecovery->dispatch(aCmd, css::uno::Sequence< css::beans::PropertyValue >());
2377 catch(const css::uno::Exception& e)
2379 OUString aMessage = OUString("Could not disable AutoRecovery.\n")
2380 + e.Message;
2381 OSL_FAIL(OUStringToOString(aMessage, RTL_TEXTENCODING_ASCII_US).getStr());
2384 else
2386 sal_Bool bCrashed = sal_False;
2387 sal_Bool bExistsRecoveryData = sal_False;
2388 sal_Bool bExistsSessionData = sal_False;
2390 impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData);
2392 if ( !getenv ("OOO_DISABLE_RECOVERY") &&
2394 ( bExistsRecoveryData ) || // => crash with files => recovery
2395 ( bCrashed ) // => crash without files => error report
2401 bRecovery = impl_callRecoveryUI(
2402 sal_False , // false => force recovery instead of emergency save
2403 bCrashed ,
2404 bExistsRecoveryData);
2406 catch(const css::uno::Exception& e)
2408 OUString aMessage = OUString("Error during recovery\n")
2409 + e.Message;
2410 OSL_FAIL(OUStringToOString(aMessage, RTL_TEXTENCODING_ASCII_US).getStr());
2414 Reference< XSessionManagerListener2 > xSessionListener;
2417 // specifies whether the UI-interaction on Session shutdown is allowed
2418 sal_Bool bAllowUI = isUIOnSessionShutdownAllowed();
2420 xSessionListener = SessionListener::createWithOnQuitFlag(::comphelper::getProcessComponentContext(), bAllowUI);
2422 // css::beans::NamedValue aProperty( OUString( "AllowUserInteractionOnQuit" ),
2423 // css::uno::makeAny( bAllowUI ) );
2424 // css::uno::Sequence< css::uno::Any > aArgs( 1 );
2425 // aArgs[0] <<= aProperty;
2427 // xSessionListener->initialize( aArgs );
2429 catch(const com::sun::star::uno::Exception& e)
2431 OUString aMessage = OUString("Registration of session listener failed\n")
2432 + e.Message;
2433 OSL_FAIL(OUStringToOString(aMessage, RTL_TEXTENCODING_ASCII_US).getStr());
2436 if ( !bExistsRecoveryData )
2438 // session management
2441 Reference< XSessionManagerListener > r(xSessionListener, UNO_QUERY_THROW);
2442 r->doRestore();
2444 catch(const com::sun::star::uno::Exception& e)
2446 OUString aMessage = OUString("Error in session management\n")
2447 + e.Message;
2448 OSL_FAIL(OUStringToOString(aMessage, RTL_TEXTENCODING_ASCII_US).getStr());
2453 OfficeIPCThread::EnableRequests();
2455 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl());
2456 aRequest.pcProcessed = NULL;
2458 aRequest.aOpenList = rArgs.GetOpenList();
2459 aRequest.aViewList = rArgs.GetViewList();
2460 aRequest.aStartList = rArgs.GetStartList();
2461 aRequest.aPrintList = rArgs.GetPrintList();
2462 aRequest.aPrintToList = rArgs.GetPrintToList();
2463 aRequest.aPrinterName = rArgs.GetPrinterName();
2464 aRequest.aForceOpenList = rArgs.GetForceOpenList();
2465 aRequest.aForceNewList = rArgs.GetForceNewList();
2466 aRequest.aConversionList = rArgs.GetConversionList();
2467 aRequest.aConversionParams = rArgs.GetConversionParams();
2468 aRequest.aConversionOut = rArgs.GetConversionOut();
2469 aRequest.aInFilter = rArgs.GetInFilter();
2471 if ( !aRequest.aOpenList.empty() ||
2472 !aRequest.aViewList.empty() ||
2473 !aRequest.aStartList.empty() ||
2474 !aRequest.aPrintList.empty() ||
2475 !aRequest.aForceOpenList.empty() ||
2476 !aRequest.aForceNewList.empty() ||
2477 ( !aRequest.aPrintToList.empty() && !aRequest.aPrinterName.isEmpty() ) ||
2478 !aRequest.aConversionList.empty() )
2480 if ( rArgs.HasModuleParam() )
2482 SvtModuleOptions aOpt;
2484 // Support command line parameters to start a module (as preselection)
2485 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2486 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::E_WRITER );
2487 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
2488 aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::E_CALC );
2489 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
2490 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::E_IMPRESS );
2491 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
2492 aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::E_DRAW );
2495 // check for printing disabled
2496 if( ( !(aRequest.aPrintList.empty() && aRequest.aPrintToList.empty()) )
2497 && Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
2499 aRequest.aPrintList.clear();
2500 aRequest.aPrintToList.clear();
2501 ResMgr* pDtResMgr = GetDesktopResManager();
2502 if( pDtResMgr )
2504 ErrorBox aBox( NULL, ResId( EBX_ERR_PRINTDISABLED, *pDtResMgr ) );
2505 aBox.Execute();
2509 // Process request
2510 if ( OfficeIPCThread::ExecuteCmdLineRequests( aRequest ) )
2512 // Don't do anything if we have successfully called terminate at desktop:
2513 return;
2517 // no default document if a document was loaded by recovery or by command line or if soffice is used as server
2518 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() );
2519 Reference< XElementAccess > xList( xDesktop->getFrames(), UNO_QUERY_THROW );
2520 if ( xList->hasElements() )
2521 return;
2523 if ( rArgs.IsQuickstart() || rArgs.IsInvisible() || Application::AnyInput( VCL_INPUT_APPEVENT ) )
2524 // soffice was started as tray icon ...
2525 return;
2527 if ( bRecovery )
2529 ShowBackingComponent(0);
2531 else
2533 OpenDefault();
2537 void Desktop::OpenDefault()
2540 RTL_LOGFILE_CONTEXT( aLog, "desktop (cd100003) ::Desktop::OpenDefault" );
2542 OUString aName;
2543 SvtModuleOptions aOpt;
2545 const CommandLineArgs& rArgs = GetCommandLineArgs();
2546 if ( rArgs.IsNoDefault() ) return;
2547 if ( rArgs.HasModuleParam() )
2549 // Support new command line parameters to start a module
2550 if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2551 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITER );
2552 else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
2553 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_CALC );
2554 else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
2555 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_IMPRESS );
2556 else if ( rArgs.IsBase() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
2557 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DATABASE );
2558 else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
2559 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DRAW );
2560 else if ( rArgs.IsMath() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) )
2561 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_MATH );
2562 else if ( rArgs.IsGlobal() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2563 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITERGLOBAL );
2564 else if ( rArgs.IsWeb() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2565 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITERWEB );
2568 if ( aName.isEmpty() )
2570 // Old way to create a default document
2571 if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
2572 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITER );
2573 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
2574 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_CALC );
2575 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
2576 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_IMPRESS );
2577 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) )
2578 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DATABASE );
2579 else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
2580 aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DRAW );
2581 else
2582 return;
2585 ProcessDocumentsRequest aRequest(rArgs.getCwdUrl());
2586 aRequest.pcProcessed = NULL;
2587 aRequest.aOpenList.push_back(aName);
2588 OfficeIPCThread::ExecuteCmdLineRequests( aRequest );
2592 String GetURL_Impl(
2593 const String& rName, boost::optional< OUString > const & cwdUrl )
2595 // if rName is a vnd.sun.star.script URL do not attempt to parse it
2596 // as INetURLObj does not handle handle there URLs
2597 if (rName.CompareToAscii("vnd.sun.star.script" , 19) == COMPARE_EQUAL)
2599 return rName;
2602 // dont touch file urls, those should already be in internal form
2603 // they won't get better here (#112849#)
2604 if (rName.CompareToAscii("file:" , 5) == COMPARE_EQUAL)
2606 return rName;
2609 if ( rName.CompareToAscii("service:" , 8) == COMPARE_EQUAL )
2611 return rName;
2614 // Add path separator to these directory and make given URL (rName) absolute by using of current working directory
2615 // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!!
2616 // Otherwhise last part will be ignored and wrong result will be returned!!!
2617 // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ...
2618 // But if we add a separator - he doesn't do it anymore.
2619 INetURLObject aObj;
2620 if (cwdUrl) {
2621 aObj.SetURL(*cwdUrl);
2622 aObj.setFinalSlash();
2625 // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths.
2626 // Otherwise this char won't get encoded and we are not able to load such files later,
2627 bool bWasAbsolute;
2628 INetURLObject aURL = aObj.smartRel2Abs( rName, bWasAbsolute, false, INetURLObject::WAS_ENCODED,
2629 RTL_TEXTENCODING_UTF8, true );
2630 String aFileURL = aURL.GetMainURL(INetURLObject::NO_DECODE);
2632 ::osl::FileStatus aStatus( osl_FileStatus_Mask_FileURL );
2633 ::osl::DirectoryItem aItem;
2634 if( ::osl::FileBase::E_None == ::osl::DirectoryItem::get( aFileURL, aItem ) &&
2635 ::osl::FileBase::E_None == aItem.getFileStatus( aStatus ) )
2636 aFileURL = aStatus.getFileURL();
2638 return aFileURL;
2641 void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent )
2643 switch ( rAppEvent.GetEvent() )
2645 case ApplicationEvent::TYPE_ACCEPT:
2646 // every time an accept parameter is used we create an acceptor
2647 // with the corresponding accept-string
2648 createAcceptor(rAppEvent.GetStringData());
2649 break;
2650 case ApplicationEvent::TYPE_APPEAR:
2651 if ( !GetCommandLineArgs().IsInvisible() )
2653 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2655 // find active task - the active task is always a visible task
2656 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
2657 Reference< css::frame::XFrame > xTask = xDesktop->getActiveFrame();
2658 if ( !xTask.is() )
2660 // get any task if there is no active one
2661 Reference< css::container::XIndexAccess > xList( xDesktop->getFrames(), ::com::sun::star::uno::UNO_QUERY );
2662 if ( xList->getCount() > 0 )
2663 xList->getByIndex(0) >>= xTask;
2666 if ( xTask.is() )
2668 Reference< com::sun::star::awt::XTopWindow > xTop( xTask->getContainerWindow(), UNO_QUERY );
2669 xTop->toFront();
2671 else
2673 // no visible task that could be activated found
2674 Reference< ::com::sun::star::awt::XWindow > xContainerWindow;
2675 Reference< XFrame > xBackingFrame = xDesktop->findFrame(OUString( "_blank" ), 0);
2676 if (xBackingFrame.is())
2677 xContainerWindow = xBackingFrame->getContainerWindow();
2678 if (xContainerWindow.is())
2680 Reference< XController > xStartModule = StartModule::createWithParentWindow(xContext, xContainerWindow);
2681 Reference< ::com::sun::star::awt::XWindow > xBackingWin(xStartModule, UNO_QUERY);
2682 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2683 // Because the backing component set the property "IsBackingMode" of the frame
2684 // to true inside attachFrame(). But setComponent() reset this state every time ...
2685 xBackingFrame->setComponent(xBackingWin, xStartModule);
2686 xStartModule->attachFrame(xBackingFrame);
2687 xContainerWindow->setVisible(sal_True);
2689 Window* pCompWindow = VCLUnoHelper::GetWindow(xBackingFrame->getComponentWindow());
2690 if (pCompWindow)
2691 pCompWindow->Update();
2695 break;
2696 case ApplicationEvent::TYPE_HELP:
2697 displayCmdlineHelp(rAppEvent.GetStringData());
2698 break;
2699 case ApplicationEvent::TYPE_VERSION:
2700 displayVersion();
2701 break;
2702 case ApplicationEvent::TYPE_OPEN:
2704 const CommandLineArgs& rCmdLine = GetCommandLineArgs();
2705 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
2707 ProcessDocumentsRequest* pDocsRequest = new ProcessDocumentsRequest(
2708 rCmdLine.getCwdUrl());
2709 std::vector<OUString> const & data(rAppEvent.GetStringsData());
2710 pDocsRequest->aOpenList.insert(
2711 pDocsRequest->aOpenList.end(), data.begin(), data.end());
2712 pDocsRequest->pcProcessed = NULL;
2714 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest );
2715 delete pDocsRequest;
2718 break;
2719 case ApplicationEvent::TYPE_OPENHELPURL:
2720 // start help for a specific URL
2721 Application::GetHelp()->Start(rAppEvent.GetStringData(), NULL);
2722 break;
2723 case ApplicationEvent::TYPE_PRINT:
2725 const CommandLineArgs& rCmdLine = GetCommandLineArgs();
2726 if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() )
2728 ProcessDocumentsRequest* pDocsRequest = new ProcessDocumentsRequest(
2729 rCmdLine.getCwdUrl());
2730 std::vector<OUString> const & data(rAppEvent.GetStringsData());
2731 pDocsRequest->aPrintList.insert(
2732 pDocsRequest->aPrintList.end(), data.begin(), data.end());
2733 pDocsRequest->pcProcessed = NULL;
2735 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest );
2736 delete pDocsRequest;
2739 break;
2740 case ApplicationEvent::TYPE_PRIVATE_DOSHUTDOWN:
2742 Desktop* pD = dynamic_cast<Desktop*>(GetpApp());
2743 OSL_ENSURE( pD, "no desktop ?!?" );
2744 if( pD )
2745 pD->doShutdown();
2747 break;
2748 case ApplicationEvent::TYPE_QUICKSTART:
2749 if ( !GetCommandLineArgs().IsInvisible() )
2751 // If the office has been started the second time its command line arguments are sent through a pipe
2752 // connection to the first office. We want to reuse the quickstart option for the first office.
2753 // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the
2754 // application events to do this (they are executed inside main thread)!!!
2755 // Don't start quickstart service if the user specified "--invisible" on the command line!
2756 sal_Bool bQuickstart( sal_True );
2757 Sequence< Any > aSeq( 1 );
2758 aSeq[0] <<= bQuickstart;
2760 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2761 Reference < XInitialization > xQuickstart( xContext->getServiceManager()->createInstanceWithContext("com.sun.star.office.Quickstart", xContext),
2762 UNO_QUERY );
2763 if ( xQuickstart.is() )
2764 xQuickstart->initialize( aSeq );
2766 break;
2767 case ApplicationEvent::TYPE_SHOWDIALOG:
2768 // ignore all errors here. It's clicking a menu entry only ...
2769 // The user will try it again, in case nothing happens .-)
2772 Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2774 Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
2776 Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext);
2777 css::util::URL aCommand;
2778 if( rAppEvent.GetStringData() == "PREFERENCES" )
2779 aCommand.Complete = ".uno:OptionsTreeDialog";
2780 else if( rAppEvent.GetStringData() == "ABOUT" )
2781 aCommand.Complete = ".uno:About";
2782 if( !aCommand.Complete.isEmpty() )
2784 xParser->parseStrict(aCommand);
2786 css::uno::Reference< css::frame::XDispatch > xDispatch = xDesktop->queryDispatch(aCommand, OUString(), 0);
2787 if (xDispatch.is())
2788 xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >());
2791 catch(const css::uno::Exception&)
2793 break;
2794 case ApplicationEvent::TYPE_UNACCEPT:
2795 // try to remove corresponding acceptor
2796 destroyAcceptor(rAppEvent.GetStringData());
2797 break;
2798 default:
2799 OSL_FAIL("this cannot happen");
2800 break;
2804 void Desktop::OpenSplashScreen()
2806 const CommandLineArgs &rCmdLine = GetCommandLineArgs();
2807 sal_Bool bVisible = sal_False;
2808 // Show intro only if this is normal start (e.g. no server, no quickstart, no printing )
2809 if ( !rCmdLine.IsInvisible() &&
2810 !rCmdLine.IsHeadless() &&
2811 !rCmdLine.IsQuickstart() &&
2812 !rCmdLine.IsMinimized() &&
2813 !rCmdLine.IsNoLogo() &&
2814 !rCmdLine.IsTerminateAfterInit() &&
2815 rCmdLine.GetPrintList().empty() &&
2816 rCmdLine.GetPrintToList().empty() &&
2817 rCmdLine.GetConversionList().empty() )
2819 // Determine application name from command line parameters
2820 OUString aAppName;
2821 if ( rCmdLine.IsWriter() )
2822 aAppName = OUString( "writer" );
2823 else if ( rCmdLine.IsCalc() )
2824 aAppName = OUString( "calc" );
2825 else if ( rCmdLine.IsDraw() )
2826 aAppName = OUString( "draw" );
2827 else if ( rCmdLine.IsImpress() )
2828 aAppName = OUString( "impress" );
2829 else if ( rCmdLine.IsBase() )
2830 aAppName = OUString( "base" );
2831 else if ( rCmdLine.IsGlobal() )
2832 aAppName = OUString( "global" );
2833 else if ( rCmdLine.IsMath() )
2834 aAppName = OUString( "math" );
2835 else if ( rCmdLine.IsWeb() )
2836 aAppName = OUString( "web" );
2838 // Which splash to use
2839 OUString aSplashService( "com.sun.star.office.SplashScreen" );
2840 if ( rCmdLine.HasSplashPipe() )
2841 aSplashService = OUString("com.sun.star.office.PipeSplashScreen");
2843 bVisible = sal_True;
2844 Sequence< Any > aSeq( 2 );
2845 aSeq[0] <<= bVisible;
2846 aSeq[1] <<= aAppName;
2847 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2848 m_rSplashScreen = Reference<XStatusIndicator>(
2849 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService, aSeq, xContext),
2850 UNO_QUERY);
2852 if(m_rSplashScreen.is())
2853 m_rSplashScreen->start(OUString("SplashScreen"), 100);
2858 void Desktop::SetSplashScreenProgress(sal_Int32 iProgress)
2860 if(m_rSplashScreen.is())
2862 m_rSplashScreen->setValue(iProgress);
2866 void Desktop::SetSplashScreenText( const OUString& rText )
2868 if( m_rSplashScreen.is() )
2870 m_rSplashScreen->setText( rText );
2874 void Desktop::CloseSplashScreen()
2876 if(m_rSplashScreen.is())
2878 m_rSplashScreen->end();
2879 m_rSplashScreen = NULL;
2883 // ========================================================================
2884 void Desktop::DoFirstRunInitializations()
2888 Reference< XJobExecutor > xExecutor = JobExecutor::create( ::comphelper::getProcessComponentContext() );
2889 xExecutor->trigger( OUString("onFirstRunInitialization") );
2891 catch(const ::com::sun::star::uno::Exception&)
2893 OSL_FAIL( "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor ..." );
2897 void Desktop::ShowBackingComponent(Desktop * progress)
2899 if (GetCommandLineArgs().IsNoDefault())
2901 return;
2903 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext();
2904 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xContext);
2905 if (progress != 0)
2907 progress->SetSplashScreenProgress(60);
2909 Reference< XFrame > xBackingFrame = xDesktop->findFrame(OUString( "_blank" ), 0);
2910 Reference< ::com::sun::star::awt::XWindow > xContainerWindow;
2912 if (xBackingFrame.is())
2913 xContainerWindow = xBackingFrame->getContainerWindow();
2914 if (xContainerWindow.is())
2916 SetDocumentExtendedStyle(xContainerWindow);
2917 if (progress != 0)
2919 progress->SetSplashScreenProgress(75);
2922 Reference< XController > xStartModule = StartModule::createWithParentWindow( xContext, xContainerWindow);
2923 // Attention: You MUST(!) call setComponent() before you call attachFrame().
2924 // Because the backing component set the property "IsBackingMode" of the frame
2925 // to true inside attachFrame(). But setComponent() reset this state everytimes ...
2926 xBackingFrame->setComponent(Reference< XWindow >(xStartModule, UNO_QUERY), xStartModule);
2927 if (progress != 0)
2929 progress->SetSplashScreenProgress(100);
2931 xStartModule->attachFrame(xBackingFrame);
2932 if (progress != 0)
2934 progress->CloseSplashScreen();
2936 xContainerWindow->setVisible(sal_True);
2940 // ========================================================================
2941 void Desktop::CheckFirstRun( )
2943 if (officecfg::Office::Common::Misc::FirstRun::get())
2945 // this has once been done using a vos timer. this could lead to problems when
2946 // the timer would trigger when the app is already going down again, since VCL would
2947 // no longer be available. Since the old handler would do a postUserEvent to the main
2948 // thread anyway, we can use a vcl timer here to prevent the race contition (#107197#)
2949 m_firstRunTimer.SetTimeout(3000); // 3 sec.
2950 m_firstRunTimer.SetTimeoutHdl(LINK(this, Desktop, AsyncInitFirstRun));
2951 m_firstRunTimer.Start();
2953 #ifdef WNT
2954 // Check if Quckstarter should be started (on Windows only)
2955 TCHAR szValue[8192];
2956 DWORD nValueSize = sizeof(szValue);
2957 HKEY hKey;
2958 if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\LibreOffice", &hKey ) )
2960 if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("RunQuickstartAtFirstStart"), NULL, NULL, (LPBYTE)szValue, &nValueSize ) )
2962 sal_Bool bQuickstart( sal_True );
2963 sal_Bool bAutostart( sal_True );
2964 Sequence< Any > aSeq( 2 );
2965 aSeq[0] <<= bQuickstart;
2966 aSeq[1] <<= bAutostart;
2968 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
2969 Reference < XInitialization > xQuickstart(
2970 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.office.Quickstart", xContext),
2971 UNO_QUERY );
2972 if ( xQuickstart.is() )
2973 xQuickstart->initialize( aSeq );
2974 RegCloseKey( hKey );
2977 #endif
2979 boost::shared_ptr< comphelper::ConfigurationChanges > batch(
2980 comphelper::ConfigurationChanges::create());
2981 officecfg::Office::Common::Misc::FirstRun::set(false, batch);
2982 batch->commit();
2988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */