Kontact Plugin Interface Library
uniqueapphandler.cpp
00001 /* 00002 This file is part of the KDE Kontact Plugin Interface Library. 00003 00004 Copyright (c) 2003,2008 David Faure <faure@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "uniqueapphandler.h" 00023 #include <qdbusabstractadaptor.h> 00024 #include "core.h" 00025 00026 #include <kpimutils/processes.h> 00027 00028 #include <kapplication.h> 00029 #include <kcmdlineargs.h> 00030 #include <kdebug.h> 00031 #include <kstartupinfo.h> 00032 #include <kuniqueapplication.h> 00033 #include <kwindowsystem.h> 00034 00035 #include <QDBusConnection> 00036 #include <QDBusConnectionInterface> 00037 00038 #ifdef Q_WS_WIN 00039 # include <process.h> 00040 #endif 00041 00042 /* 00043 Test plan for the various cases of interaction between standalone apps and kontact: 00044 00045 1) start kontact, select "Mail". 00046 1a) type "korganizer" -> it switches to korganizer 00047 1b) type "kmail" -> it switches to kmail 00048 1c) type "kaddressbook" -> it switches to kaddressbook 00049 1d) type "kmail foo@kde.org" -> it opens a kmail composer, without switching 00050 1e) type "knode" -> it switches to knode [unless configured to be external] 00051 1f) type "kaddressbook --new-contact" -> it opens a kaddressbook contact window 00052 1g) type "knode news://foobar/group" -> it pops up "can't resolve hostname" 00053 00054 2) close kontact. Launch kmail. Launch kontact again. 00055 2a) click "Mail" icon -> kontact doesn't load a part, but activates the kmail window 00056 2b) type "kmail foo@kde.org" -> standalone kmail opens composer. 00057 2c) close kmail, click "Mail" icon -> kontact loads the kmail part. 00058 2d) type "kmail" -> kontact is brought to front 00059 00060 3) close kontact. Launch korganizer, then kontact. 00061 3a) both Todo and Calendar activate the running korganizer. 00062 3b) type "korganizer" -> standalone korganizer is brought to front 00063 3c) close korganizer, click Calendar or Todo -> kontact loads part. 00064 3d) type "korganizer" -> kontact is brought to front 00065 00066 4) close kontact. Launch kaddressbook, then kontact. 00067 4a) "Contacts" icon activate the running kaddressbook. 00068 4b) type "kaddressbook" -> standalone kaddressbook is brought to front 00069 4c) close kaddressbook, type "kaddressbook -a foo@kde.org" -> kontact loads part and opens editor 00070 4d) type "kaddressbook" -> kontact is brought to front 00071 00072 5) close kontact. Launch knode, then kontact. 00073 5a) "News" icon activate the running knode. 00074 5b) type "knode" -> standalone knode is brought to front 00075 5c) close knode, type "knode news://foobar/group" -> kontact loads knode and pops up msgbox 00076 5d) type "knode" -> kontact is brought to front 00077 00078 6) start "kontact --module summaryplugin" 00079 6a) type "qdbus org.kde.kmail /kmail_PimApplication newInstance '' ''" -> 00080 kontact switches to kmail (#103775) 00081 6b) type "kmail" -> kontact is brought to front 00082 6c) type "kontact" -> kontact is brought to front 00083 6d) type "kontact --module summaryplugin" -> kontact switches to summary 00084 00085 */ 00086 00087 using namespace KontactInterface; 00088 00089 //@cond PRIVATE 00090 class UniqueAppHandler::Private 00091 { 00092 public: 00093 Plugin *mPlugin; 00094 }; 00095 //@endcond 00096 00097 UniqueAppHandler::UniqueAppHandler( Plugin *plugin ) 00098 : QObject( plugin ), d( new Private ) 00099 { 00100 //kDebug() << "plugin->objectName():" << plugin->objectName(); 00101 00102 d->mPlugin = plugin; 00103 QDBusConnection session = QDBusConnection::sessionBus(); 00104 const QString appName = plugin->objectName(); 00105 session.registerService( "org.kde." + appName ); 00106 const QString objectName = QString( '/' ) + appName + "_PimApplication"; 00107 session.registerObject( objectName, this, QDBusConnection::ExportAllSlots ); 00108 } 00109 00110 UniqueAppHandler::~UniqueAppHandler() 00111 { 00112 QDBusConnection session = QDBusConnection::sessionBus(); 00113 const QString appName = parent()->objectName(); 00114 session.unregisterService( "org.kde." + appName ); 00115 delete d; 00116 } 00117 00118 // DBUS call 00119 int UniqueAppHandler::newInstance( const QByteArray &asn_id, const QByteArray &args ) 00120 { 00121 if ( !asn_id.isEmpty() ) { 00122 kapp->setStartupId( asn_id ); 00123 } 00124 00125 KCmdLineArgs::reset(); // forget options defined by other "applications" 00126 loadCommandLineOptions(); // implemented by plugin 00127 00128 // This bit is duplicated from KUniqueApplicationAdaptor::newInstance() 00129 QDataStream ds( args ); 00130 KCmdLineArgs::loadAppArgs( ds ); 00131 00132 return newInstance(); 00133 } 00134 00135 static QWidget *s_mainWidget = 0; 00136 00137 // Plugin-specific newInstance implementation, called by above method 00138 int KontactInterface::UniqueAppHandler::newInstance() 00139 { 00140 if ( s_mainWidget ) { 00141 s_mainWidget->show(); 00142 KWindowSystem::forceActiveWindow( s_mainWidget->winId() ); 00143 KStartupInfo::appStarted(); 00144 } 00145 00146 // Then ensure the part appears in kontact 00147 d->mPlugin->core()->selectPlugin( d->mPlugin ); 00148 return 0; 00149 } 00150 00151 Plugin *UniqueAppHandler::plugin() const 00152 { 00153 return d->mPlugin; 00154 } 00155 00156 bool KontactInterface::UniqueAppHandler::load() 00157 { 00158 (void)d->mPlugin->part(); // load the part without bringing it to front 00159 return true; 00160 } 00161 00162 //@cond PRIVATE 00163 class UniqueAppWatcher::Private 00164 { 00165 public: 00166 UniqueAppHandlerFactoryBase *mFactory; 00167 Plugin *mPlugin; 00168 bool mRunningStandalone; 00169 }; 00170 //@endcond 00171 00172 UniqueAppWatcher::UniqueAppWatcher( UniqueAppHandlerFactoryBase *factory, Plugin *plugin ) 00173 : QObject( plugin ), d( new Private ) 00174 { 00175 d->mFactory = factory; 00176 d->mPlugin = plugin; 00177 00178 // The app is running standalone if 1) that name is known to D-Bus 00179 const QString serviceName = "org.kde." + plugin->objectName(); 00180 //Needed for wince build 00181 #undef interface 00182 d->mRunningStandalone = 00183 QDBusConnection::sessionBus().interface()->isServiceRegistered( serviceName ); 00184 #ifdef Q_WS_WIN 00185 if ( d->mRunningStandalone ) { 00186 QList<int> pids; 00187 KPIMUtils::getProcessesIdForName( plugin->objectName(), pids ); 00188 const int mypid = getpid(); 00189 bool processExits = false; 00190 foreach ( int pid, pids ) { 00191 if ( mypid != pid ) { 00192 processExits = true; 00193 break; 00194 } 00195 } 00196 if ( !processExits ) { 00197 d->mRunningStandalone = false; 00198 } 00199 } 00200 #endif 00201 00202 QString owner = QDBusConnection::sessionBus().interface()->serviceOwner( serviceName ); 00203 if ( d->mRunningStandalone && ( owner == QDBusConnection::sessionBus().baseService() ) ) { 00204 d->mRunningStandalone = false; 00205 } 00206 //kDebug() << " plugin->objectName()=" << plugin->objectName() 00207 // << " running standalone:" << d->mRunningStandalone; 00208 00209 if ( d->mRunningStandalone ) { 00210 QObject::connect( QDBusConnection::sessionBus().interface(), 00211 SIGNAL(serviceOwnerChanged(QString,QString,QString)), 00212 this, SLOT(slotApplicationRemoved(QString,QString,QString)) ); 00213 } else { 00214 d->mFactory->createHandler( d->mPlugin ); 00215 } 00216 } 00217 00218 UniqueAppWatcher::~UniqueAppWatcher() 00219 { 00220 delete d->mFactory; 00221 delete d; 00222 } 00223 00224 bool UniqueAppWatcher::isRunningStandalone() const 00225 { 00226 return d->mRunningStandalone; 00227 } 00228 00229 void KontactInterface::UniqueAppWatcher::slotApplicationRemoved( const QString &name, 00230 const QString &oldOwner, 00231 const QString &newOwner ) 00232 { 00233 if ( oldOwner.isEmpty() || !newOwner.isEmpty() ) { 00234 return; 00235 } 00236 00237 const QString serviceName = "org.kde." + d->mPlugin->objectName(); 00238 if ( name == serviceName && d->mRunningStandalone ) { 00239 d->mFactory->createHandler( d->mPlugin ); 00240 d->mRunningStandalone = false; 00241 } 00242 } 00243 00244 void KontactInterface::UniqueAppHandler::setMainWidget( QWidget *widget ) 00245 { 00246 s_mainWidget = widget; 00247 } 00248 00249 QWidget *KontactInterface::UniqueAppHandler::mainWidget() 00250 { 00251 return s_mainWidget; 00252 } 00253 00254 #include "uniqueapphandler.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:51:33 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:51:33 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.