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 <tdestartupinfo.h> 00024 #include <tdeapplication.h> 00025 #include <tdecmdlineargs.h> 00026 #include "core.h" 00027 #include <twin.h> 00028 #include <dcopclient.h> 00029 #include <kdebug.h> 00030 #include <tdelocale.h> 00031 #include <kuniqueapplication.h> 00032 00033 /* 00034 Test plan for the various cases of interaction between standalone apps and kontact: 00035 00036 1) start kontact, select "Mail". 00037 1a) type "korganizer" -> it switches to korganizer 00038 1b) type "kmail" -> it switches to kmail 00039 1c) type "kaddressbook" -> it switches to kaddressbook 00040 1d) type "kmail foo@kde.org" -> it opens a kmail composer, without switching 00041 1e) type "knode" -> it switches to knode 00042 1f) type "kaddressbook --new-contact" -> it opens a kaddressbook contact window 00043 1g) type "knode news://foobar/group" -> it pops up "can't resolve hostname" 00044 00045 2) close kontact. Launch kmail. Launch kontact again. 00046 2a) click "Mail" icon -> kontact doesn't load a part, but activates the kmail window 00047 2b) type "kmail foo@kde.org" -> standalone kmail opens composer. 00048 2c) close kmail, click "Mail" icon -> kontact loads the kmail part. 00049 2d) type "kmail" -> kontact is brought to front 00050 00051 3) close kontact. Launch korganizer, then kontact. 00052 3a) both Todo and Calendar activate the running korganizer. 00053 3b) type "korganizer" -> standalone korganizer is brought to front 00054 3c) close korganizer, click Calendar or Todo -> kontact loads part. 00055 3d) type "korganizer" -> kontact is brought to front 00056 00057 4) close kontact. Launch kaddressbook, then kontact. 00058 4a) "Contacts" icon activate the running kaddressbook. 00059 4b) type "kaddressbook" -> standalone kaddressbook is brought to front 00060 4c) close kaddressbook, type "kaddressbook -a foo@kde.org" -> kontact loads part and opens editor 00061 4d) type "kaddressbook" -> kontact is brought to front 00062 00063 5) close kontact. Launch knode, then kontact. 00064 5a) "News" icon activate the running knode. 00065 5b) type "knode" -> standalone knode is brought to front 00066 5c) close knode, type "knode news://foobar/group" -> kontact loads knode and pops up msgbox 00067 5d) type "knode" -> kontact is brought to front 00068 00069 6) start "kontact --module summaryplugin" 00070 6a) type "dcop kmail kmail newInstance" -> kontact switches to kmail (#103775) 00071 6b) type "kmail" -> kontact is brought to front 00072 6c) type "kontact" -> kontact is brought to front 00073 6d) type "kontact --module summaryplugin" -> kontact switches to summary 00074 00075 */ 00076 00077 using namespace Kontact; 00078 00079 int UniqueAppHandler::newInstance() 00080 { 00081 // This bit is duplicated from KUniqueApplication::newInstance() 00082 if ( kapp->mainWidget() ) { 00083 kapp->mainWidget()->show(); 00084 KWin::forceActiveWindow( kapp->mainWidget()->winId() ); 00085 TDEStartupInfo::appStarted(); 00086 } 00087 00088 // Then ensure the part appears in kontact 00089 mPlugin->core()->selectPlugin( mPlugin ); 00090 return 0; 00091 } 00092 00093 bool UniqueAppHandler::process( const TQCString &fun, const TQByteArray &data, 00094 TQCString& replyType, TQByteArray &replyData ) 00095 { 00096 if ( fun == "newInstance()" ) { 00097 replyType = "int"; 00098 00099 TDECmdLineArgs::reset(); // forget options defined by other "applications" 00100 loadCommandLineOptions(); // implemented by plugin 00101 00102 // This bit is duplicated from KUniqueApplication::processDelayed() 00103 TQDataStream ds( data, IO_ReadOnly ); 00104 TDECmdLineArgs::loadAppArgs( ds ); 00105 if ( !ds.atEnd() ) { // backwards compatibility 00106 TQCString asn_id; 00107 ds >> asn_id; 00108 kapp->setStartupId( asn_id ); 00109 } 00110 00111 TQDataStream _replyStream( replyData, IO_WriteOnly ); 00112 _replyStream << newInstance(); 00113 00114 // OK, we're done, reload the initial kontact command line options, 00115 // so that "kontact --module foo" keeps working (#103775). 00116 00117 TDECmdLineArgs::reset(); // forget options defined above 00118 loadKontactCommandLineOptions(); 00119 00120 } else if ( fun == "load()" ) { 00121 replyType = "bool"; 00122 (void)mPlugin->part(); // load the part without bringing it to front 00123 00124 TQDataStream _replyStream( replyData, IO_WriteOnly ); 00125 _replyStream << true; 00126 } else { 00127 return DCOPObject::process( fun, data, replyType, replyData ); 00128 } 00129 return true; 00130 } 00131 00132 QCStringList UniqueAppHandler::interfaces() 00133 { 00134 QCStringList ifaces = DCOPObject::interfaces(); 00135 ifaces += "Kontact::UniqueAppHandler"; 00136 return ifaces; 00137 } 00138 00139 QCStringList UniqueAppHandler::functions() 00140 { 00141 QCStringList funcs = DCOPObject::functions(); 00142 funcs << "int newInstance()"; 00143 funcs << "bool load()"; 00144 return funcs; 00145 } 00146 00147 UniqueAppWatcher::UniqueAppWatcher( UniqueAppHandlerFactoryBase* factory, Plugin* plugin ) 00148 : TQObject( plugin ), mFactory( factory ), mPlugin( plugin ) 00149 { 00150 // The app is running standalone if 1) that name is known to DCOP 00151 mRunningStandalone = kapp->dcopClient()->isApplicationRegistered( plugin->name() ); 00152 00153 // and 2) it's not registered by kontact (e.g. in another plugin) 00154 if ( mRunningStandalone && kapp->dcopClient()->findLocalClient( plugin->name() ) ) 00155 mRunningStandalone = false; 00156 00157 if ( mRunningStandalone ) { 00158 kapp->dcopClient()->setNotifications( true ); 00159 connect( kapp->dcopClient(), TQT_SIGNAL( applicationRemoved( const TQCString& ) ), 00160 this, TQT_SLOT( unregisteredFromDCOP( const TQCString& ) ) ); 00161 } else { 00162 mFactory->createHandler( mPlugin ); 00163 } 00164 } 00165 00166 UniqueAppWatcher::~UniqueAppWatcher() 00167 { 00168 if ( mRunningStandalone ) 00169 kapp->dcopClient()->setNotifications( false ); 00170 00171 delete mFactory; 00172 } 00173 00174 void UniqueAppWatcher::unregisteredFromDCOP( const TQCString& appId ) 00175 { 00176 if ( appId == mPlugin->name() && mRunningStandalone ) { 00177 disconnect( kapp->dcopClient(), TQT_SIGNAL( applicationRemoved( const TQCString& ) ), 00178 this, TQT_SLOT( unregisteredFromDCOP( const TQCString& ) ) ); 00179 kdDebug(5601) << k_funcinfo << appId << endl; 00180 mFactory->createHandler( mPlugin ); 00181 kapp->dcopClient()->setNotifications( false ); 00182 mRunningStandalone = false; 00183 } 00184 } 00185 00186 static TDECmdLineOptions options[] = 00187 { 00188 { "module <module>", I18N_NOOP( "Start with a specific Kontact module" ), 0 }, 00189 { "iconify", I18N_NOOP( "Start in iconified (minimized) mode" ), 0 }, 00190 { "list", I18N_NOOP( "List all possible modules and exit" ), 0 }, 00191 { "listprofiles", I18N_NOOP( "List all possible profiles and exit" ), 0 }, 00192 { "profile <profile>", I18N_NOOP( "Start with a specific Kontact profile" ), 0 }, 00193 TDECmdLineLastOption 00194 }; 00195 00196 void Kontact::UniqueAppHandler::loadKontactCommandLineOptions() 00197 { 00198 TDECmdLineArgs::addCmdLineOptions( options ); 00199 KUniqueApplication::addCmdLineOptions(); 00200 TDEApplication::addCmdLineOptions(); 00201 } 00202 00203 #include "uniqueapphandler.moc"