• Skip to content
  • Skip to link menu
KDE 4.5 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

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  : 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   delete d;
00113 }
00114 
00115 // DBUS call
00116 int UniqueAppHandler::newInstance( const QByteArray &asn_id, const QByteArray &args )
00117 {
00118   if ( !asn_id.isEmpty() ) {
00119     kapp->setStartupId( asn_id );
00120   }
00121 
00122   KCmdLineArgs::reset(); // forget options defined by other "applications"
00123   loadCommandLineOptions(); // implemented by plugin
00124 
00125   // This bit is duplicated from KUniqueApplicationAdaptor::newInstance()
00126   QDataStream ds( args );
00127   KCmdLineArgs::loadAppArgs( ds );
00128 
00129   return newInstance();
00130 }
00131 
00132 static QWidget *s_mainWidget = 0;
00133 
00134 // Plugin-specific newInstance implementation, called by above method
00135 int KontactInterface::UniqueAppHandler::newInstance()
00136 {
00137   if ( s_mainWidget ) {
00138     s_mainWidget->show();
00139     KWindowSystem::forceActiveWindow( s_mainWidget->winId() );
00140     KStartupInfo::appStarted();
00141   }
00142 
00143   // Then ensure the part appears in kontact
00144   d->mPlugin->core()->selectPlugin( d->mPlugin );
00145   return 0;
00146 }
00147 
00148 Plugin *UniqueAppHandler::plugin() const
00149 {
00150   return d->mPlugin;
00151 }
00152 
00153 bool KontactInterface::UniqueAppHandler::load()
00154 {
00155   (void)d->mPlugin->part(); // load the part without bringing it to front
00156   return true;
00157 }
00158 
00159 //@cond PRIVATE
00160 class UniqueAppWatcher::Private
00161 {
00162   public:
00163     UniqueAppHandlerFactoryBase *mFactory;
00164     Plugin *mPlugin;
00165     bool mRunningStandalone;
00166 };
00167 //@endcond
00168 
00169 UniqueAppWatcher::UniqueAppWatcher( UniqueAppHandlerFactoryBase *factory, Plugin *plugin )
00170   : QObject( plugin ), d( new Private )
00171 {
00172   d->mFactory = factory;
00173   d->mPlugin = plugin;
00174 
00175   // The app is running standalone if 1) that name is known to D-Bus
00176   const QString serviceName = "org.kde." + plugin->objectName();
00177   d->mRunningStandalone =
00178     QDBusConnection::sessionBus().interface()->isServiceRegistered( serviceName );
00179 #ifdef Q_WS_WIN
00180   if ( d->mRunningStandalone ) {
00181     QList<int> pids;
00182     KPIMUtils::getProcessesIdForName( plugin->objectName(), pids );
00183     const int mypid = getpid();
00184     bool processExits = false;
00185     foreach ( int pid, pids ) {
00186       if ( mypid != pid ) {
00187         processExits = true;
00188         break;
00189       }
00190     }
00191     if ( !processExits ) {
00192       d->mRunningStandalone = false;
00193     }
00194   }
00195 #endif
00196 
00197   QString owner = QDBusConnection::sessionBus().interface()->serviceOwner( serviceName );
00198   if ( d->mRunningStandalone && ( owner == QDBusConnection::sessionBus().baseService() ) ) {
00199     d->mRunningStandalone = false;
00200   }
00201   //kDebug() << " plugin->objectName()=" << plugin->objectName()
00202   //         << " running standalone:" << d->mRunningStandalone;
00203 
00204   if ( d->mRunningStandalone ) {
00205     QObject::connect( QDBusConnection::sessionBus().interface(),
00206                       SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00207                       this, SLOT(slotApplicationRemoved(QString,QString,QString)) );
00208   } else {
00209     d->mFactory->createHandler( d->mPlugin );
00210   }
00211 }
00212 
00213 UniqueAppWatcher::~UniqueAppWatcher()
00214 {
00215   delete d->mFactory;
00216   delete d;
00217 }
00218 
00219 bool UniqueAppWatcher::isRunningStandalone() const
00220 {
00221   return d->mRunningStandalone;
00222 }
00223 
00224 void KontactInterface::UniqueAppWatcher::slotApplicationRemoved( const QString &name,
00225                                                                  const QString &oldOwner,
00226                                                                  const QString &newOwner )
00227 {
00228   if ( oldOwner.isEmpty() || !newOwner.isEmpty() ) {
00229     return;
00230   }
00231 
00232   const QString serviceName = "org.kde." + d->mPlugin->objectName();
00233   if ( name == serviceName && d->mRunningStandalone ) {
00234     d->mFactory->createHandler( d->mPlugin );
00235     d->mRunningStandalone = false;
00236   }
00237 }
00238 
00239 void KontactInterface::UniqueAppHandler::setMainWidget( QWidget *widget )
00240 {
00241   s_mainWidget = widget;
00242 }
00243 
00244 #include "uniqueapphandler.moc"

Kontact Plugin Interface Library

Skip menu "Kontact Plugin Interface Library"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.7.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal