1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #include <config_features.h> |
21 | #include <config_folders.h> |
22 | |
23 | #include "sal/config.h" |
24 | |
25 | #include <iostream> |
26 | |
27 | #include "app.hxx" |
28 | #include "desktop.hrc" |
29 | #include "cmdlineargs.hxx" |
30 | #include "cmdlinehelp.hxx" |
31 | #include "dispatchwatcher.hxx" |
32 | #include "configinit.hxx" |
33 | #include "lockfile.hxx" |
34 | #include "userinstall.hxx" |
35 | #include "desktopcontext.hxx" |
36 | #include "exithelper.h" |
37 | #include "migration.hxx" |
38 | |
39 | #include <svl/languageoptions.hxx> |
40 | #include <svtools/javacontext.hxx> |
41 | #include <com/sun/star/beans/XPropertySet.hpp> |
42 | #include <com/sun/star/frame/theAutoRecovery.hpp> |
43 | #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp> |
44 | #include <com/sun/star/frame/SessionListener.hpp> |
45 | #include <com/sun/star/frame/XSessionManagerListener.hpp> |
46 | #include <com/sun/star/frame/XSynchronousDispatch.hpp> |
47 | #include <com/sun/star/document/CorruptedFilterConfigurationException.hpp> |
48 | #include <com/sun/star/configuration/CorruptedConfigurationException.hpp> |
49 | #include <com/sun/star/configuration/theDefaultProvider.hpp> |
50 | #include <com/sun/star/util/XFlushable.hpp> |
51 | #include <com/sun/star/system/SystemShellExecuteFlags.hpp> |
52 | #include <com/sun/star/frame/Desktop.hpp> |
53 | #include <com/sun/star/frame/StartModule.hpp> |
54 | #include <com/sun/star/frame/XComponentLoader.hpp> |
55 | #include <com/sun/star/view/XPrintable.hpp> |
56 | #include <com/sun/star/awt/XTopWindow.hpp> |
57 | #include "com/sun/star/util/URLTransformer.hpp" |
58 | #include <com/sun/star/util/XURLTransformer.hpp> |
59 | #include <com/sun/star/util/XCloseable.hpp> |
60 | #include <com/sun/star/frame/XDispatchProvider.hpp> |
61 | #include <com/sun/star/lang/ServiceNotRegisteredException.hpp> |
62 | #include <com/sun/star/configuration/MissingBootstrapFileException.hpp> |
63 | #include <com/sun/star/configuration/InvalidBootstrapFileException.hpp> |
64 | #include <com/sun/star/configuration/InstallationIncompleteException.hpp> |
65 | #include <com/sun/star/configuration/backend/BackendSetupException.hpp> |
66 | #include <com/sun/star/configuration/backend/BackendAccessException.hpp> |
67 | #include <com/sun/star/task/theJobExecutor.hpp> |
68 | #include <com/sun/star/task/OfficeRestartManager.hpp> |
69 | #include <com/sun/star/task/XRestartManager.hpp> |
70 | #include <com/sun/star/document/XEventListener.hpp> |
71 | #include <com/sun/star/frame/theUICommandDescription.hpp> |
72 | #include <com/sun/star/ui/theUIElementFactoryManager.hpp> |
73 | #include <com/sun/star/ui/theWindowStateConfiguration.hpp> |
74 | #include <com/sun/star/frame/XUIControllerRegistration.hpp> |
75 | #include <com/sun/star/frame/thePopupMenuControllerFactory.hpp> |
76 | #include <com/sun/star/office/Quickstart.hpp> |
77 | |
78 | #include <toolkit/helper/vclunohelper.hxx> |
79 | #include <comphelper/configuration.hxx> |
80 | #include <comphelper/processfactory.hxx> |
81 | #include <unotools/bootstrap.hxx> |
82 | #include <unotools/configmgr.hxx> |
83 | #include <unotools/moduleoptions.hxx> |
84 | #include <officecfg/Office/Common.hxx> |
85 | #include <officecfg/Office/Recovery.hxx> |
86 | #include <officecfg/Setup.hxx> |
87 | #include <osl/file.hxx> |
88 | #include <osl/process.h> |
89 | #include <rtl/uri.hxx> |
90 | #include <unotools/pathoptions.hxx> |
91 | #include <svtools/miscopt.hxx> |
92 | #include <svtools/menuoptions.hxx> |
93 | #include <rtl/bootstrap.hxx> |
94 | #include <vcl/help.hxx> |
95 | #include <vcl/msgbox.hxx> |
96 | #include <sfx2/sfx.hrc> |
97 | #include <sfx2/app.hxx> |
98 | #include <svl/itemset.hxx> |
99 | #include <svl/eitem.hxx> |
100 | |
101 | #include <svtools/fontsubstconfig.hxx> |
102 | #include <svtools/accessibilityoptions.hxx> |
103 | #include <svtools/apearcfg.hxx> |
104 | #include <vcl/graphicfilter.hxx> |
105 | |
106 | #include "langselect.hxx" |
107 | |
108 | #include <config_telepathy.h> |
109 | |
110 | #if ENABLE_TELEPATHY |
111 | #include <tubes/manager.hxx> |
112 | #endif |
113 | |
114 | #if defined MACOSX |
115 | #include <errno.h> |
116 | #include <sys/wait.h> |
117 | #endif |
118 | |
119 | #ifdef WNT |
120 | #ifdef _MSC_VER |
121 | #pragma warning(push, 1) /* disable warnings within system headers */ |
122 | #pragma warning (disable: 4005) |
123 | #endif |
124 | #define WIN32_LEAN_AND_MEAN |
125 | #include <windows.h> |
126 | #ifdef _MSC_VER |
127 | #pragma warning(pop) |
128 | #endif |
129 | #endif //WNT |
130 | |
131 | #if defined WNT |
132 | #include <process.h> |
133 | #define GETPID _getpid |
134 | #else |
135 | #include <unistd.h> |
136 | #define GETPID getpid |
137 | #endif |
138 | |
139 | using namespace ::com::sun::star::awt; |
140 | using namespace ::com::sun::star::uno; |
141 | using namespace ::com::sun::star::util; |
142 | using namespace ::com::sun::star::lang; |
143 | using namespace ::com::sun::star::beans; |
144 | using namespace ::com::sun::star::frame; |
145 | using namespace ::com::sun::star::document; |
146 | using namespace ::com::sun::star::view; |
147 | using namespace ::com::sun::star::task; |
148 | using namespace ::com::sun::star::system; |
149 | using namespace ::com::sun::star::ui; |
150 | using namespace ::com::sun::star::ui::dialogs; |
151 | using namespace ::com::sun::star::container; |
152 | |
153 | ResMgr* desktop::Desktop::pResMgr = 0; |
154 | |
155 | namespace desktop |
156 | { |
157 | |
158 | static oslSignalHandler pSignalHandler = 0; |
159 | static sal_Bool _bCrashReporterEnabled = sal_True; |
160 | |
161 | namespace { |
162 | |
163 | void removeTree(OUString const & url) { |
164 | osl::Directory dir(url); |
165 | osl::FileBase::RC rc = dir.open(); |
166 | switch (rc) { |
167 | case osl::FileBase::E_None: |
168 | break; |
169 | case osl::FileBase::E_NOENT: |
170 | return; //TODO: SAL_WARN if recursive |
171 | default: |
172 | SAL_WARN("desktop.app" , "cannot open directory " << dir.getURL() << ": " << +rc); |
173 | return; |
174 | } |
175 | for (;;) { |
176 | osl::DirectoryItem i; |
177 | rc = dir.getNextItem(i, SAL_MAX_UINT32); |
178 | if (rc == osl::FileBase::E_NOENT) { |
179 | break; |
180 | } |
181 | if (rc != osl::FileBase::E_None) { |
182 | SAL_WARN( "desktop.app" , "cannot iterate directory " << dir.getURL() << ": " << +rc); |
183 | break; |
184 | } |
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( "desktop.app" , "cannot stat in directory " << dir.getURL() << ": " << +rc); |
191 | continue; |
192 | } |
193 | if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks |
194 | removeTree(stat.getFileURL()); |
195 | } else { |
196 | rc = osl::File::remove(stat.getFileURL()); |
197 | SAL_WARN_IF( |
198 | rc != osl::FileBase::E_None, "desktop.app" , |
199 | "cannot remove file " << stat.getFileURL() << ": " << +rc); |
200 | } |
201 | } |
202 | if (dir.isOpen()) { |
203 | rc = dir.close(); |
204 | SAL_WARN_IF( |
205 | rc != osl::FileBase::E_None, "desktop.app" , |
206 | "cannot close directory " << dir.getURL() << ": " << +rc); |
207 | } |
208 | rc = osl::Directory::remove(url); |
209 | SAL_WARN_IF( |
210 | rc != osl::FileBase::E_None, "desktop.app" , |
211 | "cannot remove directory " << url << ": " << +rc); |
212 | } |
213 | |
214 | // Remove any existing UserInstallation's extensions cache data remaining from |
215 | // old installations. This addresses at least two problems: |
216 | // |
217 | // For one, apparently due to the old share/prereg/bundled mechanism (disabled |
218 | // since 5c47e5f63a79a9e72ec4a100786b1bbf65137ed4 "fdo#51252 Disable copying |
219 | // share/prereg/bundled to avoid startup crashes"), the user/extensions/bundled |
220 | // cache could contain corrupted information (like a UNO component registered |
221 | // twice, which got changed from active to passive registration in one LO |
222 | // version, but the version of the corresponding bundled extension only |
223 | // incremented in a later LO version). |
224 | // |
225 | // For another, UserInstallations have been seen in the wild where no extensions |
226 | // were installed per-user (any longer), but user/uno_packages/cache/registry/ |
227 | // com.sun.star.comp.deployment.component.PackageRegistryBackend/*.rdb files |
228 | // contained data nevertheless. |
229 | // |
230 | // When a LO upgrade is detected (i.e., no user/extensions/buildid or one |
231 | // containing an old build ID), then user/extensions and |
232 | // user/uno_packages/cache/registry/ |
233 | // com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc are |
234 | // removed. That should prevent any problems starting the service manager due |
235 | // to old junk. Later on in Desktop::SynchronizeExtensionRepositories, the |
236 | // removed cache data is recreated. |
237 | // |
238 | // Multiple instances of soffice.bin can execute this code in parallel for a |
239 | // single UserInstallation, as it is called before OfficeIPCThread is set up. |
240 | // Therefore, any errors here only lead to SAL_WARNs. |
241 | // |
242 | // At least in theory, this function could be removed again once no |
243 | // UserInstallation can be poisoned by old junk any more. |
244 | bool cleanExtensionCache() { |
245 | OUString buildId( |
246 | "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version" ) ":buildid}" ); |
247 | rtl::Bootstrap::expandMacros(buildId); //TODO: detect failure |
248 | OUString extDir( |
249 | "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap" ) |
250 | ":UserInstallation}/user/extensions" ); |
251 | rtl::Bootstrap::expandMacros(extDir); //TODO: detect failure |
252 | OUString buildIdFile(extDir + "/buildid" ); |
253 | osl::File fr(buildIdFile); |
254 | osl::FileBase::RC rc = fr.open(osl_File_OpenFlag_Read); |
255 | switch (rc) { |
256 | case osl::FileBase::E_None: |
257 | { |
258 | rtl::ByteSequence s1; |
259 | rc = fr.readLine(s1); |
260 | osl::FileBase::RC rc2 = fr.close(); |
261 | SAL_WARN_IF( |
262 | rc2 != osl::FileBase::E_None, "desktop.app" , |
263 | "cannot close " << fr.getURL() << " after reading: " << +rc2); |
264 | if (rc != osl::FileBase::E_None) { |
265 | SAL_WARN( "desktop.app" , "cannot read from " << fr.getURL() << ": " << +rc); |
266 | break; |
267 | } |
268 | OUString s2( |
269 | reinterpret_cast< char const * >(s1.getConstArray()), |
270 | s1.getLength(), RTL_TEXTENCODING_ISO_8859_1); |
271 | // using ISO 8859-1 avoids any and all conversion errors; the |
272 | // content should only be a subset of ASCII, anyway |
273 | if (s2 == buildId) { |
274 | return false; |
275 | } |
276 | break; |
277 | } |
278 | case osl::FileBase::E_NOENT: |
279 | break; |
280 | default: |
281 | SAL_WARN( "desktop.app" , "cannot open " << fr.getURL() << " for reading: " << +rc); |
282 | break; |
283 | } |
284 | removeTree(extDir); |
285 | OUString userRcFile( |
286 | "$UNO_USER_PACKAGES_CACHE/registry/" |
287 | "com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc" ); |
288 | rtl::Bootstrap::expandMacros(userRcFile); //TODO: detect failure |
289 | rc = osl::File::remove(userRcFile); |
290 | SAL_WARN_IF( |
291 | rc != osl::FileBase::E_None && rc != osl::FileBase::E_NOENT, "desktop.app" , |
292 | "cannot remove file " << userRcFile << ": " << +rc); |
293 | rc = osl::Directory::createPath(extDir); |
294 | SAL_WARN_IF( |
295 | rc != osl::FileBase::E_None && rc != osl::FileBase::E_EXIST, "desktop.app" , |
296 | "cannot create path " << extDir << ": " << +rc); |
297 | osl::File fw(buildIdFile); |
298 | rc = fw.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); |
299 | if (rc != osl::FileBase::E_None) { |
300 | SAL_WARN( "desktop.app" , "cannot open " << fw.getURL() << " for writing: " << +rc); |
301 | return true; |
302 | } |
303 | OString buf(OUStringToOString(buildId, RTL_TEXTENCODING_UTF8)); |
304 | // using UTF-8 avoids almost all conversion errors (and buildid |
305 | // containing single surrogate halves should never happen, anyway); the |
306 | // content should only be a subset of ASCII, anyway |
307 | sal_uInt64 n = 0; |
308 | rc = fw.write(buf.getStr(), buf.getLength(), n); |
309 | SAL_WARN_IF( |
310 | (rc != osl::FileBase::E_None |
311 | || n != static_cast< sal_uInt32 >(buf.getLength())), |
312 | "desktop.app" , |
313 | "cannot write to " << fw.getURL() << ": " << +rc << ", " << n); |
314 | rc = fw.close(); |
315 | SAL_WARN_IF( |
316 | rc != osl::FileBase::E_None, "desktop.app" , |
317 | "cannot close " << fw.getURL() << " after writing: " << +rc); |
318 | return true; |
319 | } |
320 | |
321 | bool shouldLaunchQuickstart() |
322 | { |
323 | bool bQuickstart = Desktop::GetCommandLineArgs().IsQuickstart(); |
324 | if (!bQuickstart) |
325 | { |
326 | const SfxPoolItem* pItem=0; |
327 | SfxItemSet aQLSet(SFX_APP()->GetPool(), SID_ATTR_QUICKLAUNCHER, SID_ATTR_QUICKLAUNCHER); |
328 | SFX_APP()->GetOptions(aQLSet); |
329 | SfxItemState eState = aQLSet.GetItemState(SID_ATTR_QUICKLAUNCHER, sal_False, &pItem); |
330 | if (SFX_ITEM_SET == eState) |
331 | bQuickstart = ((SfxBoolItem*)pItem)->GetValue(); |
332 | } |
333 | return bQuickstart; |
334 | } |
335 | |
336 | void SetRestartState() { |
337 | try { |
338 | boost::shared_ptr< comphelper::ConfigurationChanges > batch( |
339 | comphelper::ConfigurationChanges::create()); |
340 | officecfg::Setup::Office::OfficeRestartInProgress::set(true, batch); |
341 | batch->commit(); |
342 | } catch (css::uno::Exception & e) { |
343 | SAL_WARN("desktop.app" , "ignoring Exception \"" << e.Message << "\"" ); |
344 | } |
345 | } |
346 | |
347 | void DoRestartActionsIfNecessary(bool quickstart) { |
348 | if (quickstart) { |
349 | try { |
350 | if (officecfg::Setup::Office::OfficeRestartInProgress::get()) { |
351 | boost::shared_ptr< comphelper::ConfigurationChanges > batch( |
352 | comphelper::ConfigurationChanges::create()); |
353 | officecfg::Setup::Office::OfficeRestartInProgress::set( |
354 | false, batch); |
355 | batch->commit(); |
356 | css::office::Quickstart::createStart( |
357 | comphelper::getProcessComponentContext(), |
358 | shouldLaunchQuickstart()); |
359 | } |
360 | } catch (css::uno::Exception & e) { |
361 | SAL_WARN( |
362 | "desktop.app" , "ignoring Exception \"" << e.Message << "\"" ); |
363 | } |
364 | } |
365 | } |
366 | |
367 | } |
368 | |
369 | // ---------------------------------------------------------------------------- |
370 | |
371 | ResMgr* Desktop::GetDesktopResManager() |
372 | { |
373 | if ( !Desktop::pResMgr ) |
374 | { |
375 | // Create desktop resource manager and bootstrap process |
376 | // was successful. Use default way to get language specific message. |
377 | if ( Application::IsInExecute() ) |
378 | Desktop::pResMgr = ResMgr::CreateResMgr("dkt" ); |
379 | |
380 | if ( !Desktop::pResMgr ) |
381 | { |
382 | // Use VCL to get the correct language specific message as we |
383 | // are in the bootstrap process and not able to get the installed |
384 | // language!! |
385 | OUString aUILocaleString = langselect::getEmergencyLocale(); |
386 | LanguageTag aLanguageTag( aUILocaleString); |
387 | //! ResMgr may modify the Locale for fallback! |
388 | Desktop::pResMgr = ResMgr::SearchCreateResMgr( "dkt" , aLanguageTag); |
389 | AllSettings as = GetSettings(); |
390 | as.SetUILanguageTag(aLanguageTag); |
391 | SetSettings(as); |
392 | } |
393 | } |
394 | |
395 | return Desktop::pResMgr; |
396 | } |
397 | |
398 | namespace { |
399 | |
400 | // ---------------------------------------------------------------------------- |
401 | // Get a message string securely. There is a fallback string if the resource |
402 | // is not available. |
403 | |
404 | OUString GetMsgString( |
405 | sal_uInt16 nId, const OUString& aFallbackMsg, |
406 | bool bAlwaysUseFallbackMsg = false ) |
407 | { |
408 | if ( !bAlwaysUseFallbackMsg ) |
409 | { |
410 | ResMgr* resMgr = Desktop::GetDesktopResManager(); |
411 | if ( resMgr ) |
412 | return ResId(nId, *resMgr).toString(); |
413 | } |
414 | return aFallbackMsg; |
415 | } |
416 | |
417 | OUString MakeStartupErrorMessage( |
418 | OUString const & aErrorMessage, bool bAlwaysUseFallbackMsg = false ) |
419 | { |
420 | OUStringBuffer aDiagnosticMessage( 100 ); |
421 | |
422 | aDiagnosticMessage.append( |
423 | GetMsgString( |
424 | STR_BOOTSTRAP_ERR_CANNOT_START, "The program cannot be started." , |
425 | bAlwaysUseFallbackMsg ) ); |
426 | |
427 | aDiagnosticMessage.appendAscii( "\n" ); |
428 | |
429 | aDiagnosticMessage.append( aErrorMessage ); |
430 | |
431 | return aDiagnosticMessage.makeStringAndClear(); |
432 | } |
433 | |
434 | OUString MakeStartupConfigAccessErrorMessage( OUString const & aInternalErrMsg ) |
435 | { |
436 | OUStringBuffer aDiagnosticMessage( 200 ); |
437 | |
438 | ResMgr* pResMgr = Desktop::GetDesktopResManager(); |
439 | if ( pResMgr ) |
440 | aDiagnosticMessage.append( ResId(STR_BOOTSTRAP_ERR_CFG_DATAACCESS, *pResMgr).toString() ); |
441 | else |
442 | aDiagnosticMessage.appendAscii( "The program cannot be started." ); |
443 | |
444 | if ( !aInternalErrMsg.isEmpty() ) |
445 | { |
446 | aDiagnosticMessage.appendAscii( "\n\n" ); |
447 | if ( pResMgr ) |
448 | aDiagnosticMessage.append( ResId(STR_INTERNAL_ERRMSG, *pResMgr).toString() ); |
449 | else |
450 | aDiagnosticMessage.appendAscii( "The following internal error has occurred:\n\n" ); |
451 | aDiagnosticMessage.append( aInternalErrMsg ); |
452 | } |
453 | |
454 | return aDiagnosticMessage.makeStringAndClear(); |
455 | } |
456 | |
457 | //============================================================================= |
458 | // shows a simple error box with the given message ... but exits from these process ! |
459 | // Fatal errors cant be solved by the process ... nor any recovery can help. |
460 | // Mostly the installation was damaged and must be repaired manually .. or by calling |
461 | // setup again. |
462 | // On the other side we must make sure that no further actions will be possible within |
463 | // the current office process ! No pipe requests, no menu/toolbar/shortuct actions |
464 | // are allowed. Otherwise we will force a "crash inside a crash". |
465 | // Thats why we have to use a special native message box here which does not use yield :-) |
466 | //============================================================================= |
467 | void FatalError(const OUString& sMessage) |
468 | { |
469 | OUString sProductKey = ::utl::Bootstrap::getProductKey(); |
470 | if ( sProductKey.isEmpty()) |
471 | { |
472 | osl_getExecutableFile( &sProductKey.pData ); |
473 | |
474 | ::sal_uInt32 nLastIndex = sProductKey.lastIndexOf('/'); |
475 | if ( nLastIndex > 0 ) |
476 | sProductKey = sProductKey.copy( nLastIndex+1 ); |
477 | } |
478 | |
479 | OUStringBuffer sTitle (128); |
480 | sTitle.append (sProductKey ); |
481 | sTitle.appendAscii (" - Fatal Error" ); |
482 | |
483 | Application::ShowNativeErrorBox (sTitle.makeStringAndClear (), sMessage); |
484 | _exit(EXITHELPER_FATAL_ERROR); |
485 | } |
486 | |
487 | static bool ShouldSuppressUI(const CommandLineArgs& rCmdLine) |
488 | { |
489 | return rCmdLine.IsInvisible() || |
490 | rCmdLine.IsHeadless() || |
491 | rCmdLine.IsQuickstart(); |
492 | } |
493 | |
494 | struct theCommandLineArgs : public rtl::Static< CommandLineArgs, theCommandLineArgs > {}; |
495 | |
496 | } |
497 | |
498 | CommandLineArgs& Desktop::GetCommandLineArgs() |
499 | { |
500 | return theCommandLineArgs::get(); |
501 | } |
502 | |
503 | namespace |
504 | { |
505 | struct BrandName |
506 | : public rtl::Static< OUString, BrandName > {}; |
507 | struct Version |
508 | : public rtl::Static< OUString, Version > {}; |
509 | struct AboutBoxVersion |
510 | : public rtl::Static< OUString, AboutBoxVersion > {}; |
511 | struct AboutBoxVersionSuffix |
512 | : public rtl::Static< OUString, AboutBoxVersionSuffix > {}; |
513 | struct OOOVendor |
514 | : public rtl::Static< OUString, OOOVendor > {}; |
515 | struct Extension |
516 | : public rtl::Static< OUString, Extension > {}; |
517 | } |
518 | |
519 | OUString ReplaceStringHookProc( const OUString& rStr ) |
520 | { |
521 | OUString sRet(rStr); |
522 | |
523 | if (sRet.indexOf("%PRODUCT" ) != -1 || sRet.indexOf("%ABOUTBOX" ) != -1) |
524 | { |
525 | OUString sBrandName = BrandName::get(); |
526 | OUString sVersion = Version::get(); |
527 | OUString sBuildId = utl::Bootstrap::getBuildIdData("development" ); |
528 | OUString sAboutBoxVersion = AboutBoxVersion::get(); |
529 | OUString sAboutBoxVersionSuffix = AboutBoxVersionSuffix::get(); |
530 | OUString sExtension = Extension::get(); |
531 | |
532 | if ( sBrandName.isEmpty() ) |
533 | { |
534 | sBrandName = utl::ConfigManager::getProductName(); |
535 | sVersion = utl::ConfigManager::getProductVersion(); |
536 | sAboutBoxVersion = utl::ConfigManager::getAboutBoxProductVersion(); |
537 | sAboutBoxVersionSuffix = utl::ConfigManager::getAboutBoxProductVersionSuffix(); |
538 | if ( sExtension.isEmpty() ) |
539 | { |
540 | sExtension = utl::ConfigManager::getProductExtension(); |
541 | } |
542 | } |
543 | |
544 | sRet = sRet.replaceAll( "%PRODUCTNAME" , sBrandName ); |
545 | sRet = sRet.replaceAll( "%PRODUCTVERSION" , sVersion ); |
546 | sRet = sRet.replaceAll( "%BUILDID" , sBuildId ); |
547 | sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSIONSUFFIX" , sAboutBoxVersionSuffix ); |
548 | sRet = sRet.replaceAll( "%ABOUTBOXPRODUCTVERSION" , sAboutBoxVersion ); |
549 | sRet = sRet.replaceAll( "%PRODUCTEXTENSION" , sExtension ); |
550 | } |
551 | |
552 | if ( sRet.indexOf( "%OOOVENDOR" ) != -1 ) |
553 | { |
554 | OUString sOOOVendor = OOOVendor::get(); |
555 | |
556 | if ( sOOOVendor.isEmpty() ) |
557 | { |
558 | sOOOVendor = utl::ConfigManager::getVendor(); |
559 | } |
560 | |
561 | sRet = sRet.replaceAll( "%OOOVENDOR" , sOOOVendor ); |
562 | } |
563 | |
564 | return sRet; |
565 | } |
566 | |
567 | Desktop::Desktop() |
568 | : m_bCleanedExtensionCache( false ) |
569 | , m_bServicesRegistered( false ) |
570 | , m_aBootstrapError( BE_OK ) |
571 | { |
572 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::Desktop::Desktop" ); |
573 | } |
574 | |
575 | Desktop::~Desktop() |
576 | { |
577 | #if ENABLE_TELEPATHY |
578 | TeleManager::finalize(); |
579 | #endif |
580 | } |
581 | |
582 | void Desktop::Init() |
583 | { |
584 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::Desktop::Init" ); |
585 | SetBootstrapStatus(BS_OK); |
586 | |
587 | m_bCleanedExtensionCache = cleanExtensionCache(); |
588 | |
589 | // We need to have service factory before going further, but see fdo#37195. |
590 | // Doing this will mmap common.rdb, making it not overwritable on windows, |
591 | // so this can't happen before the synchronization above. Lets rework this |
592 | // so that the above is called *from* CreateApplicationServiceManager or |
593 | // something to enforce this gotcha |
594 | try |
595 | { |
596 | InitApplicationServiceManager(); |
597 | } |
598 | catch (css::uno::Exception & e) |
599 | { |
600 | SetBootstrapError( BE_UNO_SERVICEMANAGER, e.Message ); |
601 | } |
602 | |
603 | if ( m_aBootstrapError == BE_OK ) |
604 | { |
605 | try |
606 | { |
607 | if (!langselect::prepareLocale()) |
608 | { |
609 | SetBootstrapError( BE_LANGUAGE_MISSING, OUString() ); |
610 | } |
611 | } |
612 | catch (css::uno::Exception & e) |
613 | { |
614 | SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message ); |
615 | } |
616 | } |
617 | |
618 | if ( true ) |
619 | { |
620 | const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); |
621 | |
622 | // start ipc thread only for non-remote offices |
623 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::OfficeIPCThread::EnableOfficeIPCThread" ); |
624 | OfficeIPCThread::Status aStatus = OfficeIPCThread::EnableOfficeIPCThread(); |
625 | if ( aStatus == OfficeIPCThread::IPC_STATUS_PIPE_ERROR ) |
626 | { |
627 | #if HAVE_FEATURE_MACOSX_SANDBOX |
628 | // In a sandboxed LO, on 10.8.2 at least, creating the |
629 | // Unix domain socket fails. Ignore that as hopefully |
630 | // people running a sandboxed LO won't attempt starting it |
631 | // from the command-line or otherwise in tricky ways, so |
632 | // the normal OS X mechanism that prevents multiple |
633 | // instances of an app from being started should work |
634 | // fine. I hope. |
635 | #elif defined ANDROID |
636 | // Ignore crack pipe errors on Android, too |
637 | #else |
638 | // Keep using this oddly named BE_PATHINFO_MISSING value |
639 | // for pipe-related errors on other platforms. Of course |
640 | // this crack with two (if not more) levels of our own |
641 | // error codes hiding the actual system error code is |
642 | // broken, but that is done all over the code, let's leave |
643 | // re-enginering that to another year. |
644 | SetBootstrapError( BE_PATHINFO_MISSING, OUString() ); |
645 | #endif |
646 | } |
647 | else if ( aStatus == OfficeIPCThread::IPC_STATUS_BOOTSTRAP_ERROR ) |
648 | { |
649 | SetBootstrapError( BE_PATHINFO_MISSING, OUString() ); |
650 | } |
651 | else if ( aStatus == OfficeIPCThread::IPC_STATUS_2ND_OFFICE ) |
652 | { |
653 | // 2nd office startup should terminate after sending cmdlineargs through pipe |
654 | SetBootstrapStatus(BS_TERMINATE); |
655 | } |
656 | else if ( !rCmdLineArgs.GetUnknown().isEmpty() |
657 | || rCmdLineArgs.IsHelp() || rCmdLineArgs.IsVersion() ) |
658 | { |
659 | // disable IPC thread in an instance that is just showing a help message |
660 | OfficeIPCThread::DisableOfficeIPCThread(); |
661 | } |
662 | pSignalHandler = osl_addSignalHandler(SalMainPipeExchangeSignal_impl, NULL); |
663 | } |
664 | } |
665 | |
666 | void Desktop::InitFinished() |
667 | { |
668 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::Desktop::InitFinished" ); |
669 | |
670 | CloseSplashScreen(); |
671 | } |
672 | |
673 | void Desktop::DeInit() |
674 | { |
675 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::Desktop::DeInit" ); |
676 | |
677 | try { |
678 | // instead of removing of the configManager just let it commit all the changes |
679 | SAL_INFO( "desktop.app" , "<- store config items" ); |
680 | utl::ConfigManager::storeConfigItems(); |
681 | FlushConfiguration(); |
682 | SAL_INFO( "desktop.app" , "<- store config items" ); |
683 | |
684 | // close splashscreen if it's still open |
685 | CloseSplashScreen(); |
686 | Reference< XComponent >( |
687 | comphelper::getProcessComponentContext(), UNO_QUERY_THROW )-> |
688 | dispose(); |
689 | // nobody should get a destroyed service factory... |
690 | ::comphelper::setProcessServiceFactory( NULL ); |
691 | |
692 | // clear lockfile |
693 | m_xLockfile.reset(); |
694 | |
695 | OfficeIPCThread::DisableOfficeIPCThread(); |
696 | if( pSignalHandler ) |
697 | osl_removeSignalHandler( pSignalHandler ); |
698 | } catch (const RuntimeException&) { |
699 | // someone threw an exception during shutdown |
700 | // this will leave some garbage behind.. |
701 | } |
702 | |
703 | SAL_INFO( "desktop.app" , "FINISHED WITH Destop::DeInit" ); |
704 | } |
705 | |
706 | sal_Bool Desktop::QueryExit() |
707 | { |
708 | try |
709 | { |
710 | SAL_INFO( "desktop.app" , "<- store config items" ); |
711 | utl::ConfigManager::storeConfigItems(); |
712 | SAL_INFO( "desktop.app" , "<- store config items" ); |
713 | } |
714 | catch ( const RuntimeException& ) |
715 | { |
716 | } |
717 | |
718 | const sal_Char SUSPEND_QUICKSTARTVETO[] = "SuspendQuickstartVeto" ; |
719 | |
720 | Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); |
721 | Reference< XPropertySet > xPropertySet(xDesktop, UNO_QUERY_THROW); |
722 | xPropertySet->setPropertyValue( OUString(SUSPEND_QUICKSTARTVETO ), Any((sal_Bool)sal_True) ); |
723 | |
724 | sal_Bool bExit = xDesktop->terminate(); |
725 | |
726 | if ( !bExit ) |
727 | { |
728 | xPropertySet->setPropertyValue( OUString(SUSPEND_QUICKSTARTVETO ), Any((sal_Bool)sal_False) ); |
729 | } |
730 | else |
731 | { |
732 | FlushConfiguration(); |
733 | try |
734 | { |
735 | // it is no problem to call DisableOfficeIPCThread() more than once |
736 | // it also looks to be threadsafe |
737 | OfficeIPCThread::DisableOfficeIPCThread(); |
738 | } |
739 | catch ( const RuntimeException& ) |
740 | { |
741 | } |
742 | |
743 | m_xLockfile.reset(); |
744 | |
745 | } |
746 | |
747 | return bExit; |
748 | } |
749 | |
750 | void Desktop::HandleBootstrapPathErrors( ::utl::Bootstrap::Status aBootstrapStatus, const OUString& aDiagnosticMessage ) |
751 | { |
752 | if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK ) |
753 | { |
754 | OUString aProductKey; |
755 | OUString aTemp; |
756 | |
757 | osl_getExecutableFile( &aProductKey.pData ); |
758 | sal_uInt32 lastIndex = aProductKey.lastIndexOf('/'); |
759 | if ( lastIndex > 0 ) |
760 | aProductKey = aProductKey.copy( lastIndex+1 ); |
761 | |
762 | aTemp = ::utl::Bootstrap::getProductKey( aProductKey ); |
763 | if ( !aTemp.isEmpty() ) |
764 | aProductKey = aTemp; |
765 | |
766 | OUString const aMessage(aDiagnosticMessage + "\n" ); |
767 | |
768 | ErrorBox aBootstrapFailedBox( NULL, WB_OK, aMessage ); |
769 | aBootstrapFailedBox.SetText( aProductKey ); |
770 | aBootstrapFailedBox.Execute(); |
771 | } |
772 | } |
773 | |
774 | // Create a error message depending on bootstrap failure code and an optional file url |
775 | OUString Desktop::CreateErrorMsgString( |
776 | utl::Bootstrap::FailureCode nFailureCode, |
777 | const OUString& aFileURL ) |
778 | { |
779 | OUString aMsg; |
780 | OUString aFilePath; |
781 | sal_Bool bFileInfo = sal_True; |
782 | |
783 | switch ( nFailureCode ) |
784 | { |
785 | /// the shared installation directory could not be located |
786 | case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY: |
787 | { |
788 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_PATH_INVALID, |
789 | OUString( "The installation path is not available." ) ); |
790 | bFileInfo = sal_False; |
791 | } |
792 | break; |
793 | |
794 | /// the bootstrap INI file could not be found or read |
795 | case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE: |
796 | { |
797 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING, |
798 | OUString( "The configuration file \"$1\" is missing." ) ); |
799 | } |
800 | break; |
801 | |
802 | /// the bootstrap INI is missing a required entry |
803 | /// the bootstrap INI contains invalid data |
804 | case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: |
805 | case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY: |
806 | { |
807 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_CORRUPT, |
808 | OUString( "The configuration file \"$1\" is corrupt." ) ); |
809 | } |
810 | break; |
811 | |
812 | /// the version locator INI file could not be found or read |
813 | case ::utl::Bootstrap::MISSING_VERSION_FILE: |
814 | { |
815 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_FILE_MISSING, |
816 | OUString( "The configuration file \"$1\" is missing." ) ); |
817 | } |
818 | break; |
819 | |
820 | /// the version locator INI has no entry for this version |
821 | case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY: |
822 | { |
823 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_SUPPORT, |
824 | OUString( "The main configuration file \"$1\" does not support the current version." ) ); |
825 | } |
826 | break; |
827 | |
828 | /// the user installation directory does not exist |
829 | case ::utl::Bootstrap::MISSING_USER_DIRECTORY: |
830 | { |
831 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_DIR_MISSING, |
832 | OUString( "The configuration directory \"$1\" is missing." ) ); |
833 | } |
834 | break; |
835 | |
836 | /// some bootstrap data was invalid in unexpected ways |
837 | case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA: |
838 | { |
839 | aMsg = GetMsgString( STR_BOOTSTRAP_ERR_INTERNAL, |
840 | OUString( "An internal failure occurred." ) ); |
841 | bFileInfo = sal_False; |
842 | } |
843 | break; |
844 | |
845 | case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY: |
846 | { |
847 | // This needs to be improved, see #i67575#: |
848 | aMsg = "Invalid version file entry" ; |
849 | bFileInfo = sal_False; |
850 | } |
851 | break; |
852 | |
853 | case ::utl::Bootstrap::NO_FAILURE: |
854 | { |
855 | OSL_ASSERT(false); |
856 | } |
857 | break; |
858 | } |
859 | |
860 | if ( bFileInfo ) |
861 | { |
862 | OUString aMsgString( aMsg ); |
863 | |
864 | osl::File::getSystemPathFromFileURL( aFileURL, aFilePath ); |
865 | |
866 | aMsgString = aMsgString.replaceFirst( "$1" , aFilePath ); |
867 | aMsg = aMsgString; |
868 | } |
869 | |
870 | return MakeStartupErrorMessage( aMsg ); |
871 | } |
872 | |
873 | void Desktop::HandleBootstrapErrors( |
874 | BootstrapError aBootstrapError, OUString const & aErrorMessage ) |
875 | { |
876 | if ( aBootstrapError == BE_PATHINFO_MISSING ) |
877 | { |
878 | OUString aErrorMsg; |
879 | OUString aBuffer; |
880 | utl::Bootstrap::Status aBootstrapStatus; |
881 | utl::Bootstrap::FailureCode nFailureCode; |
882 | |
883 | aBootstrapStatus = ::utl::Bootstrap::checkBootstrapStatus( aBuffer, nFailureCode ); |
884 | if ( aBootstrapStatus != ::utl::Bootstrap::DATA_OK ) |
885 | { |
886 | switch ( nFailureCode ) |
887 | { |
888 | case ::utl::Bootstrap::MISSING_INSTALL_DIRECTORY: |
889 | case ::utl::Bootstrap::INVALID_BOOTSTRAP_DATA: |
890 | { |
891 | aErrorMsg = CreateErrorMsgString( nFailureCode, OUString() ); |
892 | } |
893 | break; |
894 | |
895 | /// the bootstrap INI file could not be found or read |
896 | /// the bootstrap INI is missing a required entry |
897 | /// the bootstrap INI contains invalid data |
898 | case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY: |
899 | case ::utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY: |
900 | case ::utl::Bootstrap::MISSING_BOOTSTRAP_FILE: |
901 | { |
902 | OUString aBootstrapFileURL; |
903 | |
904 | utl::Bootstrap::locateBootstrapFile( aBootstrapFileURL ); |
905 | aErrorMsg = CreateErrorMsgString( nFailureCode, aBootstrapFileURL ); |
906 | } |
907 | break; |
908 | |
909 | /// the version locator INI file could not be found or read |
910 | /// the version locator INI has no entry for this version |
911 | /// the version locator INI entry is not a valid directory URL |
912 | case ::utl::Bootstrap::INVALID_VERSION_FILE_ENTRY: |
913 | case ::utl::Bootstrap::MISSING_VERSION_FILE_ENTRY: |
914 | case ::utl::Bootstrap::MISSING_VERSION_FILE: |
915 | { |
916 | OUString aVersionFileURL; |
917 | |
918 | utl::Bootstrap::locateVersionFile( aVersionFileURL ); |
919 | aErrorMsg = CreateErrorMsgString( nFailureCode, aVersionFileURL ); |
920 | } |
921 | break; |
922 | |
923 | /// the user installation directory does not exist |
924 | case ::utl::Bootstrap::MISSING_USER_DIRECTORY: |
925 | { |
926 | OUString aUserInstallationURL; |
927 | |
928 | utl::Bootstrap::locateUserInstallation( aUserInstallationURL ); |
929 | aErrorMsg = CreateErrorMsgString( nFailureCode, aUserInstallationURL ); |
930 | } |
931 | break; |
932 | |
933 | case ::utl::Bootstrap::NO_FAILURE: |
934 | { |
935 | OSL_ASSERT(false); |
936 | } |
937 | break; |
938 | } |
939 | |
940 | HandleBootstrapPathErrors( aBootstrapStatus, aErrorMsg ); |
941 | } |
942 | } |
943 | else if ( aBootstrapError == BE_UNO_SERVICEMANAGER || aBootstrapError == BE_UNO_SERVICE_CONFIG_MISSING ) |
944 | { |
945 | // Uno service manager is not available. VCL needs a uno service manager to display a message box!!! |
946 | // Currently we are not able to display a message box with a service manager due to this limitations inside VCL. |
947 | |
948 | // When UNO is not properly initialized, all kinds of things can fail |
949 | // and cause the process to crash (e.g., a call to GetMsgString may |
950 | // crash when somewhere deep within that call Any::operator <= is used |
951 | // with a PropertyValue, and no binary UNO type description for |
952 | // PropertyValue is available). To give the user a hint even if |
953 | // generating and displaying a message box below crashes, print a |
954 | // hard-coded message on stderr first: |
955 | std::cerr |
956 | << "The application cannot be started.\n" |
957 | // STR_BOOTSTRAP_ERR_CANNOT_START |
958 | << (aBootstrapError == BE_UNO_SERVICEMANAGER |
959 | ? "The component manager is not available.\n" |
960 | // STR_BOOTSTRAP_ERR_NO_SERVICE |
961 | : "The configuration service is not available.\n" ); |
962 | // STR_BOOTSTRAP_ERR_NO_CFG_SERVICE |
963 | if ( !aErrorMessage.isEmpty() ) |
964 | { |
965 | std::cerr << "(\"" << aErrorMessage << "\")\n" ; |
966 | } |
967 | |
968 | // First sentence. We cannot bootstrap office further! |
969 | OUString aMessage; |
970 | OUStringBuffer aDiagnosticMessage( 100 ); |
971 | |
972 | OUString aErrorMsg; |
973 | |
974 | if ( aBootstrapError == BE_UNO_SERVICEMANAGER ) |
975 | aErrorMsg = "The service manager is not available." ; |
976 | else |
977 | aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_NO_CFG_SERVICE, |
978 | OUString( "The configuration service is not available." ) ); |
979 | |
980 | aDiagnosticMessage.append( aErrorMsg ); |
981 | aDiagnosticMessage.appendAscii( "\n" ); |
982 | if ( !aErrorMessage.isEmpty() ) |
983 | { |
984 | aDiagnosticMessage.appendAscii( "(\"" ); |
985 | aDiagnosticMessage.append( aErrorMessage ); |
986 | aDiagnosticMessage.appendAscii( "\")\n" ); |
987 | } |
988 | |
989 | // Due to the fact the we haven't a backup applicat.rdb file anymore it is not possible to |
990 | // repair the installation with the setup executable besides the office executable. Now |
991 | // we have to ask the user to start the setup on CD/installation directory manually!! |
992 | OUString aStartSetupManually( GetMsgString( |
993 | STR_ASK_START_SETUP_MANUALLY, |
994 | OUString( "Start setup application to repair the installation from CD, or the folder containing the installation packages." ), |
995 | aBootstrapError == BE_UNO_SERVICEMANAGER ) ); |
996 | |
997 | aDiagnosticMessage.append( aStartSetupManually ); |
998 | aMessage = MakeStartupErrorMessage( |
999 | aDiagnosticMessage.makeStringAndClear(), |
1000 | aBootstrapError == BE_UNO_SERVICEMANAGER ); |
1001 | |
1002 | FatalError( aMessage); |
1003 | } |
1004 | else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN ) |
1005 | { |
1006 | OUString msg( |
1007 | GetMsgString( |
1008 | STR_CONFIG_ERR_ACCESS_GENERAL, |
1009 | ("A general error occurred while accessing your central" |
1010 | " configuration." ))); |
1011 | if (!aErrorMessage.isEmpty()) { |
1012 | msg += "\n(\"" + aErrorMessage + "\")" ; |
1013 | } |
1014 | FatalError(MakeStartupErrorMessage(msg)); |
1015 | } |
1016 | else if ( aBootstrapError == BE_USERINSTALL_FAILED ) |
1017 | { |
1018 | OUString aMessage; |
1019 | OUStringBuffer aDiagnosticMessage( 100 ); |
1020 | OUString aErrorMsg; |
1021 | aErrorMsg = GetMsgString( STR_BOOTSTRAP_ERR_USERINSTALL_FAILED, |
1022 | OUString( "User installation could not be completed" ) ); |
1023 | aDiagnosticMessage.append( aErrorMsg ); |
1024 | aMessage = MakeStartupErrorMessage( aDiagnosticMessage.makeStringAndClear() ); |
1025 | FatalError(aMessage); |
1026 | } |
1027 | else if ( aBootstrapError == BE_LANGUAGE_MISSING ) |
1028 | { |
1029 | OUString aMessage; |
1030 | OUStringBuffer aDiagnosticMessage( 100 ); |
1031 | OUString aErrorMsg; |
1032 | aErrorMsg = GetMsgString( |
1033 | //@@@ FIXME: should use an own resource string => #i36213# |
1034 | STR_BOOTSTRAP_ERR_LANGUAGE_MISSING, |
1035 | OUString( "Language could not be determined." ) ); |
1036 | aDiagnosticMessage.append( aErrorMsg ); |
1037 | aMessage = MakeStartupErrorMessage( |
1038 | aDiagnosticMessage.makeStringAndClear() ); |
1039 | FatalError(aMessage); |
1040 | } |
1041 | else if (( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) || |
1042 | ( aBootstrapError == BE_USERINSTALL_NOWRITEACCESS )) |
1043 | { |
1044 | OUString aUserInstallationURL; |
1045 | OUString aUserInstallationPath; |
1046 | OUString aMessage; |
1047 | OUString aErrorMsg; |
1048 | OUStringBuffer aDiagnosticMessage( 100 ); |
1049 | |
1050 | utl::Bootstrap::locateUserInstallation( aUserInstallationURL ); |
1051 | |
1052 | if ( aBootstrapError == BE_USERINSTALL_NOTENOUGHDISKSPACE ) |
1053 | aErrorMsg = GetMsgString( |
1054 | STR_BOOSTRAP_ERR_NOTENOUGHDISKSPACE, |
1055 | OUString( "User installation could not be completed due to insufficient free disk space." ) ); |
1056 | else |
1057 | aErrorMsg = GetMsgString( |
1058 | STR_BOOSTRAP_ERR_NOACCESSRIGHTS, |
1059 | OUString( "User installation could not be processed due to missing access rights." ) ); |
1060 | |
1061 | osl::File::getSystemPathFromFileURL( aUserInstallationURL, aUserInstallationPath ); |
1062 | |
1063 | aDiagnosticMessage.append( aErrorMsg ); |
1064 | aDiagnosticMessage.append( aUserInstallationPath ); |
1065 | aMessage = MakeStartupErrorMessage( |
1066 | aDiagnosticMessage.makeStringAndClear() ); |
1067 | FatalError(aMessage); |
1068 | } |
1069 | |
1070 | return; |
1071 | } |
1072 | |
1073 | |
1074 | void Desktop::retrieveCrashReporterState() |
1075 | { |
1076 | _bCrashReporterEnabled |
1077 | = officecfg::Office::Recovery::CrashReporter::Enabled::get(); |
1078 | } |
1079 | |
1080 | sal_Bool Desktop::isUIOnSessionShutdownAllowed() |
1081 | { |
1082 | return officecfg::Office::Recovery::SessionShutdown::DocumentStoreUIEnabled |
1083 | ::get(); |
1084 | } |
1085 | |
1086 | //----------------------------------------------- |
1087 | /** @short check if crash reporter feature is enabled or |
1088 | disabled. |
1089 | */ |
1090 | sal_Bool Desktop::isCrashReporterEnabled() |
1091 | { |
1092 | return _bCrashReporterEnabled; |
1093 | } |
1094 | |
1095 | //----------------------------------------------- |
1096 | /** @short check if recovery must be started or not. |
1097 | |
1098 | @param bCrashed [boolean ... out!] |
1099 | the office crashed last times. |
1100 | But may be there are no recovery data. |
1101 | Useful to trigger the error report tool without |
1102 | showing the recovery UI. |
1103 | |
1104 | @param bRecoveryDataExists [boolean ... out!] |
1105 | there exists some recovery data. |
1106 | |
1107 | @param bSessionDataExists [boolean ... out!] |
1108 | there exists some session data. |
1109 | Because the user may be logged out last time from it's |
1110 | unix session... |
1111 | */ |
1112 | void impl_checkRecoveryState(sal_Bool& bCrashed , |
1113 | sal_Bool& bRecoveryDataExists, |
1114 | sal_Bool& bSessionDataExists ) |
1115 | { |
1116 | bCrashed = officecfg::Office::Recovery::RecoveryInfo::Crashed::get(); |
1117 | bool elements = officecfg::Office::Recovery::RecoveryList::get()-> |
1118 | hasElements(); |
1119 | bool session |
1120 | = officecfg::Office::Recovery::RecoveryInfo::SessionData::get(); |
1121 | bRecoveryDataExists = elements && !session; |
1122 | bSessionDataExists = elements && session; |
1123 | } |
1124 | |
1125 | //----------------------------------------------- |
1126 | /* @short start the recovery wizard. |
1127 | |
1128 | @param bEmergencySave |
1129 | differs between EMERGENCY_SAVE and RECOVERY |
1130 | */ |
1131 | sal_Bool impl_callRecoveryUI(sal_Bool bEmergencySave , |
1132 | sal_Bool bCrashed , |
1133 | sal_Bool bExistsRecoveryData) |
1134 | { |
1135 | static OUString SERVICENAME_RECOVERYUI("com.sun.star.comp.svx.RecoveryUI" ); |
1136 | static OUString COMMAND_EMERGENCYSAVE("vnd.sun.star.autorecovery:/doEmergencySave" ); |
1137 | static OUString COMMAND_RECOVERY("vnd.sun.star.autorecovery:/doAutoRecovery" ); |
1138 | static OUString COMMAND_CRASHREPORT("vnd.sun.star.autorecovery:/doCrashReport" ); |
1139 | |
1140 | css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
1141 | |
1142 | Reference< css::frame::XSynchronousDispatch > xRecoveryUI( |
1143 | xContext->getServiceManager()->createInstanceWithContext(SERVICENAME_RECOVERYUI, xContext), |
1144 | css::uno::UNO_QUERY_THROW); |
1145 | |
1146 | Reference< css::util::XURLTransformer > xURLParser = |
1147 | css::util::URLTransformer::create(::comphelper::getProcessComponentContext()); |
1148 | |
1149 | css::util::URL aURL; |
1150 | if (bEmergencySave) |
1151 | aURL.Complete = COMMAND_EMERGENCYSAVE; |
1152 | else if (bExistsRecoveryData) |
1153 | aURL.Complete = COMMAND_RECOVERY; |
1154 | else if (bCrashed && Desktop::isCrashReporterEnabled() ) |
1155 | aURL.Complete = COMMAND_CRASHREPORT; |
1156 | else |
1157 | return false; |
1158 | |
1159 | xURLParser->parseStrict(aURL); |
1160 | |
1161 | css::uno::Any aRet = xRecoveryUI->dispatchWithReturnValue(aURL, css::uno::Sequence< css::beans::PropertyValue >()); |
1162 | sal_Bool bRet = sal_False; |
1163 | aRet >>= bRet; |
1164 | return !bEmergencySave || bRet; |
1165 | } |
1166 | |
1167 | /* |
1168 | * Save all open documents so they will be reopened |
1169 | * the next time the application is started |
1170 | * |
1171 | * returns sal_True if at least one document could be saved... |
1172 | * |
1173 | */ |
1174 | |
1175 | sal_Bool Desktop::SaveTasks() |
1176 | { |
1177 | return impl_callRecoveryUI( |
1178 | sal_True , // sal_True => force emergency save |
1179 | sal_False, // 2. and 3. param not used if 1. = true! |
1180 | sal_False); |
1181 | } |
1182 | |
1183 | namespace { |
1184 | |
1185 | void restartOnMac(bool passArguments) { |
1186 | #if defined MACOSX |
1187 | OfficeIPCThread::DisableOfficeIPCThread(); |
1188 | #if HAVE_FEATURE_MACOSX_SANDBOX |
1189 | (void) passArguments; // avoid warnings |
1190 | ResMgr *resMgr = Desktop::GetDesktopResManager(); |
1191 | OUString aMessage = ResId(STR_LO_MUST_BE_RESTARTED, *resMgr).toString(); |
1192 | |
1193 | ErrorBox aRestartBox( NULL, WB_OK, aMessage ); |
1194 | aRestartBox.Execute(); |
1195 | #else |
1196 | OUString execUrl; |
1197 | OSL_VERIFY(osl_getExecutableFile(&execUrl.pData) == osl_Process_E_None); |
1198 | OUString execPath; |
1199 | OString execPath8; |
1200 | if ((osl::FileBase::getSystemPathFromFileURL(execUrl, execPath) |
1201 | != osl::FileBase::E_None) || |
1202 | !execPath.convertToString( |
1203 | &execPath8, osl_getThreadTextEncoding(), |
1204 | (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | |
1205 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) |
1206 | { |
1207 | std::abort(); |
1208 | } |
1209 | std::vector< OString > args; |
1210 | args.push_back(execPath8); |
1211 | bool wait = false; |
1212 | if (passArguments) { |
1213 | sal_uInt32 n = osl_getCommandArgCount(); |
1214 | for (sal_uInt32 i = 0; i < n; ++i) { |
1215 | OUString arg; |
1216 | OSL_VERIFY(osl_getCommandArg(i, &arg.pData) == osl_Process_E_None); |
1217 | if (arg.match("--accept=" )) { |
1218 | wait = true; |
1219 | } |
1220 | OString arg8; |
1221 | if (!arg.convertToString( |
1222 | &arg8, osl_getThreadTextEncoding(), |
1223 | (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | |
1224 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) |
1225 | { |
1226 | std::abort(); |
1227 | } |
1228 | args.push_back(arg8); |
1229 | } |
1230 | } |
1231 | std::vector< char const * > argPtrs; |
1232 | for (std::vector< OString >::iterator i(args.begin()); i != args.end(); |
1233 | ++i) |
1234 | { |
1235 | argPtrs.push_back(i->getStr()); |
1236 | } |
1237 | argPtrs.push_back(0); |
1238 | execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0])); |
1239 | if (errno == ENOTSUP) { // happens when multithreaded on OS X < 10.6 |
1240 | pid_t pid = fork(); |
1241 | if (pid == 0) { |
1242 | execv(execPath8.getStr(), const_cast< char ** >(&argPtrs[0])); |
1243 | } else if (pid > 0) { |
1244 | // Two simultaneously running soffice processes lead to two dock |
1245 | // icons, so avoid waiting here unless it must be assumed that the |
1246 | // process invoking soffice itself wants to wait for soffice to |
1247 | // finish: |
1248 | if (!wait) { |
1249 | return; |
1250 | } |
1251 | int stat; |
1252 | if (waitpid(pid, &stat, 0) == pid && WIFEXITED(stat)) { |
1253 | _exit(WEXITSTATUS(stat)); |
1254 | } |
1255 | } |
1256 | } |
1257 | std::abort(); |
1258 | #endif |
1259 | #else |
1260 | (void) passArguments; // avoid warnings |
1261 | #endif |
1262 | } |
1263 | |
1264 | } |
1265 | |
1266 | sal_uInt16 Desktop::Exception(sal_uInt16 nError) |
1267 | { |
1268 | // protect against recursive calls |
1269 | static sal_Bool bInException = sal_False; |
1270 | |
1271 | sal_uInt16 nOldMode = Application::GetSystemWindowMode(); |
1272 | Application::SetSystemWindowMode( nOldMode & ~SYSTEMWINDOW_MODE_NOAUTOMODE ); |
1273 | Application::SetDefDialogParent( NULL ); |
1274 | |
1275 | if ( bInException ) |
1276 | { |
1277 | OUString aDoubleExceptionString; |
1278 | Application::Abort( aDoubleExceptionString ); |
1279 | } |
1280 | |
1281 | bInException = sal_True; |
1282 | const CommandLineArgs& rArgs = GetCommandLineArgs(); |
1283 | |
1284 | // save all modified documents ... if it's allowed doing so. |
1285 | sal_Bool bRestart = sal_False; |
1286 | sal_Bool bAllowRecoveryAndSessionManagement = ( |
1287 | ( !rArgs.IsNoRestore() ) && // some use cases of office must work without recovery |
1288 | ( !rArgs.IsHeadless() ) && |
1289 | (( nError & EXC_MAJORTYPE ) != EXC_DISPLAY ) && // recovery cant work without UI ... but UI layer seams to be the reason for this crash |
1290 | ( Application::IsInExecute() ) // crashes during startup and shutdown should be ignored (they indicates a corrupt installation ...) |
1291 | ); |
1292 | if ( bAllowRecoveryAndSessionManagement ) |
1293 | bRestart = SaveTasks(); |
1294 | |
1295 | FlushConfiguration(); |
1296 | |
1297 | switch( nError & EXC_MAJORTYPE ) |
1298 | { |
1299 | case EXC_RSCNOTLOADED: |
1300 | { |
1301 | OUString aResExceptionString; |
1302 | Application::Abort( aResExceptionString ); |
1303 | break; |
1304 | } |
1305 | |
1306 | default: |
1307 | { |
1308 | m_xLockfile.reset(); |
1309 | |
1310 | if( bRestart ) |
1311 | { |
1312 | OfficeIPCThread::DisableOfficeIPCThread(); |
1313 | if( pSignalHandler ) |
1314 | osl_removeSignalHandler( pSignalHandler ); |
1315 | |
1316 | restartOnMac(false); |
1317 | if ( m_rSplashScreen.is() ) |
1318 | m_rSplashScreen->reset(); |
1319 | |
1320 | _exit( EXITHELPER_CRASH_WITH_RESTART ); |
1321 | } |
1322 | else |
1323 | { |
1324 | Application::Abort( OUString() ); |
1325 | } |
1326 | |
1327 | break; |
1328 | } |
1329 | } |
1330 | |
1331 | OSL_ASSERT(false); // unreachable |
1332 | return 0; |
1333 | } |
1334 | |
1335 | void Desktop::AppEvent( const ApplicationEvent& rAppEvent ) |
1336 | { |
1337 | HandleAppEvent( rAppEvent ); |
1338 | } |
1339 | |
1340 | |
1341 | struct ExecuteGlobals |
1342 | { |
1343 | Reference < css::document::XEventListener > xGlobalBroadcaster; |
1344 | sal_Bool bRestartRequested; |
1345 | sal_Bool bUseSystemFileDialog; |
1346 | std::auto_ptr<SvtLanguageOptions> pLanguageOptions; |
1347 | std::auto_ptr<SvtPathOptions> pPathOptions; |
1348 | |
1349 | ExecuteGlobals() |
1350 | : bRestartRequested( sal_False ) |
1351 | , bUseSystemFileDialog( sal_True ) |
1352 | {} |
1353 | }; |
1354 | |
1355 | static ExecuteGlobals* pExecGlobals = NULL; |
1356 | |
1357 | int Desktop::Main() |
1358 | { |
1359 | pExecGlobals = new ExecuteGlobals(); |
1360 | |
1361 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::Desktop::Main" ); |
1362 | |
1363 | // Remember current context object |
1364 | com::sun::star::uno::ContextLayer layer( |
1365 | com::sun::star::uno::getCurrentContext() ); |
1366 | |
1367 | if ( m_aBootstrapError != BE_OK ) |
1368 | { |
1369 | HandleBootstrapErrors( m_aBootstrapError, m_aBootstrapErrorMessage ); |
1370 | return EXIT_FAILURE; |
1371 | } |
1372 | |
1373 | BootstrapStatus eStatus = GetBootstrapStatus(); |
1374 | if (eStatus == BS_TERMINATE) { |
1375 | return EXIT_SUCCESS; |
1376 | } |
1377 | |
1378 | // Detect desktop environment - need to do this as early as possible |
1379 | com::sun::star::uno::setCurrentContext( |
1380 | new DesktopContext( com::sun::star::uno::getCurrentContext() ) ); |
1381 | |
1382 | CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); |
1383 | |
1384 | #if HAVE_FEATURE_DESKTOP |
1385 | OUString aUnknown( rCmdLineArgs.GetUnknown() ); |
1386 | if ( !aUnknown.isEmpty() ) |
1387 | { |
1388 | displayCmdlineHelp( aUnknown ); |
1389 | return EXIT_FAILURE; |
1390 | } |
1391 | if ( rCmdLineArgs.IsHelp() ) |
1392 | { |
1393 | displayCmdlineHelp( OUString() ); |
1394 | return EXIT_SUCCESS; |
1395 | } |
1396 | if ( rCmdLineArgs.IsVersion() ) |
1397 | { |
1398 | displayVersion(); |
1399 | return EXIT_SUCCESS; |
1400 | } |
1401 | #endif |
1402 | // setup configuration error handling |
1403 | ConfigurationErrorHandler aConfigErrHandler; |
1404 | if (!ShouldSuppressUI(rCmdLineArgs)) |
1405 | aConfigErrHandler.activate(); |
1406 | |
1407 | ResMgr::SetReadStringHook( ReplaceStringHookProc ); |
1408 | |
1409 | // Startup screen |
1410 | SAL_INFO( "desktop.app" , "desktop (lo119109) Desktop::Main { OpenSplashScreen" ); |
1411 | OpenSplashScreen(); |
1412 | SAL_INFO( "desktop.app" , "desktop (lo119109) Desktop::Main } OpenSplashScreen" ); |
1413 | |
1414 | SetSplashScreenProgress(10); |
1415 | |
1416 | userinstall::Status inst_fin = userinstall::finalize(); |
1417 | if (inst_fin != userinstall::EXISTED && inst_fin != userinstall::CREATED) |
1418 | { |
1419 | SAL_WARN( "desktop.app" , "userinstall failed" ); |
1420 | if ( inst_fin == userinstall::ERROR_NO_SPACE ) |
1421 | HandleBootstrapErrors( |
1422 | BE_USERINSTALL_NOTENOUGHDISKSPACE, OUString() ); |
1423 | else if ( inst_fin == userinstall::ERROR_CANT_WRITE ) |
1424 | HandleBootstrapErrors( BE_USERINSTALL_NOWRITEACCESS, OUString() ); |
1425 | else |
1426 | HandleBootstrapErrors( BE_USERINSTALL_FAILED, OUString() ); |
1427 | return EXIT_FAILURE; |
1428 | } |
1429 | // refresh path information |
1430 | utl::Bootstrap::reloadData(); |
1431 | SetSplashScreenProgress(20); |
1432 | |
1433 | Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
1434 | |
1435 | Reference< XRestartManager > xRestartManager( OfficeRestartManager::get(xContext) ); |
1436 | |
1437 | Reference< XDesktop2 > xDesktop; |
1438 | try |
1439 | { |
1440 | RegisterServices(xContext); |
1441 | |
1442 | SetSplashScreenProgress(25); |
1443 | |
1444 | // check user installation directory for lockfile so we can be sure |
1445 | // there is no other instance using our data files from a remote host |
1446 | SAL_INFO( "desktop.app" , "desktop (lo119109) Desktop::Main -> Lockfile" ); |
1447 | m_xLockfile.reset(new Lockfile); |
1448 | |
1449 | #if HAVE_FEATURE_DESKTOP |
1450 | if ( !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsInvisible() && |
1451 | !rCmdLineArgs.IsNoLockcheck() && !m_xLockfile->check( Lockfile_execWarning )) |
1452 | { |
1453 | // Lockfile exists, and user clicked 'no' |
1454 | return EXIT_FAILURE; |
1455 | } |
1456 | SAL_INFO( "desktop.app" , "desktop (lo119109) Desktop::Main <- Lockfile" ); |
1457 | |
1458 | // check if accessibility is enabled but not working and allow to quit |
1459 | SAL_INFO( "desktop.app" , "{ GetEnableATToolSupport" ); |
1460 | if( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() ) |
1461 | { |
1462 | if( !InitAccessBridge() ) |
1463 | return EXIT_FAILURE; |
1464 | } |
1465 | SAL_INFO( "desktop.app" , "} GetEnableATToolSupport" ); |
1466 | #endif |
1467 | |
1468 | // terminate if requested... |
1469 | if( rCmdLineArgs.IsTerminateAfterInit() ) |
1470 | return EXIT_SUCCESS; |
1471 | |
1472 | // Read the common configuration items for optimization purpose |
1473 | if ( !InitializeConfiguration() ) |
1474 | return EXIT_FAILURE; |
1475 | |
1476 | SetSplashScreenProgress(30); |
1477 | |
1478 | // set static variable to enabled/disable crash reporter |
1479 | retrieveCrashReporterState(); |
1480 | const bool bCrashReporterEnabled = isCrashReporterEnabled(); |
1481 | osl_setErrorReporting( !bCrashReporterEnabled ); |
1482 | |
1483 | // create title string |
1484 | LanguageTag aLocale( LANGUAGE_SYSTEM); |
1485 | ResMgr* pLabelResMgr = ResMgr::SearchCreateResMgr( "ofa" , aLocale ); |
1486 | OUString aTitle = pLabelResMgr ? ResId(RID_APPTITLE, *pLabelResMgr).toString() : OUString(); |
1487 | delete pLabelResMgr; |
1488 | |
1489 | #ifdef DBG_UTIL |
1490 | //include buildid in non product builds |
1491 | OUString aDefault("development" ); |
1492 | aTitle += " [" ; |
1493 | aTitle += utl::Bootstrap::getBuildIdData(aDefault); |
1494 | aTitle += "]" ; |
1495 | #endif |
1496 | |
1497 | SetDisplayName( aTitle ); |
1498 | SetSplashScreenProgress(35); |
1499 | SAL_INFO( "desktop.app" , "{ create SvtPathOptions and SvtLanguageOptions" ); |
1500 | pExecGlobals->pPathOptions.reset( new SvtPathOptions); |
1501 | SetSplashScreenProgress(40); |
1502 | SAL_INFO( "desktop.app" , "} create SvtPathOptions and SvtLanguageOptions" ); |
1503 | |
1504 | xDesktop = css::frame::Desktop::create( xContext ); |
1505 | |
1506 | // create service for loadin SFX (still needed in startup) |
1507 | pExecGlobals->xGlobalBroadcaster = Reference < css::document::XEventListener > |
1508 | ( css::frame::theGlobalEventBroadcaster::get(xContext), UNO_QUERY_THROW ); |
1509 | |
1510 | /* ensure existance of a default window that messages can be dispatched to |
1511 | This is for the benefit of testtool which uses PostUserEvent extensively |
1512 | and else can deadlock while creating this window from another tread while |
1513 | the main thread is not yet in the event loop. |
1514 | */ |
1515 | Application::GetDefaultDevice(); |
1516 | |
1517 | #if HAVE_FEATURE_EXTENSIONS |
1518 | // Check if bundled or shared extensions were added /removed |
1519 | // and process those extensions (has to be done before checking |
1520 | // the extension dependencies! |
1521 | SynchronizeExtensionRepositories(); |
1522 | bool bAbort = CheckExtensionDependencies(); |
1523 | if ( bAbort ) |
1524 | return EXIT_FAILURE; |
1525 | |
1526 | if (inst_fin == userinstall::CREATED) |
1527 | { |
1528 | Migration::migrateSettingsIfNecessary(); |
1529 | } |
1530 | #endif |
1531 | |
1532 | // keep a language options instance... |
1533 | pExecGlobals->pLanguageOptions.reset( new SvtLanguageOptions(sal_True)); |
1534 | |
1535 | css::document::EventObject aEvent; |
1536 | aEvent.EventName = "OnStartApp" ; |
1537 | pExecGlobals->xGlobalBroadcaster->notifyEvent(aEvent); |
1538 | |
1539 | SetSplashScreenProgress(50); |
1540 | |
1541 | // Backing Component |
1542 | sal_Bool bCrashed = sal_False; |
1543 | sal_Bool bExistsRecoveryData = sal_False; |
1544 | sal_Bool bExistsSessionData = sal_False; |
1545 | |
1546 | SAL_INFO( "desktop.app" , "{ impl_checkRecoveryState" ); |
1547 | impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData); |
1548 | SAL_INFO( "desktop.app" , "} impl_checkRecoveryState" ); |
1549 | |
1550 | OUString pidfileName = rCmdLineArgs.GetPidfileName(); |
1551 | if ( !pidfileName.isEmpty() ) |
1552 | { |
1553 | OUString pidfileURL; |
1554 | |
1555 | if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None ) |
1556 | { |
1557 | osl::File pidfile( pidfileURL ); |
1558 | osl::FileBase::RC rc; |
1559 | |
1560 | osl::File::remove( pidfileURL ); |
1561 | if ( (rc = pidfile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ) ) == osl::File::E_None ) |
1562 | { |
1563 | OString pid( OString::number( GETPID() ) ); |
1564 | sal_uInt64 written = 0; |
1565 | if ( pidfile.write(pid.getStr(), pid.getLength(), written) != osl::File::E_None ) |
1566 | { |
1567 | SAL_WARN("desktop.app" , "cannot write pidfile " << pidfile.getURL()); |
1568 | } |
1569 | pidfile.close(); |
1570 | } |
1571 | else |
1572 | { |
1573 | SAL_WARN("desktop.app" , "cannot open pidfile " << pidfile.getURL() << osl::FileBase::RC(rc)); |
1574 | } |
1575 | } |
1576 | else |
1577 | { |
1578 | SAL_WARN("desktop.app" , "cannot get pidfile URL from path" << pidfileName); |
1579 | } |
1580 | } |
1581 | |
1582 | if ( rCmdLineArgs.IsHeadless() ) |
1583 | { |
1584 | // Ensure that we use not the system file dialogs as |
1585 | // headless mode relies on Application::EnableHeadlessMode() |
1586 | // which does only work for VCL dialogs!! |
1587 | SvtMiscOptions aMiscOptions; |
1588 | pExecGlobals->bUseSystemFileDialog = aMiscOptions.UseSystemFileDialog(); |
1589 | aMiscOptions.SetUseSystemFileDialog( sal_False ); |
1590 | } |
1591 | |
1592 | pExecGlobals->bRestartRequested = xRestartManager->isRestartRequested( |
1593 | true); |
1594 | if ( !pExecGlobals->bRestartRequested ) |
1595 | { |
1596 | if ((!rCmdLineArgs.WantsToLoadDocument() && !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsHeadless() && !rCmdLineArgs.IsQuickstart()) && |
1597 | (SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE)) && |
1598 | (!bExistsRecoveryData ) && |
1599 | (!bExistsSessionData ) && |
1600 | (!Application::AnyInput( VCL_INPUT_APPEVENT ) )) |
1601 | { |
1602 | SAL_INFO( "desktop.app" , "{ create BackingComponent" ); |
1603 | ShowBackingComponent(this); |
1604 | SAL_INFO( "desktop.app" , "} create BackingComponent" ); |
1605 | } |
1606 | } |
1607 | } |
1608 | catch ( const com::sun::star::lang::WrappedTargetException& wte ) |
1609 | { |
1610 | com::sun::star::uno::Exception te; |
1611 | wte.TargetException >>= te; |
1612 | FatalError( MakeStartupConfigAccessErrorMessage(wte.Message + te.Message) ); |
1613 | } |
1614 | catch ( const com::sun::star::uno::Exception& e ) |
1615 | { |
1616 | FatalError( MakeStartupErrorMessage(e.Message) ); |
1617 | } |
1618 | SetSplashScreenProgress(55); |
1619 | |
1620 | SvtFontSubstConfig().Apply(); |
1621 | |
1622 | SvtTabAppearanceCfg aAppearanceCfg; |
1623 | aAppearanceCfg.SetInitialized(); |
1624 | aAppearanceCfg.SetApplicationDefaults( this ); |
1625 | SvtAccessibilityOptions aOptions; |
1626 | aOptions.SetVCLSettings(); |
1627 | SetSplashScreenProgress(60); |
1628 | |
1629 | #if ENABLE_TELEPATHY |
1630 | bool bListen = rCmdLineArgs.IsInvisible(); |
1631 | TeleManager::init( bListen ); |
1632 | #endif |
1633 | |
1634 | if ( !pExecGlobals->bRestartRequested ) |
1635 | { |
1636 | Application::SetFilterHdl( LINK( this, Desktop, ImplInitFilterHdl ) ); |
1637 | sal_Bool bTerminateRequested = sal_False; |
1638 | |
1639 | // Preload function depends on an initialized sfx application! |
1640 | SetSplashScreenProgress(75); |
1641 | |
1642 | // use system window dialogs |
1643 | Application::SetSystemWindowMode( SYSTEMWINDOW_MODE_DIALOG ); |
1644 | |
1645 | SetSplashScreenProgress(80); |
1646 | |
1647 | if ( !bTerminateRequested && !rCmdLineArgs.IsInvisible() && |
1648 | !rCmdLineArgs.IsNoQuickstart() ) |
1649 | InitializeQuickstartMode( xContext ); |
1650 | |
1651 | SAL_INFO( "desktop.app" , "desktop (cd100003) createInstance com.sun.star.frame.Desktop" ); |
1652 | try |
1653 | { |
1654 | if ( xDesktop.is() ) |
1655 | xDesktop->addTerminateListener( new OfficeIPCThreadController ); |
1656 | SetSplashScreenProgress(100); |
1657 | } |
1658 | catch ( const com::sun::star::uno::Exception& e ) |
1659 | { |
1660 | FatalError( MakeStartupErrorMessage(e.Message) ); |
1661 | } |
1662 | |
1663 | // Release solar mutex just before we wait for our client to connect |
1664 | int nAcquireCount = Application::ReleaseSolarMutex(); |
1665 | |
1666 | // Post user event to startup first application component window |
1667 | // We have to send this OpenClients message short before execute() to |
1668 | // minimize the risk that this message overtakes type detection contruction!! |
1669 | Application::PostUserEvent( LINK( this, Desktop, OpenClients_Impl ) ); |
1670 | |
1671 | // Post event to enable acceptors |
1672 | Application::PostUserEvent( LINK( this, Desktop, EnableAcceptors_Impl) ); |
1673 | |
1674 | // The configuration error handler currently is only for startup |
1675 | aConfigErrHandler.deactivate(); |
1676 | |
1677 | // Acquire solar mutex just before we enter our message loop |
1678 | if ( nAcquireCount ) |
1679 | Application::AcquireSolarMutex( nAcquireCount ); |
1680 | |
1681 | // call Application::Execute to process messages in vcl message loop |
1682 | SAL_INFO( "desktop.app" , "PERFORMANCE - enter Application::Execute()" ); |
1683 | |
1684 | try |
1685 | { |
1686 | #if HAVE_FEATURE_JAVA |
1687 | // The JavaContext contains an interaction handler which is used when |
1688 | // the creation of a Java Virtual Machine fails |
1689 | com::sun::star::uno::ContextLayer layer2( |
1690 | new svt::JavaContext( com::sun::star::uno::getCurrentContext() ) ); |
1691 | #endif |
1692 | // check whether the shutdown is caused by restart just before entering the Execute |
1693 | pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested || |
1694 | xRestartManager->isRestartRequested(true); |
1695 | |
1696 | if ( !pExecGlobals->bRestartRequested ) |
1697 | { |
1698 | // if this run of the office is triggered by restart, some additional actions should be done |
1699 | DoRestartActionsIfNecessary( !rCmdLineArgs.IsInvisible() && !rCmdLineArgs.IsNoQuickstart() ); |
1700 | |
1701 | Execute(); |
1702 | } |
1703 | } |
1704 | catch(const com::sun::star::document::CorruptedFilterConfigurationException& exFilterCfg) |
1705 | { |
1706 | OfficeIPCThread::SetDowning(); |
1707 | FatalError( MakeStartupErrorMessage(exFilterCfg.Message) ); |
1708 | } |
1709 | catch(const com::sun::star::configuration::CorruptedConfigurationException& exAnyCfg) |
1710 | { |
1711 | OfficeIPCThread::SetDowning(); |
1712 | FatalError( MakeStartupErrorMessage(exAnyCfg.Message) ); |
1713 | } |
1714 | catch( const ::com::sun::star::uno::Exception& exUNO) |
1715 | { |
1716 | OfficeIPCThread::SetDowning(); |
1717 | FatalError( exUNO.Message); |
1718 | } |
1719 | catch( const std::exception& exSTD) |
1720 | { |
1721 | OfficeIPCThread::SetDowning(); |
1722 | FatalError( OUString::createFromAscii( exSTD.what())); |
1723 | } |
1724 | catch( ...) |
1725 | { |
1726 | OfficeIPCThread::SetDowning(); |
1727 | FatalError( OUString( "Caught Unknown Exception: Aborting!" )); |
1728 | } |
1729 | } |
1730 | else |
1731 | { |
1732 | if (xDesktop.is()) |
1733 | xDesktop->terminate(); |
1734 | } |
1735 | // CAUTION: you do not necessarily get here e.g. on the Mac. |
1736 | // please put all deinitialization code into doShutdown |
1737 | return doShutdown(); |
1738 | } |
1739 | |
1740 | int Desktop::doShutdown() |
1741 | { |
1742 | if( ! pExecGlobals ) |
1743 | return EXIT_SUCCESS; |
1744 | |
1745 | pExecGlobals->bRestartRequested = pExecGlobals->bRestartRequested || |
1746 | OfficeRestartManager::get(comphelper::getProcessComponentContext())-> |
1747 | isRestartRequested(true); |
1748 | if ( pExecGlobals->bRestartRequested ) |
1749 | SetRestartState(); |
1750 | |
1751 | if (pExecGlobals->xGlobalBroadcaster.is()) |
1752 | { |
1753 | css::document::EventObject aEvent; |
1754 | aEvent.EventName = "OnCloseApp" ; |
1755 | pExecGlobals->xGlobalBroadcaster->notifyEvent(aEvent); |
1756 | } |
1757 | |
1758 | delete pResMgr, pResMgr = NULL; |
1759 | // Restore old value |
1760 | const CommandLineArgs& rCmdLineArgs = GetCommandLineArgs(); |
1761 | if ( rCmdLineArgs.IsHeadless() ) |
1762 | SvtMiscOptions().SetUseSystemFileDialog( pExecGlobals->bUseSystemFileDialog ); |
1763 | |
1764 | OUString pidfileName = rCmdLineArgs.GetPidfileName(); |
1765 | if ( !pidfileName.isEmpty() ) |
1766 | { |
1767 | OUString pidfileURL; |
1768 | |
1769 | if ( osl_getFileURLFromSystemPath(pidfileName.pData, &pidfileURL.pData) == osl_File_E_None ) |
1770 | { |
1771 | if ( osl::File::remove( pidfileURL ) != osl::FileBase::E_None ) |
1772 | { |
1773 | SAL_WARN("desktop.app" , "shutdown: cannot remove pidfile " << pidfileURL); |
1774 | } |
1775 | } |
1776 | else |
1777 | { |
1778 | SAL_WARN("desktop.app" , "shutdown: cannot get pidfile URL from path" << pidfileName); |
1779 | } |
1780 | } |
1781 | |
1782 | // remove temp directory |
1783 | RemoveTemporaryDirectory(); |
1784 | FlushConfiguration(); |
1785 | // The acceptors in the AcceptorMap must be released (in DeregisterServices) |
1786 | // with the solar mutex unlocked, to avoid deadlock: |
1787 | sal_uLong nAcquireCount = Application::ReleaseSolarMutex(); |
1788 | DeregisterServices(); |
1789 | Application::AcquireSolarMutex(nAcquireCount); |
1790 | // be sure that path/language options gets destroyed before |
1791 | // UCB is deinitialized |
1792 | SAL_INFO( "desktop.app" , "-> dispose path/language options" ); |
1793 | pExecGlobals->pLanguageOptions.reset( 0 ); |
1794 | pExecGlobals->pPathOptions.reset( 0 ); |
1795 | SAL_INFO( "desktop.app" , "<- dispose path/language options" ); |
1796 | |
1797 | sal_Bool bRR = pExecGlobals->bRestartRequested; |
1798 | delete pExecGlobals, pExecGlobals = NULL; |
1799 | |
1800 | SAL_INFO( "desktop.app" , "FINISHED WITH Destop::Main" ); |
1801 | if ( bRR ) |
1802 | { |
1803 | restartOnMac(true); |
1804 | if ( m_rSplashScreen.is() ) |
1805 | m_rSplashScreen->reset(); |
1806 | |
1807 | return EXITHELPER_NORMAL_RESTART; |
1808 | } |
1809 | return EXIT_SUCCESS; |
1810 | } |
1811 | |
1812 | IMPL_LINK( Desktop, ImplInitFilterHdl, ConvertData*, pData ) |
1813 | { |
1814 | return GraphicFilter::GetGraphicFilter().GetFilterCallback().Call( pData ); |
1815 | } |
1816 | |
1817 | bool Desktop::InitializeConfiguration() |
1818 | { |
1819 | SAL_INFO( "desktop.app" , "desktop (jb99855) ::InitConfiguration" ); |
1820 | try |
1821 | { |
1822 | css::configuration::theDefaultProvider::get( |
1823 | comphelper::getProcessComponentContext() ); |
1824 | return true; |
1825 | } |
1826 | catch( ::com::sun::star::lang::ServiceNotRegisteredException & e ) |
1827 | { |
1828 | this->HandleBootstrapErrors( |
1829 | Desktop::BE_UNO_SERVICE_CONFIG_MISSING, e.Message ); |
1830 | } |
1831 | catch( const ::com::sun::star::configuration::MissingBootstrapFileException& e ) |
1832 | { |
1833 | OUString aMsg( CreateErrorMsgString( utl::Bootstrap::MISSING_BOOTSTRAP_FILE, |
1834 | e.BootstrapFileURL )); |
1835 | HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_USER_INSTALL, aMsg ); |
1836 | } |
1837 | catch( const ::com::sun::star::configuration::InvalidBootstrapFileException& e ) |
1838 | { |
1839 | OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY, |
1840 | e.BootstrapFileURL )); |
1841 | HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg ); |
1842 | } |
1843 | catch( const ::com::sun::star::configuration::InstallationIncompleteException& ) |
1844 | { |
1845 | OUString aVersionFileURL; |
1846 | OUString aMsg; |
1847 | utl::Bootstrap::PathStatus aPathStatus = utl::Bootstrap::locateVersionFile( aVersionFileURL ); |
1848 | if ( aPathStatus == utl::Bootstrap::PATH_EXISTS ) |
1849 | aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE_ENTRY, aVersionFileURL ); |
1850 | else |
1851 | aMsg = CreateErrorMsgString( utl::Bootstrap::MISSING_VERSION_FILE, aVersionFileURL ); |
1852 | |
1853 | HandleBootstrapPathErrors( ::utl::Bootstrap::MISSING_USER_INSTALL, aMsg ); |
1854 | } |
1855 | catch ( const com::sun::star::configuration::backend::BackendAccessException& exception) |
1856 | { |
1857 | // [cm122549] It is assumed in this case that the message |
1858 | // coming from InitConfiguration (in fact CreateApplicationConf...) |
1859 | // is suitable for display directly. |
1860 | FatalError( MakeStartupErrorMessage( exception.Message ) ); |
1861 | } |
1862 | catch ( const com::sun::star::configuration::backend::BackendSetupException& exception) |
1863 | { |
1864 | // [cm122549] It is assumed in this case that the message |
1865 | // coming from InitConfiguration (in fact CreateApplicationConf...) |
1866 | // is suitable for display directly. |
1867 | FatalError( MakeStartupErrorMessage( exception.Message ) ); |
1868 | } |
1869 | catch ( const ::com::sun::star::configuration::CannotLoadConfigurationException& ) |
1870 | { |
1871 | OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA, |
1872 | OUString() )); |
1873 | HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg ); |
1874 | } |
1875 | catch( const ::com::sun::star::uno::Exception& ) |
1876 | { |
1877 | OUString aMsg( CreateErrorMsgString( utl::Bootstrap::INVALID_BOOTSTRAP_DATA, |
1878 | OUString() )); |
1879 | HandleBootstrapPathErrors( ::utl::Bootstrap::INVALID_BASE_INSTALL, aMsg ); |
1880 | } |
1881 | return false; |
1882 | } |
1883 | |
1884 | void Desktop::FlushConfiguration() |
1885 | { |
1886 | css::uno::Reference< css::util::XFlushable >( |
1887 | css::configuration::theDefaultProvider::get( |
1888 | comphelper::getProcessComponentContext()), |
1889 | css::uno::UNO_QUERY_THROW)->flush(); |
1890 | } |
1891 | |
1892 | sal_Bool Desktop::InitializeQuickstartMode( const Reference< XComponentContext >& rxContext ) |
1893 | { |
1894 | try |
1895 | { |
1896 | // the shutdown icon sits in the systray and allows the user to keep |
1897 | // the office instance running for quicker restart |
1898 | // this will only be activated if --quickstart was specified on cmdline |
1899 | SAL_INFO( "desktop.app" , "desktop (cd100003) createInstance com.sun.star.office.Quickstart" ); |
1900 | |
1901 | sal_Bool bQuickstart = shouldLaunchQuickstart(); |
1902 | |
1903 | // Try to instantiate quickstart service. This service is not mandatory, so |
1904 | // do nothing if service is not available |
1905 | |
1906 | // #i105753# the following if was invented for performance |
1907 | // unfortunately this broke the Mac behavior which is to always run |
1908 | // in quickstart mode since Mac applications do not usually quit |
1909 | // when the last document closes. |
1910 | // Note that this claim that on OS X we "always run in quickstart mode" |
1911 | // has nothing to do with (quick) *starting* (i.e. starting automatically |
1912 | // when the user logs in), though, but with not quitting when no documents |
1913 | // are open. |
1914 | #ifndef MACOSX |
1915 | if ( bQuickstart ) |
1916 | #endif |
1917 | { |
1918 | css::office::Quickstart::createStart(rxContext, bQuickstart); |
1919 | } |
1920 | return sal_True; |
1921 | } |
1922 | catch( const ::com::sun::star::uno::Exception& ) |
1923 | { |
1924 | return sal_False; |
1925 | } |
1926 | } |
1927 | |
1928 | void Desktop::OverrideSystemSettings( AllSettings& rSettings ) |
1929 | { |
1930 | if ( !SvtTabAppearanceCfg::IsInitialized () ) |
1931 | return; |
1932 | |
1933 | StyleSettings hStyleSettings = rSettings.GetStyleSettings(); |
1934 | MouseSettings hMouseSettings = rSettings.GetMouseSettings(); |
1935 | |
1936 | sal_uInt32 nDragFullOptions = hStyleSettings.GetDragFullOptions(); |
1937 | |
1938 | SvtTabAppearanceCfg aAppearanceCfg; |
1939 | sal_uInt16 nDragMode = aAppearanceCfg.GetDragMode(); |
1940 | switch ( nDragMode ) |
1941 | { |
1942 | case DragFullWindow: |
1943 | nDragFullOptions |= DRAGFULL_OPTION_ALL; |
1944 | break; |
1945 | case DragFrame: |
1946 | nDragFullOptions &= ((sal_uInt32)~DRAGFULL_OPTION_ALL); |
1947 | break; |
1948 | case DragSystemDep: |
1949 | default: |
1950 | break; |
1951 | } |
1952 | |
1953 | sal_uInt32 nFollow = hMouseSettings.GetFollow(); |
1954 | hMouseSettings.SetFollow( aAppearanceCfg.IsMenuMouseFollow() ? (nFollow|MOUSE_FOLLOW_MENU) : (nFollow&~MOUSE_FOLLOW_MENU)); |
1955 | rSettings.SetMouseSettings(hMouseSettings); |
1956 | |
1957 | SvtMenuOptions ; |
1958 | hStyleSettings.SetUseImagesInMenus(aMenuOpt.GetMenuIconsState()); |
1959 | hStyleSettings.SetDragFullOptions( nDragFullOptions ); |
1960 | rSettings.SetStyleSettings ( hStyleSettings ); |
1961 | } |
1962 | |
1963 | // ======================================================================== |
1964 | IMPL_LINK_NOARG(Desktop, AsyncInitFirstRun) |
1965 | { |
1966 | DoFirstRunInitializations(); |
1967 | return 0L; |
1968 | } |
1969 | |
1970 | // ======================================================================== |
1971 | |
1972 | class ExitTimer : public Timer |
1973 | { |
1974 | public: |
1975 | ExitTimer() |
1976 | { |
1977 | SetTimeout(500); |
1978 | Start(); |
1979 | } |
1980 | virtual void Timeout() |
1981 | { |
1982 | exit(42); |
1983 | } |
1984 | }; |
1985 | |
1986 | IMPL_LINK_NOARG(Desktop, OpenClients_Impl) |
1987 | { |
1988 | SAL_INFO( "desktop.app" , "PERFORMANCE - DesktopOpenClients_Impl()" ); |
1989 | |
1990 | try { |
1991 | OpenClients(); |
1992 | |
1993 | OfficeIPCThread::SetReady(); |
1994 | |
1995 | CloseSplashScreen(); |
1996 | CheckFirstRun( ); |
1997 | EnableOleAutomation(); |
1998 | |
1999 | if (getenv ("OOO_EXIT_POST_STARTUP" )) |
2000 | new ExitTimer(); |
2001 | } catch (const ::com::sun::star::uno::Exception &e) { |
2002 | OUString a( "UNO exception during client open:\n" ); |
2003 | Application::Abort( a + e.Message ); |
2004 | } |
2005 | return 0; |
2006 | } |
2007 | |
2008 | // enable acceptos |
2009 | IMPL_LINK_NOARG(Desktop, EnableAcceptors_Impl) |
2010 | { |
2011 | enableAcceptors(); |
2012 | return 0; |
2013 | } |
2014 | |
2015 | |
2016 | // Registers a COM class factory of the service manager with the windows operating system. |
2017 | void Desktop::EnableOleAutomation() |
2018 | { |
2019 | SAL_INFO( "desktop.app" , "desktop (jl97489) ::Desktop::EnableOleAutomation" ); |
2020 | #ifdef WNT |
2021 | Reference< XMultiServiceFactory > xSMgr= comphelper::getProcessServiceFactory(); |
2022 | xSMgr->createInstance("com.sun.star.bridge.OleApplicationRegistration" ); |
2023 | xSMgr->createInstance("com.sun.star.comp.ole.EmbedServer" ); |
2024 | #endif |
2025 | } |
2026 | |
2027 | void Desktop::PreloadModuleData( const CommandLineArgs& rArgs ) |
2028 | { |
2029 | Sequence < com::sun::star::beans::PropertyValue > args(1); |
2030 | args[0].Name = "Hidden" ; |
2031 | args[0].Value <<= sal_True; |
2032 | Reference < XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); |
2033 | |
2034 | if ( rArgs.IsWriter() ) |
2035 | { |
2036 | try |
2037 | { |
2038 | Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/swriter" ), |
2039 | OUString("_blank" ), 0, args ), UNO_QUERY_THROW ); |
2040 | xDoc->close( sal_False ); |
2041 | } |
2042 | catch ( const com::sun::star::uno::Exception& ) |
2043 | { |
2044 | } |
2045 | } |
2046 | if ( rArgs.IsCalc() ) |
2047 | { |
2048 | try |
2049 | { |
2050 | Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/scalc" ), |
2051 | OUString("_blank" ), 0, args ), UNO_QUERY_THROW ); |
2052 | xDoc->close( sal_False ); |
2053 | } |
2054 | catch ( const com::sun::star::uno::Exception& ) |
2055 | { |
2056 | } |
2057 | } |
2058 | if ( rArgs.IsDraw() ) |
2059 | { |
2060 | try |
2061 | { |
2062 | Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/sdraw" ), |
2063 | OUString("_blank" ), 0, args ), UNO_QUERY_THROW ); |
2064 | xDoc->close( sal_False ); |
2065 | } |
2066 | catch ( const com::sun::star::uno::Exception& ) |
2067 | { |
2068 | } |
2069 | } |
2070 | if ( rArgs.IsImpress() ) |
2071 | { |
2072 | try |
2073 | { |
2074 | Reference < ::com::sun::star::util::XCloseable > xDoc( xDesktop->loadComponentFromURL( OUString("private:factory/simpress" ), |
2075 | OUString("_blank" ), 0, args ), UNO_QUERY_THROW ); |
2076 | xDoc->close( sal_False ); |
2077 | } |
2078 | catch ( const com::sun::star::uno::Exception& ) |
2079 | { |
2080 | } |
2081 | } |
2082 | } |
2083 | |
2084 | void Desktop::PreloadConfigurationData() |
2085 | { |
2086 | Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
2087 | Reference< XNameAccess > xNameAccess = css::frame::theUICommandDescription::get(xContext); |
2088 | |
2089 | OUString aWriterDoc( "com.sun.star.text.TextDocument" ); |
2090 | OUString aCalcDoc( "com.sun.star.sheet.SpreadsheetDocument" ); |
2091 | OUString aDrawDoc( "com.sun.star.drawing.DrawingDocument" ); |
2092 | OUString aImpressDoc( "com.sun.star.presentation.PresentationDocument" ); |
2093 | |
2094 | // preload commands configuration |
2095 | Any a; |
2096 | Reference< XNameAccess > xCmdAccess; |
2097 | |
2098 | try |
2099 | { |
2100 | a = xNameAccess->getByName( aWriterDoc ); |
2101 | a >>= xCmdAccess; |
2102 | if ( xCmdAccess.is() ) |
2103 | { |
2104 | xCmdAccess->getByName(".uno:BasicShapes" ); |
2105 | xCmdAccess->getByName(".uno:EditGlossary" ); |
2106 | } |
2107 | } |
2108 | catch ( const ::com::sun::star::uno::Exception& ) |
2109 | { |
2110 | } |
2111 | |
2112 | try |
2113 | { |
2114 | a = xNameAccess->getByName( aCalcDoc ); |
2115 | a >>= xCmdAccess; |
2116 | if ( xCmdAccess.is() ) |
2117 | xCmdAccess->getByName(".uno:InsertObjectStarMath" ); |
2118 | } |
2119 | catch ( const ::com::sun::star::uno::Exception& ) |
2120 | { |
2121 | } |
2122 | |
2123 | try |
2124 | { |
2125 | // draw and impress share the same configuration file (DrawImpressCommands.xcu) |
2126 | a = xNameAccess->getByName( aDrawDoc ); |
2127 | a >>= xCmdAccess; |
2128 | if ( xCmdAccess.is() ) |
2129 | xCmdAccess->getByName(".uno:Polygon" ); |
2130 | } |
2131 | catch ( const ::com::sun::star::uno::Exception& ) |
2132 | { |
2133 | } |
2134 | |
2135 | // preload window state configuration |
2136 | xNameAccess = theWindowStateConfiguration::get( xContext ); |
2137 | Reference< XNameAccess > xWindowAccess; |
2138 | try |
2139 | { |
2140 | a = xNameAccess->getByName( aWriterDoc ); |
2141 | a >>= xWindowAccess; |
2142 | if ( xWindowAccess.is() ) |
2143 | xWindowAccess->getByName("private:resource/toolbar/standardbar" ); |
2144 | } |
2145 | catch ( const ::com::sun::star::uno::Exception& ) |
2146 | { |
2147 | } |
2148 | try |
2149 | { |
2150 | a = xNameAccess->getByName( aCalcDoc ); |
2151 | a >>= xWindowAccess; |
2152 | if ( xWindowAccess.is() ) |
2153 | xWindowAccess->getByName("private:resource/toolbar/standardbar" ); |
2154 | } |
2155 | catch ( const ::com::sun::star::uno::Exception& ) |
2156 | { |
2157 | } |
2158 | try |
2159 | { |
2160 | a = xNameAccess->getByName( aDrawDoc ); |
2161 | a >>= xWindowAccess; |
2162 | if ( xWindowAccess.is() ) |
2163 | xWindowAccess->getByName("private:resource/toolbar/standardbar" ); |
2164 | } |
2165 | catch ( const ::com::sun::star::uno::Exception& ) |
2166 | { |
2167 | } |
2168 | try |
2169 | { |
2170 | a = xNameAccess->getByName( aImpressDoc ); |
2171 | a >>= xWindowAccess; |
2172 | if ( xWindowAccess.is() ) |
2173 | xWindowAccess->getByName("private:resource/toolbar/standardbar" ); |
2174 | } |
2175 | catch ( const ::com::sun::star::uno::Exception& ) |
2176 | { |
2177 | } |
2178 | |
2179 | // preload user interface element factories |
2180 | Sequence< Sequence< css::beans::PropertyValue > > aSeqSeqPropValue; |
2181 | Reference< XUIElementFactoryManager > xUIElementFactory = theUIElementFactoryManager::get( xContext ); |
2182 | try |
2183 | { |
2184 | aSeqSeqPropValue = xUIElementFactory->getRegisteredFactories(); |
2185 | } |
2186 | catch ( const ::com::sun::star::uno::Exception& ) |
2187 | { |
2188 | } |
2189 | |
2190 | // preload popup menu controller factories. As all controllers are in the same |
2191 | // configuration file they also get preloaded! |
2192 | |
2193 | Reference< css::frame::XUIControllerRegistration > = |
2194 | css::frame::thePopupMenuControllerFactory::get( xContext ); |
2195 | try |
2196 | { |
2197 | xPopupMenuControllerFactory->hasController( |
2198 | OUString( ".uno:CharFontName" ), |
2199 | OUString() ); |
2200 | } |
2201 | catch ( const ::com::sun::star::uno::Exception& ) |
2202 | { |
2203 | } |
2204 | |
2205 | // preload filter configuration |
2206 | Sequence< OUString > aSeq; |
2207 | xNameAccess = Reference< XNameAccess >( |
2208 | xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory" , xContext), |
2209 | UNO_QUERY ); |
2210 | if ( xNameAccess.is() ) |
2211 | { |
2212 | try |
2213 | { |
2214 | aSeq = xNameAccess->getElementNames(); |
2215 | } |
2216 | catch ( const ::com::sun::star::uno::Exception& ) |
2217 | { |
2218 | } |
2219 | } |
2220 | |
2221 | // preload type detection configuration |
2222 | xNameAccess = Reference< XNameAccess >( |
2223 | xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection" , xContext), |
2224 | UNO_QUERY ); |
2225 | if ( xNameAccess.is() ) |
2226 | { |
2227 | try |
2228 | { |
2229 | aSeq = xNameAccess->getElementNames(); |
2230 | } |
2231 | catch ( const ::com::sun::star::uno::Exception& ) |
2232 | { |
2233 | } |
2234 | } |
2235 | } |
2236 | |
2237 | void Desktop::OpenClients() |
2238 | { |
2239 | |
2240 | // check if a document has been recovered - if there is one of if a document was loaded by cmdline, no default document |
2241 | // should be created |
2242 | Reference < XComponent > xFirst; |
2243 | bool bRecovery = false; |
2244 | |
2245 | const CommandLineArgs& rArgs = GetCommandLineArgs(); |
2246 | |
2247 | if (!rArgs.IsQuickstart()) |
2248 | { |
2249 | sal_Bool bShowHelp = sal_False; |
2250 | OUStringBuffer aHelpURLBuffer; |
2251 | if (rArgs.IsHelpWriter()) { |
2252 | bShowHelp = sal_True; |
2253 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://swriter/start" ); |
2254 | } else if (rArgs.IsHelpCalc()) { |
2255 | bShowHelp = sal_True; |
2256 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://scalc/start" ); |
2257 | } else if (rArgs.IsHelpDraw()) { |
2258 | bShowHelp = sal_True; |
2259 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdraw/start" ); |
2260 | } else if (rArgs.IsHelpImpress()) { |
2261 | bShowHelp = sal_True; |
2262 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://simpress/start" ); |
2263 | } else if (rArgs.IsHelpBase()) { |
2264 | bShowHelp = sal_True; |
2265 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdatabase/start" ); |
2266 | } else if (rArgs.IsHelpBasic()) { |
2267 | bShowHelp = sal_True; |
2268 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://sbasic/start" ); |
2269 | } else if (rArgs.IsHelpMath()) { |
2270 | bShowHelp = sal_True; |
2271 | aHelpURLBuffer.appendAscii("vnd.sun.star.help://smath/start" ); |
2272 | } |
2273 | if (bShowHelp) { |
2274 | aHelpURLBuffer.appendAscii("?Language=" ); |
2275 | aHelpURLBuffer.append(utl::ConfigManager::getLocale()); |
2276 | #if defined UNX |
2277 | aHelpURLBuffer.appendAscii("&System=UNX" ); |
2278 | #elif defined WNT |
2279 | aHelpURLBuffer.appendAscii("&System=WIN" ); |
2280 | #endif |
2281 | Application::GetHelp()->Start( |
2282 | aHelpURLBuffer.makeStringAndClear(), NULL); |
2283 | return; |
2284 | } |
2285 | } |
2286 | else |
2287 | { |
2288 | OUString aIniName; |
2289 | |
2290 | osl_getExecutableFile( &aIniName.pData ); |
2291 | sal_uInt32 lastIndex = aIniName.lastIndexOf('/'); |
2292 | if ( lastIndex > 0 ) |
2293 | { |
2294 | aIniName = aIniName.copy( 0, lastIndex+1 ); |
2295 | aIniName += "perftune" ; |
2296 | #if defined(WNT) |
2297 | aIniName += ".ini" ; |
2298 | #else |
2299 | aIniName += "rc" ; |
2300 | #endif |
2301 | } |
2302 | |
2303 | rtl::Bootstrap aPerfTuneIniFile( aIniName ); |
2304 | |
2305 | OUString aDefault( "0" ); |
2306 | OUString aPreloadData; |
2307 | |
2308 | aPerfTuneIniFile.getFrom( OUString( "QuickstartPreloadConfiguration" ), aPreloadData, aDefault ); |
2309 | if ( aPreloadData == "1" ) |
2310 | { |
2311 | if ( rArgs.IsWriter() || |
2312 | rArgs.IsCalc() || |
2313 | rArgs.IsDraw() || |
2314 | rArgs.IsImpress() ) |
2315 | { |
2316 | PreloadModuleData( rArgs ); |
2317 | } |
2318 | |
2319 | PreloadConfigurationData(); |
2320 | } |
2321 | } |
2322 | |
2323 | // Disable AutoSave feature in case "--norestore" or a similar command line switch is set on the command line. |
2324 | // The reason behind: AutoSave/EmergencySave/AutoRecovery share the same data. |
2325 | // But the require that all documents, which are saved as backup should exists inside |
2326 | // memory. May be this mechanism will be inconsistent if the configuration exists ... |
2327 | // but no document inside memory corrspond to this data. |
2328 | // Furter it's not acceptable to recover such documents without any UI. It can |
2329 | // need some time, where the user wont see any results and wait for finishing the office startup ... |
2330 | sal_Bool bAllowRecoveryAndSessionManagement = ( |
2331 | ( !rArgs.IsNoRestore() ) && |
2332 | ( !rArgs.IsHeadless() ) |
2333 | ); |
2334 | |
2335 | if ( ! bAllowRecoveryAndSessionManagement ) |
2336 | { |
2337 | try |
2338 | { |
2339 | Reference< XDispatch > xRecovery = css::frame::theAutoRecovery::get( ::comphelper::getProcessComponentContext() ); |
2340 | Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create( ::comphelper::getProcessComponentContext() ); |
2341 | |
2342 | css::util::URL aCmd; |
2343 | aCmd.Complete = "vnd.sun.star.autorecovery:/disableRecovery" ; |
2344 | xParser->parseStrict(aCmd); |
2345 | |
2346 | xRecovery->dispatch(aCmd, css::uno::Sequence< css::beans::PropertyValue >()); |
2347 | } |
2348 | catch(const css::uno::Exception& e) |
2349 | { |
2350 | SAL_WARN( "desktop.app" , "Could not disable AutoRecovery." << e.Message); |
2351 | } |
2352 | } |
2353 | else |
2354 | { |
2355 | sal_Bool bCrashed = sal_False; |
2356 | sal_Bool bExistsRecoveryData = sal_False; |
2357 | sal_Bool bExistsSessionData = sal_False; |
2358 | |
2359 | impl_checkRecoveryState(bCrashed, bExistsRecoveryData, bExistsSessionData); |
2360 | |
2361 | if ( !getenv ("OOO_DISABLE_RECOVERY" ) && |
2362 | ( |
2363 | ( bExistsRecoveryData ) || // => crash with files => recovery |
2364 | ( bCrashed ) // => crash without files => error report |
2365 | ) |
2366 | ) |
2367 | { |
2368 | try |
2369 | { |
2370 | bRecovery = impl_callRecoveryUI( |
2371 | sal_False , // false => force recovery instead of emergency save |
2372 | bCrashed , |
2373 | bExistsRecoveryData); |
2374 | } |
2375 | catch(const css::uno::Exception& e) |
2376 | { |
2377 | SAL_WARN( "desktop.app" , "Error during recovery" << e.Message); |
2378 | } |
2379 | } |
2380 | |
2381 | Reference< XSessionManagerListener2 > xSessionListener; |
2382 | try |
2383 | { |
2384 | // specifies whether the UI-interaction on Session shutdown is allowed |
2385 | sal_Bool bAllowUI = isUIOnSessionShutdownAllowed(); |
2386 | |
2387 | xSessionListener = SessionListener::createWithOnQuitFlag(::comphelper::getProcessComponentContext(), bAllowUI); |
2388 | |
2389 | // css::beans::NamedValue aProperty( OUString( "AllowUserInteractionOnQuit" ), |
2390 | // css::uno::makeAny( bAllowUI ) ); |
2391 | // css::uno::Sequence< css::uno::Any > aArgs( 1 ); |
2392 | // aArgs[0] <<= aProperty; |
2393 | |
2394 | // xSessionListener->initialize( aArgs ); |
2395 | } |
2396 | catch(const com::sun::star::uno::Exception& e) |
2397 | { |
2398 | SAL_WARN( "desktop.app" , "Registration of session listener failed" << e.Message); |
2399 | } |
2400 | |
2401 | if ( !bExistsRecoveryData ) |
2402 | { |
2403 | // session management |
2404 | try |
2405 | { |
2406 | xSessionListener->doRestore(); |
2407 | } |
2408 | catch(const com::sun::star::uno::Exception& e) |
2409 | { |
2410 | SAL_WARN( "desktop.app" , "Error in session management" << e.Message); |
2411 | } |
2412 | } |
2413 | } |
2414 | |
2415 | OfficeIPCThread::EnableRequests(); |
2416 | |
2417 | ProcessDocumentsRequest aRequest(rArgs.getCwdUrl()); |
2418 | aRequest.pcProcessed = NULL; |
2419 | |
2420 | aRequest.aOpenList = rArgs.GetOpenList(); |
2421 | aRequest.aViewList = rArgs.GetViewList(); |
2422 | aRequest.aStartList = rArgs.GetStartList(); |
2423 | aRequest.aPrintList = rArgs.GetPrintList(); |
2424 | aRequest.aPrintToList = rArgs.GetPrintToList(); |
2425 | aRequest.aPrinterName = rArgs.GetPrinterName(); |
2426 | aRequest.aForceOpenList = rArgs.GetForceOpenList(); |
2427 | aRequest.aForceNewList = rArgs.GetForceNewList(); |
2428 | aRequest.aConversionList = rArgs.GetConversionList(); |
2429 | aRequest.aConversionParams = rArgs.GetConversionParams(); |
2430 | aRequest.aConversionOut = rArgs.GetConversionOut(); |
2431 | aRequest.aInFilter = rArgs.GetInFilter(); |
2432 | |
2433 | if ( !aRequest.aOpenList.empty() || |
2434 | !aRequest.aViewList.empty() || |
2435 | !aRequest.aStartList.empty() || |
2436 | !aRequest.aPrintList.empty() || |
2437 | !aRequest.aForceOpenList.empty() || |
2438 | !aRequest.aForceNewList.empty() || |
2439 | ( !aRequest.aPrintToList.empty() && !aRequest.aPrinterName.isEmpty() ) || |
2440 | !aRequest.aConversionList.empty() ) |
2441 | { |
2442 | if ( rArgs.HasModuleParam() ) |
2443 | { |
2444 | SvtModuleOptions aOpt; |
2445 | |
2446 | // Support command line parameters to start a module (as preselection) |
2447 | if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) |
2448 | aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::E_WRITER ); |
2449 | else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) ) |
2450 | aRequest.aModule = aOpt.GetFactoryName( SvtModuleOptions::E_CALC ); |
2451 | else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) ) |
2452 | aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::E_IMPRESS ); |
2453 | else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) ) |
2454 | aRequest.aModule= aOpt.GetFactoryName( SvtModuleOptions::E_DRAW ); |
2455 | } |
2456 | |
2457 | // check for printing disabled |
2458 | if( ( !(aRequest.aPrintList.empty() && aRequest.aPrintToList.empty()) ) |
2459 | && Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) |
2460 | { |
2461 | aRequest.aPrintList.clear(); |
2462 | aRequest.aPrintToList.clear(); |
2463 | ResMgr* pDtResMgr = GetDesktopResManager(); |
2464 | if( pDtResMgr ) |
2465 | { |
2466 | ErrorBox aBox( NULL, ResId( EBX_ERR_PRINTDISABLED, *pDtResMgr ) ); |
2467 | aBox.Execute(); |
2468 | } |
2469 | } |
2470 | |
2471 | // Process request |
2472 | if ( OfficeIPCThread::ExecuteCmdLineRequests( aRequest ) ) |
2473 | { |
2474 | // Don't do anything if we have successfully called terminate at desktop: |
2475 | return; |
2476 | } |
2477 | } |
2478 | |
2479 | // no default document if a document was loaded by recovery or by command line or if soffice is used as server |
2480 | Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( ::comphelper::getProcessComponentContext() ); |
2481 | Reference< XElementAccess > xList( xDesktop->getFrames(), UNO_QUERY_THROW ); |
2482 | if ( xList->hasElements() ) |
2483 | return; |
2484 | |
2485 | if ( rArgs.IsQuickstart() || rArgs.IsInvisible() || Application::AnyInput( VCL_INPUT_APPEVENT ) ) |
2486 | // soffice was started as tray icon ... |
2487 | return; |
2488 | |
2489 | if ( bRecovery ) |
2490 | { |
2491 | ShowBackingComponent(0); |
2492 | } |
2493 | else |
2494 | { |
2495 | OpenDefault(); |
2496 | } |
2497 | } |
2498 | |
2499 | void Desktop::OpenDefault() |
2500 | { |
2501 | |
2502 | SAL_INFO( "desktop.app" , "desktop (cd100003) ::Desktop::OpenDefault" ); |
2503 | |
2504 | OUString aName; |
2505 | SvtModuleOptions aOpt; |
2506 | |
2507 | const CommandLineArgs& rArgs = GetCommandLineArgs(); |
2508 | if ( rArgs.IsNoDefault() ) return; |
2509 | if ( rArgs.HasModuleParam() ) |
2510 | { |
2511 | // Support new command line parameters to start a module |
2512 | if ( rArgs.IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) |
2513 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITER ); |
2514 | else if ( rArgs.IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) ) |
2515 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_CALC ); |
2516 | else if ( rArgs.IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) ) |
2517 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_IMPRESS ); |
2518 | else if ( rArgs.IsBase() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) |
2519 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DATABASE ); |
2520 | else if ( rArgs.IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) ) |
2521 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DRAW ); |
2522 | else if ( rArgs.IsMath() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SMATH ) ) |
2523 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_MATH ); |
2524 | else if ( rArgs.IsGlobal() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) |
2525 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITERGLOBAL ); |
2526 | else if ( rArgs.IsWeb() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) |
2527 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITERWEB ); |
2528 | } |
2529 | |
2530 | if ( aName.isEmpty() ) |
2531 | { |
2532 | // Old way to create a default document |
2533 | if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) ) |
2534 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_WRITER ); |
2535 | else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) ) |
2536 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_CALC ); |
2537 | else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) ) |
2538 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_IMPRESS ); |
2539 | else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) |
2540 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DATABASE ); |
2541 | else if ( aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) ) |
2542 | aName = aOpt.GetFactoryEmptyDocumentURL( SvtModuleOptions::E_DRAW ); |
2543 | else |
2544 | return; |
2545 | } |
2546 | |
2547 | ProcessDocumentsRequest aRequest(rArgs.getCwdUrl()); |
2548 | aRequest.pcProcessed = NULL; |
2549 | aRequest.aOpenList.push_back(aName); |
2550 | OfficeIPCThread::ExecuteCmdLineRequests( aRequest ); |
2551 | } |
2552 | |
2553 | |
2554 | OUString GetURL_Impl( |
2555 | const OUString& rName, boost::optional< OUString > const & cwdUrl ) |
2556 | { |
2557 | // if rName is a vnd.sun.star.script URL do not attempt to parse it |
2558 | // as INetURLObj does not handle handle there URLs |
2559 | if (rName.startsWith("vnd.sun.star.script" )) |
2560 | { |
2561 | return rName; |
2562 | } |
2563 | |
2564 | // dont touch file urls, those should already be in internal form |
2565 | // they won't get better here (#112849#) |
2566 | if (rName.startsWith("file:" )) |
2567 | { |
2568 | return rName; |
2569 | } |
2570 | |
2571 | if ( rName.startsWith("service:" )) |
2572 | { |
2573 | return rName; |
2574 | } |
2575 | |
2576 | // Add path separator to these directory and make given URL (rName) absolute by using of current working directory |
2577 | // Attention: "setFinalSlash()" is necessary for calling "smartRel2Abs()"!!! |
2578 | // Otherwhise last part will be ignored and wrong result will be returned!!! |
2579 | // "smartRel2Abs()" interpret given URL as file not as path. So he truncate last element to get the base path ... |
2580 | // But if we add a separator - he doesn't do it anymore. |
2581 | INetURLObject aObj; |
2582 | if (cwdUrl) { |
2583 | aObj.SetURL(*cwdUrl); |
2584 | aObj.setFinalSlash(); |
2585 | } |
2586 | |
2587 | // Use the provided parameters for smartRel2Abs to support the usage of '%' in system paths. |
2588 | // Otherwise this char won't get encoded and we are not able to load such files later, |
2589 | bool bWasAbsolute; |
2590 | INetURLObject aURL = aObj.smartRel2Abs( rName, bWasAbsolute, false, INetURLObject::WAS_ENCODED, |
2591 | RTL_TEXTENCODING_UTF8, true ); |
2592 | OUString aFileURL = aURL.GetMainURL(INetURLObject::NO_DECODE); |
2593 | |
2594 | ::osl::FileStatus aStatus( osl_FileStatus_Mask_FileURL ); |
2595 | ::osl::DirectoryItem aItem; |
2596 | if( ::osl::FileBase::E_None == ::osl::DirectoryItem::get( aFileURL, aItem ) && |
2597 | ::osl::FileBase::E_None == aItem.getFileStatus( aStatus ) ) |
2598 | aFileURL = aStatus.getFileURL(); |
2599 | |
2600 | return aFileURL; |
2601 | } |
2602 | |
2603 | void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent ) |
2604 | { |
2605 | switch ( rAppEvent.GetEvent() ) |
2606 | { |
2607 | case ApplicationEvent::TYPE_ACCEPT: |
2608 | // every time an accept parameter is used we create an acceptor |
2609 | // with the corresponding accept-string |
2610 | createAcceptor(rAppEvent.GetStringData()); |
2611 | break; |
2612 | case ApplicationEvent::TYPE_APPEAR: |
2613 | if ( !GetCommandLineArgs().IsInvisible() ) |
2614 | { |
2615 | Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
2616 | |
2617 | // find active task - the active task is always a visible task |
2618 | Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext ); |
2619 | Reference< css::frame::XFrame > xTask = xDesktop->getActiveFrame(); |
2620 | if ( !xTask.is() ) |
2621 | { |
2622 | // get any task if there is no active one |
2623 | Reference< css::container::XIndexAccess > xList( xDesktop->getFrames(), ::com::sun::star::uno::UNO_QUERY ); |
2624 | if ( xList->getCount() > 0 ) |
2625 | xList->getByIndex(0) >>= xTask; |
2626 | } |
2627 | |
2628 | if ( xTask.is() ) |
2629 | { |
2630 | Reference< com::sun::star::awt::XTopWindow > xTop( xTask->getContainerWindow(), UNO_QUERY ); |
2631 | xTop->toFront(); |
2632 | } |
2633 | else |
2634 | { |
2635 | // no visible task that could be activated found |
2636 | Reference< ::com::sun::star::awt::XWindow > xContainerWindow; |
2637 | Reference< XFrame > xBackingFrame = xDesktop->findFrame(OUString( "_blank" ), 0); |
2638 | if (xBackingFrame.is()) |
2639 | xContainerWindow = xBackingFrame->getContainerWindow(); |
2640 | if (xContainerWindow.is()) |
2641 | { |
2642 | Reference< XController > xStartModule = StartModule::createWithParentWindow(xContext, xContainerWindow); |
2643 | Reference< ::com::sun::star::awt::XWindow > xBackingWin(xStartModule, UNO_QUERY); |
2644 | // Attention: You MUST(!) call setComponent() before you call attachFrame(). |
2645 | // Because the backing component set the property "IsBackingMode" of the frame |
2646 | // to true inside attachFrame(). But setComponent() reset this state every time ... |
2647 | xBackingFrame->setComponent(xBackingWin, xStartModule); |
2648 | xStartModule->attachFrame(xBackingFrame); |
2649 | xContainerWindow->setVisible(sal_True); |
2650 | |
2651 | Window* pCompWindow = VCLUnoHelper::GetWindow(xBackingFrame->getComponentWindow()); |
2652 | if (pCompWindow) |
2653 | pCompWindow->Update(); |
2654 | } |
2655 | } |
2656 | } |
2657 | break; |
2658 | case ApplicationEvent::TYPE_HELP: |
2659 | displayCmdlineHelp(rAppEvent.GetStringData()); |
2660 | break; |
2661 | case ApplicationEvent::TYPE_VERSION: |
2662 | displayVersion(); |
2663 | break; |
2664 | case ApplicationEvent::TYPE_OPEN: |
2665 | { |
2666 | const CommandLineArgs& rCmdLine = GetCommandLineArgs(); |
2667 | if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() ) |
2668 | { |
2669 | ProcessDocumentsRequest* pDocsRequest = new ProcessDocumentsRequest( |
2670 | rCmdLine.getCwdUrl()); |
2671 | std::vector<OUString> const & data(rAppEvent.GetStringsData()); |
2672 | pDocsRequest->aOpenList.insert( |
2673 | pDocsRequest->aOpenList.end(), data.begin(), data.end()); |
2674 | pDocsRequest->pcProcessed = NULL; |
2675 | |
2676 | OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest ); |
2677 | delete pDocsRequest; |
2678 | } |
2679 | } |
2680 | break; |
2681 | case ApplicationEvent::TYPE_OPENHELPURL: |
2682 | // start help for a specific URL |
2683 | Application::GetHelp()->Start(rAppEvent.GetStringData(), NULL); |
2684 | break; |
2685 | case ApplicationEvent::TYPE_PRINT: |
2686 | { |
2687 | const CommandLineArgs& rCmdLine = GetCommandLineArgs(); |
2688 | if ( !rCmdLine.IsInvisible() && !rCmdLine.IsTerminateAfterInit() ) |
2689 | { |
2690 | ProcessDocumentsRequest* pDocsRequest = new ProcessDocumentsRequest( |
2691 | rCmdLine.getCwdUrl()); |
2692 | std::vector<OUString> const & data(rAppEvent.GetStringsData()); |
2693 | pDocsRequest->aPrintList.insert( |
2694 | pDocsRequest->aPrintList.end(), data.begin(), data.end()); |
2695 | pDocsRequest->pcProcessed = NULL; |
2696 | |
2697 | OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest ); |
2698 | delete pDocsRequest; |
2699 | } |
2700 | } |
2701 | break; |
2702 | case ApplicationEvent::TYPE_PRIVATE_DOSHUTDOWN: |
2703 | { |
2704 | Desktop* pD = dynamic_cast<Desktop*>(GetpApp()); |
2705 | OSL_ENSURE( pD, "no desktop ?!?" ); |
2706 | if( pD ) |
2707 | pD->doShutdown(); |
2708 | } |
2709 | break; |
2710 | case ApplicationEvent::TYPE_QUICKSTART: |
2711 | if ( !GetCommandLineArgs().IsInvisible() ) |
2712 | { |
2713 | // If the office has been started the second time its command line arguments are sent through a pipe |
2714 | // connection to the first office. We want to reuse the quickstart option for the first office. |
2715 | // NOTICE: The quickstart service must be initialized inside the "main thread", so we use the |
2716 | // application events to do this (they are executed inside main thread)!!! |
2717 | // Don't start quickstart service if the user specified "--invisible" on the command line! |
2718 | Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
2719 | css::office::Quickstart::createStart(xContext, true/*Quickstart*/); |
2720 | } |
2721 | break; |
2722 | case ApplicationEvent::TYPE_SHOWDIALOG: |
2723 | // ignore all errors here. It's clicking a menu entry only ... |
2724 | // The user will try it again, in case nothing happens .-) |
2725 | try |
2726 | { |
2727 | Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
2728 | |
2729 | Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( xContext ); |
2730 | |
2731 | Reference< css::util::XURLTransformer > xParser = css::util::URLTransformer::create(xContext); |
2732 | css::util::URL aCommand; |
2733 | if( rAppEvent.GetStringData() == "PREFERENCES" ) |
2734 | aCommand.Complete = ".uno:OptionsTreeDialog" ; |
2735 | else if( rAppEvent.GetStringData() == "ABOUT" ) |
2736 | aCommand.Complete = ".uno:About" ; |
2737 | if( !aCommand.Complete.isEmpty() ) |
2738 | { |
2739 | xParser->parseStrict(aCommand); |
2740 | |
2741 | css::uno::Reference< css::frame::XDispatch > xDispatch = xDesktop->queryDispatch(aCommand, OUString(), 0); |
2742 | if (xDispatch.is()) |
2743 | xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >()); |
2744 | } |
2745 | } |
2746 | catch(const css::uno::Exception&) |
2747 | {} |
2748 | break; |
2749 | case ApplicationEvent::TYPE_UNACCEPT: |
2750 | // try to remove corresponding acceptor |
2751 | destroyAcceptor(rAppEvent.GetStringData()); |
2752 | break; |
2753 | default: |
2754 | SAL_WARN( "desktop.app" , "this cannot happen" ); |
2755 | break; |
2756 | } |
2757 | } |
2758 | |
2759 | void Desktop::OpenSplashScreen() |
2760 | { |
2761 | const CommandLineArgs &rCmdLine = GetCommandLineArgs(); |
2762 | sal_Bool bVisible = sal_False; |
2763 | // Show intro only if this is normal start (e.g. no server, no quickstart, no printing ) |
2764 | if ( !rCmdLine.IsInvisible() && |
2765 | !rCmdLine.IsHeadless() && |
2766 | !rCmdLine.IsQuickstart() && |
2767 | !rCmdLine.IsMinimized() && |
2768 | !rCmdLine.IsNoLogo() && |
2769 | !rCmdLine.IsTerminateAfterInit() && |
2770 | rCmdLine.GetPrintList().empty() && |
2771 | rCmdLine.GetPrintToList().empty() && |
2772 | rCmdLine.GetConversionList().empty() ) |
2773 | { |
2774 | // Determine application name from command line parameters |
2775 | OUString aAppName; |
2776 | if ( rCmdLine.IsWriter() ) |
2777 | aAppName = "writer" ; |
2778 | else if ( rCmdLine.IsCalc() ) |
2779 | aAppName = "calc" ; |
2780 | else if ( rCmdLine.IsDraw() ) |
2781 | aAppName = "draw" ; |
2782 | else if ( rCmdLine.IsImpress() ) |
2783 | aAppName = "impress" ; |
2784 | else if ( rCmdLine.IsBase() ) |
2785 | aAppName = "base" ; |
2786 | else if ( rCmdLine.IsGlobal() ) |
2787 | aAppName = "global" ; |
2788 | else if ( rCmdLine.IsMath() ) |
2789 | aAppName = "math" ; |
2790 | else if ( rCmdLine.IsWeb() ) |
2791 | aAppName = "web" ; |
2792 | |
2793 | // Which splash to use |
2794 | OUString aSplashService( "com.sun.star.office.SplashScreen" ); |
2795 | if ( rCmdLine.HasSplashPipe() ) |
2796 | aSplashService = "com.sun.star.office.PipeSplashScreen" ; |
2797 | |
2798 | bVisible = sal_True; |
2799 | Sequence< Any > aSeq( 2 ); |
2800 | aSeq[0] <<= bVisible; |
2801 | aSeq[1] <<= aAppName; |
2802 | css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
2803 | m_rSplashScreen = Reference<XStatusIndicator>( |
2804 | xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aSplashService, aSeq, xContext), |
2805 | UNO_QUERY); |
2806 | |
2807 | if(m_rSplashScreen.is()) |
2808 | m_rSplashScreen->start(OUString("SplashScreen" ), 100); |
2809 | } |
2810 | |
2811 | } |
2812 | |
2813 | void Desktop::SetSplashScreenProgress(sal_Int32 iProgress) |
2814 | { |
2815 | if(m_rSplashScreen.is()) |
2816 | { |
2817 | m_rSplashScreen->setValue(iProgress); |
2818 | } |
2819 | } |
2820 | |
2821 | void Desktop::SetSplashScreenText( const OUString& rText ) |
2822 | { |
2823 | if( m_rSplashScreen.is() ) |
2824 | { |
2825 | m_rSplashScreen->setText( rText ); |
2826 | } |
2827 | } |
2828 | |
2829 | void Desktop::CloseSplashScreen() |
2830 | { |
2831 | if(m_rSplashScreen.is()) |
2832 | { |
2833 | m_rSplashScreen->end(); |
2834 | m_rSplashScreen = NULL; |
2835 | } |
2836 | } |
2837 | |
2838 | // ======================================================================== |
2839 | void Desktop::DoFirstRunInitializations() |
2840 | { |
2841 | try |
2842 | { |
2843 | Reference< XJobExecutor > xExecutor = theJobExecutor::get( ::comphelper::getProcessComponentContext() ); |
2844 | xExecutor->trigger( OUString("onFirstRunInitialization" ) ); |
2845 | } |
2846 | catch(const ::com::sun::star::uno::Exception&) |
2847 | { |
2848 | SAL_WARN( "desktop.app" , "Desktop::DoFirstRunInitializations: caught an exception while trigger job executor ..." ); |
2849 | } |
2850 | } |
2851 | |
2852 | void Desktop::ShowBackingComponent(Desktop * progress) |
2853 | { |
2854 | if (GetCommandLineArgs().IsNoDefault()) |
2855 | { |
2856 | return; |
2857 | } |
2858 | Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); |
2859 | Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xContext); |
2860 | if (progress != 0) |
2861 | { |
2862 | progress->SetSplashScreenProgress(60); |
2863 | } |
2864 | Reference< XFrame > xBackingFrame = xDesktop->findFrame(OUString( "_blank" ), 0); |
2865 | Reference< ::com::sun::star::awt::XWindow > xContainerWindow; |
2866 | |
2867 | if (xBackingFrame.is()) |
2868 | xContainerWindow = xBackingFrame->getContainerWindow(); |
2869 | if (xContainerWindow.is()) |
2870 | { |
2871 | // set the WB_EXT_DOCUMENT style. Normally, this is done by the TaskCreator service when a "_blank" |
2872 | // frame/window is created. Since we do not use the TaskCreator here, we need to mimic its behavior, |
2873 | // otherwise documents loaded into this frame will later on miss functionality depending on the style. |
2874 | Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow ); |
2875 | SAL_WARN_IF( !pContainerWindow, "desktop.app" , "Desktop::Main: no implementation access to the frame's container window!" ); |
2876 | pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WB_EXT_DOCUMENT ); |
2877 | if (progress != 0) |
2878 | { |
2879 | progress->SetSplashScreenProgress(75); |
2880 | } |
2881 | |
2882 | Reference< XController > xStartModule = StartModule::createWithParentWindow( xContext, xContainerWindow); |
2883 | // Attention: You MUST(!) call setComponent() before you call attachFrame(). |
2884 | // Because the backing component set the property "IsBackingMode" of the frame |
2885 | // to true inside attachFrame(). But setComponent() reset this state everytimes ... |
2886 | xBackingFrame->setComponent(Reference< XWindow >(xStartModule, UNO_QUERY), xStartModule); |
2887 | if (progress != 0) |
2888 | { |
2889 | progress->SetSplashScreenProgress(100); |
2890 | } |
2891 | xStartModule->attachFrame(xBackingFrame); |
2892 | if (progress != 0) |
2893 | { |
2894 | progress->CloseSplashScreen(); |
2895 | } |
2896 | xContainerWindow->setVisible(sal_True); |
2897 | } |
2898 | } |
2899 | |
2900 | // ======================================================================== |
2901 | void Desktop::CheckFirstRun( ) |
2902 | { |
2903 | if (officecfg::Office::Common::Misc::FirstRun::get()) |
2904 | { |
2905 | // this has once been done using a vos timer. this could lead to problems when |
2906 | // the timer would trigger when the app is already going down again, since VCL would |
2907 | // no longer be available. Since the old handler would do a postUserEvent to the main |
2908 | // thread anyway, we can use a vcl timer here to prevent the race contition (#107197#) |
2909 | m_firstRunTimer.SetTimeout(3000); // 3 sec. |
2910 | m_firstRunTimer.SetTimeoutHdl(LINK(this, Desktop, AsyncInitFirstRun)); |
2911 | m_firstRunTimer.Start(); |
2912 | |
2913 | #ifdef WNT |
2914 | // Check if Quckstarter should be started (on Windows only) |
2915 | TCHAR szValue[8192]; |
2916 | DWORD nValueSize = sizeof(szValue); |
2917 | HKEY hKey; |
2918 | if ( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\LibreOffice" , &hKey ) ) |
2919 | { |
2920 | if ( ERROR_SUCCESS == RegQueryValueEx( hKey, TEXT("RunQuickstartAtFirstStart" ), NULL, NULL, (LPBYTE)szValue, &nValueSize ) ) |
2921 | { |
2922 | css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); |
2923 | css::office::Quickstart::createAutoStart(xContext, true/*Quickstart*/, true/*bAutostart*/); |
2924 | RegCloseKey( hKey ); |
2925 | } |
2926 | } |
2927 | #endif |
2928 | |
2929 | boost::shared_ptr< comphelper::ConfigurationChanges > batch( |
2930 | comphelper::ConfigurationChanges::create()); |
2931 | officecfg::Office::Common::Misc::FirstRun::set(false, batch); |
2932 | batch->commit(); |
2933 | } |
2934 | } |
2935 | |
2936 | } |
2937 | |
2938 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
2939 | |