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

KIO

  • sources
  • kde-4.14
  • kdelibs
  • kio
  • kio
slave.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
4  * 2000 Stephan Kulow <coolo@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 version 2 as published by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  **/
20 
21 #include "slave.h"
22 
23 #include <time.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <signal.h>
29 #include <sys/types.h>
30 
31 #include <QtCore/QFile>
32 #include <QtCore/QTimer>
33 #include <QtDBus/QtDBus>
34 #include <QtCore/QProcess>
35 
36 #include <kdebug.h>
37 #include <klocale.h>
38 #include <kglobal.h>
39 #include <kstandarddirs.h>
40 #include <ktoolinvocation.h>
41 #include <klauncher_iface.h>
42 #include <klibrary.h>
43 
44 #include "dataprotocol.h"
45 #include "kservice.h"
46 #include <kio/global.h>
47 #include "kio/connection.h"
48 #include <kprotocolinfo.h>
49 
50 #include "slaveinterface_p.h"
51 
52 using namespace KIO;
53 
54 #define SLAVE_CONNECTION_TIMEOUT_MIN 2
55 
56 // Without debug info we consider it an error if the slave doesn't connect
57 // within 10 seconds.
58 // With debug info we give the slave an hour so that developers have a chance
59 // to debug their slave.
60 #ifdef NDEBUG
61 #define SLAVE_CONNECTION_TIMEOUT_MAX 10
62 #else
63 #define SLAVE_CONNECTION_TIMEOUT_MAX 3600
64 #endif
65 
66 namespace KIO {
67 
71  class SlavePrivate: public SlaveInterfacePrivate
72  {
73  public:
74  SlavePrivate(const QString &protocol) :
75  m_protocol(protocol),
76  m_slaveProtocol(protocol),
77  slaveconnserver(new KIO::ConnectionServer),
78  m_job(0),
79  m_pid(0),
80  m_port(0),
81  contacted(false),
82  dead(false),
83  contact_started(time(0)),
84  m_idleSince(0),
85  m_refCount(1)
86  {
87  slaveconnserver->listenForRemote();
88  if ( !slaveconnserver->isListening() )
89  kWarning() << "Connection server not listening, could not connect";
90  }
91  ~SlavePrivate()
92  {
93  delete slaveconnserver;
94  }
95 
96  QString m_protocol;
97  QString m_slaveProtocol;
98  QString m_host;
99  QString m_user;
100  QString m_passwd;
101  KIO::ConnectionServer *slaveconnserver;
102  KIO::SimpleJob *m_job;
103  pid_t m_pid;
104  quint16 m_port;
105  bool contacted;
106  bool dead;
107  time_t contact_started;
108  time_t m_idleSince;
109  int m_refCount;
110  };
111 }
112 
113 void Slave::accept()
114 {
115  Q_D(Slave);
116  d->slaveconnserver->setNextPendingConnection(d->connection);
117  d->slaveconnserver->deleteLater();
118  d->slaveconnserver = 0;
119 
120  connect(d->connection, SIGNAL(readyRead()), SLOT(gotInput()));
121 }
122 
123 void Slave::timeout()
124 {
125  Q_D(Slave);
126  if (d->dead) //already dead? then slaveDied was emitted and we are done
127  return;
128  if (d->connection->isConnected())
129  return;
130 
131  kDebug(7002) << "slave failed to connect to application pid=" << d->m_pid
132  << " protocol=" << d->m_protocol;
133  if (d->m_pid && (::kill(d->m_pid, 0) == 0))
134  {
135  int delta_t = (int) difftime(time(0), d->contact_started);
136  kDebug(7002) << "slave is slow... pid=" << d->m_pid << " t=" << delta_t;
137  if (delta_t < SLAVE_CONNECTION_TIMEOUT_MAX)
138  {
139  QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, this, SLOT(timeout()));
140  return;
141  }
142  }
143  kDebug(7002) << "Houston, we lost our slave, pid=" << d->m_pid;
144  d->connection->close();
145  d->dead = true;
146  QString arg = d->m_protocol;
147  if (!d->m_host.isEmpty())
148  arg += "://"+d->m_host;
149  kDebug(7002) << "slave died pid = " << d->m_pid;
150 
151  ref();
152  // Tell the job about the problem.
153  emit error(ERR_SLAVE_DIED, arg);
154  // Tell the scheduler about the problem.
155  emit slaveDied(this);
156  // After the above signal we're dead!!
157  deref();
158 }
159 
160 Slave::Slave(const QString &protocol, QObject *parent)
161  : SlaveInterface(*new SlavePrivate(protocol), parent)
162 {
163  Q_D(Slave);
164  d->slaveconnserver->setParent(this);
165  d->connection = new Connection(this);
166  connect(d->slaveconnserver, SIGNAL(newConnection()), SLOT(accept()));
167 }
168 
169 Slave::~Slave()
170 {
171  // kDebug(7002) << "destructing slave object pid = " << d->m_pid;
172  //delete d;
173 }
174 
175 QString Slave::protocol()
176 {
177  Q_D(Slave);
178  return d->m_protocol;
179 }
180 
181 void Slave::setProtocol(const QString & protocol)
182 {
183  Q_D(Slave);
184  d->m_protocol = protocol;
185 }
186 
187 QString Slave::slaveProtocol()
188 {
189  Q_D(Slave);
190  return d->m_slaveProtocol;
191 }
192 
193 QString Slave::host()
194 {
195  Q_D(Slave);
196  return d->m_host;
197 }
198 
199 quint16 Slave::port()
200 {
201  Q_D(Slave);
202  return d->m_port;
203 }
204 
205 QString Slave::user()
206 {
207  Q_D(Slave);
208  return d->m_user;
209 }
210 
211 QString Slave::passwd()
212 {
213  Q_D(Slave);
214  return d->m_passwd;
215 }
216 
217 void Slave::setIdle()
218 {
219  Q_D(Slave);
220  d->m_idleSince = time(0);
221 }
222 
223 bool Slave::isConnected()
224 {
225  Q_D(Slave);
226  return d->contacted;
227 }
228 
229 void Slave::setConnected(bool c)
230 {
231  Q_D(Slave);
232  d->contacted = c;
233 }
234 
235 void Slave::ref()
236 {
237  Q_D(Slave);
238  d->m_refCount++;
239 }
240 
241 void Slave::deref()
242 {
243  Q_D(Slave);
244  d->m_refCount--;
245  if (!d->m_refCount) {
246  d->connection->disconnect(this);
247  this->disconnect();
248  deleteLater();
249  }
250 }
251 
252 time_t Slave::idleTime()
253 {
254  Q_D(Slave);
255  if (!d->m_idleSince) {
256  return time_t(0);
257  }
258  return time_t(difftime(time(0), d->m_idleSince));
259 }
260 
261 void Slave::setPID(pid_t pid)
262 {
263  Q_D(Slave);
264  d->m_pid = pid;
265 }
266 
267 int Slave::slave_pid()
268 {
269  Q_D(Slave);
270  return d->m_pid;
271 }
272 
273 void Slave::setJob(KIO::SimpleJob *job)
274 {
275  Q_D(Slave);
276  if (!d->sslMetaData.isEmpty()) {
277  emit metaData(d->sslMetaData);
278  }
279  d->m_job = job;
280 }
281 
282 KIO::SimpleJob *Slave::job() const
283 {
284  Q_D(const Slave);
285  return d->m_job;
286 }
287 
288 bool Slave::isAlive()
289 {
290  Q_D(Slave);
291  return !d->dead;
292 }
293 
294 void Slave::hold(const KUrl &url)
295 {
296  Q_D(Slave);
297  ref();
298  {
299  QByteArray data;
300  QDataStream stream( &data, QIODevice::WriteOnly );
301  stream << url;
302  d->connection->send( CMD_SLAVE_HOLD, data );
303  d->connection->close();
304  d->dead = true;
305  emit slaveDied(this);
306  }
307  deref();
308  // Call KLauncher::waitForSlave(pid);
309  {
310  KToolInvocation::klauncher()->waitForSlave(d->m_pid);
311  }
312 }
313 
314 void Slave::suspend()
315 {
316  Q_D(Slave);
317  d->connection->suspend();
318 }
319 
320 void Slave::resume()
321 {
322  Q_D(Slave);
323  d->connection->resume();
324 }
325 
326 bool Slave::suspended()
327 {
328  Q_D(Slave);
329  return d->connection->suspended();
330 }
331 
332 void Slave::send(int cmd, const QByteArray &arr)
333 {
334  Q_D(Slave);
335  d->connection->send(cmd, arr);
336 }
337 
338 void Slave::gotInput()
339 {
340  Q_D(Slave);
341  if (d->dead) //already dead? then slaveDied was emitted and we are done
342  return;
343  ref();
344  if (!dispatch())
345  {
346  d->connection->close();
347  d->dead = true;
348  QString arg = d->m_protocol;
349  if (!d->m_host.isEmpty())
350  arg += "://"+d->m_host;
351  kDebug(7002) << "slave died pid = " << d->m_pid;
352  // Tell the job about the problem.
353  emit error(ERR_SLAVE_DIED, arg);
354  // Tell the scheduler about the problem.
355  emit slaveDied(this);
356  }
357  deref();
358  // Here we might be dead!!
359 }
360 
361 void Slave::kill()
362 {
363  Q_D(Slave);
364  d->dead = true; // OO can be such simple.
365  kDebug(7002) << "killing slave pid" << d->m_pid
366  << "(" << QString(d->m_protocol) + "://" + d->m_host << ")";
367  if (d->m_pid)
368  {
369 #ifndef _WIN32_WCE
370  ::kill(d->m_pid, SIGTERM);
371 #else
372  ::kill(d->m_pid, SIGKILL);
373 #endif
374  d->m_pid = 0;
375  }
376 }
377 
378 void Slave::setHost( const QString &host, quint16 port,
379  const QString &user, const QString &passwd)
380 {
381  Q_D(Slave);
382  d->m_host = host;
383  d->m_port = port;
384  d->m_user = user;
385  d->m_passwd = passwd;
386  d->sslMetaData.clear();
387 
388  QByteArray data;
389  QDataStream stream( &data, QIODevice::WriteOnly );
390  stream << d->m_host << d->m_port << d->m_user << d->m_passwd;
391  d->connection->send( CMD_HOST, data );
392 }
393 
394 void Slave::resetHost()
395 {
396  Q_D(Slave);
397  d->sslMetaData.clear();
398  d->m_host = "<reset>";
399 }
400 
401 void Slave::setConfig(const MetaData &config)
402 {
403  Q_D(Slave);
404  QByteArray data;
405  QDataStream stream( &data, QIODevice::WriteOnly );
406  stream << config;
407  d->connection->send( CMD_CONFIG, data );
408 }
409 
410 Slave* Slave::createSlave( const QString &protocol, const KUrl& url, int& error, QString& error_text )
411 {
412  kDebug(7002) << "createSlave" << protocol << "for" << url;
413  // Firstly take into account all special slaves
414  if (protocol == "data")
415  return new DataProtocol();
416  Slave *slave = new Slave(protocol);
417  QString slaveAddress = slave->d_func()->slaveconnserver->address();
418 
419 #ifdef Q_OS_UNIX
420  // In such case we start the slave via QProcess.
421  // It's possible to force this by setting the env. variable
422  // KDE_FORK_SLAVES, Clearcase seems to require this.
423  static bool bForkSlaves = !qgetenv("KDE_FORK_SLAVES").isEmpty();
424 
425  if (!bForkSlaves)
426  {
427  // check the UID of klauncher
428  QDBusReply<uint> reply = QDBusConnection::sessionBus().interface()->serviceUid(KToolInvocation::klauncher()->service());
429  if (reply.isValid() && getuid() != reply)
430  bForkSlaves = true;
431  }
432 
433  if (bForkSlaves)
434  {
435  QString _name = KProtocolInfo::exec(protocol);
436  if (_name.isEmpty())
437  {
438  error_text = i18n("Unknown protocol '%1'.", protocol);
439  error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
440  delete slave;
441  return 0;
442  }
443  KLibrary lib(_name, KGlobal::mainComponent());
444  QString lib_path = lib.fileName();
445  if (lib_path.isEmpty())
446  {
447  error_text = i18n("Can not find io-slave for protocol '%1'.", protocol);
448  error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
449  delete slave;
450  return 0;
451  }
452 
453  const QStringList args = QStringList() << lib_path << protocol << "" << slaveAddress;
454  kDebug() << "kioslave" << ", " << lib_path << ", " << protocol << ", " << QString() << ", " << slaveAddress;
455 
456  QProcess::startDetached( KStandardDirs::locate("exe", "kioslave"), args );
457 
458  return slave;
459  }
460 #endif
461 
462  org::kde::KLauncher* klauncher = KToolInvocation::klauncher();
463  QString errorStr;
464  QDBusReply<int> reply = klauncher->requestSlave(protocol, url.host(), slaveAddress, errorStr);
465  if (!reply.isValid()) {
466  error_text = i18n("Cannot talk to klauncher: %1", klauncher->lastError().message() );
467  error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
468  delete slave;
469  return 0;
470  }
471  pid_t pid = reply;
472  if (!pid)
473  {
474  error_text = i18n("Unable to create io-slave:\nklauncher said: %1", errorStr);
475  error = KIO::ERR_CANNOT_LAUNCH_PROCESS;
476  delete slave;
477  return 0;
478  }
479  slave->setPID(pid);
480  QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
481  return slave;
482 }
483 
484 Slave* Slave::holdSlave( const QString &protocol, const KUrl& url )
485 {
486  //kDebug(7002) << "holdSlave" << protocol << "for" << url;
487  // Firstly take into account all special slaves
488  if (protocol == "data")
489  return 0;
490  Slave *slave = new Slave(protocol);
491  QString slaveAddress = slave->d_func()->slaveconnserver->address();
492  QDBusReply<int> reply = KToolInvocation::klauncher()->requestHoldSlave(url.url(), slaveAddress);
493  if (!reply.isValid()) {
494  delete slave;
495  return 0;
496  }
497  pid_t pid = reply;
498  if (!pid)
499  {
500  delete slave;
501  return 0;
502  }
503  slave->setPID(pid);
504  QTimer::singleShot(1000*SLAVE_CONNECTION_TIMEOUT_MIN, slave, SLOT(timeout()));
505  return slave;
506 }
507 
508 bool Slave::checkForHeldSlave(const KUrl &url)
509 {
510  return KToolInvocation::klauncher()->checkForHeldSlave(url.url());
511 }
512 
513 #include "slave.moc"
i18n
QString i18n(const char *text)
KIO::Slave::slaveDied
void slaveDied(KIO::Slave *slave)
KIO::Slave::resume
virtual void resume()
Resumes the operation of the attached kioslave.
Definition: slave.cpp:320
KIO::SlaveInterface::data
void data(const QByteArray &)
KIO::Slave::slave_pid
int slave_pid()
Definition: slave.cpp:267
kdebug.h
OrgKdeKLauncherInterface::requestSlave
QDBusReply< int > requestSlave(const QString &protocol, const QString &host, const QString &app_socket, QString &error)
KIO::CMD_CONFIG
Definition: global.h:177
OrgKdeKLauncherInterface::waitForSlave
QDBusReply< void > waitForSlave(int pid)
QByteArray
KIO::CMD_HOST
Definition: global.h:151
connection.h
QDBusReply
QDataStream
KIO::SlaveInterface
There are two classes that specifies the protocol between application ( KIO::Job) and kioslave...
Definition: slaveinterface.h:98
slave.h
QDBusConnectionInterface::serviceUid
QDBusReply< uint > serviceUid(const QString &serviceName) const
QDBusConnection::interface
QDBusConnectionInterface * interface() const
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
KIO::Slave::Slave
Slave(const QString &protocol, QObject *parent=0)
Definition: slave.cpp:160
klauncher_iface.h
QProcess::startDetached
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
KIO::Slave::suspended
virtual bool suspended()
Tells whether the kioslave is suspended.
Definition: slave.cpp:326
QDBusError::message
QString message() const
OrgKdeKLauncherInterface
QDBusReply::isValid
bool isValid() const
QDBusConnection::sessionBus
QDBusConnection sessionBus()
KIO::ERR_CANNOT_LAUNCH_PROCESS
Definition: global.h:197
KIO::ERR_SLAVE_DIED
Definition: global.h:238
KIO::Slave::kill
void kill()
Force termination.
Definition: slave.cpp:361
KIO::CMD_SLAVE_HOLD
Definition: global.h:156
ktoolinvocation.h
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
global.h
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
KIO::MetaData
MetaData is a simple map of key/value strings.
Definition: global.h:396
KUrl
KIO::Slave
Definition: slave.h:48
KIO::Slave::ref
void ref()
Definition: slave.cpp:235
QString::clear
void clear()
KIO::Slave::holdSlave
static Slave * holdSlave(const QString &protocol, const KUrl &url)
Requests a slave on hold for ths url, from klauncher, if there is such a job.
Definition: slave.cpp:484
KIO::Slave::~Slave
virtual ~Slave()
Definition: slave.cpp:169
SLAVE_CONNECTION_TIMEOUT_MAX
#define SLAVE_CONNECTION_TIMEOUT_MAX
Definition: slave.cpp:63
KIO::SlaveInterfacePrivate
Definition: slaveinterface_p.h:32
kglobal.h
KIO::Slave::port
quint16 port()
Definition: slave.cpp:199
KIO::Slave::host
QString host()
Definition: slave.cpp:193
KIO::Slave::setPID
void setPID(pid_t)
Definition: slave.cpp:261
KIO::Slave::setHost
virtual void setHost(const QString &host, quint16 port, const QString &user, const QString &passwd)
Set host for url.
Definition: slave.cpp:378
KIO::Slave::slaveProtocol
QString slaveProtocol()
The actual protocol used to handle the request.
Definition: slave.cpp:187
dataprotocol.h
KIO::Slave::deref
void deref()
Definition: slave.cpp:241
KIO::Slave::protocol
QString protocol()
The protocol this slave handles.
Definition: slave.cpp:175
KIO::Slave::job
KIO::SimpleJob * job() const
Definition: slave.cpp:282
QObject
KIO::Slave::resetHost
void resetHost()
Clear host info.
Definition: slave.cpp:394
QString::isEmpty
bool isEmpty() const
KIO::Slave::setProtocol
void setProtocol(const QString &protocol)
Definition: slave.cpp:181
KLibrary
QObject::deleteLater
void deleteLater()
KLibrary::fileName
QString fileName
SLAVE_CONNECTION_TIMEOUT_MIN
#define SLAVE_CONNECTION_TIMEOUT_MIN
Definition: slave.cpp:54
KIO::Slave::send
virtual void send(int cmd, const QByteArray &arr=QByteArray())
Sends the given command to the kioslave.
Definition: slave.cpp:332
QString
QStringList
kservice.h
KIO::Slave::timeout
void timeout()
Definition: slave.cpp:123
KIO::Slave::idleTime
time_t idleTime()
Definition: slave.cpp:252
kprotocolinfo.h
KProtocolInfo::exec
static QString exec(const QString &protocol)
KIO::Slave::suspend
virtual void suspend()
Suspends the operation of the attached kioslave.
Definition: slave.cpp:314
KIO::Slave::user
QString user()
Definition: slave.cpp:205
KIO::Slave::hold
virtual void hold(const KUrl &url)
Puts the kioslave associated with url at halt, and return it to klauncher, in order to let another ap...
Definition: slave.cpp:294
KIO::Slave::setConfig
virtual void setConfig(const MetaData &config)
Configure slave.
Definition: slave.cpp:401
kstandarddirs.h
KIO::SlaveInterface::error
void error(int, const QString &)
KGlobal::mainComponent
const KComponentData & mainComponent()
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KIO::SlaveInterface::metaData
void metaData(const KIO::MetaData &)
KIO::Slave::accept
void accept()
Definition: slave.cpp:113
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
KIO::Slave::passwd
QString passwd()
Definition: slave.cpp:211
KIO::Slave::setIdle
void setIdle()
Marks this slave as idle.
Definition: slave.cpp:217
KIO::Slave::createSlave
static Slave * createSlave(const QString &protocol, const KUrl &url, int &error, QString &error_text)
Creates a new slave.
Definition: slave.cpp:410
KIO::Slave::isAlive
bool isAlive()
Definition: slave.cpp:288
KIO::Slave::isConnected
bool isConnected()
Definition: slave.cpp:223
QDBusAbstractInterface::lastError
QDBusError lastError() const
KIO::Slave::setJob
void setJob(KIO::SimpleJob *job)
Definition: slave.cpp:273
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
klibrary.h
OrgKdeKLauncherInterface::requestHoldSlave
QDBusReply< int > requestHoldSlave(const QString &url, const QString &app_socket)
KIO::SlaveInterface::dispatch
virtual bool dispatch()
Definition: slaveinterface.cpp:80
KIO::Slave::checkForHeldSlave
static bool checkForHeldSlave(const KUrl &url)
Returns true if klauncher is holding a slave for url.
Definition: slave.cpp:508
slaveinterface_p.h
KIO::DataProtocol
This kioslave provides support of data urls as specified by rfc 2397.
Definition: dataprotocol.h:63
KIO::Slave::setConnected
void setConnected(bool c)
Definition: slave.cpp:229
QTimer::singleShot
singleShot
KIO::Slave::gotInput
void gotInput()
Definition: slave.cpp:338
OrgKdeKLauncherInterface::checkForHeldSlave
QDBusReply< bool > checkForHeldSlave(const QString &url)
KToolInvocation::klauncher
static OrgKdeKLauncherInterface * klauncher()
KIO::SimpleJob
A simple job (one url and one command).
Definition: jobclasses.h:322
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:53 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

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