GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / desktop / source / app / officeipcthread.cxx
blobee4a779e01afed2370b2f65fb63b36edb323e5d2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include "app.hxx"
23 #include "officeipcthread.hxx"
24 #include "cmdlineargs.hxx"
25 #include "dispatchwatcher.hxx"
26 #include <memory>
27 #include <stdio.h>
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;
56 namespace {
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
68 // signal failure):
69 OString readStringFromPipe(osl::StreamPipe & pipe) {
70 for (OStringBuffer str;;) {
71 char buf[1024];
72 sal_Int32 n = pipe.recv(buf, SAL_N_ELEMENTS(buf));
73 if (n <= 0) {
74 return "";
76 bool end = false;
77 if (buf[n - 1] == '\0') {
78 end = true;
79 --n;
81 str.append(buf, n);
82 //TODO: how does OStringBuffer.append handle overflow?
83 if (end) {
84 return str.makeStringAndClear();
89 #endif
93 // Type of pipe we use
94 enum PipeMode
96 PIPEMODE_DONTKNOW,
97 PIPEMODE_CREATED,
98 PIPEMODE_CONNECTED
101 namespace desktop
104 namespace {
106 #if HAVE_FEATURE_DESKTOP
108 class Parser: public CommandLineArgs::Supplier {
109 public:
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++]) {
118 case '0':
119 break;
120 case '1':
122 OUString url;
123 if (!next(&url, false)) {
124 throw CommandLineArgs::Supplier::Exception();
126 m_cwdUrl.reset(url);
127 break;
129 case '2':
131 OUString path;
132 if (!next(&path, false)) {
133 throw CommandLineArgs::Supplier::Exception();
135 OUString url;
136 if (osl::FileBase::getFileURLFromSystemPath(path, url) ==
137 osl::FileBase::E_None)
139 m_cwdUrl.reset(url);
141 break;
143 default:
144 throw CommandLineArgs::Supplier::Exception();
148 virtual ~Parser() {}
150 virtual boost::optional< OUString > getCwdUrl() { return m_cwdUrl; }
152 virtual bool next(OUString * argument) { return next(argument, true); }
154 private:
155 virtual bool next(OUString * argument, bool prefix) {
156 OSL_ASSERT(argument != NULL);
157 if (m_index < m_input.getLength()) {
158 if (prefix) {
159 if (m_input[m_index] != ',') {
160 throw CommandLineArgs::Supplier::Exception();
162 ++m_index;
164 OStringBuffer b;
165 while (m_index < m_input.getLength()) {
166 char c = m_input[m_index];
167 if (c == ',') {
168 break;
170 ++m_index;
171 if (c == '\\') {
172 if (m_index < m_input.getLength()) {
173 c = m_input[m_index++];
174 switch (c) {
175 case '0':
176 c = '\0';
177 break;
178 case ',':
179 case '\\':
180 break;
181 default:
182 throw CommandLineArgs::Supplier::Exception();
184 } else {
185 throw CommandLineArgs::Supplier::Exception();
188 b.append(c);
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();
200 return true;
201 } else {
202 return false;
206 boost::optional< OUString > m_cwdUrl;
207 OString m_input;
208 sal_Int32 m_index;
211 bool addArgument(OStringBuffer &rArguments, char prefix,
212 const OUString &rArgument)
214 OString utf8;
215 if (!rArgument.convertToString(
216 &utf8, RTL_TEXTENCODING_UTF8,
217 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
218 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
220 return false;
222 rArguments.append(prefix);
223 for (sal_Int32 i = 0; i < utf8.getLength(); ++i) {
224 char c = utf8[i];
225 switch (c) {
226 case '\0':
227 rArguments.append("\\0");
228 break;
229 case ',':
230 rArguments.append("\\,");
231 break;
232 case '\\':
233 rArguments.append("\\\\");
234 break;
235 default:
236 rArguments.append(c);
237 break;
240 return true;
243 #endif
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 OUString 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() );
257 #endif
259 rtlDigest handle = rtl_digest_create( rtl_Digest_AlgorithmMD5 );
260 if ( handle )
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();
281 return OUString();
284 class ProcessEventsClass_Impl
286 public:
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;
296 return 0;
299 IMPL_STATIC_LINK_NOINSTANCE( ProcessEventsClass_Impl, ProcessDocumentsEvent, void*, pEvent )
301 // Documents requests are processed by the OfficeIPCThread implementation
302 ProcessDocumentsRequest* pDocsRequest = (ProcessDocumentsRequest*)pEvent;
304 if ( pDocsRequest )
306 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest );
307 delete pDocsRequest;
309 return 0;
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
337 // concurrently.
340 // XServiceInfo
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 );
357 return aSeq;
360 // XEventListener
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();
376 else
377 OfficeIPCThread::SetDowning();
380 void SAL_CALL OfficeIPCThreadController::notifyTermination( const EventObject& )
381 throw( RuntimeException )
385 namespace
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;
418 if( 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 );
435 else
436 return sal_False;
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;
459 OUString aDummy;
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;
468 else
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
477 // and connectPipe!!
479 OUString aIniName;
481 osl_getExecutableFile( &aIniName.pData );
483 sal_uInt32 lastIndex = aIniName.lastIndexOf('/');
484 if ( lastIndex > 0 )
486 aIniName = aIniName.copy( 0, lastIndex+1 );
487 aIniName += "perftune";
488 #if defined(WNT)
489 aIniName += ".ini";
490 #else
491 aIniName += "rc";
492 #endif
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() );
511 else
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();
526 // Try to create pipe
527 if ( pThread->maPipe.create( aPipeIdent.getStr(), osl_Pipe_CREATE, rSecurity ))
529 // Pipe created
530 nPipeMode = PIPEMODE_CREATED;
532 else if( pThread->maPipe.create( aPipeIdent.getStr(), osl_Pipe_OPEN, rSecurity )) // Creation not successful, now we try to connect
534 osl::StreamPipe aStreamPipe(pThread->maPipe.getHandle());
535 if (readStringFromPipe(aStreamPipe) == SEND_ARGUMENTS)
537 // Pipe connected to first office
538 nPipeMode = PIPEMODE_CONNECTED;
540 else
542 // Pipe connection failed (other office exited or crashed)
543 TimeValue tval;
544 tval.Seconds = 0;
545 tval.Nanosec = 500000000;
546 salhelper::Thread::wait( tval );
549 else
551 oslPipeError eReason = pThread->maPipe.getError();
552 if ((eReason == osl_Pipe_E_ConnectionRefused) || (eReason == osl_Pipe_E_invalidError))
553 return IPC_STATUS_PIPE_ERROR;
555 // Wait for second office to be ready
556 TimeValue aTimeValue;
557 aTimeValue.Seconds = 0;
558 aTimeValue.Nanosec = 10000000; // 10ms
559 salhelper::Thread::wait( aTimeValue );
562 } while ( nPipeMode == PIPEMODE_DONTKNOW );
564 if ( nPipeMode == PIPEMODE_CREATED )
566 // Seems we are the one and only, so start listening thread
567 pGlobalOfficeIPCThread = pThread;
568 pThread->launch();
570 else
572 // Seems another office is running. Pipe arguments to it and self terminate
573 osl::StreamPipe aStreamPipe(pThread->maPipe.getHandle());
575 OStringBuffer aArguments(ARGUMENT_PREFIX);
576 OUString cwdUrl;
577 if (!(tools::getProcessWorkingDir(cwdUrl) &&
578 addArgument(aArguments, '1', cwdUrl)))
580 aArguments.append('0');
582 sal_uInt32 nCount = rtl_getAppCommandArgCount();
583 for( sal_uInt32 i=0; i < nCount; i++ )
585 rtl_getAppCommandArg( i, &aDummy.pData );
586 if (!addArgument(aArguments, ',', aDummy)) {
587 return IPC_STATUS_BOOTSTRAP_ERROR;
590 aArguments.append('\0');
591 // finally, write the string onto the pipe
592 sal_Int32 n = aStreamPipe.write(
593 aArguments.getStr(), aArguments.getLength());
594 if (n != aArguments.getLength()) {
595 SAL_INFO("desktop", "short write: " << n);
596 return IPC_STATUS_BOOTSTRAP_ERROR;
599 if (readStringFromPipe(aStreamPipe) != PROCESSING_DONE)
601 // something went wrong
602 return IPC_STATUS_BOOTSTRAP_ERROR;
605 return IPC_STATUS_2ND_OFFICE;
607 #else
608 pGlobalOfficeIPCThread = rtl::Reference< OfficeIPCThread >(new OfficeIPCThread);
609 #endif
610 return IPC_STATUS_OK;
613 void OfficeIPCThread::DisableOfficeIPCThread(bool join)
615 #if HAVE_FEATURE_DESKTOP
616 osl::ClearableMutexGuard aMutex( GetMutex() );
618 if( pGlobalOfficeIPCThread.is() )
620 rtl::Reference< OfficeIPCThread > pOfficeIPCThread(
621 pGlobalOfficeIPCThread);
622 pGlobalOfficeIPCThread.clear();
624 pOfficeIPCThread->mbDowning = true;
625 pOfficeIPCThread->maPipe.close();
627 // release mutex to avoid deadlocks
628 aMutex.clear();
630 OfficeIPCThread::SetReady(pOfficeIPCThread);
632 // exit gracefully and join
633 if (join)
635 pOfficeIPCThread->join();
638 #else
639 (void) join;
640 #endif
643 OfficeIPCThread::OfficeIPCThread() :
644 Thread( "OfficeIPCThread" ),
645 mbDowning( false ),
646 mbRequestsEnabled( false ),
647 mnPendingRequests( 0 ),
648 mpDispatchWatcher( 0 )
652 OfficeIPCThread::~OfficeIPCThread()
654 ::osl::ClearableMutexGuard aGuard( GetMutex() );
656 if ( mpDispatchWatcher )
657 mpDispatchWatcher->release();
658 maPipe.close();
659 pGlobalOfficeIPCThread.clear();
662 void OfficeIPCThread::SetReady(
663 rtl::Reference< OfficeIPCThread > const & pThread)
665 rtl::Reference< OfficeIPCThread > const & t(
666 pThread.is() ? pThread : pGlobalOfficeIPCThread);
667 if (t.is())
669 t->cReady.set();
673 void OfficeIPCThread::execute()
675 #if HAVE_FEATURE_DESKTOP
678 osl::StreamPipe aStreamPipe;
679 oslPipeError nError = maPipe.accept( aStreamPipe );
682 if( nError == osl_Pipe_E_None )
684 // if we receive a request while the office is displaying some dialog or error during
685 // bootstrap, that dialogs event loop might get events that are dispatched by this thread
686 // we have to wait for cReady to be set by the real main loop.
687 // only reqests that dont dispatch events may be processed before cReady is set.
688 cReady.wait();
690 // we might have decided to shutdown while we were sleeping
691 if (!pGlobalOfficeIPCThread.is()) return;
693 // only lock the mutex when processing starts, othewise we deadlock when the office goes
694 // down during wait
695 osl::ClearableMutexGuard aGuard( GetMutex() );
697 if ( mbDowning )
699 break;
702 // notify client we're ready to process its args:
703 sal_Int32 n = aStreamPipe.write(
704 SEND_ARGUMENTS, SAL_N_ELEMENTS(SEND_ARGUMENTS));
705 // incl. terminating NUL
706 if (n != SAL_N_ELEMENTS(SEND_ARGUMENTS)) {
707 SAL_WARN("desktop", "short write: " << n);
708 continue;
711 OString aArguments = readStringFromPipe(aStreamPipe);
713 // Is this a lookup message from another application? if so, ignore
714 if (aArguments.isEmpty())
715 continue;
717 std::auto_ptr< CommandLineArgs > aCmdLineArgs;
720 Parser p(aArguments);
721 aCmdLineArgs.reset( new CommandLineArgs( p ) );
723 catch ( const CommandLineArgs::Supplier::Exception & )
725 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
726 fprintf( stderr, "Error in received command line arguments\n" );
727 #endif
728 continue;
731 sal_Bool bDocRequestSent = sal_False;
733 OUString aUnknown( aCmdLineArgs->GetUnknown() );
734 if ( !aUnknown.isEmpty() || aCmdLineArgs->IsHelp() )
736 ApplicationEvent* pAppEvent =
737 new ApplicationEvent(ApplicationEvent::TYPE_HELP, aUnknown);
738 ImplPostForeignAppEvent( pAppEvent );
740 else if ( aCmdLineArgs->IsVersion() )
742 ApplicationEvent* pAppEvent =
743 new ApplicationEvent(ApplicationEvent::TYPE_VERSION);
744 ImplPostForeignAppEvent( pAppEvent );
746 else
748 const CommandLineArgs &rCurrentCmdLineArgs = Desktop::GetCommandLineArgs();
750 if ( aCmdLineArgs->IsQuickstart() )
752 // we have to use application event, because we have to start quickstart service in main thread!!
753 ApplicationEvent* pAppEvent =
754 new ApplicationEvent(ApplicationEvent::TYPE_QUICKSTART);
755 ImplPostForeignAppEvent( pAppEvent );
758 // handle request for acceptor
759 std::vector< OUString > const & accept = aCmdLineArgs->
760 GetAccept();
761 for (std::vector< OUString >::const_iterator i(accept.begin());
762 i != accept.end(); ++i)
764 ApplicationEvent* pAppEvent = new ApplicationEvent(
765 ApplicationEvent::TYPE_ACCEPT, *i);
766 ImplPostForeignAppEvent( pAppEvent );
768 // handle acceptor removal
769 std::vector< OUString > const & unaccept = aCmdLineArgs->
770 GetUnaccept();
771 for (std::vector< OUString >::const_iterator i(
772 unaccept.begin());
773 i != unaccept.end(); ++i)
775 ApplicationEvent* pAppEvent = new ApplicationEvent(
776 ApplicationEvent::TYPE_UNACCEPT, *i);
777 ImplPostForeignAppEvent( pAppEvent );
780 ProcessDocumentsRequest* pRequest = new ProcessDocumentsRequest(
781 aCmdLineArgs->getCwdUrl());
782 cProcessed.reset();
783 pRequest->pcProcessed = &cProcessed;
785 // Print requests are not dependent on the --invisible cmdline argument as they are
786 // loaded with the "hidden" flag! So they are always checked.
787 pRequest->aPrintList = aCmdLineArgs->GetPrintList();
788 bDocRequestSent |= !pRequest->aPrintList.empty();
789 pRequest->aPrintToList = aCmdLineArgs->GetPrintToList();
790 pRequest->aPrinterName = aCmdLineArgs->GetPrinterName();
791 bDocRequestSent |= !( pRequest->aPrintToList.empty() || pRequest->aPrinterName.isEmpty() );
793 if ( !rCurrentCmdLineArgs.IsInvisible() )
795 // Read cmdline args that can open/create documents. As they would open a window
796 // they are only allowed if the "--invisible" is currently not used!
797 pRequest->aOpenList = aCmdLineArgs->GetOpenList();
798 bDocRequestSent |= !pRequest->aOpenList.empty();
799 pRequest->aViewList = aCmdLineArgs->GetViewList();
800 bDocRequestSent |= !pRequest->aViewList.empty();
801 pRequest->aStartList = aCmdLineArgs->GetStartList();
802 bDocRequestSent |= !pRequest->aStartList.empty();
803 pRequest->aForceOpenList = aCmdLineArgs->GetForceOpenList();
804 bDocRequestSent |= !pRequest->aForceOpenList.empty();
805 pRequest->aForceNewList = aCmdLineArgs->GetForceNewList();
806 bDocRequestSent |= !pRequest->aForceNewList.empty();
808 // Special command line args to create an empty document for a given module
810 // #i18338# (lo)
811 // we only do this if no document was specified on the command line,
812 // since this would be inconsistent with the behaviour of
813 // the first process, see OpenClients() (call to OpenDefault()) in app.cxx
814 if ( aCmdLineArgs->HasModuleParam() && (!bDocRequestSent) )
816 SvtModuleOptions aOpt;
817 SvtModuleOptions::EFactory eFactory = SvtModuleOptions::E_WRITER;
818 if ( aCmdLineArgs->IsWriter() )
819 eFactory = SvtModuleOptions::E_WRITER;
820 else if ( aCmdLineArgs->IsCalc() )
821 eFactory = SvtModuleOptions::E_CALC;
822 else if ( aCmdLineArgs->IsDraw() )
823 eFactory = SvtModuleOptions::E_DRAW;
824 else if ( aCmdLineArgs->IsImpress() )
825 eFactory = SvtModuleOptions::E_IMPRESS;
826 else if ( aCmdLineArgs->IsBase() )
827 eFactory = SvtModuleOptions::E_DATABASE;
828 else if ( aCmdLineArgs->IsMath() )
829 eFactory = SvtModuleOptions::E_MATH;
830 else if ( aCmdLineArgs->IsGlobal() )
831 eFactory = SvtModuleOptions::E_WRITERGLOBAL;
832 else if ( aCmdLineArgs->IsWeb() )
833 eFactory = SvtModuleOptions::E_WRITERWEB;
835 if ( !pRequest->aOpenList.empty() )
836 pRequest->aModule = aOpt.GetFactoryName( eFactory );
837 else
838 pRequest->aOpenList.push_back( aOpt.GetFactoryEmptyDocumentURL( eFactory ) );
839 bDocRequestSent = sal_True;
843 if ( !aCmdLineArgs->IsQuickstart() ) {
844 sal_Bool bShowHelp = sal_False;
845 OUStringBuffer aHelpURLBuffer;
846 if (aCmdLineArgs->IsHelpWriter()) {
847 bShowHelp = sal_True;
848 aHelpURLBuffer.appendAscii("vnd.sun.star.help://swriter/start");
849 } else if (aCmdLineArgs->IsHelpCalc()) {
850 bShowHelp = sal_True;
851 aHelpURLBuffer.appendAscii("vnd.sun.star.help://scalc/start");
852 } else if (aCmdLineArgs->IsHelpDraw()) {
853 bShowHelp = sal_True;
854 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdraw/start");
855 } else if (aCmdLineArgs->IsHelpImpress()) {
856 bShowHelp = sal_True;
857 aHelpURLBuffer.appendAscii("vnd.sun.star.help://simpress/start");
858 } else if (aCmdLineArgs->IsHelpBase()) {
859 bShowHelp = sal_True;
860 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sdatabase/start");
861 } else if (aCmdLineArgs->IsHelpBasic()) {
862 bShowHelp = sal_True;
863 aHelpURLBuffer.appendAscii("vnd.sun.star.help://sbasic/start");
864 } else if (aCmdLineArgs->IsHelpMath()) {
865 bShowHelp = sal_True;
866 aHelpURLBuffer.appendAscii("vnd.sun.star.help://smath/start");
868 if (bShowHelp) {
869 aHelpURLBuffer.appendAscii("?Language=");
870 aHelpURLBuffer.append(utl::ConfigManager::getLocale());
871 #if defined UNX
872 aHelpURLBuffer.appendAscii("&System=UNX");
873 #elif defined WNT
874 aHelpURLBuffer.appendAscii("&System=WIN");
875 #endif
876 ApplicationEvent* pAppEvent = new ApplicationEvent(
877 ApplicationEvent::TYPE_OPENHELPURL,
878 aHelpURLBuffer.makeStringAndClear());
879 ImplPostForeignAppEvent( pAppEvent );
883 if ( bDocRequestSent )
885 // Send requests to dispatch watcher if we have at least one. The receiver
886 // is responsible to delete the request after processing it.
887 if ( aCmdLineArgs->HasModuleParam() )
889 SvtModuleOptions aOpt;
891 // Support command line parameters to start a module (as preselection)
892 if ( aCmdLineArgs->IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SWRITER ) )
893 pRequest->aModule = aOpt.GetFactoryName( SvtModuleOptions::E_WRITER );
894 else if ( aCmdLineArgs->IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SCALC ) )
895 pRequest->aModule = aOpt.GetFactoryName( SvtModuleOptions::E_CALC );
896 else if ( aCmdLineArgs->IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS ) )
897 pRequest->aModule= aOpt.GetFactoryName( SvtModuleOptions::E_IMPRESS );
898 else if ( aCmdLineArgs->IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::E_SDRAW ) )
899 pRequest->aModule= aOpt.GetFactoryName( SvtModuleOptions::E_DRAW );
902 ImplPostProcessDocumentsEvent( pRequest );
904 else
906 // delete not used request again
907 delete pRequest;
908 pRequest = NULL;
910 if (aArguments.equalsL(sc_aShowSequence, sc_nShSeqLength) ||
911 aCmdLineArgs->IsEmpty())
913 // no document was sent, just bring Office to front
914 ApplicationEvent* pAppEvent =
915 new ApplicationEvent(ApplicationEvent::TYPE_APPEAR);
916 ImplPostForeignAppEvent( pAppEvent );
920 // we don't need the mutex any longer...
921 aGuard.clear();
922 // wait for processing to finish
923 if (bDocRequestSent)
924 cProcessed.wait();
925 // processing finished, inform the requesting end:
926 n = aStreamPipe.write(
927 PROCESSING_DONE, SAL_N_ELEMENTS(PROCESSING_DONE));
928 // incl. terminating NUL
929 if (n != SAL_N_ELEMENTS(PROCESSING_DONE)) {
930 SAL_WARN("desktop", "short write: " << n);
931 continue;
934 else
937 osl::MutexGuard aGuard( GetMutex() );
938 if ( mbDowning )
940 break;
944 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
945 fprintf( stderr, "Error on accept: %d\n", (int)nError );
946 #endif
947 TimeValue tval;
948 tval.Seconds = 1;
949 tval.Nanosec = 0;
950 salhelper::Thread::wait( tval );
952 } while( schedule() );
953 #endif
956 static void AddToDispatchList(
957 DispatchWatcher::DispatchList& rDispatchList,
958 boost::optional< OUString > const & cwdUrl,
959 std::vector< OUString > const & aRequestList,
960 DispatchWatcher::RequestType nType,
961 const OUString& aParam,
962 const OUString& aFactory )
964 for (std::vector< OUString >::const_iterator i(aRequestList.begin());
965 i != aRequestList.end(); ++i)
967 rDispatchList.push_back(
968 DispatchWatcher::DispatchRequest( nType, *i, cwdUrl, aParam, aFactory ));
972 static void AddConversionsToDispatchList(
973 DispatchWatcher::DispatchList& rDispatchList,
974 boost::optional< OUString > const & cwdUrl,
975 std::vector< OUString > const & rRequestList,
976 const OUString& rParam,
977 const OUString& rPrinterName,
978 const OUString& rFactory,
979 const OUString& rParamOut )
981 DispatchWatcher::RequestType nType;
982 OUString aParam( rParam );
984 if( !rParam.isEmpty() )
986 nType = DispatchWatcher::REQUEST_CONVERSION;
987 aParam = rParam;
989 else
991 nType = DispatchWatcher::REQUEST_BATCHPRINT;
992 aParam = rPrinterName;
995 OUString aOutDir( rParamOut.trim() );
996 OUString aPWD;
997 ::tools::getProcessWorkingDir( aPWD );
999 if( !::osl::FileBase::getAbsoluteFileURL( aPWD, rParamOut, aOutDir ) )
1000 ::osl::FileBase::getSystemPathFromFileURL( aOutDir, aOutDir );
1002 if( !rParamOut.trim().isEmpty() )
1004 aParam += ";";
1005 aParam += aOutDir;
1007 else
1009 ::osl::FileBase::getSystemPathFromFileURL( aPWD, aPWD );
1010 aParam += ";" + aPWD;
1013 for (std::vector< OUString >::const_iterator i(rRequestList.begin());
1014 i != rRequestList.end(); ++i)
1016 rDispatchList.push_back(
1017 DispatchWatcher::DispatchRequest( nType, *i, cwdUrl, aParam, rFactory ));
1022 sal_Bool OfficeIPCThread::ExecuteCmdLineRequests( ProcessDocumentsRequest& aRequest )
1024 // protect the dispatch list
1025 osl::ClearableMutexGuard aGuard( GetMutex() );
1027 static DispatchWatcher::DispatchList aDispatchList;
1029 OUString aEmpty;
1030 // Create dispatch list for dispatch watcher
1031 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aInFilter, DispatchWatcher::REQUEST_INFILTER, aEmpty, aRequest.aModule );
1032 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aOpenList, DispatchWatcher::REQUEST_OPEN, aEmpty, aRequest.aModule );
1033 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aViewList, DispatchWatcher::REQUEST_VIEW, aEmpty, aRequest.aModule );
1034 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aStartList, DispatchWatcher::REQUEST_START, aEmpty, aRequest.aModule );
1035 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aPrintList, DispatchWatcher::REQUEST_PRINT, aEmpty, aRequest.aModule );
1036 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aPrintToList, DispatchWatcher::REQUEST_PRINTTO, aRequest.aPrinterName, aRequest.aModule );
1037 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aForceOpenList, DispatchWatcher::REQUEST_FORCEOPEN, aEmpty, aRequest.aModule );
1038 AddToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aForceNewList, DispatchWatcher::REQUEST_FORCENEW, aEmpty, aRequest.aModule );
1039 AddConversionsToDispatchList( aDispatchList, aRequest.aCwdUrl, aRequest.aConversionList, aRequest.aConversionParams, aRequest.aPrinterName, aRequest.aModule, aRequest.aConversionOut );
1040 sal_Bool bShutdown( sal_False );
1042 if ( pGlobalOfficeIPCThread.is() )
1044 if( ! pGlobalOfficeIPCThread->AreRequestsEnabled() )
1045 return bShutdown;
1047 pGlobalOfficeIPCThread->mnPendingRequests += aDispatchList.size();
1048 if ( !pGlobalOfficeIPCThread->mpDispatchWatcher )
1050 pGlobalOfficeIPCThread->mpDispatchWatcher = DispatchWatcher::GetDispatchWatcher();
1051 pGlobalOfficeIPCThread->mpDispatchWatcher->acquire();
1054 // copy for execute
1055 DispatchWatcher::DispatchList aTempList( aDispatchList );
1056 aDispatchList.clear();
1058 aGuard.clear();
1060 // Execute dispatch requests
1061 bShutdown = pGlobalOfficeIPCThread->mpDispatchWatcher->executeDispatchRequests( aTempList, s_bInEnableRequests );
1063 // set processed flag
1064 if (aRequest.pcProcessed != NULL)
1065 aRequest.pcProcessed->set();
1068 return bShutdown;
1073 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */