[Libreoffice-commits] core.git: 2 commits - desktop/Library_sofficeapp.mk desktop/source desktop/unx
Stephan Bergmann
sbergman at redhat.com
Mon Apr 4 15:35:54 UTC 2016
desktop/Library_sofficeapp.mk | 5
desktop/source/app/officeipcthread.cxx | 799 +++++++++++++++++++++++----------
desktop/source/app/officeipcthread.hxx | 10
desktop/unx/source/start.c | 2
4 files changed, 574 insertions(+), 242 deletions(-)
New commits:
commit 5da71ff3b088f224cd3a731ce51c620e0cd3e5d3
Author: Stephan Bergmann <sbergman at redhat.com>
Date: Mon Apr 4 17:34:03 2016 +0200
Add DBus-based IPC mechanism for xdg-app
first cut; triggered on LIBO_XDGAPP env var for now
Change-Id: If4586aedb58499e36a5d87cc8d171400ce7e9499
diff --git a/desktop/Library_sofficeapp.mk b/desktop/Library_sofficeapp.mk
index 30dc907..04bc491 100644
--- a/desktop/Library_sofficeapp.mk
+++ b/desktop/Library_sofficeapp.mk
@@ -23,7 +23,10 @@ $(eval $(call gb_Library_add_libs,sofficeapp,\
) \
))
-$(eval $(call gb_Library_use_external,sofficeapp,boost_headers))
+$(eval $(call gb_Library_use_externals,sofficeapp, \
+ boost_headers \
+ dbus \
+))
ifeq ($(ENABLE_BREAKPAD),TRUE)
$(eval $(call gb_Library_use_external,sofficeapp,breakpad))
diff --git a/desktop/source/app/officeipcthread.cxx b/desktop/source/app/officeipcthread.cxx
index c4f50f4..a5d9ac7 100644
--- a/desktop/source/app/officeipcthread.cxx
+++ b/desktop/source/app/officeipcthread.cxx
@@ -17,6 +17,9 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <sal/config.h>
+
+#include <config_dbus.h>
#include <config_features.h>
#include "app.hxx"
@@ -44,8 +47,13 @@
#include <tools/getprocessworkingdir.hxx>
#include <cassert>
+#include <cstdlib>
#include <memory>
+#if ENABLE_DBUS
+#include <dbus/dbus.h>
+#endif
+
using namespace desktop;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
@@ -365,6 +373,8 @@ protected:
virtual ~IpcThread() {}
+ bool process(OString const & arguments, bool * wait);
+
RequestHandler * handler_;
};
@@ -386,6 +396,262 @@ private:
osl::Pipe pipe_;
};
+#if ENABLE_DBUS
+
+namespace {
+
+struct DbusConnectionHolder {
+ explicit DbusConnectionHolder(DBusConnection * theConnection):
+ connection(theConnection)
+ {}
+
+ ~DbusConnectionHolder() { clear(); }
+
+ void clear() {
+ if (connection != nullptr) {
+ dbus_connection_unref(connection);
+ }
+ connection = nullptr;
+ }
+
+ DBusConnection * connection;
+
+private:
+ DbusConnectionHolder(DbusConnectionHolder &) = delete;
+ void operator =(DbusConnectionHolder) = delete;
+};
+
+struct DbusMessageHolder {
+ explicit DbusMessageHolder(DBusMessage * theMessage): message(theMessage) {}
+
+ ~DbusMessageHolder() { clear(); }
+
+ void clear() {
+ if (message != nullptr) {
+ dbus_message_unref(message);
+ }
+ message = nullptr;
+ }
+
+ DBusMessage * message;
+
+private:
+ DbusMessageHolder(DbusMessageHolder &) = delete;
+ void operator =(DbusMessageHolder) = delete;
+};
+
+}
+
+class DbusIpcThread: public IpcThread {
+public:
+ static RequestHandler::Status enable(rtl::Reference<IpcThread> * thread);
+
+private:
+ explicit DbusIpcThread(DBusConnection * connection):
+ IpcThread("DbusIPC"), connection_(connection)
+ {}
+
+ virtual ~DbusIpcThread() {}
+
+ void execute() override;
+
+ void close() override;
+
+ DbusConnectionHolder connection_;
+};
+
+RequestHandler::Status DbusIpcThread::enable(rtl::Reference<IpcThread> * thread)
+{
+ assert(thread != nullptr);
+ if (!dbus_threads_init_default()) {
+ SAL_WARN("desktop.app", "dbus_threads_init_default failed");
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ }
+ DBusError e;
+ dbus_error_init(&e);
+ DbusConnectionHolder con(dbus_bus_get(DBUS_BUS_SESSION, &e));
+ assert((con.connection == nullptr) == bool(dbus_error_is_set(&e)));
+ if (con.connection == nullptr) {
+ SAL_WARN(
+ "desktop.app",
+ "dbus_bus_get failed with: " << e.name << ": " << e.message);
+ dbus_error_free(&e);
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ }
+ for (;;) {
+ int n = dbus_bus_request_name(
+ con.connection, "org.libreoffice.LibreOfficeIpc0",
+ DBUS_NAME_FLAG_DO_NOT_QUEUE, &e);
+ assert((n == -1) == bool(dbus_error_is_set(&e)));
+ switch (n) {
+ case -1:
+ SAL_WARN(
+ "desktop.app",
+ "dbus_bus_request_name failed with: " << e.name << ": "
+ << e.message);
+ dbus_error_free(&e);
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ *thread = new DbusIpcThread(con.connection);
+ con.connection = nullptr;
+ return RequestHandler::IPC_STATUS_OK;
+ case DBUS_REQUEST_NAME_REPLY_EXISTS:
+ {
+ OStringBuffer buf(ARGUMENT_PREFIX);
+ OUString arg;
+ if (!(tools::getProcessWorkingDir(arg)
+ && addArgument(buf, '1', arg)))
+ {
+ buf.append('0');
+ }
+ sal_uInt32 narg = rtl_getAppCommandArgCount();
+ for (sal_uInt32 i = 0; i != narg; ++i) {
+ rtl_getAppCommandArg(i, &arg.pData);
+ if (!addArgument(buf, ',', arg)) {
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ }
+ }
+ char const * argstr = buf.getStr();
+ DbusMessageHolder msg(
+ dbus_message_new_method_call(
+ "org.libreoffice.LibreOfficeIpc0",
+ "/org/libreoffice/LibreOfficeIpc0",
+ "org.libreoffice.LibreOfficeIpcIfc0", "Execute"));
+ if (msg.message == nullptr) {
+ SAL_WARN(
+ "desktop.app", "dbus_message_new_method_call failed");
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ }
+ DBusMessageIter it;
+ dbus_message_iter_init_append(msg.message, &it);
+ if (!dbus_message_iter_append_basic(
+ &it, DBUS_TYPE_STRING, &argstr))
+ {
+ SAL_WARN(
+ "desktop.app", "dbus_message_iter_append_basic failed");
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ }
+ DbusMessageHolder repl(
+ dbus_connection_send_with_reply_and_block(
+ con.connection, msg.message, DBUS_TIMEOUT_INFINITE,
+ &e));
+ assert(
+ (repl.message == nullptr) == bool(dbus_error_is_set(&e)));
+ if (repl.message == nullptr) {
+ SAL_INFO(
+ "desktop.app",
+ "dbus_connection_send_with_reply_and_block failed"
+ " with: " << e.name << ": " << e.message);
+ dbus_error_free(&e);
+ break;
+ }
+ return RequestHandler::IPC_STATUS_2ND_OFFICE;
+ }
+ default:
+ assert(false);
+ // fall through
+ case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+ SAL_WARN(
+ "desktop.app",
+ "dbus_bus_request_name failed with unexpected " << +n);
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
+ }
+ }
+}
+
+void DbusIpcThread::execute()
+{
+ assert(handler_ != nullptr);
+ handler_->cReady.wait();
+ for (;;) {
+ {
+ osl::MutexGuard g(RequestHandler::GetMutex());
+ if (handler_->mState == RequestHandler::State::Downing) {
+ break;
+ }
+ }
+ dbus_connection_read_write(connection_.connection, 0);
+ DbusMessageHolder msg(
+ dbus_connection_pop_message(connection_.connection));
+ if (msg.message == nullptr) {
+ continue;
+ }
+ if (!dbus_message_is_method_call(
+ msg.message, "org.libreoffice.LibreOfficeIpcIfc0", "Execute"))
+ {
+ SAL_INFO("desktop.app", "unknown DBus message ignored");
+ continue;
+ }
+ DBusMessageIter it;
+ if (!dbus_message_iter_init(msg.message, &it)) {
+ SAL_WARN("desktop.app", "DBus message without argument ignored");
+ continue;
+ }
+ if (dbus_message_iter_get_arg_type(&it) != DBUS_TYPE_STRING) {
+ SAL_WARN(
+ "desktop.app", "DBus message with non-string argument ignored");
+ continue;
+ }
+ char const * argstr;
+ dbus_message_iter_get_basic(&it, &argstr);
+ bool wait = false;
+ {
+ osl::MutexGuard g(RequestHandler::GetMutex());
+ if (!process(argstr, &wait)) {
+ continue;
+ }
+ }
+ if (wait) {
+ handler_->cProcessed.wait();
+ }
+ DbusMessageHolder repl(dbus_message_new_method_return(msg.message));
+ if (repl.message == nullptr) {
+ SAL_WARN("desktop.app", "dbus_message_new_method_return failed");
+ continue;
+ }
+ dbus_uint32_t serial = 0;
+ if (!dbus_connection_send(
+ connection_.connection, repl.message, &serial)) {
+ SAL_WARN("desktop.app", "dbus_connection_send failed");
+ continue;
+ }
+ dbus_connection_flush(connection_.connection);
+ }
+}
+
+void DbusIpcThread::close() {
+ assert(connection_.connection != nullptr);
+ DBusError e;
+ dbus_error_init(&e);
+ int n = dbus_bus_release_name(
+ connection_.connection, "org.libreoffice.LibreOfficeIpc0", &e);
+ assert((n == -1) == bool(dbus_error_is_set(&e)));
+ switch (n) {
+ case -1:
+ SAL_WARN(
+ "desktop.app",
+ "dbus_bus_release_name failed with: " << e.name << ": "
+ << e.message);
+ dbus_error_free(&e);
+ break;
+ case DBUS_RELEASE_NAME_REPLY_RELEASED:
+ break;
+ default:
+ assert(false);
+ // fall through
+ case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
+ case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
+ SAL_WARN(
+ "desktop.app",
+ "dbus_bus_release_name failed with unexpected " << +n);
+ break;
+ }
+ connection_.clear();
+}
+
+#endif
+
namespace
{
class theRequestHandlerMutex
@@ -462,8 +728,27 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
return IPC_STATUS_OK;
}
+ enum class Kind { Pipe, Dbus };
+ Kind kind = Kind::Pipe;
+#if ENABLE_DBUS
+ if (std::getenv("LIBO_XDGAPP") != nullptr) {
+ kind = Kind::Dbus;
+ }
+#endif
rtl::Reference<IpcThread> thread;
- Status stat = PipeIpcThread::enable(&thread);
+ Status stat;
+ switch (kind) {
+ case Kind::Pipe:
+ stat = PipeIpcThread::enable(&thread);
+ break;
+ case Kind::Dbus:
+#if ENABLE_DBUS
+ stat = DbusIpcThread::enable(&thread);
+ break;
+#endif
+ default:
+ assert(false);
+ }
assert(thread.is() == (stat == IPC_STATUS_OK));
if (stat == IPC_STATUS_OK) {
pGlobal = new RequestHandler;
@@ -656,6 +941,209 @@ void RequestHandler::WaitForReady()
}
}
+bool IpcThread::process(OString const & arguments, bool * wait) {
+ assert(wait != nullptr);
+
+ std::unique_ptr< CommandLineArgs > aCmdLineArgs;
+ try
+ {
+ Parser p(arguments);
+ aCmdLineArgs.reset( new CommandLineArgs( p ) );
+ }
+ catch ( const CommandLineArgs::Supplier::Exception & )
+ {
+ SAL_WARN("desktop.app", "Error in received command line arguments");
+ return false;
+ }
+
+ bool bDocRequestSent = false;
+
+ OUString aUnknown( aCmdLineArgs->GetUnknown() );
+ if ( !aUnknown.isEmpty() || aCmdLineArgs->IsHelp() )
+ {
+ ApplicationEvent* pAppEvent =
+ new ApplicationEvent(ApplicationEvent::TYPE_HELP, aUnknown);
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+ else if ( aCmdLineArgs->IsVersion() )
+ {
+ ApplicationEvent* pAppEvent =
+ new ApplicationEvent(ApplicationEvent::TYPE_VERSION);
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+ else
+ {
+ const CommandLineArgs &rCurrentCmdLineArgs = Desktop::GetCommandLineArgs();
+
+ if ( aCmdLineArgs->IsQuickstart() )
+ {
+ // we have to use application event, because we have to start quickstart service in main thread!!
+ ApplicationEvent* pAppEvent =
+ new ApplicationEvent(ApplicationEvent::TYPE_QUICKSTART);
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+
+ // handle request for acceptor
+ std::vector< OUString > const & accept = aCmdLineArgs->GetAccept();
+ for (std::vector< OUString >::const_iterator i(accept.begin());
+ i != accept.end(); ++i)
+ {
+ ApplicationEvent* pAppEvent = new ApplicationEvent(
+ ApplicationEvent::TYPE_ACCEPT, *i);
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+ // handle acceptor removal
+ std::vector< OUString > const & unaccept = aCmdLineArgs->GetUnaccept();
+ for (std::vector< OUString >::const_iterator i(unaccept.begin());
+ i != unaccept.end(); ++i)
+ {
+ ApplicationEvent* pAppEvent = new ApplicationEvent(
+ ApplicationEvent::TYPE_UNACCEPT, *i);
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+
+ ProcessDocumentsRequest* pRequest = new ProcessDocumentsRequest(
+ aCmdLineArgs->getCwdUrl());
+ handler_->cProcessed.reset();
+ pRequest->pcProcessed = &handler_->cProcessed;
+
+ // Print requests are not dependent on the --invisible cmdline argument as they are
+ // loaded with the "hidden" flag! So they are always checked.
+ pRequest->aPrintList = aCmdLineArgs->GetPrintList();
+ bDocRequestSent |= !pRequest->aPrintList.empty();
+ pRequest->aPrintToList = aCmdLineArgs->GetPrintToList();
+ pRequest->aPrinterName = aCmdLineArgs->GetPrinterName();
+ bDocRequestSent |= !( pRequest->aPrintToList.empty() || pRequest->aPrinterName.isEmpty() );
+
+ if ( !rCurrentCmdLineArgs.IsInvisible() )
+ {
+ // Read cmdline args that can open/create documents. As they would open a window
+ // they are only allowed if the "--invisible" is currently not used!
+ pRequest->aOpenList = aCmdLineArgs->GetOpenList();
+ bDocRequestSent |= !pRequest->aOpenList.empty();
+ pRequest->aViewList = aCmdLineArgs->GetViewList();
+ bDocRequestSent |= !pRequest->aViewList.empty();
+ pRequest->aStartList = aCmdLineArgs->GetStartList();
+ bDocRequestSent |= !pRequest->aStartList.empty();
+ pRequest->aForceOpenList = aCmdLineArgs->GetForceOpenList();
+ bDocRequestSent |= !pRequest->aForceOpenList.empty();
+ pRequest->aForceNewList = aCmdLineArgs->GetForceNewList();
+ bDocRequestSent |= !pRequest->aForceNewList.empty();
+
+ // Special command line args to create an empty document for a given module
+
+ // #i18338# (lo)
+ // we only do this if no document was specified on the command line,
+ // since this would be inconsistent with the behaviour of
+ // the first process, see OpenClients() (call to OpenDefault()) in app.cxx
+ if ( aCmdLineArgs->HasModuleParam() && !bDocRequestSent )
+ {
+ SvtModuleOptions aOpt;
+ SvtModuleOptions::EFactory eFactory = SvtModuleOptions::EFactory::WRITER;
+ if ( aCmdLineArgs->IsWriter() )
+ eFactory = SvtModuleOptions::EFactory::WRITER;
+ else if ( aCmdLineArgs->IsCalc() )
+ eFactory = SvtModuleOptions::EFactory::CALC;
+ else if ( aCmdLineArgs->IsDraw() )
+ eFactory = SvtModuleOptions::EFactory::DRAW;
+ else if ( aCmdLineArgs->IsImpress() )
+ eFactory = SvtModuleOptions::EFactory::IMPRESS;
+ else if ( aCmdLineArgs->IsBase() )
+ eFactory = SvtModuleOptions::EFactory::DATABASE;
+ else if ( aCmdLineArgs->IsMath() )
+ eFactory = SvtModuleOptions::EFactory::MATH;
+ else if ( aCmdLineArgs->IsGlobal() )
+ eFactory = SvtModuleOptions::EFactory::WRITERGLOBAL;
+ else if ( aCmdLineArgs->IsWeb() )
+ eFactory = SvtModuleOptions::EFactory::WRITERWEB;
+
+ if ( !pRequest->aOpenList.empty() )
+ pRequest->aModule = aOpt.GetFactoryName( eFactory );
+ else
+ pRequest->aOpenList.push_back( aOpt.GetFactoryEmptyDocumentURL( eFactory ) );
+ bDocRequestSent = true;
+ }
+ }
+
+ if ( !aCmdLineArgs->IsQuickstart() ) {
+ bool bShowHelp = false;
+ OUStringBuffer aHelpURLBuffer;
+ if (aCmdLineArgs->IsHelpWriter()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://swriter/start");
+ } else if (aCmdLineArgs->IsHelpCalc()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://scalc/start");
+ } else if (aCmdLineArgs->IsHelpDraw()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://sdraw/start");
+ } else if (aCmdLineArgs->IsHelpImpress()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://simpress/start");
+ } else if (aCmdLineArgs->IsHelpBase()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://sdatabase/start");
+ } else if (aCmdLineArgs->IsHelpBasic()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://sbasic/start");
+ } else if (aCmdLineArgs->IsHelpMath()) {
+ bShowHelp = true;
+ aHelpURLBuffer.append("vnd.sun.star.help://smath/start");
+ }
+ if (bShowHelp) {
+ aHelpURLBuffer.append("?Language=");
+ aHelpURLBuffer.append(utl::ConfigManager::getLocale());
+#if defined UNX
+ aHelpURLBuffer.append("&System=UNX");
+#elif defined WNT
+ aHelpURLBuffer.appendAscii("&System=WIN");
+#endif
+ ApplicationEvent* pAppEvent = new ApplicationEvent(
+ ApplicationEvent::TYPE_OPENHELPURL,
+ aHelpURLBuffer.makeStringAndClear());
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+ }
+
+ if ( bDocRequestSent )
+ {
+ // Send requests to dispatch watcher if we have at least one. The receiver
+ // is responsible to delete the request after processing it.
+ if ( aCmdLineArgs->HasModuleParam() )
+ {
+ SvtModuleOptions aOpt;
+
+ // Support command line parameters to start a module (as preselection)
+ if ( aCmdLineArgs->IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
+ pRequest->aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::WRITER );
+ else if ( aCmdLineArgs->IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) )
+ pRequest->aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::CALC );
+ else if ( aCmdLineArgs->IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) )
+ pRequest->aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::IMPRESS );
+ else if ( aCmdLineArgs->IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) )
+ pRequest->aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::DRAW );
+ }
+
+ ImplPostProcessDocumentsEvent( pRequest );
+ }
+ else
+ {
+ // delete not used request again
+ delete pRequest;
+ pRequest = nullptr;
+ }
+ if (aCmdLineArgs->IsEmpty())
+ {
+ // no document was sent, just bring Office to front
+ ApplicationEvent* pAppEvent =
+ new ApplicationEvent(ApplicationEvent::TYPE_APPEAR);
+ ImplPostForeignAppEvent( pAppEvent );
+ }
+ }
+ *wait = bDocRequestSent;
+ return true;
+}
+
void PipeIpcThread::execute()
{
assert(handler_ != nullptr);
@@ -700,210 +1188,15 @@ void PipeIpcThread::execute()
if (aArguments.isEmpty())
continue;
- std::unique_ptr< CommandLineArgs > aCmdLineArgs;
- try
- {
- Parser p(aArguments);
- aCmdLineArgs.reset( new CommandLineArgs( p ) );
- }
- catch ( const CommandLineArgs::Supplier::Exception & )
- {
- SAL_WARN("desktop.app", "Error in received command line arguments");
+ bool wait = false;
+ if (!process(aArguments, &wait)) {
continue;
}
- bool bDocRequestSent = false;
-
- OUString aUnknown( aCmdLineArgs->GetUnknown() );
- if ( !aUnknown.isEmpty() || aCmdLineArgs->IsHelp() )
- {
- ApplicationEvent* pAppEvent =
- new ApplicationEvent(ApplicationEvent::TYPE_HELP, aUnknown);
- ImplPostForeignAppEvent( pAppEvent );
- }
- else if ( aCmdLineArgs->IsVersion() )
- {
- ApplicationEvent* pAppEvent =
- new ApplicationEvent(ApplicationEvent::TYPE_VERSION);
- ImplPostForeignAppEvent( pAppEvent );
- }
- else
- {
- const CommandLineArgs &rCurrentCmdLineArgs = Desktop::GetCommandLineArgs();
-
- if ( aCmdLineArgs->IsQuickstart() )
- {
- // we have to use application event, because we have to start quickstart service in main thread!!
- ApplicationEvent* pAppEvent =
- new ApplicationEvent(ApplicationEvent::TYPE_QUICKSTART);
- ImplPostForeignAppEvent( pAppEvent );
- }
-
- // handle request for acceptor
- std::vector< OUString > const & accept = aCmdLineArgs->
- GetAccept();
- for (std::vector< OUString >::const_iterator i(accept.begin());
- i != accept.end(); ++i)
- {
- ApplicationEvent* pAppEvent = new ApplicationEvent(
- ApplicationEvent::TYPE_ACCEPT, *i);
- ImplPostForeignAppEvent( pAppEvent );
- }
- // handle acceptor removal
- std::vector< OUString > const & unaccept = aCmdLineArgs->
- GetUnaccept();
- for (std::vector< OUString >::const_iterator i(
- unaccept.begin());
- i != unaccept.end(); ++i)
- {
- ApplicationEvent* pAppEvent = new ApplicationEvent(
- ApplicationEvent::TYPE_UNACCEPT, *i);
- ImplPostForeignAppEvent( pAppEvent );
- }
-
- ProcessDocumentsRequest* pRequest = new ProcessDocumentsRequest(
- aCmdLineArgs->getCwdUrl());
- handler_->cProcessed.reset();
- pRequest->pcProcessed = &handler_->cProcessed;
-
- // Print requests are not dependent on the --invisible cmdline argument as they are
- // loaded with the "hidden" flag! So they are always checked.
- pRequest->aPrintList = aCmdLineArgs->GetPrintList();
- bDocRequestSent |= !pRequest->aPrintList.empty();
- pRequest->aPrintToList = aCmdLineArgs->GetPrintToList();
- pRequest->aPrinterName = aCmdLineArgs->GetPrinterName();
- bDocRequestSent |= !( pRequest->aPrintToList.empty() || pRequest->aPrinterName.isEmpty() );
-
- if ( !rCurrentCmdLineArgs.IsInvisible() )
- {
- // Read cmdline args that can open/create documents. As they would open a window
- // they are only allowed if the "--invisible" is currently not used!
- pRequest->aOpenList = aCmdLineArgs->GetOpenList();
- bDocRequestSent |= !pRequest->aOpenList.empty();
- pRequest->aViewList = aCmdLineArgs->GetViewList();
- bDocRequestSent |= !pRequest->aViewList.empty();
- pRequest->aStartList = aCmdLineArgs->GetStartList();
- bDocRequestSent |= !pRequest->aStartList.empty();
- pRequest->aForceOpenList = aCmdLineArgs->GetForceOpenList();
- bDocRequestSent |= !pRequest->aForceOpenList.empty();
- pRequest->aForceNewList = aCmdLineArgs->GetForceNewList();
- bDocRequestSent |= !pRequest->aForceNewList.empty();
-
- // Special command line args to create an empty document for a given module
-
- // #i18338# (lo)
- // we only do this if no document was specified on the command line,
- // since this would be inconsistent with the behaviour of
- // the first process, see OpenClients() (call to OpenDefault()) in app.cxx
- if ( aCmdLineArgs->HasModuleParam() && !bDocRequestSent )
- {
- SvtModuleOptions aOpt;
- SvtModuleOptions::EFactory eFactory = SvtModuleOptions::EFactory::WRITER;
- if ( aCmdLineArgs->IsWriter() )
- eFactory = SvtModuleOptions::EFactory::WRITER;
- else if ( aCmdLineArgs->IsCalc() )
- eFactory = SvtModuleOptions::EFactory::CALC;
- else if ( aCmdLineArgs->IsDraw() )
- eFactory = SvtModuleOptions::EFactory::DRAW;
- else if ( aCmdLineArgs->IsImpress() )
- eFactory = SvtModuleOptions::EFactory::IMPRESS;
- else if ( aCmdLineArgs->IsBase() )
- eFactory = SvtModuleOptions::EFactory::DATABASE;
- else if ( aCmdLineArgs->IsMath() )
- eFactory = SvtModuleOptions::EFactory::MATH;
- else if ( aCmdLineArgs->IsGlobal() )
- eFactory = SvtModuleOptions::EFactory::WRITERGLOBAL;
- else if ( aCmdLineArgs->IsWeb() )
- eFactory = SvtModuleOptions::EFactory::WRITERWEB;
-
- if ( !pRequest->aOpenList.empty() )
- pRequest->aModule = aOpt.GetFactoryName( eFactory );
- else
- pRequest->aOpenList.push_back( aOpt.GetFactoryEmptyDocumentURL( eFactory ) );
- bDocRequestSent = true;
- }
- }
-
- if ( !aCmdLineArgs->IsQuickstart() ) {
- bool bShowHelp = false;
- OUStringBuffer aHelpURLBuffer;
- if (aCmdLineArgs->IsHelpWriter()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://swriter/start");
- } else if (aCmdLineArgs->IsHelpCalc()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://scalc/start");
- } else if (aCmdLineArgs->IsHelpDraw()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://sdraw/start");
- } else if (aCmdLineArgs->IsHelpImpress()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://simpress/start");
- } else if (aCmdLineArgs->IsHelpBase()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://sdatabase/start");
- } else if (aCmdLineArgs->IsHelpBasic()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://sbasic/start");
- } else if (aCmdLineArgs->IsHelpMath()) {
- bShowHelp = true;
- aHelpURLBuffer.append("vnd.sun.star.help://smath/start");
- }
- if (bShowHelp) {
- aHelpURLBuffer.append("?Language=");
- aHelpURLBuffer.append(utl::ConfigManager::getLocale());
-#if defined UNX
- aHelpURLBuffer.append("&System=UNX");
-#elif defined WNT
- aHelpURLBuffer.appendAscii("&System=WIN");
-#endif
- ApplicationEvent* pAppEvent = new ApplicationEvent(
- ApplicationEvent::TYPE_OPENHELPURL,
- aHelpURLBuffer.makeStringAndClear());
- ImplPostForeignAppEvent( pAppEvent );
- }
- }
-
- if ( bDocRequestSent )
- {
- // Send requests to dispatch watcher if we have at least one. The receiver
- // is responsible to delete the request after processing it.
- if ( aCmdLineArgs->HasModuleParam() )
- {
- SvtModuleOptions aOpt;
-
- // Support command line parameters to start a module (as preselection)
- if ( aCmdLineArgs->IsWriter() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) )
- pRequest->aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::WRITER );
- else if ( aCmdLineArgs->IsCalc() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::CALC ) )
- pRequest->aModule = aOpt.GetFactoryName( SvtModuleOptions::EFactory::CALC );
- else if ( aCmdLineArgs->IsImpress() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::IMPRESS ) )
- pRequest->aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::IMPRESS );
- else if ( aCmdLineArgs->IsDraw() && aOpt.IsModuleInstalled( SvtModuleOptions::EModule::DRAW ) )
- pRequest->aModule= aOpt.GetFactoryName( SvtModuleOptions::EFactory::DRAW );
- }
-
- ImplPostProcessDocumentsEvent( pRequest );
- }
- else
- {
- // delete not used request again
- delete pRequest;
- pRequest = nullptr;
- }
- if (aCmdLineArgs->IsEmpty())
- {
- // no document was sent, just bring Office to front
- ApplicationEvent* pAppEvent =
- new ApplicationEvent(ApplicationEvent::TYPE_APPEAR);
- ImplPostForeignAppEvent( pAppEvent );
- }
- }
-
// we don't need the mutex any longer...
aGuard.clear();
// wait for processing to finish
- if (bDocRequestSent)
+ if (wait)
handler_->cProcessed.wait();
// processing finished, inform the requesting end:
n = aStreamPipe.write(
diff --git a/desktop/source/app/officeipcthread.hxx b/desktop/source/app/officeipcthread.hxx
index 55e5fc3..1d3b2cc 100644
--- a/desktop/source/app/officeipcthread.hxx
+++ b/desktop/source/app/officeipcthread.hxx
@@ -69,10 +69,13 @@ struct ProcessDocumentsRequest
class DispatchWatcher;
class IpcThread;
class PipeIpcThread;
+class DbusIpcThread;
class RequestHandler: public salhelper::SimpleReferenceObject
{
+ friend IpcThread;
friend PipeIpcThread;
+ friend DbusIpcThread;
private:
static rtl::Reference< RequestHandler > pGlobal;
diff --git a/desktop/unx/source/start.c b/desktop/unx/source/start.c
index a988fc8..3b23124 100644
--- a/desktop/unx/source/start.c
+++ b/desktop/unx/source/start.c
@@ -757,7 +757,7 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv )
if ( pUsePlugin && !strcmp(pUsePlugin, "svp") )
args->bInhibitSplash = sal_True;
- if ( !args->bInhibitPipe )
+ if ( !args->bInhibitPipe && getenv("LIBO_XDGAPP") == NULL )
{
int fd = 0;
pPipePath = get_pipe_path( args->pAppPath );
commit ec655c8e8f6ff476fb70135927ce38d1b1000982
Author: Stephan Bergmann <sbergman at redhat.com>
Date: Fri Apr 1 14:22:44 2016 +0200
Prepare for using other IPC mechanisms besides an osl::Pipe
Change-Id: Ie34330508563bef25185216bdc1dc3ae84d084d4
diff --git a/desktop/source/app/officeipcthread.cxx b/desktop/source/app/officeipcthread.cxx
index 891f021..c4f50f4 100644
--- a/desktop/source/app/officeipcthread.cxx
+++ b/desktop/source/app/officeipcthread.cxx
@@ -42,6 +42,8 @@
#include <osl/file.hxx>
#include <rtl/process.h>
#include <tools/getprocessworkingdir.hxx>
+
+#include <cassert>
#include <memory>
using namespace desktop;
@@ -81,14 +83,6 @@ OString readStringFromPipe(osl::StreamPipe & pipe) {
}
-// Type of pipe we use
-enum PipeMode
-{
- PIPEMODE_DONTKNOW,
- PIPEMODE_CREATED,
- PIPEMODE_CONNECTED
-};
-
namespace desktop
{
@@ -357,20 +351,38 @@ throw( RuntimeException, std::exception )
{
}
-class PipeReaderThread: public salhelper::Thread {
+class IpcThread: public salhelper::Thread {
public:
- PipeReaderThread(RequestHandler & handler, osl::Pipe const & pipe):
- Thread("PipeReader"), handler_(handler), pipe_(pipe)
- {}
+ void start(RequestHandler * handler) {
+ handler_ = handler;
+ launch();
+ }
- void close() { pipe_.close(); }
+ virtual void close() = 0;
+
+protected:
+ explicit IpcThread(char const * name): Thread(name), handler_(nullptr) {}
+
+ virtual ~IpcThread() {}
+
+ RequestHandler * handler_;
+};
+
+class PipeIpcThread: public IpcThread {
+public:
+ static RequestHandler::Status enable(rtl::Reference<IpcThread> * thread);
private:
- virtual ~PipeReaderThread() {}
+ explicit PipeIpcThread(osl::Pipe const & pipe):
+ IpcThread("PipeIPC"), pipe_(pipe)
+ {}
+
+ virtual ~PipeIpcThread() {}
void execute() override;
- RequestHandler & handler_;
+ void close() override { pipe_.close(); }
+
osl::Pipe pipe_;
};
@@ -450,6 +462,21 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
return IPC_STATUS_OK;
}
+ rtl::Reference<IpcThread> thread;
+ Status stat = PipeIpcThread::enable(&thread);
+ assert(thread.is() == (stat == IPC_STATUS_OK));
+ if (stat == IPC_STATUS_OK) {
+ pGlobal = new RequestHandler;
+ pGlobal->mIpcThread = thread;
+ pGlobal->mIpcThread->start(pGlobal.get());
+ }
+ return stat;
+}
+
+RequestHandler::Status PipeIpcThread::enable(rtl::Reference<IpcThread> * thread)
+{
+ assert(thread != nullptr);
+
// The name of the named pipe is created with the hashcode of the user installation directory (without /user). We have to retrieve
// this information from a unotools implementation.
OUString aUserInstallPath;
@@ -457,7 +484,7 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
if (aLocateResult != utl::Bootstrap::PATH_EXISTS
&& aLocateResult != utl::Bootstrap::PATH_VALID)
{
- return IPC_STATUS_BOOTSTRAP_ERROR;
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
}
// Try to determine if we are the first office or not! This should prevent multiple
@@ -469,9 +496,15 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
// Check result to create a hash code from the user install path
if ( aUserInstallPathHashCode.isEmpty() )
- return IPC_STATUS_BOOTSTRAP_ERROR; // Something completely broken, we cannot create a valid hash code!
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR; // Something completely broken, we cannot create a valid hash code!
osl::Pipe pipe;
+ enum PipeMode
+ {
+ PIPEMODE_DONTKNOW,
+ PIPEMODE_CREATED,
+ PIPEMODE_CONNECTED
+ };
PipeMode nPipeMode = PIPEMODE_DONTKNOW;
OUString aPipeIdent( "SingleOfficeIPC_" + aUserInstallPathHashCode );
@@ -506,7 +539,7 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
{
oslPipeError eReason = pipe.getError();
if ((eReason == osl_Pipe_E_ConnectionRefused) || (eReason == osl_Pipe_E_invalidError))
- return IPC_STATUS_PIPE_ERROR;
+ return RequestHandler::IPC_STATUS_PIPE_ERROR;
// Wait for second office to be ready
TimeValue aTimeValue;
@@ -519,11 +552,9 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
if ( nPipeMode == PIPEMODE_CREATED )
{
- // Seems we are the one and only, so start listening thread
- pGlobal = new RequestHandler;
- pGlobal->mPipeReaderThread = new PipeReaderThread(*pGlobal, pipe);
- pGlobal->mPipeReaderThread->launch();
- return IPC_STATUS_OK;
+ // Seems we are the one and only, so create listening thread
+ *thread = new PipeIpcThread(pipe);
+ return RequestHandler::IPC_STATUS_OK;
}
else
{
@@ -542,7 +573,7 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
{
rtl_getAppCommandArg( i, &aUserInstallPath.pData );
if (!addArgument(aArguments, ',', aUserInstallPath)) {
- return IPC_STATUS_BOOTSTRAP_ERROR;
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
}
}
aArguments.append('\0');
@@ -551,16 +582,16 @@ RequestHandler::Status RequestHandler::Enable(bool ipc)
aArguments.getStr(), aArguments.getLength());
if (n != aArguments.getLength()) {
SAL_INFO("desktop", "short write: " << n);
- return IPC_STATUS_BOOTSTRAP_ERROR;
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
}
if (readStringFromPipe(aStreamPipe) != PROCESSING_DONE)
{
// something went wrong
- return IPC_STATUS_BOOTSTRAP_ERROR;
+ return RequestHandler::IPC_STATUS_BOOTSTRAP_ERROR;
}
- return IPC_STATUS_2ND_OFFICE;
+ return RequestHandler::IPC_STATUS_2ND_OFFICE;
}
}
@@ -574,8 +605,8 @@ void RequestHandler::Disable(bool join)
pGlobal.clear();
handler->mState = State::Downing;
- if (handler->mPipeReaderThread.is()) {
- handler->mPipeReaderThread->close();
+ if (handler->mIpcThread.is()) {
+ handler->mIpcThread->close();
}
// release mutex to avoid deadlocks
@@ -584,10 +615,10 @@ void RequestHandler::Disable(bool join)
handler->cReady.set();
// exit gracefully and join
- if (join && handler->mPipeReaderThread.is())
+ if (join && handler->mIpcThread.is())
{
- handler->mPipeReaderThread->join();
- handler->mPipeReaderThread.clear();
+ handler->mIpcThread->join();
+ handler->mIpcThread.clear();
}
}
}
@@ -600,7 +631,7 @@ RequestHandler::RequestHandler() :
RequestHandler::~RequestHandler()
{
- assert(!mPipeReaderThread.is());
+ assert(!mIpcThread.is());
}
void RequestHandler::SetReady()
@@ -625,8 +656,9 @@ void RequestHandler::WaitForReady()
}
}
-void PipeReaderThread::execute()
+void PipeIpcThread::execute()
{
+ assert(handler_ != nullptr);
do
{
osl::StreamPipe aStreamPipe;
@@ -639,16 +671,16 @@ void PipeReaderThread::execute()
// bootstrap, that dialogs event loop might get events that are dispatched by this thread
// we have to wait for cReady to be set by the real main loop.
// only requests that don't dispatch events may be processed before cReady is set.
- handler_.cReady.wait();
+ handler_->cReady.wait();
// we might have decided to shutdown while we were sleeping
- if (!handler_.pGlobal.is()) return;
+ if (!handler_->pGlobal.is()) return;
// only lock the mutex when processing starts, othewise we deadlock when the office goes
// down during wait
osl::ClearableMutexGuard aGuard( RequestHandler::GetMutex() );
- if ( handler_.mState == RequestHandler::State::Downing )
+ if ( handler_->mState == RequestHandler::State::Downing )
{
break;
}
@@ -731,8 +763,8 @@ void PipeReaderThread::execute()
ProcessDocumentsRequest* pRequest = new ProcessDocumentsRequest(
aCmdLineArgs->getCwdUrl());
- handler_.cProcessed.reset();
- pRequest->pcProcessed = &handler_.cProcessed;
+ handler_->cProcessed.reset();
+ pRequest->pcProcessed = &handler_->cProcessed;
// Print requests are not dependent on the --invisible cmdline argument as they are
// loaded with the "hidden" flag! So they are always checked.
@@ -872,7 +904,7 @@ void PipeReaderThread::execute()
aGuard.clear();
// wait for processing to finish
if (bDocRequestSent)
- handler_.cProcessed.wait();
+ handler_->cProcessed.wait();
// processing finished, inform the requesting end:
n = aStreamPipe.write(
PROCESSING_DONE, SAL_N_ELEMENTS(PROCESSING_DONE));
@@ -886,7 +918,7 @@ void PipeReaderThread::execute()
{
{
osl::MutexGuard aGuard( RequestHandler::GetMutex() );
- if ( handler_.mState == RequestHandler::State::Downing )
+ if ( handler_->mState == RequestHandler::State::Downing )
{
break;
}
diff --git a/desktop/source/app/officeipcthread.hxx b/desktop/source/app/officeipcthread.hxx
index 7b154d5..55e5fc3 100644
--- a/desktop/source/app/officeipcthread.hxx
+++ b/desktop/source/app/officeipcthread.hxx
@@ -67,11 +67,12 @@ struct ProcessDocumentsRequest
};
class DispatchWatcher;
-class PipeReaderThread;
+class IpcThread;
+class PipeIpcThread;
class RequestHandler: public salhelper::SimpleReferenceObject
{
- friend PipeReaderThread;
+ friend PipeIpcThread;
private:
static rtl::Reference< RequestHandler > pGlobal;
@@ -81,7 +82,7 @@ class RequestHandler: public salhelper::SimpleReferenceObject
State mState;
int mnPendingRequests;
rtl::Reference<DispatchWatcher> mpDispatchWatcher;
- rtl::Reference<PipeReaderThread> mPipeReaderThread;
+ rtl::Reference<IpcThread> mIpcThread;
/* condition to be set when the request has been processed */
::osl::Condition cProcessed;
More information about the Libreoffice-commits
mailing list