kontact

uniqueapphandler.cpp

00001 /*
00002    This file is part of KDE Kontact.
00003 
00004    Copyright (c) 2003 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 <kstartupinfo.h>
00024 #include <kapplication.h>
00025 #include <kcmdlineargs.h>
00026 #include "core.h"
00027 #include <kwin.h>
00028 #include <dcopclient.h>
00029 #include <kdebug.h>
00030 
00031 /*
00032  Test plan for the various cases of interaction between standalone apps and kontact:
00033 
00034  1) start kontact, select "Mail".
00035  1a) type "korganizer" -> it switches to korganizer
00036  1b) type "kmail" -> it switches to kmail
00037  1c) type "kaddressbook" -> it switches to kaddressbook
00038  1d) type "kmail foo@kde.org" -> it opens a kmail composer, without switching
00039  1e) type "knode" -> it switches to knode
00040  1f) type "kaddressbook --new-contact" -> it opens a kaddressbook contact window
00041  1g) type "knode news://foobar/group" -> it pops up "can't resolve hostname"
00042 
00043  2) close kontact. Launch kmail. Launch kontact again.
00044  2a) click "Mail" icon -> kontact doesn't load a part, but activates the kmail window
00045  2b) type "kmail foo@kde.org" -> standalone kmail opens composer.
00046  2c) close kmail, click "Mail" icon -> kontact loads the kmail part.
00047  2d) type "kmail" -> kontact is brought to front
00048 
00049  3) close kontact. Launch korganizer, then kontact.
00050  3a) both Todo and Calendar activate the running korganizer.
00051  3b) type "korganizer" -> standalone korganizer is brought to front
00052  3c) close korganizer, click Calendar or Todo -> kontact loads part.
00053  3d) type "korganizer" -> kontact is brought to front
00054 
00055  4) close kontact. Launch kaddressbook, then kontact.
00056  4a) "Contacts" icon activate the running kaddressbook.
00057  4b) type "kaddressbook" -> standalone kaddressbook is brought to front
00058  4c) close kaddressbook, type "kaddressbook -a foo@kde.org" -> kontact loads part and opens editor
00059  4d) type "kaddressbook" -> kontact is brought to front
00060 
00061  5) close kontact. Launch knode, then kontact.
00062  5a) "News" icon activate the running knode.
00063  5b) type "knode" -> standalone knode is brought to front
00064  5c) close knode, type "knode news://foobar/group" -> kontact loads knode and pops up msgbox
00065  5d) type "knode" -> kontact is brought to front
00066 
00067 */
00068 
00069 using namespace Kontact;
00070 
00071 int UniqueAppHandler::newInstance()
00072 {
00073   // This bit is duplicated from KUniqueApplication::newInstance()
00074   if ( kapp->mainWidget() ) {
00075     kapp->mainWidget()->show();
00076     KWin::forceActiveWindow( kapp->mainWidget()->winId() );
00077     KStartupInfo::appStarted();
00078   }
00079 
00080   // Then ensure the part appears in kontact
00081   mPlugin->core()->selectPlugin( mPlugin );
00082   return 0;
00083 }
00084 
00085 bool UniqueAppHandler::process( const QCString &fun, const QByteArray &data,
00086                                 QCString& replyType, QByteArray &replyData )
00087 {
00088   if ( fun == "newInstance()" ) {
00089     replyType = "int";
00090 
00091     KCmdLineArgs::reset(); // forget options defined by other "applications"
00092     loadCommandLineOptions();
00093 
00094     // This bit is duplicated from KUniqueApplication::processDelayed()
00095     QDataStream ds( data, IO_ReadOnly );
00096     KCmdLineArgs::loadAppArgs( ds );
00097     if ( !ds.atEnd() ) { // backwards compatibility
00098       QCString asn_id;
00099       ds >> asn_id;
00100       kapp->setStartupId( asn_id );
00101     }
00102 
00103     QDataStream _replyStream( replyData, IO_WriteOnly );
00104     _replyStream << newInstance( );
00105   } else if ( fun == "load()" ) {
00106     replyType = "bool";
00107     (void)mPlugin->part(); // load the part without bringing it to front
00108 
00109     QDataStream _replyStream( replyData, IO_WriteOnly );
00110     _replyStream << true;
00111   } else {
00112     return DCOPObject::process( fun, data, replyType, replyData );
00113   }
00114   return true;
00115 }
00116 
00117 QCStringList UniqueAppHandler::interfaces()
00118 {
00119   QCStringList ifaces = DCOPObject::interfaces();
00120   ifaces += "Kontact::UniqueAppHandler";
00121   return ifaces;
00122 }
00123 
00124 QCStringList UniqueAppHandler::functions()
00125 {
00126   QCStringList funcs = DCOPObject::functions();
00127   funcs << "int newInstance()";
00128   funcs << "bool load()";
00129   return funcs;
00130 }
00131 
00132 UniqueAppWatcher::UniqueAppWatcher( UniqueAppHandlerFactoryBase* factory, Plugin* plugin )
00133     : QObject( plugin ), mFactory( factory ), mPlugin( plugin )
00134 {
00135   // The app is running standalone if 1) that name is known to DCOP
00136   mRunningStandalone = kapp->dcopClient()->isApplicationRegistered( plugin->name() );
00137 
00138   // and 2) it's not registered by kontact (e.g. in another plugin)
00139   if ( mRunningStandalone && kapp->dcopClient()->findLocalClient( plugin->name() ) )
00140       mRunningStandalone = false;
00141 
00142   if ( mRunningStandalone ) {
00143     kapp->dcopClient()->setNotifications( true );
00144     connect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString& ) ),
00145              this, SLOT( unregisteredFromDCOP( const QCString& ) ) );
00146   } else {
00147     mFactory->createHandler( mPlugin );
00148   }
00149 }
00150 
00151 UniqueAppWatcher::~UniqueAppWatcher()
00152 {
00153   if ( mRunningStandalone )
00154     kapp->dcopClient()->setNotifications( false );
00155 
00156   delete mFactory;
00157 }
00158 
00159 void UniqueAppWatcher::unregisteredFromDCOP( const QCString& appId )
00160 {
00161   if ( appId == mPlugin->name() && mRunningStandalone ) {
00162     disconnect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString& ) ),
00163                 this, SLOT( unregisteredFromDCOP( const QCString& ) ) );
00164     kdDebug(5601) << k_funcinfo << appId << endl;
00165     mFactory->createHandler( mPlugin );
00166     kapp->dcopClient()->setNotifications( false );
00167     mRunningStandalone = false;
00168   }
00169 }
00170 
00171 #include "uniqueapphandler.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys