• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepimlibs API Reference
  • KDE Home
  • Contact Us
 

Kontact Plugin Interface Library

  • sources
  • kde-4.14
  • kdepimlibs
  • kontactinterface
uniqueapphandler.cpp
1 /*
2  This file is part of the KDE Kontact Plugin Interface Library.
3 
4  Copyright (c) 2003,2008 David Faure <faure@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "uniqueapphandler.h"
23 #include <qdbusabstractadaptor.h>
24 #include "core.h"
25 
26 #include <kpimutils/processes.h>
27 
28 #include <kapplication.h>
29 #include <kcmdlineargs.h>
30 #include <kdebug.h>
31 #include <kstartupinfo.h>
32 #include <kuniqueapplication.h>
33 #include <kwindowsystem.h>
34 
35 #include <QDBusConnection>
36 #include <QDBusConnectionInterface>
37 
38 #ifdef Q_WS_WIN
39 # include <process.h>
40 #endif
41 
42 /*
43  Test plan for the various cases of interaction between standalone apps and kontact:
44 
45  1) start kontact, select "Mail".
46  1a) type "korganizer" -> it switches to korganizer
47  1b) type "kmail" -> it switches to kmail
48  1c) type "kaddressbook" -> it switches to kaddressbook
49  1d) type "kmail foo@kde.org" -> it opens a kmail composer, without switching
50  1e) type "knode" -> it switches to knode [unless configured to be external]
51  1f) type "kaddressbook --new-contact" -> it opens a kaddressbook contact window
52  1g) type "knode news://foobar/group" -> it pops up "can't resolve hostname"
53 
54  2) close kontact. Launch kmail. Launch kontact again.
55  2a) click "Mail" icon -> kontact doesn't load a part, but activates the kmail window
56  2b) type "kmail foo@kde.org" -> standalone kmail opens composer.
57  2c) close kmail, click "Mail" icon -> kontact loads the kmail part.
58  2d) type "kmail" -> kontact is brought to front
59 
60  3) close kontact. Launch korganizer, then kontact.
61  3a) both Todo and Calendar activate the running korganizer.
62  3b) type "korganizer" -> standalone korganizer is brought to front
63  3c) close korganizer, click Calendar or Todo -> kontact loads part.
64  3d) type "korganizer" -> kontact is brought to front
65 
66  4) close kontact. Launch kaddressbook, then kontact.
67  4a) "Contacts" icon activate the running kaddressbook.
68  4b) type "kaddressbook" -> standalone kaddressbook is brought to front
69  4c) close kaddressbook, type "kaddressbook -a foo@kde.org" -> kontact loads part and opens editor
70  4d) type "kaddressbook" -> kontact is brought to front
71 
72  5) close kontact. Launch knode, then kontact.
73  5a) "News" icon activate the running knode.
74  5b) type "knode" -> standalone knode is brought to front
75  5c) close knode, type "knode news://foobar/group" -> kontact loads knode and pops up msgbox
76  5d) type "knode" -> kontact is brought to front
77 
78  6) start "kontact --module summaryplugin"
79  6a) type "qdbus org.kde.kmail /kmail_PimApplication newInstance '' ''" ->
80  kontact switches to kmail (#103775)
81  6b) type "kmail" -> kontact is brought to front
82  6c) type "kontact" -> kontact is brought to front
83  6d) type "kontact --module summaryplugin" -> kontact switches to summary
84 
85 */
86 
87 using namespace KontactInterface;
88 
89 //@cond PRIVATE
90 class UniqueAppHandler::Private
91 {
92  public:
93  Plugin *mPlugin;
94 };
95 //@endcond
96 
97 UniqueAppHandler::UniqueAppHandler( Plugin *plugin )
98  : QObject( plugin ), d( new Private )
99 {
100  //kDebug() << "plugin->objectName():" << plugin->objectName();
101 
102  d->mPlugin = plugin;
103  QDBusConnection session = QDBusConnection::sessionBus();
104  const QString appName = plugin->objectName();
105  session.registerService( QLatin1String("org.kde.") + appName );
106  const QString objectName = QLatin1Char( '/' ) + appName + QLatin1String("_PimApplication");
107  session.registerObject( objectName, this, QDBusConnection::ExportAllSlots );
108 }
109 
110 UniqueAppHandler::~UniqueAppHandler()
111 {
112  QDBusConnection session = QDBusConnection::sessionBus();
113  const QString appName = parent()->objectName();
114  session.unregisterService( QLatin1String("org.kde.") + appName );
115  delete d;
116 }
117 
118 // DBUS call
119 int UniqueAppHandler::newInstance( const QByteArray &asn_id, const QByteArray &args )
120 {
121  if ( !asn_id.isEmpty() ) {
122  kapp->setStartupId( asn_id );
123  }
124 
125  KCmdLineArgs::reset(); // forget options defined by other "applications"
126  loadCommandLineOptions(); // implemented by plugin
127 
128  // This bit is duplicated from KUniqueApplicationAdaptor::newInstance()
129  QDataStream ds( args );
130  KCmdLineArgs::loadAppArgs( ds );
131 
132  return newInstance();
133 }
134 
135 static QWidget *s_mainWidget = 0;
136 
137 // Plugin-specific newInstance implementation, called by above method
138 int KontactInterface::UniqueAppHandler::newInstance()
139 {
140  if ( s_mainWidget ) {
141  s_mainWidget->show();
142  KWindowSystem::forceActiveWindow( s_mainWidget->winId() );
143  KStartupInfo::appStarted();
144  }
145 
146  // Then ensure the part appears in kontact
147  d->mPlugin->core()->selectPlugin( d->mPlugin );
148  return 0;
149 }
150 
151 Plugin *UniqueAppHandler::plugin() const
152 {
153  return d->mPlugin;
154 }
155 
156 bool KontactInterface::UniqueAppHandler::load()
157 {
158  (void)d->mPlugin->part(); // load the part without bringing it to front
159  return true;
160 }
161 
162 //@cond PRIVATE
163 class UniqueAppWatcher::Private
164 {
165  public:
166  UniqueAppHandlerFactoryBase *mFactory;
167  Plugin *mPlugin;
168  bool mRunningStandalone;
169 };
170 //@endcond
171 
172 UniqueAppWatcher::UniqueAppWatcher( UniqueAppHandlerFactoryBase *factory, Plugin *plugin )
173  : QObject( plugin ), d( new Private )
174 {
175  d->mFactory = factory;
176  d->mPlugin = plugin;
177 
178  // The app is running standalone if 1) that name is known to D-Bus
179  const QString serviceName = QLatin1String("org.kde.") + plugin->objectName();
180  //Needed for wince build
181  #undef interface
182  d->mRunningStandalone =
183  QDBusConnection::sessionBus().interface()->isServiceRegistered( serviceName );
184 #ifdef Q_WS_WIN
185  if ( d->mRunningStandalone ) {
186  QList<int> pids;
187  KPIMUtils::getProcessesIdForName( plugin->objectName(), pids );
188  const int mypid = getpid();
189  bool processExits = false;
190  foreach ( int pid, pids ) {
191  if ( mypid != pid ) {
192  processExits = true;
193  break;
194  }
195  }
196  if ( !processExits ) {
197  d->mRunningStandalone = false;
198  }
199  }
200 #endif
201 
202  QString owner = QDBusConnection::sessionBus().interface()->serviceOwner( serviceName );
203  if ( d->mRunningStandalone && ( owner == QDBusConnection::sessionBus().baseService() ) ) {
204  d->mRunningStandalone = false;
205  }
206  //kDebug() << " plugin->objectName()=" << plugin->objectName()
207  // << " running standalone:" << d->mRunningStandalone;
208 
209  if ( d->mRunningStandalone ) {
210  QObject::connect( QDBusConnection::sessionBus().interface(),
211  SIGNAL(serviceOwnerChanged(QString,QString,QString)),
212  this, SLOT(slotApplicationRemoved(QString,QString,QString)) );
213  } else {
214  d->mFactory->createHandler( d->mPlugin );
215  }
216 }
217 
218 UniqueAppWatcher::~UniqueAppWatcher()
219 {
220  delete d->mFactory;
221  delete d;
222 }
223 
224 bool UniqueAppWatcher::isRunningStandalone() const
225 {
226  return d->mRunningStandalone;
227 }
228 
229 void KontactInterface::UniqueAppWatcher::slotApplicationRemoved( const QString &name,
230  const QString &oldOwner,
231  const QString &newOwner )
232 {
233  if ( oldOwner.isEmpty() || !newOwner.isEmpty() ) {
234  return;
235  }
236 
237  const QString serviceName = QLatin1String("org.kde.") + d->mPlugin->objectName();
238  if ( name == serviceName && d->mRunningStandalone ) {
239  d->mFactory->createHandler( d->mPlugin );
240  d->mRunningStandalone = false;
241  }
242 }
243 
244 void KontactInterface::UniqueAppHandler::setMainWidget( QWidget *widget )
245 {
246  s_mainWidget = widget;
247 }
248 
249 QWidget *KontactInterface::UniqueAppHandler::mainWidget()
250 {
251  return s_mainWidget;
252 }
253 
QWidget
KontactInterface::UniqueAppWatcher::UniqueAppWatcher
UniqueAppWatcher(UniqueAppHandlerFactoryBase *factory, Plugin *plugin)
Create an instance of UniqueAppWatcher, which does everything necessary for the "unique application" ...
Definition: uniqueapphandler.cpp:172
QByteArray
QDataStream
QDBusConnection::interface
QDBusConnectionInterface * interface() const
QDBusConnection::registerObject
bool registerObject(const QString &path, QObject *object, QFlags< QDBusConnection::RegisterOption > options)
QByteArray::isEmpty
bool isEmpty() const
KontactInterface::UniqueAppHandler::mainWidget
QWidget * mainWidget()
Returns the main widget, which will zero if setMainWidget() has not be called yet.
Definition: uniqueapphandler.cpp:249
QDBusConnection
QDBusConnection::sessionBus
QDBusConnection sessionBus()
QDBusConnectionInterface::isServiceRegistered
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const
QDBusConnection::baseService
QString baseService() const
KontactInterface::UniqueAppHandler::loadCommandLineOptions
virtual void loadCommandLineOptions()=0
This must be reimplemented so that app-specific command line options can be parsed.
QObject
QObject::objectName
objectName
QString::isEmpty
bool isEmpty() const
QWidget::winId
WId winId() const
QString
QList
QDBusConnection::unregisterService
bool unregisterService(const QString &serviceName)
QLatin1Char
QLatin1String
KontactInterface::UniqueAppHandlerFactoryBase
Base class for UniqueAppHandler.
Definition: uniqueapphandler.h:77
KontactInterface::Plugin
Base class for all Plugins in Kontact.
Definition: plugin.h:77
QWidget::show
void show()
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::parent
QObject * parent() const
QDBusConnectionInterface::serviceOwner
QDBusReply< QString > serviceOwner(const QString &name) const
QDBusConnection::registerService
bool registerService(const QString &serviceName)
KontactInterface::UniqueAppHandler::setMainWidget
static void setMainWidget(QWidget *widget)
Sets the main QWidget widget associated with this application.
Definition: uniqueapphandler.cpp:244
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:37:55 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kontact Plugin Interface Library

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

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal