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

KInit

  • sources
  • kde-4.14
  • kdelibs
  • kinit
kinit_win.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 1999-2000 Waldo Bastian <bastian@kde.org>
4  * (c) 1999 Mario Weilguni <mweilguni@sime.com>
5  * (c) 2001 Lubos Lunak <l.lunak@kde.org>
6  * (c) 2006-2011 Ralf Habacker <ralf.habacker@freenet.de>
7  * (c) 2009 Patrick Spendrin <ps_ml@gmx.de>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License version 2 as published by the Free Software Foundation.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB. If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #include <config.h>
25 
26 
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <windows.h>
33 #ifndef _WIN32_WCE
34 #include <Sddl.h>
35 #endif
36 #include <tlhelp32.h>
37 #include <psapi.h>
38 
39 
40 #include <QtCore/QProcess>
41 #include <QtCore/QFileInfo>
42 // Under wince interface is defined, so undef it otherwise it breaks it
43 #undef interface
44 #include <QtDBus/QtDBus>
45 
46 #include <kcomponentdata.h>
47 #include <kstandarddirs.h>
48 #include <kapplication.h>
49 #include <kdeversion.h>
50 
51 //#define ENABLE_SUICIDE
52 //#define ENABLE_EXIT
53 
54 #define KDED_EXENAME "kded4"
55 
56 static KComponentData *s_instance = 0;
57 
58 // print verbose messages
59 int verbose=0;
60 
62 QList<QProcess*> startedProcesses;
63 
64 /* --------------------------------------------------------------------
65  sid helper - will be migrated later to a class named Sid, which could
66  be used as base class for platform independent K_UID and K_GID types
67  - would this be possible before KDE 5 ?
68  --------------------------------------------------------------------- */
69 
76 PSID copySid(PSID from)
77 {
78  if (!from)
79  return 0;
80  int sidLength = GetLengthSid(from);
81  PSID to = (PSID) malloc(sidLength);
82  CopySid(sidLength, to, from);
83  return to;
84 }
85 
92 void freeSid(PSID sid)
93 {
94  if (sid)
95  free(sid);
96 }
97 
104 QString toString(PSID sid)
105 {
106  LPWSTR s;
107  if (!ConvertSidToStringSid(sid, &s))
108  return QString();
109 
110  QString result = QString::fromUtf16(reinterpret_cast<ushort*>(s));
111  LocalFree(s);
112  return result;
113 }
114 
115 /* --------------------------------------------------------------------
116  process helper
117  --------------------------------------------------------------------- */
118 
124 static HANDLE getProcessHandle(int processID)
125 {
126  return OpenProcess( SYNCHRONIZE|PROCESS_QUERY_INFORMATION |
127  PROCESS_VM_READ | PROCESS_TERMINATE,
128  false, processID );
129 }
130 
136 static QString getProcessName(DWORD pid)
137 {
138  HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
139  MODULEENTRY32 me32;
140 
141  hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
142  if( hModuleSnap == INVALID_HANDLE_VALUE )
143  return QString();
144 
145  me32.dwSize = sizeof( MODULEENTRY32 );
146 
147  if( !Module32First( hModuleSnap, &me32 ) ) {
148  CloseHandle( hModuleSnap ); // clean the snapshot object
149  return QString();
150  }
151  QString name = QString::fromWCharArray(me32.szExePath);
152  CloseHandle( hModuleSnap );
153  return name;
154 }
155 
161 static PSID getProcessOwner(HANDLE hProcess)
162 {
163 #ifndef _WIN32_WCE
164  HANDLE hToken = NULL;
165  PSID sid;
166 
167  OpenProcessToken(hProcess, TOKEN_READ, &hToken);
168  if(hToken)
169  {
170  DWORD size;
171  PTOKEN_USER userStruct;
172 
173  // check how much space is needed
174  GetTokenInformation(hToken, TokenUser, NULL, 0, &size);
175  if( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
176  {
177  userStruct = reinterpret_cast<PTOKEN_USER>( new BYTE[size] );
178  GetTokenInformation(hToken, TokenUser, userStruct, size, &size);
179 
180  sid = copySid(userStruct->User.Sid);
181  CloseHandle(hToken);
182  delete [] userStruct;
183  return sid;
184  }
185  }
186 #endif
187  return 0;
188 }
189 
193 static PSID getCurrentProcessOwner()
194 {
195  return getProcessOwner(GetCurrentProcess());
196 }
197 
201 class ProcessListEntry {
202  public:
203  ProcessListEntry( HANDLE _handle, QString _path, int _pid, PSID _owner=0 )
204  {
205  QFileInfo p(_path);
206  path = p.absolutePath();
207  name = p.baseName();
208  handle = _handle;
209  pid = _pid;
210  owner = copySid(_owner);
211  }
212 
213  ~ProcessListEntry()
214  {
215  freeSid(owner);
216  CloseHandle(handle);
217  }
218 
219  QString name;
220  QString path;
221  int pid;
222  HANDLE handle;
223  PSID owner;
224  friend QDebug operator <<(QDebug out, const ProcessListEntry &c);
225 };
226 
227 QDebug operator <<(QDebug out, const ProcessListEntry &c)
228 {
229  out << "(ProcessListEntry"
230  << "name" << c.name
231  << "path" << c.path
232  << "pid" << c.pid
233  << "handle" << c.handle
234  << "sid" << toString(c.owner)
235  << ")";
236  return out;
237 }
238 
246 class ProcessList {
247 public:
252  ProcessList(PSID userSid=0);
253 
254  ~ProcessList();
255 
261  ProcessListEntry *find(const QString &name);
262 
268  bool terminateProcess(const QString &name);
269 
274  QList<ProcessListEntry *> &list() { return m_processes; }
275 
276 private:
277  void init();
278  QList<ProcessListEntry *> m_processes;
279  PSID m_userId;
280 };
281 
282 ProcessList::ProcessList(PSID userSid)
283 {
284  m_userId = userSid;
285  init();
286 }
287 
288 ProcessList::~ProcessList()
289 {
290  foreach(const ProcessListEntry *ple,m_processes)
291  delete ple;
292 }
293 
294 void ProcessList::init()
295 {
296  HANDLE h;
297  PROCESSENTRY32 pe32;
298 
299  h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
300  if (h == INVALID_HANDLE_VALUE) {
301  return;
302  }
303  pe32.dwSize = sizeof(PROCESSENTRY32);
304  if (!Process32First( h, &pe32 ))
305  return;
306 
307  do
308  {
309  HANDLE hProcess = getProcessHandle(pe32.th32ProcessID);
310  if (!hProcess)
311  continue;
312  QString name = getProcessName(pe32.th32ProcessID);
313 #ifndef _WIN32_WCE
314  PSID sid = getProcessOwner(hProcess);
315  if (!sid || m_userId && !EqualSid(m_userId,sid))
316  {
317  freeSid(sid);
318  continue;
319  }
320 #else
321  PSID sid = 0;
322 #endif
323  m_processes << new ProcessListEntry( hProcess, name, pe32.th32ProcessID, sid);
324  } while(Process32Next( h, &pe32 ));
325 #ifndef _WIN32_WCE
326  CloseHandle(h);
327 #else
328  CloseToolhelp32Snapshot(h);
329 #endif
330 }
331 
332 ProcessListEntry *ProcessList::find(const QString &name)
333 {
334  ProcessListEntry *ple;
335  foreach(ple,m_processes) {
336  if (ple->pid < 0) {
337  qDebug() << "negative pid!";
338  continue;
339  }
340 
341  if (ple->name != name && ple->name != name + ".exe") {
342  continue;
343  }
344 
345  if (!ple->path.isEmpty() && !ple->path.toLower().startsWith(KStandardDirs::installPath("kdedir").toLower())) {
346  // process is outside of installation directory
347  qDebug() << "path of the process" << name << "seems to be outside of the installPath:" << ple->path << KStandardDirs::installPath("kdedir");
348  continue;
349  }
350  return ple;
351  }
352  return NULL;
353 }
354 
355 bool ProcessList::terminateProcess(const QString &name)
356 {
357  qDebug() << "going to terminate process" << name;
358  ProcessListEntry *p = find(name);
359  if (!p) {
360  qDebug() << "could not find ProcessListEntry for process name" << name;
361  return false;
362  }
363 
364  bool ret = TerminateProcess(p->handle,0);
365  if (ret) {
366  int i = m_processes.indexOf(p);
367  if(i != -1) m_processes.removeAt(i);
368  delete p;
369  return true;
370  } else {
371  return false;
372  }
373 }
374 
375 // internal launch function
376 int launch(const QString &cmd)
377 {
378  QProcess *proc = new QProcess();
379  proc->start(cmd);
380  proc->waitForStarted();
381  startedProcesses << proc;
382  _PROCESS_INFORMATION* _pid = proc->pid();
383  int pid = _pid ? _pid->dwProcessId : 0;
384  if (verbose) {
385  fprintf(stderr,"%s",proc->readAllStandardError().constData());
386  fprintf(stderr,"%s",proc->readAllStandardOutput().constData());
387  }
388  if (pid) {
389  if (verbose)
390  fprintf(stderr, "kdeinit4: Launched %s, pid = %ld\n", qPrintable(cmd),(long) pid);
391  }
392  else {
393  if (verbose)
394  fprintf(stderr, "kdeinit4: could not launch %s, exiting\n",qPrintable(cmd));
395  }
396  return pid;
397 }
398 
400 bool checkIfRegisteredInDBus(const QString &name, int _timeout=10)
401 {
402  int timeout = _timeout * 5;
403  while(timeout) {
404  if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( name ) )
405  break;
406  Sleep(200);
407  timeout--;
408  }
409  if (!timeout) {
410  if (verbose)
411  fprintf(stderr,"not registered %s in dbus after %d secs\n",qPrintable(name),_timeout);
412  return false;
413  }
414  if (verbose)
415  fprintf(stderr,"%s is registered in dbus\n",qPrintable(name));
416  return true;
417 }
418 
419 void listAllRunningKDEProcesses(ProcessList &processList)
420 {
421  QString installPrefix = KStandardDirs::installPath("kdedir");
422 
423  foreach(const ProcessListEntry *ple, processList.list())
424  {
425  if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower()))
426  fprintf(stderr,"path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
427  }
428 }
429 
430 void terminateAllRunningKDEProcesses(ProcessList &processList)
431 {
432  QString installPrefix = KStandardDirs::installPath("kdedir");
433 
434  foreach(const ProcessListEntry *ple, processList.list())
435  {
436  if (!ple->path.isEmpty() && ple->path.toLower().startsWith(installPrefix.toLower()))
437  {
438  if (verbose)
439  fprintf(stderr,"terminating path: %s name: %s pid: %u\n", ple->path.toLatin1().data(), ple->name.toLatin1().data(), ple->pid);
440  processList.terminateProcess(ple->name);
441  }
442  }
443 }
444 
445 void listAllNamedAppsInDBus()
446 {
447  QDBusConnection connection = QDBusConnection::sessionBus();
448  QDBusConnectionInterface *bus = connection.interface();
449  const QStringList services = bus->registeredServiceNames();
450  foreach(const QString &service, services) {
451  if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':')))
452  continue;
453  fprintf(stderr, "%s \n", service.toLatin1().data());
454  }
455 }
456 
457 void quitApplicationsOverDBus()
458 {
459  QDBusConnection connection = QDBusConnection::sessionBus();
460  QDBusConnectionInterface *bus = connection.interface();
461  const QStringList services = bus->registeredServiceNames();
462  foreach(const QString &service, services) {
463  if (service.startsWith(QLatin1String("org.freedesktop.DBus")) || service.startsWith(QLatin1Char(':')))
464  continue;
465  QDBusInterface *iface = new QDBusInterface(service,
466  QLatin1String("/MainApplication"),
467  QLatin1String("org.kde.KApplication"),
468  connection);
469  if (!iface->isValid()) {
470  if (verbose)
471  fprintf(stderr, "invalid interface of service %s\n", service.toLatin1().data());
472  continue;
473  }
474  iface->call("quit");
475  if (iface->lastError().isValid()) {
476  if (verbose)
477  fprintf(stderr,"killing %s with result\n", iface->lastError().message().toLatin1().data());
478  }
479  delete iface;
480  }
481 }
482 
483 int main(int argc, char **argv, char **envp)
484 {
485  pid_t pid = 0;
486  bool launch_dbus = true;
487  bool launch_klauncher = true;
488  bool launch_kded = true;
489  bool suicide = false;
490  bool listProcesses = false;
491  bool killProcesses = false;
492  bool listAppsInDBus = false;
493  bool quitAppsOverDBus = false;
494  bool shutdown = false;
495 
497  char **safe_argv = (char **) malloc( sizeof(char *) * argc);
498  for(int i = 0; i < argc; i++)
499  {
500  safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
501  if (strcmp(safe_argv[i], "--no-dbus") == 0)
502  launch_dbus = false;
503  if (strcmp(safe_argv[i], "--no-klauncher") == 0)
504  launch_klauncher = false;
505  if (strcmp(safe_argv[i], "--no-kded") == 0)
506  launch_kded = false;
507  if (strcmp(safe_argv[i], "--suicide") == 0)
508  suicide = true;
509 #ifdef ENABLE_EXIT
510  if (strcmp(safe_argv[i], "--exit") == 0)
511  keep_running = 0;
512 #endif
513  if (strcmp(safe_argv[i], "--verbose") == 0)
514  verbose = 1;
515  if (strcmp(safe_argv[i], "--version") == 0)
516  {
517  printf("Qt: %s\n",qVersion());
518  printf("KDE: %s\n", KDE_VERSION_STRING);
519  exit(0);
520  }
521  if (strcmp(safe_argv[i], "--help") == 0)
522  {
523  printf("Usage: kdeinit4 [options]\n");
524 #ifdef ENABLE_EXIT
525  printf(" --exit Terminate when kded has run\n");
526 #endif
527  printf(" --help this help page\n");
528  printf(" --list list kde processes\n");
529  printf(" --list-dbus-apps list all applications registered in dbus\n");
530  printf(" --quit-over-dbus quit all application registered in dbus\n");
531  printf(" --no-dbus do not start dbus-daemon\n");
532  printf(" --no-klauncher do not start klauncher\n");
533  printf(" --no-kded do not start kded\n");
534  printf(" --shutdown safe shutdown of all running kde processes\n");
535  printf(" first over dbus, then using hard kill\n");
536 #ifdef ENABLE_SUICIDE
537  printf(" --suicide terminate when no KDE applications are left running\n");
538 #endif
539  printf(" --terminate hard kill of *all* running kde processes\n");
540  printf(" --verbose print verbose messages\n");
541  printf(" --version Show version information\n");
542  exit(0);
543  }
544  if (strcmp(safe_argv[i], "--list") == 0)
545  listProcesses = true;
546  if (strcmp(safe_argv[i], "--shutdown") == 0)
547  shutdown = true;
548  if (strcmp(safe_argv[i], "--terminate") == 0 || strcmp(safe_argv[i], "--kill") == 0)
549  killProcesses = true;
550  if (strcmp(safe_argv[i], "--list-dbus-apps") == 0)
551  listAppsInDBus = true;
552  if (strcmp(safe_argv[i], "--quit-over-dbus") == 0)
553  quitAppsOverDBus = true;
554  }
555 
556  PSID currentSid = getCurrentProcessOwner();
557  if (verbose)
558  fprintf(stderr,"current user sid: %s\n",qPrintable(toString(currentSid)));
559  ProcessList processList(currentSid);
560  freeSid(currentSid);
561 
562  if (listProcesses) {
563  listAllRunningKDEProcesses(processList);
564  return 0;
565  }
566  else if (killProcesses) {
567  terminateAllRunningKDEProcesses(processList);
568  return 0;
569  }
570  else if (listAppsInDBus) {
571  listAllNamedAppsInDBus();
572  return 0;
573  }
574  else if (quitAppsOverDBus) {
575  quitApplicationsOverDBus();
576  return 0;
577  }
578  else if (shutdown) {
579  quitApplicationsOverDBus();
580  Sleep(2000);
581  terminateAllRunningKDEProcesses(processList);
582  }
583 
585  s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
586 
587 #ifdef _DEBUG
588  // first try to launch dbus-daemond in debug mode
589  if (launch_dbus && processList.find("dbus-daemond"))
590  launch_dbus = false;
591  if (launch_dbus)
592  {
593  pid = launch("dbus-launchd.exe");
594  if (!pid)
595  pid = launch("dbus-launchd.bat");
596  launch_dbus = (pid == 0);
597  }
598 #endif
599  if (launch_dbus && !processList.find("dbus-daemon"))
600  {
601  if (!pid)
602  pid = launch("dbus-launch.exe");
603  if (!pid)
604  pid = launch("dbus-launch.bat");
605  if (!pid)
606  exit(1);
607  }
608 
609  if (launch_klauncher && !processList.find("klauncher"))
610  {
611  pid = launch("klauncher");
612  if (!pid || !checkIfRegisteredInDBus("org.kde.klauncher",10))
613  exit(1);
614  }
615 
616 
617  if (launch_kded && !processList.find(KDED_EXENAME))
618  {
619  pid = launch(KDED_EXENAME);
620  if (!pid || !checkIfRegisteredInDBus("org.kde.kded",10))
621  exit(1);
622  }
623 
624  for(int i = 1; i < argc; i++)
625  {
626  if (safe_argv[i][0] == '+')
627  {
628  pid = launch(safe_argv[i]+1);
629  }
630  else if (safe_argv[i][0] == '-')
631  {
632  // Ignore
633  }
634  else
635  {
636  pid = launch( safe_argv[i]);
637  }
638  }
639 
641  for(int i = 0; i < argc; i++)
642  {
643  free(safe_argv[i]);
644  }
645  free (safe_argv);
646 
648 #ifdef ENABLE_SUICIDE
649  if (suicide) {
650  QProcess *proc;
651  int can_exit=1;
652  do {
653  foreach(proc,startedProcesses) {
654  if (proc->state() != QProcess::NotRunning)
655  can_exit = 0;
656  }
657  if (!can_exit)
658  Sleep(2000);
659  } while(!can_exit);
660  return 0;
661  }
662 #endif
663  return 0;
664 }
QString::fromWCharArray
QString fromWCharArray(const wchar_t *string, int size)
getProcessOwner
static PSID getProcessOwner(HANDLE hProcess)
return sid of specific process
Definition: kinit_win.cpp:161
QDBusAbstractInterface::isValid
bool isValid() const
QDBusConnectionInterface::registeredServiceNames
registeredServiceNames
result
char result
Definition: kinit.cpp:135
QByteArray
QDBusError::isValid
bool isValid() const
timeout
int timeout
suicide
bool suicide
Definition: kinit.cpp:147
QDBusConnection::interface
QDBusConnectionInterface * interface() const
getProcessName
static QString getProcessName(DWORD pid)
return absolute path of process
Definition: kinit_win.cpp:136
listAllRunningKDEProcesses
void listAllRunningKDEProcesses(ProcessList &processList)
Definition: kinit_win.cpp:419
KDED_EXENAME
#define KDED_EXENAME
Definition: kinit_win.cpp:54
verbose
int verbose
Definition: kinit_win.cpp:59
QDBusError::message
QString message() const
QDBusConnection
toString
QString toString(PSID sid)
copy sid
Definition: kinit_win.cpp:104
QDBusConnection::sessionBus
QDBusConnection sessionBus()
KDE_VERSION_STRING
#define KDE_VERSION_STRING
argv
char ** argv
Definition: kinit.cpp:141
getCurrentProcessOwner
static PSID getCurrentProcessOwner()
return sid of current process owner
Definition: kinit_win.cpp:193
QDBusAbstractInterface::call
QDBusMessage call(const QString &method, const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8)
operator<<
QDebug operator<<(QDebug out, const ProcessListEntry &c)
Definition: kinit_win.cpp:227
QString::fromUtf16
QString fromUtf16(const ushort *unicode, int size)
QProcess
QDBusConnectionInterface
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
startedProcesses
QList< QProcess * > startedProcesses
holds process list for suicide mode
Definition: kinit_win.cpp:62
launch
int launch(const QString &cmd)
Definition: kinit_win.cpp:376
Qt::HANDLE
typedef HANDLE
QString
QList
Definition: klauncher_adaptor.h:28
terminateAllRunningKDEProcesses
void terminateAllRunningKDEProcesses(ProcessList &processList)
Definition: kinit_win.cpp:430
QStringList
QDBusInterface
QFileInfo
QString::toLower
QString toLower() const
QProcess::pid
Q_PID pid() const
quitApplicationsOverDBus
void quitApplicationsOverDBus()
Definition: kinit_win.cpp:457
KStandardDirs::installPath
static QString installPath(const char *type)
QProcess::waitForStarted
bool waitForStarted(int msecs)
QLatin1Char
checkIfRegisteredInDBus
bool checkIfRegisteredInDBus(const QString &name, int _timeout=10)
check dbus registration
Definition: kinit_win.cpp:400
QDebug
getProcessHandle
static HANDLE getProcessHandle(int processID)
return process handle
Definition: kinit_win.cpp:124
listAllNamedAppsInDBus
void listAllNamedAppsInDBus()
Definition: kinit_win.cpp:445
main
int main(int argc, char **argv, char **envp)
Definition: kinit_win.cpp:483
QString::toLatin1
QByteArray toLatin1() const
QLatin1String
kstandarddirs.h
KComponentData::SkipMainComponentRegistration
freeSid
void freeSid(PSID sid)
copy sid
Definition: kinit_win.cpp:92
QByteArray::data
char * data()
QDBusAbstractInterface::lastError
QDBusError lastError() const
kcomponentdata.h
s_instance
static KComponentData * s_instance
Definition: kinit_win.cpp:56
KComponentData
QProcess::start
void start(const QString &program, const QStringList &arguments, QFlags< QIODevice::OpenModeFlag > mode)
QProcess::state
QProcess::ProcessState state() const
copySid
PSID copySid(PSID from)
copy sid
Definition: kinit_win.cpp:76
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:23:53 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KInit

Skip menu "KInit"
  • Main Page
  • 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