1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
23 #include "officeipcthread.hxx"
24 #include "cmdlineargs.hxx"
25 #include "dispatchwatcher.hxx"
28 #include <osl/process.h>
29 #include <unotools/bootstrap.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/help.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <osl/thread.hxx>
34 #include <rtl/digest.h>
35 #include <rtl/ustrbuf.hxx>
36 #include <rtl/instance.hxx>
37 #include <osl/conditn.hxx>
38 #include <unotools/moduleoptions.hxx>
39 #include <rtl/bootstrap.hxx>
40 #include <rtl/strbuf.hxx>
41 #include <comphelper/processfactory.hxx>
42 #include <cppuhelper/supportsservice.hxx>
43 #include <osl/file.hxx>
44 #include <rtl/process.h>
45 #include "tools/getprocessworkingdir.hxx"
47 using namespace desktop
;
48 using namespace ::com::sun::star::uno
;
49 using namespace ::com::sun::star::lang
;
50 using namespace ::com::sun::star::frame
;
53 const char *OfficeIPCThread::sc_aShowSequence
= "-tofront";
54 const int OfficeIPCThread::sc_nShSeqLength
= 5;
58 static char const ARGUMENT_PREFIX
[] = "InternalIPC::Arguments";
60 #if HAVE_FEATURE_DESKTOP
62 static char const SEND_ARGUMENTS
[] = "InternalIPC::SendArguments";
63 static char const PROCESSING_DONE
[] = "InternalIPC::ProcessingDone";
65 // Receives packets from the pipe until a packet ends in a NUL character (that
66 // will not be included in the returned string) or it cannot read anything (due
67 // to error or closed pipe, in which case an empty string will be returned to
69 OString
readStringFromPipe(osl::StreamPipe
& pipe
) {
70 for (OStringBuffer str
;;) {
72 sal_Int32 n
= pipe
.recv(buf
, SAL_N_ELEMENTS(buf
));
77 if (buf
[n
- 1] == '\0') {
82 //TODO: how does OStringBuffer.append handle overflow?
84 return str
.makeStringAndClear();
93 // Type of pipe we use
106 #if HAVE_FEATURE_DESKTOP
108 class Parser
: public CommandLineArgs::Supplier
{
110 explicit Parser(OString
const & input
): m_input(input
) {
111 if (!m_input
.match(ARGUMENT_PREFIX
) ||
112 m_input
.getLength() == RTL_CONSTASCII_LENGTH(ARGUMENT_PREFIX
))
114 throw CommandLineArgs::Supplier::Exception();
116 m_index
= RTL_CONSTASCII_LENGTH(ARGUMENT_PREFIX
);
117 switch (m_input
[m_index
++]) {
123 if (!next(&url
, false)) {
124 throw CommandLineArgs::Supplier::Exception();
132 if (!next(&path
, false)) {
133 throw CommandLineArgs::Supplier::Exception();
136 if (osl::FileBase::getFileURLFromSystemPath(path
, url
) ==
137 osl::FileBase::E_None
)
144 throw CommandLineArgs::Supplier::Exception();
150 virtual boost::optional
< OUString
> getCwdUrl() { return m_cwdUrl
; }
152 virtual bool next(OUString
* argument
) { return next(argument
, true); }
155 virtual bool next(OUString
* argument
, bool prefix
) {
156 OSL_ASSERT(argument
!= NULL
);
157 if (m_index
< m_input
.getLength()) {
159 if (m_input
[m_index
] != ',') {
160 throw CommandLineArgs::Supplier::Exception();
165 while (m_index
< m_input
.getLength()) {
166 char c
= m_input
[m_index
];
172 if (m_index
< m_input
.getLength()) {
173 c
= m_input
[m_index
++];
182 throw CommandLineArgs::Supplier::Exception();
185 throw CommandLineArgs::Supplier::Exception();
190 OString
b2(b
.makeStringAndClear());
191 if (!rtl_convertStringToUString(
192 &argument
->pData
, b2
.getStr(), b2
.getLength(),
193 RTL_TEXTENCODING_UTF8
,
194 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
195 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
196 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
198 throw CommandLineArgs::Supplier::Exception();
206 boost::optional
< OUString
> m_cwdUrl
;
211 bool addArgument(OStringBuffer
&rArguments
, char prefix
,
212 const OUString
&rArgument
)
215 if (!rArgument
.convertToString(
216 &utf8
, RTL_TEXTENCODING_UTF8
,
217 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
218 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
222 rArguments
.append(prefix
);
223 for (sal_Int32 i
= 0; i
< utf8
.getLength(); ++i
) {
227 rArguments
.append("\\0");
230 rArguments
.append("\\,");
233 rArguments
.append("\\\\");
236 rArguments
.append(c
);
247 rtl::Reference
< OfficeIPCThread
> OfficeIPCThread::pGlobalOfficeIPCThread
;
248 namespace { struct Security
: public rtl::Static
<osl::Security
, Security
> {}; }
250 // Turns a string in aMsg such as file:///home/foo/.libreoffice/3
251 // Into a hex string of well known length ff132a86...
252 String
CreateMD5FromString( const OUString
& aMsg
)
254 #if (OSL_DEBUG_LEVEL > 2)
255 fprintf( stderr
, "create md5 from '%s'\n",
256 OUStringToOString (aMsg
, RTL_TEXTENCODING_UTF8
).getStr() );
259 rtlDigest handle
= rtl_digest_create( rtl_Digest_AlgorithmMD5
);
262 const sal_uInt8
* pData
= (const sal_uInt8
*)aMsg
.getStr();
263 sal_uInt32 nSize
= ( aMsg
.getLength() * sizeof( sal_Unicode
));
264 sal_uInt32 nMD5KeyLen
= rtl_digest_queryLength( handle
);
265 sal_uInt8
* pMD5KeyBuffer
= new sal_uInt8
[ nMD5KeyLen
];
267 rtl_digest_init( handle
, pData
, nSize
);
268 rtl_digest_update( handle
, pData
, nSize
);
269 rtl_digest_get( handle
, pMD5KeyBuffer
, nMD5KeyLen
);
270 rtl_digest_destroy( handle
);
272 // Create hex-value string from the MD5 value to keep the string size minimal
273 OUStringBuffer
aBuffer( nMD5KeyLen
* 2 + 1 );
274 for ( sal_uInt32 i
= 0; i
< nMD5KeyLen
; i
++ )
275 aBuffer
.append( (sal_Int32
)pMD5KeyBuffer
[i
], 16 );
277 delete [] pMD5KeyBuffer
;
278 return aBuffer
.makeStringAndClear();
284 class ProcessEventsClass_Impl
287 DECL_STATIC_LINK( ProcessEventsClass_Impl
, CallEvent
, void* pEvent
);
288 DECL_STATIC_LINK( ProcessEventsClass_Impl
, ProcessDocumentsEvent
, void* pEvent
);
291 IMPL_STATIC_LINK_NOINSTANCE( ProcessEventsClass_Impl
, CallEvent
, void*, pEvent
)
293 // Application events are processed by the Desktop::HandleAppEvent implementation.
294 Desktop::HandleAppEvent( *((ApplicationEvent
*)pEvent
) );
295 delete (ApplicationEvent
*)pEvent
;
299 IMPL_STATIC_LINK_NOINSTANCE( ProcessEventsClass_Impl
, ProcessDocumentsEvent
, void*, pEvent
)
301 // Documents requests are processed by the OfficeIPCThread implementation
302 ProcessDocumentsRequest
* pDocsRequest
= (ProcessDocumentsRequest
*)pEvent
;
306 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest
);
312 void ImplPostForeignAppEvent( ApplicationEvent
* pEvent
)
314 Application::PostUserEvent( STATIC_LINK( NULL
, ProcessEventsClass_Impl
, CallEvent
), pEvent
);
317 void ImplPostProcessDocumentsEvent( ProcessDocumentsRequest
* pEvent
)
319 Application::PostUserEvent( STATIC_LINK( NULL
, ProcessEventsClass_Impl
, ProcessDocumentsEvent
), pEvent
);
322 oslSignalAction SAL_CALL
SalMainPipeExchangeSignal_impl(void* /*pData*/, oslSignalInfo
* pInfo
)
324 if( pInfo
->Signal
== osl_Signal_Terminate
)
325 OfficeIPCThread::DisableOfficeIPCThread(false);
326 return osl_Signal_ActCallNextHdl
;
329 // ----------------------------------------------------------------------------
331 // The OfficeIPCThreadController implementation is a bookkeeper for all pending requests
332 // that were created by the OfficeIPCThread. The requests are waiting to be processed by
333 // our framework loadComponentFromURL function (e.g. open/print request).
334 // During shutdown the framework is asking OfficeIPCThreadController about pending requests.
335 // If there are pending requests framework has to stop the shutdown process. It is waiting
336 // for these requests because framework is not able to handle shutdown and open a document
341 OUString SAL_CALL
OfficeIPCThreadController::getImplementationName()
342 throw ( RuntimeException
)
344 return OUString( "com.sun.star.comp.OfficeIPCThreadController" );
347 sal_Bool
OfficeIPCThreadController::supportsService(
348 OUString
const & ServiceName
) throw (css::uno::RuntimeException
)
350 return cppu::supportsService(this, ServiceName
);
353 Sequence
< OUString
> SAL_CALL
OfficeIPCThreadController::getSupportedServiceNames()
354 throw ( RuntimeException
)
356 Sequence
< OUString
> aSeq( 0 );
361 void SAL_CALL
OfficeIPCThreadController::disposing( const EventObject
& )
362 throw( RuntimeException
)
366 // XTerminateListener
367 void SAL_CALL
OfficeIPCThreadController::queryTermination( const EventObject
& )
368 throw( TerminationVetoException
, RuntimeException
)
370 // Desktop ask about pending request through our office ipc pipe. We have to
371 // be sure that no pending request is waiting because framework is not able to
372 // handle shutdown and open a document concurrently.
374 if ( OfficeIPCThread::AreRequestsPending() )
375 throw TerminationVetoException();
377 OfficeIPCThread::SetDowning();
380 void SAL_CALL
OfficeIPCThreadController::notifyTermination( const EventObject
& )
381 throw( RuntimeException
)
387 class theOfficeIPCThreadMutex
388 : public rtl::Static
<osl::Mutex
, theOfficeIPCThreadMutex
> {};
391 ::osl::Mutex
& OfficeIPCThread::GetMutex()
393 return theOfficeIPCThreadMutex::get();
396 void OfficeIPCThread::SetDowning()
398 // We have the order to block all incoming requests. Framework
399 // wants to shutdown and we have to make sure that no loading/printing
400 // requests are executed anymore.
401 ::osl::MutexGuard
aGuard( GetMutex() );
403 if ( pGlobalOfficeIPCThread
.is() )
404 pGlobalOfficeIPCThread
->mbDowning
= true;
407 static bool s_bInEnableRequests
= false;
409 void OfficeIPCThread::EnableRequests( bool i_bEnable
)
411 // switch between just queueing the requests and executing them
412 ::osl::MutexGuard
aGuard( GetMutex() );
414 if ( pGlobalOfficeIPCThread
.is() )
416 s_bInEnableRequests
= true;
417 pGlobalOfficeIPCThread
->mbRequestsEnabled
= i_bEnable
;
420 // hit the compiler over the head
421 ProcessDocumentsRequest aEmptyReq
= ProcessDocumentsRequest( boost::optional
< OUString
>() );
422 // trigger already queued requests
423 OfficeIPCThread::ExecuteCmdLineRequests( aEmptyReq
);
425 s_bInEnableRequests
= false;
429 sal_Bool
OfficeIPCThread::AreRequestsPending()
431 // Give info about pending requests
432 ::osl::MutexGuard
aGuard( GetMutex() );
433 if ( pGlobalOfficeIPCThread
.is() )
434 return ( pGlobalOfficeIPCThread
->mnPendingRequests
> 0 );
439 void OfficeIPCThread::RequestsCompleted( int nCount
)
441 // Remove nCount pending requests from our internal counter
442 ::osl::MutexGuard
aGuard( GetMutex() );
443 if ( pGlobalOfficeIPCThread
.is() )
445 if ( pGlobalOfficeIPCThread
->mnPendingRequests
> 0 )
446 pGlobalOfficeIPCThread
->mnPendingRequests
-= nCount
;
450 OfficeIPCThread::Status
OfficeIPCThread::EnableOfficeIPCThread()
452 #if HAVE_FEATURE_DESKTOP
453 ::osl::MutexGuard
aGuard( GetMutex() );
455 if( pGlobalOfficeIPCThread
.is() )
456 return IPC_STATUS_OK
;
458 OUString aUserInstallPath
;
461 rtl::Reference
< OfficeIPCThread
> pThread(new OfficeIPCThread
);
463 // The name of the named pipe is created with the hashcode of the user installation directory (without /user). We have to retrieve
464 // this information from a unotools implementation.
465 ::utl::Bootstrap::PathStatus aLocateResult
= ::utl::Bootstrap::locateUserInstallation( aUserInstallPath
);
466 if ( aLocateResult
== ::utl::Bootstrap::PATH_EXISTS
|| aLocateResult
== ::utl::Bootstrap::PATH_VALID
)
467 aDummy
= aUserInstallPath
;
470 return IPC_STATUS_BOOTSTRAP_ERROR
;
473 // Try to determine if we are the first office or not! This should prevent multiple
474 // access to the user directory !
475 // First we try to create our pipe if this fails we try to connect. We have to do this
476 // in a loop because the other office can crash or shutdown between createPipe
481 osl_getExecutableFile( &aIniName
.pData
);
483 sal_uInt32 lastIndex
= aIniName
.lastIndexOf('/');
486 aIniName
= aIniName
.copy( 0, lastIndex
+1 );
487 aIniName
+= "perftune";
495 ::rtl::Bootstrap
aPerfTuneIniFile( aIniName
);
497 OUString
aDefault( "0" );
498 OUString aPreloadData
;
500 aPerfTuneIniFile
.getFrom( OUString( "FastPipeCommunication" ), aPreloadData
, aDefault
);
503 OUString aUserInstallPathHashCode
;
505 if ( aPreloadData
== "1" )
507 sal_Char szBuffer
[32];
508 sprintf( szBuffer
, "%d", SUPD
);
509 aUserInstallPathHashCode
= OUString( szBuffer
, strlen(szBuffer
), osl_getThreadTextEncoding() );
512 aUserInstallPathHashCode
= CreateMD5FromString( aDummy
);
515 // Check result to create a hash code from the user install path
516 if ( aUserInstallPathHashCode
.isEmpty() )
517 return IPC_STATUS_BOOTSTRAP_ERROR
; // Something completely broken, we cannot create a valid hash code!
519 OUString
aPipeIdent( "SingleOfficeIPC_" + aUserInstallPathHashCode
);
521 PipeMode nPipeMode
= PIPEMODE_DONTKNOW
;
524 osl::Security
&rSecurity
= Security::get();
525 // Try to create pipe
526 if ( pThread
->maPipe
.create( aPipeIdent
.getStr(), osl_Pipe_CREATE
, rSecurity
))
529 nPipeMode
= PIPEMODE_CREATED
;
531 else if( pThread
->maPipe
.create( aPipeIdent
.getStr(), osl_Pipe_OPEN
, rSecurity
)) // Creation not successful, now we try to connect
533 osl::StreamPipe
aStreamPipe(pThread
->maPipe
.getHandle());
534 if (readStringFromPipe(aStreamPipe
) == SEND_ARGUMENTS
)
536 // Pipe connected to first office
537 nPipeMode
= PIPEMODE_CONNECTED
;
541 // Pipe connection failed (other office exited or crashed)
544 tval
.Nanosec
= 500000000;
545 salhelper::Thread::wait( tval
);
550 oslPipeError eReason
= pThread
->maPipe
.getError();
551 if ((eReason
== osl_Pipe_E_ConnectionRefused
) || (eReason
== osl_Pipe_E_invalidError
))
552 return IPC_STATUS_PIPE_ERROR
;
554 // Wait for second office to be ready
555 TimeValue aTimeValue
;
556 aTimeValue
.Seconds
= 0;
557 aTimeValue
.Nanosec
= 10000000; // 10ms
558 salhelper::Thread::wait( aTimeValue
);
561 } while ( nPipeMode
== PIPEMODE_DONTKNOW
);
563 if ( nPipeMode
== PIPEMODE_CREATED
)
565 // Seems we are the one and only, so start listening thread
566 pGlobalOfficeIPCThread
= pThread
;
571 // Seems another office is running. Pipe arguments to it and self terminate
572 osl::StreamPipe
aStreamPipe(pThread
->maPipe
.getHandle());
574 OStringBuffer
aArguments(ARGUMENT_PREFIX
);
576 if (!(tools::getProcessWorkingDir(cwdUrl
) &&
577 addArgument(aArguments
, '1', cwdUrl
)))
579 aArguments
.append('0');
581 sal_uInt32 nCount
= rtl_getAppCommandArgCount();
582 for( sal_uInt32 i
=0; i
< nCount
; i
++ )
584 rtl_getAppCommandArg( i
, &aDummy
.pData
);
585 if (!addArgument(aArguments
, ',', aDummy
)) {
586 return IPC_STATUS_BOOTSTRAP_ERROR
;
589 aArguments
.append('\0');
590 // finally, write the string onto the pipe
591 sal_Int32 n
= aStreamPipe
.write(
592 aArguments
.getStr(), aArguments
.getLength());
593 if (n
!= aArguments
.getLength()) {
594 SAL_INFO("desktop", "short write: " << n
);
595 return IPC_STATUS_BOOTSTRAP_ERROR
;
598 if (readStringFromPipe(aStreamPipe
) != PROCESSING_DONE
)
600 // something went wrong
601 return IPC_STATUS_BOOTSTRAP_ERROR
;
604 return IPC_STATUS_2ND_OFFICE
;
607 pGlobalOfficeIPCThread
= rtl::Reference
< OfficeIPCThread
>(new OfficeIPCThread
);
609 return IPC_STATUS_OK
;
612 void OfficeIPCThread::DisableOfficeIPCThread(bool join
)
614 #if HAVE_FEATURE_DESKTOP
615 osl::ClearableMutexGuard
aMutex( GetMutex() );
617 if( pGlobalOfficeIPCThread
.is() )
619 rtl::Reference
< OfficeIPCThread
> pOfficeIPCThread(
620 pGlobalOfficeIPCThread
);
621 pGlobalOfficeIPCThread
.clear();
623 pOfficeIPCThread
->mbDowning
= true;
624 pOfficeIPCThread
->maPipe
.close();
626 // release mutex to avoid deadlocks
629 OfficeIPCThread::SetReady(pOfficeIPCThread
);
631 // exit gracefully and join
634 pOfficeIPCThread
->join();
642 OfficeIPCThread::OfficeIPCThread() :
643 Thread( "OfficeIPCThread" ),
645 mbRequestsEnabled( false ),
646 mnPendingRequests( 0 ),
647 mpDispatchWatcher( 0 )
651 OfficeIPCThread::~OfficeIPCThread()
653 ::osl::ClearableMutexGuard
aGuard( GetMutex() );
655 if ( mpDispatchWatcher
)
656 mpDispatchWatcher
->release();
658 pGlobalOfficeIPCThread
.clear();
661 void OfficeIPCThread::SetReady(
662 rtl::Reference
< OfficeIPCThread
> const & pThread
)
664 rtl::Reference
< OfficeIPCThread
> const & t(
665 pThread
.is() ? pThread
: pGlobalOfficeIPCThread
);
672 void OfficeIPCThread::execute()
674 #if HAVE_FEATURE_DESKTOP
677 osl::StreamPipe aStreamPipe
;
678 oslPipeError nError
= maPipe
.accept( aStreamPipe
);
681 if( nError
== osl_Pipe_E_None
)
683 // if we receive a request while the office is displaying some dialog or error during
684 // bootstrap, that dialogs event loop might get events that are dispatched by this thread
685 // we have to wait for cReady to be set by the real main loop.
686 // only reqests that dont dispatch events may be processed before cReady is set.
689 // we might have decided to shutdown while we were sleeping
690 if (!pGlobalOfficeIPCThread
.is()) return;
692 // only lock the mutex when processing starts, othewise we deadlock when the office goes
694 osl::ClearableMutexGuard
aGuard( GetMutex() );
701 // notify client we're ready to process its args:
702 sal_Int32 n
= aStreamPipe
.write(
703 SEND_ARGUMENTS
, SAL_N_ELEMENTS(SEND_ARGUMENTS
));
704 // incl. terminating NUL
705 if (n
!= SAL_N_ELEMENTS(SEND_ARGUMENTS
)) {
706 SAL_WARN("desktop", "short write: " << n
);
710 OString aArguments
= readStringFromPipe(aStreamPipe
);
712 // Is this a lookup message from another application? if so, ignore
713 if (aArguments
.isEmpty())
716 std::auto_ptr
< CommandLineArgs
> aCmdLineArgs
;
719 Parser
p(aArguments
);
720 aCmdLineArgs
.reset( new CommandLineArgs( p
) );
722 catch ( const CommandLineArgs::Supplier::Exception
& )
724 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
725 fprintf( stderr
, "Error in received command line arguments\n" );
730 sal_Bool bDocRequestSent
= sal_False
;
732 OUString
aUnknown( aCmdLineArgs
->GetUnknown() );
733 if ( !aUnknown
.isEmpty() || aCmdLineArgs
->IsHelp() )
735 ApplicationEvent
* pAppEvent
=
736 new ApplicationEvent(ApplicationEvent::TYPE_HELP
, aUnknown
);
737 ImplPostForeignAppEvent( pAppEvent
);
739 else if ( aCmdLineArgs
->IsVersion() )
741 ApplicationEvent
* pAppEvent
=
742 new ApplicationEvent(ApplicationEvent::TYPE_VERSION
);
743 ImplPostForeignAppEvent( pAppEvent
);
747 const CommandLineArgs
&rCurrentCmdLineArgs
= Desktop::GetCommandLineArgs();
749 if ( aCmdLineArgs
->IsQuickstart() )
751 // we have to use application event, because we have to start quickstart service in main thread!!
752 ApplicationEvent
* pAppEvent
=
753 new ApplicationEvent(ApplicationEvent::TYPE_QUICKSTART
);
754 ImplPostForeignAppEvent( pAppEvent
);
757 // handle request for acceptor
758 std::vector
< OUString
> const & accept
= aCmdLineArgs
->
760 for (std::vector
< OUString
>::const_iterator
i(accept
.begin());
761 i
!= accept
.end(); ++i
)
763 ApplicationEvent
* pAppEvent
= new ApplicationEvent(
764 ApplicationEvent::TYPE_ACCEPT
, *i
);
765 ImplPostForeignAppEvent( pAppEvent
);
767 // handle acceptor removal
768 std::vector
< OUString
> const & unaccept
= aCmdLineArgs
->
770 for (std::vector
< OUString
>::const_iterator
i(
772 i
!= unaccept
.end(); ++i
)
774 ApplicationEvent
* pAppEvent
= new ApplicationEvent(
775 ApplicationEvent::TYPE_UNACCEPT
, *i
);
776 ImplPostForeignAppEvent( pAppEvent
);
779 ProcessDocumentsRequest
* pRequest
= new ProcessDocumentsRequest(
780 aCmdLineArgs
->getCwdUrl());
782 pRequest
->pcProcessed
= &cProcessed
;
784 // Print requests are not dependent on the --invisible cmdline argument as they are
785 // loaded with the "hidden" flag! So they are always checked.
786 pRequest
->aPrintList
= aCmdLineArgs
->GetPrintList();
787 bDocRequestSent
|= !pRequest
->aPrintList
.empty();
788 pRequest
->aPrintToList
= aCmdLineArgs
->GetPrintToList();
789 pRequest
->aPrinterName
= aCmdLineArgs
->GetPrinterName();
790 bDocRequestSent
|= !( pRequest
->aPrintToList
.empty() || pRequest
->aPrinterName
.isEmpty() );
792 if ( !rCurrentCmdLineArgs
.IsInvisible() )
794 // Read cmdline args that can open/create documents. As they would open a window
795 // they are only allowed if the "--invisible" is currently not used!
796 pRequest
->aOpenList
= aCmdLineArgs
->GetOpenList();
797 bDocRequestSent
|= !pRequest
->aOpenList
.empty();
798 pRequest
->aViewList
= aCmdLineArgs
->GetViewList();
799 bDocRequestSent
|= !pRequest
->aViewList
.empty();
800 pRequest
->aStartList
= aCmdLineArgs
->GetStartList();
801 bDocRequestSent
|= !pRequest
->aStartList
.empty();
802 pRequest
->aForceOpenList
= aCmdLineArgs
->GetForceOpenList();
803 bDocRequestSent
|= !pRequest
->aForceOpenList
.empty();
804 pRequest
->aForceNewList
= aCmdLineArgs
->GetForceNewList();
805 bDocRequestSent
|= !pRequest
->aForceNewList
.empty();
807 // Special command line args to create an empty document for a given module
810 // we only do this if no document was specified on the command line,
811 // since this would be inconsistent with the behaviour of
812 // the first process, see OpenClients() (call to OpenDefault()) in app.cxx
813 if ( aCmdLineArgs
->HasModuleParam() && (!bDocRequestSent
) )
815 SvtModuleOptions aOpt
;
816 SvtModuleOptions::EFactory eFactory
= SvtModuleOptions::E_WRITER
;
817 if ( aCmdLineArgs
->IsWriter() )
818 eFactory
= SvtModuleOptions::E_WRITER
;
819 else if ( aCmdLineArgs
->IsCalc() )
820 eFactory
= SvtModuleOptions::E_CALC
;
821 else if ( aCmdLineArgs
->IsDraw() )
822 eFactory
= SvtModuleOptions::E_DRAW
;
823 else if ( aCmdLineArgs
->IsImpress() )
824 eFactory
= SvtModuleOptions::E_IMPRESS
;
825 else if ( aCmdLineArgs
->IsBase() )
826 eFactory
= SvtModuleOptions::E_DATABASE
;
827 else if ( aCmdLineArgs
->IsMath() )
828 eFactory
= SvtModuleOptions::E_MATH
;
829 else if ( aCmdLineArgs
->IsGlobal() )
830 eFactory
= SvtModuleOptions::E_WRITERGLOBAL
;
831 else if ( aCmdLineArgs
->IsWeb() )
832 eFactory
= SvtModuleOptions::E_WRITERWEB
;
834 if ( !pRequest
->aOpenList
.empty() )
835 pRequest
->aModule
= aOpt
.GetFactoryName( eFactory
);
837 pRequest
->aOpenList
.push_back( aOpt
.GetFactoryEmptyDocumentURL( eFactory
) );
838 bDocRequestSent
= sal_True
;
842 if ( !aCmdLineArgs
->IsQuickstart() ) {
843 sal_Bool bShowHelp
= sal_False
;
844 OUStringBuffer aHelpURLBuffer
;
845 if (aCmdLineArgs
->IsHelpWriter()) {
846 bShowHelp
= sal_True
;
847 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://swriter/start");
848 } else if (aCmdLineArgs
->IsHelpCalc()) {
849 bShowHelp
= sal_True
;
850 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://scalc/start");
851 } else if (aCmdLineArgs
->IsHelpDraw()) {
852 bShowHelp
= sal_True
;
853 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://sdraw/start");
854 } else if (aCmdLineArgs
->IsHelpImpress()) {
855 bShowHelp
= sal_True
;
856 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://simpress/start");
857 } else if (aCmdLineArgs
->IsHelpBase()) {
858 bShowHelp
= sal_True
;
859 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://sdatabase/start");
860 } else if (aCmdLineArgs
->IsHelpBasic()) {
861 bShowHelp
= sal_True
;
862 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://sbasic/start");
863 } else if (aCmdLineArgs
->IsHelpMath()) {
864 bShowHelp
= sal_True
;
865 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://smath/start");
868 aHelpURLBuffer
.appendAscii("?Language=");
869 aHelpURLBuffer
.append(utl::ConfigManager::getLocale());
871 aHelpURLBuffer
.appendAscii("&System=UNX");
873 aHelpURLBuffer
.appendAscii("&System=WIN");
875 ApplicationEvent
* pAppEvent
= new ApplicationEvent(
876 ApplicationEvent::TYPE_OPENHELPURL
,
877 aHelpURLBuffer
.makeStringAndClear());
878 ImplPostForeignAppEvent( pAppEvent
);
882 if ( bDocRequestSent
)
884 // Send requests to dispatch watcher if we have at least one. The receiver
885 // is responsible to delete the request after processing it.
886 if ( aCmdLineArgs
->HasModuleParam() )
888 SvtModuleOptions aOpt
;
890 // Support command line parameters to start a module (as preselection)
891 if ( aCmdLineArgs
->IsWriter() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SWRITER
) )
892 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_WRITER
);
893 else if ( aCmdLineArgs
->IsCalc() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SCALC
) )
894 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_CALC
);
895 else if ( aCmdLineArgs
->IsImpress() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS
) )
896 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_IMPRESS
);
897 else if ( aCmdLineArgs
->IsDraw() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SDRAW
) )
898 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_DRAW
);
901 ImplPostProcessDocumentsEvent( pRequest
);
905 // delete not used request again
909 if (aArguments
.equalsL(sc_aShowSequence
, sc_nShSeqLength
) ||
910 aCmdLineArgs
->IsEmpty())
912 // no document was sent, just bring Office to front
913 ApplicationEvent
* pAppEvent
=
914 new ApplicationEvent(ApplicationEvent::TYPE_APPEAR
);
915 ImplPostForeignAppEvent( pAppEvent
);
919 // we don't need the mutex any longer...
921 // wait for processing to finish
924 // processing finished, inform the requesting end:
925 n
= aStreamPipe
.write(
926 PROCESSING_DONE
, SAL_N_ELEMENTS(PROCESSING_DONE
));
927 // incl. terminating NUL
928 if (n
!= SAL_N_ELEMENTS(PROCESSING_DONE
)) {
929 SAL_WARN("desktop", "short write: " << n
);
936 osl::MutexGuard
aGuard( GetMutex() );
943 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
944 fprintf( stderr
, "Error on accept: %d\n", (int)nError
);
949 salhelper::Thread::wait( tval
);
951 } while( schedule() );
955 static void AddToDispatchList(
956 DispatchWatcher::DispatchList
& rDispatchList
,
957 boost::optional
< OUString
> const & cwdUrl
,
958 std::vector
< OUString
> const & aRequestList
,
959 DispatchWatcher::RequestType nType
,
960 const OUString
& aParam
,
961 const OUString
& aFactory
)
963 for (std::vector
< OUString
>::const_iterator
i(aRequestList
.begin());
964 i
!= aRequestList
.end(); ++i
)
966 rDispatchList
.push_back(
967 DispatchWatcher::DispatchRequest( nType
, *i
, cwdUrl
, aParam
, aFactory
));
971 static void AddConversionsToDispatchList(
972 DispatchWatcher::DispatchList
& rDispatchList
,
973 boost::optional
< OUString
> const & cwdUrl
,
974 std::vector
< OUString
> const & rRequestList
,
975 const OUString
& rParam
,
976 const OUString
& rPrinterName
,
977 const OUString
& rFactory
,
978 const OUString
& rParamOut
)
980 DispatchWatcher::RequestType nType
;
981 OUString
aParam( rParam
);
983 if( !rParam
.isEmpty() )
985 nType
= DispatchWatcher::REQUEST_CONVERSION
;
990 nType
= DispatchWatcher::REQUEST_BATCHPRINT
;
991 aParam
= rPrinterName
;
994 OUString
aOutDir( rParamOut
.trim() );
996 ::tools::getProcessWorkingDir( aPWD
);
998 if( !::osl::FileBase::getAbsoluteFileURL( aPWD
, rParamOut
, aOutDir
) )
999 ::osl::FileBase::getSystemPathFromFileURL( aOutDir
, aOutDir
);
1001 if( !rParamOut
.trim().isEmpty() )
1003 aParam
+= OUString(";");
1008 ::osl::FileBase::getSystemPathFromFileURL( aPWD
, aPWD
);
1009 aParam
+= OUString(";" ) + aPWD
;
1012 for (std::vector
< OUString
>::const_iterator
i(rRequestList
.begin());
1013 i
!= rRequestList
.end(); ++i
)
1015 rDispatchList
.push_back(
1016 DispatchWatcher::DispatchRequest( nType
, *i
, cwdUrl
, aParam
, rFactory
));
1021 sal_Bool
OfficeIPCThread::ExecuteCmdLineRequests( ProcessDocumentsRequest
& aRequest
)
1023 // protect the dispatch list
1024 osl::ClearableMutexGuard
aGuard( GetMutex() );
1026 static DispatchWatcher::DispatchList aDispatchList
;
1029 // Create dispatch list for dispatch watcher
1030 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aInFilter
, DispatchWatcher::REQUEST_INFILTER
, aEmpty
, aRequest
.aModule
);
1031 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aOpenList
, DispatchWatcher::REQUEST_OPEN
, aEmpty
, aRequest
.aModule
);
1032 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aViewList
, DispatchWatcher::REQUEST_VIEW
, aEmpty
, aRequest
.aModule
);
1033 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aStartList
, DispatchWatcher::REQUEST_START
, aEmpty
, aRequest
.aModule
);
1034 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aPrintList
, DispatchWatcher::REQUEST_PRINT
, aEmpty
, aRequest
.aModule
);
1035 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aPrintToList
, DispatchWatcher::REQUEST_PRINTTO
, aRequest
.aPrinterName
, aRequest
.aModule
);
1036 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aForceOpenList
, DispatchWatcher::REQUEST_FORCEOPEN
, aEmpty
, aRequest
.aModule
);
1037 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aForceNewList
, DispatchWatcher::REQUEST_FORCENEW
, aEmpty
, aRequest
.aModule
);
1038 AddConversionsToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aConversionList
, aRequest
.aConversionParams
, aRequest
.aPrinterName
, aRequest
.aModule
, aRequest
.aConversionOut
);
1039 sal_Bool
bShutdown( sal_False
);
1041 if ( pGlobalOfficeIPCThread
.is() )
1043 if( ! pGlobalOfficeIPCThread
->AreRequestsEnabled() )
1046 pGlobalOfficeIPCThread
->mnPendingRequests
+= aDispatchList
.size();
1047 if ( !pGlobalOfficeIPCThread
->mpDispatchWatcher
)
1049 pGlobalOfficeIPCThread
->mpDispatchWatcher
= DispatchWatcher::GetDispatchWatcher();
1050 pGlobalOfficeIPCThread
->mpDispatchWatcher
->acquire();
1054 DispatchWatcher::DispatchList
aTempList( aDispatchList
);
1055 aDispatchList
.clear();
1059 // Execute dispatch requests
1060 bShutdown
= pGlobalOfficeIPCThread
->mpDispatchWatcher
->executeDispatchRequests( aTempList
, s_bInEnableRequests
);
1062 // set processed flag
1063 if (aRequest
.pcProcessed
!= NULL
)
1064 aRequest
.pcProcessed
->set();
1072 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */