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

kopete/libkopete

  • sources
  • kde-4.14
  • kdenetwork
  • kopete
  • libkopete
kopetepluginmanager.cpp
Go to the documentation of this file.
1 /*
2  kopetepluginmanager.cpp - Kopete Plugin Loader
3 
4  Copyright (c) 2002-2003 by Duncan Mac-Vicar Prett <duncan@kde.org>
5  Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
6  Copyright (c) 2002-2004 by Olivier Goffart <ogoffart @tiscalinet.be>
7 
8  Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
9 
10  *************************************************************************
11  * *
12  * This library is free software; you can redistribute it and/or *
13  * modify it under the terms of the GNU Lesser General Public *
14  * License as published by the Free Software Foundation; either *
15  * version 2 of the License, or (at your option) any later version. *
16  * *
17  *************************************************************************
18 */
19 
20 #include "kopetepluginmanager.h"
21 
22 #if defined(HAVE_VALGRIND_H) && !defined(NDEBUG)
23 // We don't want the per-skin includes, so pretend we have a skin header already
24 #define __VALGRIND_SOMESKIN_H
25 #include <valgrind/valgrind.h>
26 #endif
27 
28 #include <QApplication>
29 #include <QFile>
30 #include <QRegExp>
31 #include <QTimer>
32 #include <QStack>
33 
34 #include <ksharedconfig.h>
35 #include <kdebug.h>
36 #include <kparts/componentfactory.h>
37 #include <kplugininfo.h>
38 #include <kconfig.h>
39 #include <kstandarddirs.h>
40 #include <kurl.h>
41 #include <kservicetypetrader.h>
42 
43 #include "kopeteplugin.h"
44 #include "kopeteprotocol.h"
45 #include "kopetecontactlist.h"
46 #include "kopeteaccountmanager.h"
47 
48 namespace Kopete
49 {
50 
51 class PluginManagerPrivate
52 {
53 public:
54  PluginManagerPrivate() : shutdownMode( StartingUp ), isAllPluginsLoaded(false)
55  {
56  plugins = KPluginInfo::fromServices( KServiceTypeTrader::self()->query( QLatin1String( "Kopete/Plugin" ), QLatin1String( "[X-Kopete-Version] == 1000900" ) ) );
57  }
58 
59  ~PluginManagerPrivate()
60  {
61  if ( shutdownMode != DoneShutdown && !loadedPlugins.empty() )
62  {
63  kWarning( 14010 ) << "Destructing plugin manager without going through the shutdown process! Backtrace is: " << endl << kBacktrace();
64  }
65 
66  // Clean up loadedPlugins manually, because PluginManager can't access our global
67  // static once this destructor has started.
68  while ( !loadedPlugins.empty() )
69  {
70  InfoToPluginMap::ConstIterator it = loadedPlugins.constBegin();
71  kWarning( 14010 ) << "Deleting stale plugin '" << it.value()->objectName() << "'";
72  KPluginInfo info = it.key();
73  Plugin *plugin = it.value();
74  loadedPlugins.remove(info);
75  plugin->disconnect(&instance, SLOT(slotPluginDestroyed(QObject*)));
76  delete plugin;
77  }
78  }
79 
80  // All available plugins, regardless of category, and loaded or not
81  QList<KPluginInfo> plugins;
82 
83  // Dict of all currently loaded plugins, mapping the KPluginInfo to
84  // a plugin
85  typedef QMap<KPluginInfo, Plugin *> InfoToPluginMap;
86  InfoToPluginMap loadedPlugins;
87 
88  // The plugin manager's mode. The mode is StartingUp until loadAllPlugins()
89  // has finished loading the plugins, after which it is set to Running.
90  // ShuttingDown and DoneShutdown are used during Kopete shutdown by the
91  // async unloading of plugins.
92  enum ShutdownMode { StartingUp, Running, ShuttingDown, DoneShutdown };
93  ShutdownMode shutdownMode;
94 
95  // Plugins pending for loading
96  QStack<QString> pluginsToLoad;
97 
98  bool isAllPluginsLoaded;
99  PluginManager instance;
100 };
101 
102 K_GLOBAL_STATIC(PluginManagerPrivate, _kpmp)
103 
104 PluginManager* PluginManager::self()
105 {
106  return &_kpmp->instance;
107 }
108 
109 PluginManager::PluginManager() : QObject( 0 )
110 {
111  // We want to add a reference to the application's event loop so we
112  // can remain in control when all windows are removed.
113  // This way we can unload plugins asynchronously, which is more
114  // robust if they are still doing processing.
115  KGlobal::ref();
116 }
117 
118 PluginManager::~PluginManager()
119 {
120 }
121 
122 QList<KPluginInfo> PluginManager::availablePlugins( const QString &category ) const
123 {
124  if ( category.isEmpty() )
125  return _kpmp->plugins;
126 
127  QList<KPluginInfo> result;
128  QList<KPluginInfo>::ConstIterator it;
129  for ( it = _kpmp->plugins.constBegin(); it != _kpmp->plugins.constEnd(); ++it )
130  {
131  if ( it->category() == category && !(*it).service()->noDisplay() )
132  result.append( *it );
133  }
134 
135  return result;
136 }
137 
138 PluginList PluginManager::loadedPlugins( const QString &category ) const
139 {
140  PluginList result;
141 
142  for ( PluginManagerPrivate::InfoToPluginMap::ConstIterator it = _kpmp->loadedPlugins.constBegin();
143  it != _kpmp->loadedPlugins.constEnd(); ++it )
144  {
145  if ( category.isEmpty() || it.key().category() == category )
146  result.append( it.value() );
147  }
148 
149  return result;
150 }
151 
152 
153 KPluginInfo PluginManager::pluginInfo( const Plugin *plugin ) const
154 {
155  for ( PluginManagerPrivate::InfoToPluginMap::ConstIterator it = _kpmp->loadedPlugins.constBegin();
156  it != _kpmp->loadedPlugins.constEnd(); ++it )
157  {
158  if ( it.value() == plugin )
159  return it.key();
160  }
161  return KPluginInfo();
162 }
163 
164 void PluginManager::shutdown()
165 {
166  if(_kpmp->shutdownMode != PluginManagerPrivate::Running)
167  {
168  kDebug( 14010 ) << "called when not running. / state = " << _kpmp->shutdownMode;
169  return;
170  }
171 
172  _kpmp->shutdownMode = PluginManagerPrivate::ShuttingDown;
173 
174  // Remove any pending plugins to load, we're shutting down now :)
175  _kpmp->pluginsToLoad.clear();
176 
177  // Ask all plugins to unload
178  for ( PluginManagerPrivate::InfoToPluginMap::ConstIterator it = _kpmp->loadedPlugins.constBegin();
179  it != _kpmp->loadedPlugins.constEnd(); /* EMPTY */ )
180  {
181  // Plugins could emit their ready for unload signal directly in response to this,
182  // which would invalidate the current iterator. Therefore, we copy the iterator
183  // and increment it beforehand.
184  PluginManagerPrivate::InfoToPluginMap::ConstIterator current( it );
185  ++it;
186  // FIXME: a much cleaner approach would be to just delete the plugin now. if it needs
187  // to do some async processing, it can grab a reference to the app itself and create
188  // another object to do it.
189  current.value()->aboutToUnload();
190  }
191 
192  // save the contact list now, just in case a change was made very recently
193  // and it hasn't autosaved yet
194  // from a OO point of view, theses lines should not be there, but i don't
195  // see better place -Olivier
196  Kopete::ContactList::self()->shutdown(); // Save and shutdown contact list
197  Kopete::AccountManager::self()->save();
198 
199  // When running under valgrind, don't enable the timer because it will almost
200  // certainly fire due to valgrind's much slower processing
201 #if defined(HAVE_VALGRIND_H) && !defined(NDEBUG) && defined(__i386__)
202  if ( RUNNING_ON_VALGRIND )
203  kDebug(14010) << "Running under valgrind, disabling plugin unload timeout guard";
204  else
205 #endif
206  QTimer::singleShot( 3000, this, SLOT(slotShutdownTimeout()) );
207 }
208 
209 void PluginManager::slotPluginReadyForUnload()
210 {
211  // Using QObject::sender() is on purpose here, because otherwise all
212  // plugins would have to pass 'this' as parameter, which makes the API
213  // less clean for plugin authors
214  // FIXME: I don't buy the above argument. Add a Kopete::Plugin::emitReadyForUnload(void),
215  // and make readyForUnload be passed a plugin. - Richard
216  Plugin *plugin = dynamic_cast<Plugin *>( const_cast<QObject *>( sender() ) );
217  if ( !plugin )
218  {
219  kWarning( 14010 ) << "Calling object is not a plugin!";
220  return;
221  }
222  kDebug( 14010 ) << plugin->pluginId() << "ready for unload";
223 
224  plugin->deleteLater();
225 }
226 
227 
228 void PluginManager::slotShutdownTimeout()
229 {
230  // When we were already done the timer might still fire.
231  // Do nothing in that case.
232  if ( _kpmp->shutdownMode == PluginManagerPrivate::DoneShutdown )
233  return;
234 
235  QStringList remaining;
236  for ( PluginManagerPrivate::InfoToPluginMap::ConstIterator it = _kpmp->loadedPlugins.constBegin(); it != _kpmp->loadedPlugins.constEnd(); ++it )
237  remaining.append( it.value()->pluginId() );
238 
239  kWarning( 14010 ) << "Some plugins didn't shutdown in time!" << endl
240  << "Remaining plugins: " << remaining.join( QLatin1String( ", " ) ) << endl
241  << "Forcing Kopete shutdown now." << endl;
242 
243  slotShutdownDone();
244 }
245 
246 void PluginManager::slotShutdownDone()
247 {
248  kDebug( 14010 ) ;
249 
250  if (QTextCodec::codecForCStrings())
251  kWarning(14010) << "WARNING: Some plugin set QTextCodec::setCodecForCStrings this may break protocols!!!";
252 
253  _kpmp->shutdownMode = PluginManagerPrivate::DoneShutdown;
254 
255  KGlobal::deref();
256 }
257 
258 void PluginManager::loadAllPlugins()
259 {
260  // FIXME: We need session management here - Martijn
261 
262  KSharedConfig::Ptr config = KGlobal::config();
263  if ( config->hasGroup( QLatin1String( "Plugins" ) ) )
264  {
265  QMap<QString, bool> pluginsMap;
266 
267  QMap<QString, QString> entries = config->entryMap( QLatin1String( "Plugins" ) );
268  QMap<QString, QString>::Iterator it;
269  for ( it = entries.begin(); it != entries.end(); ++it )
270  {
271  QString key = it.key();
272  if ( key.endsWith( QLatin1String( "Enabled" ) ) )
273  pluginsMap.insert( key.left(key.length() - 7), (it.value() == QLatin1String( "true" )) );
274  }
275 
276  QList<KPluginInfo> plugins = availablePlugins( QString::null ); //krazy:exclude=nullstrassign for old broken gcc
277  QList<KPluginInfo>::ConstIterator it2 = plugins.constBegin();
278  QList<KPluginInfo>::ConstIterator end = plugins.constEnd();
279  for ( ; it2 != end; ++it2 )
280  {
281  // Protocols are loaded automatically so they aren't always in Plugins group. (fixes bug 167113)
282  if ( it2->category() == QLatin1String( "Protocols" ) )
283  continue;
284 
285  QString pluginName = it2->pluginName();
286  if ( pluginsMap.value( pluginName, it2->isPluginEnabledByDefault() ) )
287  {
288  if ( !plugin( pluginName ) )
289  _kpmp->pluginsToLoad.push( pluginName );
290  }
291  else
292  {
293  //This happens if the user unloaded plugins with the config plugin page.
294  // No real need to be assync because the user usually unload few plugins
295  // compared tto the number of plugin to load in a cold start. - Olivier
296  if ( plugin( pluginName ) )
297  unloadPlugin( pluginName );
298  }
299  }
300  }
301  else
302  {
303  // we had no config, so we load any plugins that should be loaded by default.
304  QList<KPluginInfo> plugins = availablePlugins( QString::null ); //krazy:exclude=nullstrassign for old broken gcc
305  QList<KPluginInfo>::ConstIterator it = plugins.constBegin();
306  QList<KPluginInfo>::ConstIterator end = plugins.constEnd();
307  for ( ; it != end; ++it )
308  {
309  if ( it->isPluginEnabledByDefault() )
310  _kpmp->pluginsToLoad.push( it->pluginName() );
311  }
312  }
313  // Schedule the plugins to load
314  QTimer::singleShot( 0, this, SLOT(slotLoadNextPlugin()) );
315 }
316 
317 void PluginManager::slotLoadNextPlugin()
318 {
319  if ( _kpmp->pluginsToLoad.isEmpty() )
320  {
321  if ( _kpmp->shutdownMode == PluginManagerPrivate::StartingUp )
322  {
323  _kpmp->shutdownMode = PluginManagerPrivate::Running;
324  _kpmp->isAllPluginsLoaded = true;
325  emit allPluginsLoaded();
326  }
327  return;
328  }
329 
330  QString key = _kpmp->pluginsToLoad.pop();
331  loadPluginInternal( key );
332 
333  // Schedule the next run unconditionally to avoid code duplication on the
334  // allPluginsLoaded() signal's handling. This has the added benefit that
335  // the signal is delayed one event loop, so the accounts are more likely
336  // to be instantiated.
337  QTimer::singleShot( 0, this, SLOT(slotLoadNextPlugin()) );
338 }
339 
340 Plugin * PluginManager::loadPlugin( const QString &_pluginId, PluginLoadMode mode /* = LoadSync */ )
341 {
342  QString pluginId = _pluginId;
343 
344  // Try to find legacy code
345  // FIXME: Find any cases causing this, remove them, and remove this too - Richard
346  if ( pluginId.endsWith( QLatin1String( ".desktop" ) ) )
347  {
348  kWarning( 14010 ) << "Trying to use old-style API!" << endl << kBacktrace();
349  pluginId = pluginId.remove( QRegExp( QLatin1String( ".desktop$" ) ) );
350  }
351 
352  if ( mode == LoadSync )
353  {
354  return loadPluginInternal( pluginId );
355  }
356  else
357  {
358  _kpmp->pluginsToLoad.push( pluginId );
359  QTimer::singleShot( 0, this, SLOT(slotLoadNextPlugin()) );
360  return 0L;
361  }
362 }
363 
364 Plugin *PluginManager::loadPluginInternal( const QString &pluginId )
365 {
366  //kDebug( 14010 ) << pluginId;
367 
368  KPluginInfo info = infoForPluginId( pluginId );
369  if ( !info.isValid() )
370  {
371  kWarning( 14010 ) << "Unable to find a plugin named '" << pluginId << "'!";
372  return 0L;
373  }
374 
375  if ( _kpmp->loadedPlugins.contains( info ) )
376  return _kpmp->loadedPlugins[ info ];
377 
378  QString error;
379  Plugin *plugin = KServiceTypeTrader::createInstanceFromQuery<Plugin>( QString::fromLatin1( "Kopete/Plugin" ), QString::fromLatin1( "[X-KDE-PluginInfo-Name]=='%1'" ).arg( pluginId ), this, QVariantList(), &error );
380 
381  if ( plugin )
382  {
383  _kpmp->loadedPlugins.insert( info, plugin );
384  info.setPluginEnabled( true );
385 
386  connect( plugin, SIGNAL(destroyed(QObject*)), this, SLOT(slotPluginDestroyed(QObject*)) );
387  connect( plugin, SIGNAL(readyForUnload()), this, SLOT(slotPluginReadyForUnload()) );
388 
389  kDebug( 14010 ) << "Successfully loaded plugin '" << pluginId << "'";
390 
391  emit pluginLoaded( plugin );
392 
393  Protocol* protocol = dynamic_cast<Protocol*>( plugin );
394  if ( protocol )
395  emit protocolLoaded( protocol );
396  }
397  else
398  {
399  kDebug( 14010 ) << "Loading plugin " << pluginId << " failed, KServiceTypeTrader reported error: " << error ;
400  }
401 
402  return plugin;
403 }
404 
405 bool PluginManager::unloadPlugin( const QString &spec )
406 {
407  //kDebug(14010) << spec;
408  if( Plugin *thePlugin = plugin( spec ) )
409  {
410  thePlugin->aboutToUnload();
411  return true;
412  }
413  else
414  return false;
415 }
416 
417 
418 
419 void PluginManager::slotPluginDestroyed( QObject *plugin )
420 {
421  for ( PluginManagerPrivate::InfoToPluginMap::Iterator it = _kpmp->loadedPlugins.begin();
422  it != _kpmp->loadedPlugins.end(); ++it )
423  {
424  if ( it.value() == plugin )
425  {
426  QString pluginName = it.key().pluginName();
427  _kpmp->loadedPlugins.erase( it );
428  emit pluginUnloaded( pluginName );
429  break;
430  }
431  }
432 
433  if ( _kpmp->shutdownMode == PluginManagerPrivate::ShuttingDown && _kpmp->loadedPlugins.isEmpty() )
434  {
435  // Use a timer to make sure any pending deleteLater() calls have
436  // been handled first
437  QTimer::singleShot( 0, this, SLOT(slotShutdownDone()) );
438  }
439 }
440 
441 
442 
443 
444 Plugin* PluginManager::plugin( const QString &_pluginId ) const
445 {
446  // Hack for compatibility with Plugin::pluginId(), which returns
447  // classname() instead of the internal name. Changing that is not easy
448  // as it invalidates the config file, the contact list, and most likely
449  // other code as well.
450  // For now, just transform FooProtocol to kopete_foo.
451  // FIXME: In the future we'll need to change this nevertheless to unify
452  // the handling - Martijn
453  QString pluginId = _pluginId;
454  if ( pluginId.endsWith( QLatin1String( "Protocol" ) ) )
455  pluginId = QLatin1String( "kopete_" ) + _pluginId.toLower().remove( QString::fromLatin1( "protocol" ) );
456  // End hack
457 
458  KPluginInfo info = infoForPluginId( pluginId );
459  if ( !info.isValid() )
460  return 0L;
461 
462  if ( _kpmp->loadedPlugins.contains( info ) )
463  return _kpmp->loadedPlugins[ info ];
464  else
465  return 0L;
466 }
467 
468 KPluginInfo PluginManager::infoForPluginId( const QString &pluginId ) const
469 {
470  QList<KPluginInfo>::ConstIterator it;
471  for ( it = _kpmp->plugins.constBegin(); it != _kpmp->plugins.constEnd(); ++it )
472  {
473  if ( it->pluginName() == pluginId )
474  return *it;
475  }
476 
477  return KPluginInfo();
478 }
479 
480 
481 bool PluginManager::setPluginEnabled( const QString &_pluginId, bool enabled /* = true */ )
482 {
483  QString pluginId = _pluginId;
484 
485  KConfigGroup config(KGlobal::config(), "Plugins");
486 
487  // FIXME: What is this for? This sort of thing is kconf_update's job - Richard
488  if ( !pluginId.startsWith( QLatin1String( "kopete_" ) ) )
489  pluginId.prepend( QLatin1String( "kopete_" ) );
490 
491  if ( !infoForPluginId( pluginId ).isValid() )
492  return false;
493 
494  config.writeEntry( pluginId + QLatin1String( "Enabled" ), enabled );
495  config.sync();
496 
497  return true;
498 }
499 
500 bool PluginManager::isAllPluginsLoaded() const
501 {
502  return _kpmp->isAllPluginsLoaded;
503 }
504 
505 } //END namespace Kopete
506 
507 
508 #include "kopetepluginmanager.moc"
509 
510 
511 
512 
513 
Kopete::ContactList::self
static ContactList * self()
The contact list is a singleton object.
Definition: kopetecontactlist.cpp:71
Kopete::PluginManager::allPluginsLoaded
void allPluginsLoaded()
All plugins have been loaded by the plugin manager.
Kopete::ContactList::shutdown
void shutdown()
Definition: kopetecontactlist.cpp:417
Kopete::PluginManager::setPluginEnabled
bool setPluginEnabled(const QString &name, bool enabled=true)
Enable a plugin.
Definition: kopetepluginmanager.cpp:481
NetworkStatus::ShuttingDown
Definition: networkstatuscommon.h:9
QObject::sender
QObject * sender() const
Kopete::PluginManager::loadedPlugins
PluginList loadedPlugins(const QString &category=QString()) const
Returns a list of all plugins that are actually loaded.
Definition: kopetepluginmanager.cpp:138
QString::prepend
QString & prepend(QChar ch)
QTextCodec::codecForCStrings
QTextCodec * codecForCStrings()
QMap< KPluginInfo, Plugin * >
Kopete::PluginManager::loadPlugin
Plugin * loadPlugin(const QString &pluginId, PluginLoadMode mode=LoadSync)
Load a single plugin by plugin name.
Definition: kopetepluginmanager.cpp:340
QStringList::join
QString join(const QString &separator) const
QString::remove
QString & remove(int position, int n)
Kopete::PluginManager::pluginLoaded
void pluginLoaded(Kopete::Plugin *plugin)
Signals a new plugin has just been loaded.
Kopete::AccountManager::self
static AccountManager * self()
Retrieve the instance of AccountManager.
Definition: kopeteaccountmanager.cpp:77
QRegExp
Kopete::PluginManager::pluginUnloaded
void pluginUnloaded(const QString &pluginName)
Signals a plugin has just been unloaded.
Kopete::PluginManager::LoadSync
Definition: kopetepluginmanager.h:129
QList::append
void append(const T &value)
Kopete::PluginManager::availablePlugins
QList< KPluginInfo > availablePlugins(const QString &category=QString()) const
Returns a list of all available plugins for the given category.
Definition: kopetepluginmanager.cpp:122
QObject
Kopete::Plugin::pluginId
QString pluginId() const
Get the plugin id.
Definition: kopeteplugin.cpp:46
Kopete::PluginManager::unloadPlugin
bool unloadPlugin(const QString &pluginName)
Unload the plugin specified by pluginName.
Definition: kopetepluginmanager.cpp:405
kopeteprotocol.h
QString::isEmpty
bool isEmpty() const
Kopete::PluginManager::loadAllPlugins
void loadAllPlugins()
Loads all the enabled plugins.
Definition: kopetepluginmanager.cpp:258
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
kopetecontactlist.h
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
QObject::deleteLater
void deleteLater()
QString
QList< KPluginInfo >
QMap::end
iterator end()
Kopete::PluginManager::pluginInfo
KPluginInfo pluginInfo(const Kopete::Plugin *plugin) const
Definition: kopetepluginmanager.cpp:153
QMap::begin
iterator begin()
QStringList
Kopete::Plugin
Base class for all plugins or protocols.
Definition: kopeteplugin.h:84
QString::toLower
QString toLower() const
QMap::key
const Key key(const T &value) const
QLatin1String
Kopete::PluginManager::shutdown
void shutdown()
Shuts down the plugin manager on Kopete shutdown, but first unloads all plugins asynchronously.
Definition: kopetepluginmanager.cpp:164
kopeteaccountmanager.h
Kopete::PluginManager::isAllPluginsLoaded
bool isAllPluginsLoaded() const
This method check if all the plugins are loaded.
Definition: kopetepluginmanager.cpp:500
QString::length
int length() const
kopeteplugin.h
Kopete::PluginManager
Definition: kopetepluginmanager.h:40
QString::left
QString left(int n) const
Kopete::PluginManager::PluginLoadMode
PluginLoadMode
Plugin loading mode.
Definition: kopetepluginmanager.h:129
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QMap::insert
iterator insert(const Key &key, const T &value)
QMap< KPluginInfo, Plugin * >::Iterator
typedef Iterator
Kopete::PluginManager::plugin
Plugin * plugin(const QString &pluginName) const
Search by plugin name.
Definition: kopetepluginmanager.cpp:444
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
QMap< KPluginInfo, Plugin * >::ConstIterator
typedef ConstIterator
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Kopete::AccountManager::save
void save()
Definition: kopeteaccountmanager.cpp:358
kopetepluginmanager.h
Kopete::PluginManager::protocolLoaded
void protocolLoaded(Kopete::Protocol *protocol)
Signals a new protocol has just been loaded.
QObject::destroyed
void destroyed(QObject *obj)
QStack< QString >
QMap::value
const T value(const Key &key) const
QTimer::singleShot
singleShot
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:29:19 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kopete/libkopete

Skip menu "kopete/libkopete"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdenetwork API Reference

Skip menu "kdenetwork API Reference"
  • kget
  • kopete
  •   kopete
  •   libkopete
  • krdc
  • krfb

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