summaryrefslogtreecommitdiffstats
path: root/kdesktop
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit4aed2c8219774f5d797760606b8489a92ddc5163 (patch)
tree3f8c130f7d269626bf6a9447407ef6c35954426a /kdesktop
downloadtdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz
tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdesktop')
-rw-r--r--kdesktop/AUTHORS4
-rw-r--r--kdesktop/DESIGN94
-rw-r--r--kdesktop/KBackgroundIface.h75
-rw-r--r--kdesktop/KDesktopIface.h113
-rw-r--r--kdesktop/KScreensaverIface.h49
-rw-r--r--kdesktop/Makefile.am71
-rw-r--r--kdesktop/bgmanager.cc811
-rw-r--r--kdesktop/bgmanager.h126
-rw-r--r--kdesktop/configure.in.in39
-rw-r--r--kdesktop/desktop.cc986
-rw-r--r--kdesktop/desktop.h212
-rw-r--r--kdesktop/init.cc247
-rw-r--r--kdesktop/init.h30
-rw-r--r--kdesktop/init/Home.desktop166
-rw-r--r--kdesktop/init/Makefile.am8
-rw-r--r--kdesktop/init/System.desktop149
-rw-r--r--kdesktop/init/Templates/CAMERA-Device.desktop7
-rw-r--r--kdesktop/init/Templates/CDROM-Device.desktop92
-rw-r--r--kdesktop/init/Templates/CDWRITER-Device.desktop92
-rw-r--r--kdesktop/init/Templates/DVDROM-Device.desktop92
-rw-r--r--kdesktop/init/Templates/Directory.desktop146
-rw-r--r--kdesktop/init/Templates/Floppy.desktop78
-rw-r--r--kdesktop/init/Templates/HD.desktop7
-rw-r--r--kdesktop/init/Templates/HTMLFile.desktop148
-rw-r--r--kdesktop/init/Templates/HTMLFile.html8
-rw-r--r--kdesktop/init/Templates/MO-Device.desktop7
-rw-r--r--kdesktop/init/Templates/Makefile.am21
-rw-r--r--kdesktop/init/Templates/NFS.desktop7
-rw-r--r--kdesktop/init/Templates/Program.desktop6
-rw-r--r--kdesktop/init/Templates/TextFile.desktop148
-rw-r--r--kdesktop/init/Templates/TextFile.txt1
-rw-r--r--kdesktop/init/Templates/URL.desktop3
-rw-r--r--kdesktop/init/Templates/ZIP-Device.desktop92
-rw-r--r--kdesktop/init/Templates/linkCAMERA.desktop150
-rw-r--r--kdesktop/init/Templates/linkCDROM.desktop150
-rw-r--r--kdesktop/init/Templates/linkCDWRITER.desktop150
-rw-r--r--kdesktop/init/Templates/linkDVDROM.desktop150
-rw-r--r--kdesktop/init/Templates/linkFloppy.desktop158
-rw-r--r--kdesktop/init/Templates/linkHD.desktop157
-rw-r--r--kdesktop/init/Templates/linkMO.desktop150
-rw-r--r--kdesktop/init/Templates/linkNFS.desktop91
-rw-r--r--kdesktop/init/Templates/linkProgram.desktop153
-rw-r--r--kdesktop/init/Templates/linkURL.desktop153
-rw-r--r--kdesktop/init/Templates/linkZIP.desktop150
-rw-r--r--kdesktop/init/directory.autostart68
-rw-r--r--kdesktop/init/directory.desktop81
-rw-r--r--kdesktop/init/directory.templates78
-rw-r--r--kdesktop/init/directory.trash160
-rw-r--r--kdesktop/kcheckrunning.cpp29
-rw-r--r--kdesktop/kcustommenu.cc111
-rw-r--r--kdesktop/kcustommenu.h56
-rw-r--r--kdesktop/kdesktop.desktop85
-rw-r--r--kdesktop/kdesktop.kcfg370
-rw-r--r--kdesktop/kdesktopSetAsBackground.desktop210
-rw-r--r--kdesktop/kdesktop_custom_menu12
-rw-r--r--kdesktop/kdesktop_custom_menu22
-rw-r--r--kdesktop/kdesktopbindings.cpp47
-rw-r--r--kdesktop/kdesktopsettings.kcfgc4
-rw-r--r--kdesktop/kdesktopshadowsettings.cpp92
-rw-r--r--kdesktop/kdesktopshadowsettings.h117
-rw-r--r--kdesktop/kdiconview.cc1668
-rw-r--r--kdesktop/kdiconview.h256
-rw-r--r--kdesktop/kfileividesktop.cpp255
-rw-r--r--kdesktop/kfileividesktop.h127
-rw-r--r--kdesktop/klaunch.kcfg40
-rw-r--r--kdesktop/klaunchsettings.kcfgc4
-rw-r--r--kdesktop/krootwm.cc859
-rw-r--r--kdesktop/krootwm.h175
-rw-r--r--kdesktop/kshadowengine.cpp194
-rw-r--r--kdesktop/kshadowengine.h113
-rw-r--r--kdesktop/kshadowsettings.cpp182
-rw-r--r--kdesktop/kshadowsettings.h234
-rw-r--r--kdesktop/kwebdesktop/Makefile.am15
-rw-r--r--kdesktop/kwebdesktop/kwebdesktop.cpp191
-rw-r--r--kdesktop/kwebdesktop/kwebdesktop.desktop80
-rw-r--r--kdesktop/kwebdesktop/kwebdesktop.h70
-rw-r--r--kdesktop/kwebdesktop/kwebdesktop.kcfg19
-rw-r--r--kdesktop/kwebdesktop/kwebdesktopsettings.kcfgc4
-rw-r--r--kdesktop/lock/Makefile.am24
-rw-r--r--kdesktop/lock/autologout.cc115
-rw-r--r--kdesktop/lock/autologout.h51
-rw-r--r--kdesktop/lock/configure.in.in37
-rw-r--r--kdesktop/lock/lockdlg.cc720
-rw-r--r--kdesktop/lock/lockdlg.h92
-rw-r--r--kdesktop/lock/lockprocess.cc1172
-rw-r--r--kdesktop/lock/lockprocess.h131
-rw-r--r--kdesktop/lock/main.cc174
-rw-r--r--kdesktop/lock/main.h39
-rw-r--r--kdesktop/lockeng.cc371
-rw-r--r--kdesktop/lockeng.h113
-rw-r--r--kdesktop/main.cc215
-rw-r--r--kdesktop/minicli.cpp886
-rw-r--r--kdesktop/minicli.h112
-rw-r--r--kdesktop/minicli_ui.ui624
-rw-r--r--kdesktop/patterns/Makefile.am5
-rw-r--r--kdesktop/patterns/fish.desktop74
-rw-r--r--kdesktop/patterns/fish.pngbin0 -> 246 bytes
-rw-r--r--kdesktop/patterns/flowers.desktop79
-rw-r--r--kdesktop/patterns/flowers.pngbin0 -> 246 bytes
-rw-r--r--kdesktop/patterns/night-rock.desktop75
-rw-r--r--kdesktop/patterns/night-rock.jpgbin0 -> 30425 bytes
-rw-r--r--kdesktop/patterns/pavement.desktop75
-rw-r--r--kdesktop/patterns/pavement.pngbin0 -> 241 bytes
-rw-r--r--kdesktop/patterns/rattan.desktop40
-rw-r--r--kdesktop/patterns/rattan.pngbin0 -> 245 bytes
-rw-r--r--kdesktop/patterns/stonewall2.desktop76
-rw-r--r--kdesktop/patterns/stonewall2.pngbin0 -> 42047 bytes
-rw-r--r--kdesktop/patterns/triangles.desktop76
-rw-r--r--kdesktop/patterns/triangles.pngbin0 -> 246 bytes
-rw-r--r--kdesktop/pics/Makefile.am9
-rw-r--r--kdesktop/pics/cr32-app-error.pngbin0 -> 1591 bytes
-rw-r--r--kdesktop/pics/kde2.xbm38
-rw-r--r--kdesktop/pics/ksslogo.pngbin0 -> 6357 bytes
-rw-r--r--kdesktop/pics/splash.pngbin0 -> 98647 bytes
-rw-r--r--kdesktop/pics/splash2.pngbin0 -> 211370 bytes
-rw-r--r--kdesktop/pixmapserver.cc254
-rw-r--r--kdesktop/pixmapserver.h124
-rw-r--r--kdesktop/programs/Makefile.am2
-rw-r--r--kdesktop/programs/xearth.desktop81
-rw-r--r--kdesktop/programs/xglobe.desktop81
-rw-r--r--kdesktop/programs/xplanet.desktop80
-rw-r--r--kdesktop/startupid.cpp301
-rw-r--r--kdesktop/startupid.h66
-rw-r--r--kdesktop/xautolock.cc289
-rw-r--r--kdesktop/xautolock.h77
-rw-r--r--kdesktop/xautolock_c.h76
-rw-r--r--kdesktop/xautolock_diy.c289
-rw-r--r--kdesktop/xautolock_engine.c419
128 files changed, 19307 insertions, 0 deletions
diff --git a/kdesktop/AUTHORS b/kdesktop/AUTHORS
new file mode 100644
index 000000000..05bcfd697
--- /dev/null
+++ b/kdesktop/AUTHORS
@@ -0,0 +1,4 @@
+Torben Weis <weis@kde.org>
+David Faure <faure@kde.org>
+Martin R. Jones <mjones@kde.org>
+Geert Jansen <g.t.jansen@stud.tue.nl>
diff --git a/kdesktop/DESIGN b/kdesktop/DESIGN
new file mode 100644
index 000000000..e2a6a2b8b
--- /dev/null
+++ b/kdesktop/DESIGN
@@ -0,0 +1,94 @@
+KDesktop Design Document
+
+Author :
+ David Faure, faure@kde.org
+ Martin R. Jones, mjones@kde.org (screensaver)
+ Geert Jansen, g.t.jansen@stud.tue.nl (background code)
+
+Last modified: 24 Oct 1999
+
+Overall design of KDesktop :
+=============================
+
+KDesktop is the program that handles the desktop icons,
+the popup menus for the desktop, the mac menubar, and the
+screensaver system.
+
+Files :
+=======
+
+main.* : main
+desktop.* : the icon container for the desktop icons
+krootwm.* : right and middle mouse button popup menus, Mac menubar
+bg*.*: Background renderer/manager.
+
+icons.* : old code, not used anymore.
+ We need to borrow ideas from it for positioning icons after a DnD
+ (in kiconcontainer so that it works with konqueror as well)
+ - well, only if we want dropped icons to remain where they have been
+ dropped :)
+ We also need to store the desktop icons position, like was done in kfm.
+ and we need to do it for konqy as well.
+
+KDesktopIface* : DCOP interface for kdesktop, used by kfmclient
+
+lock* : screen saver/locker
+
+Libs used by KDesktop
+======================
+
+kdecore, kdeui, kfile - usual stuff :)
+libkio - I/O stuff, mimetypes, services, registry
+libkonq - properties dialog, templates ("new") menu, dir lister, settings
+
+Screensaver
+===========
+
+The screensaver now works in a similar way to xscreensaver, i.e. a driver
+(kdesktop) provides the timeout, locking, and blanking functionality, but
+does no actual drawing. A separate stand-alone program capable of
+drawing on a supplied window is used to do the actual fancy graphics.
+xscreensaver's "hacks" will work with the KDE screensaver engine.
+
+This makes adding new screensavers trivial, and means one less process that
+must always be running (compared to KDE 1.x).
+
+The screensaver is controlled via DCOP:
+
+KScreensaverIface::configure() Reloads the screensaver config from desktoprc.
+KScreensaverIface::lock() Locks the screen immediately.
+KScreensaverIface::save() Saves the screen immediately.
+KScreensaverIface::isEnabled() returns true if the screensaver is enabled.
+KScreensaverIface::isBlanked() returns true if the screen is currently blank.
+
+Backgrounds
+===========
+
+The new background code is in bgrender.cpp and bgmanager.cpp. Some features:
+
+* Support for xearth like programs.
+* Can export a pixmap of the desktop background for pseudo transparency.
+
+Multiple monitors
+=================
+Two monitors showing different things (not a mirror-setup) can be configured
+in X to either use one X screen, or 2 X screens. Difference is that if I
+drag a window from one monitor to the other the application gets asked to
+repaint itself on a 2 screen setup and a simple move of the window will be
+done in memory (by XFree) if you have a 1 screen setup.
+
+Monitors example:
+ +----+ +-----+ 2 monitors, with same resolution to keep it simple.
+ | | | |
+ +----+ +-----+
+
+In case of 1 screen (xinerama)
+ +------------+
+ | + desktopGeometry == screenGeometry == 3200 x 1200
+ +------------+
+
+In case of 2 screen (multihead)
+ +----+ +-----+
+ | | | | desktopGeometry = 3200 x 1200
+ +----+ +-----+ screenGeometry = 1600 x 1200 (for each monitor)
+
diff --git a/kdesktop/KBackgroundIface.h b/kdesktop/KBackgroundIface.h
new file mode 100644
index 000000000..bd2a6ba05
--- /dev/null
+++ b/kdesktop/KBackgroundIface.h
@@ -0,0 +1,75 @@
+/**
+ * DCOP interface for the background manager.
+ */
+
+#ifndef __KBackgroundIface_h__
+#define __KBackgroundIface_h__
+
+#include <dcopobject.h>
+#include <qcolor.h>
+
+class KBackgroundIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+ /** Reread the configuration */
+ virtual void configure() = 0;
+
+ /** Enable/disable export of the background pixmap. */
+ virtual void setExport(int xport) = 0;
+
+ /** Returns the export desktop pixmap state. */
+ virtual bool isExport() = 0;
+
+ /** Enable/disable common desktop background. */
+ virtual void setCommon(int common) = 0;
+
+ /** Returns the common desktop background state. */
+ virtual bool isCommon() = 0;
+
+ /** Change caching behaviour.
+ * @param bLimit Limit cache if not equal to zero.
+ * @param size Cache size in kilobytes. */
+ virtual void setCache(int bLimit, int size) = 0;
+
+ /** Change the wallpaper.
+ * @param desk desktop number, or 0 for the current visible desktop.
+ * @param wallpaper The (local) path to the wallpaper.
+ * @param mode The tiling mode. */
+ virtual void setWallpaper(int desk, QString wallpaper, int mode) = 0;
+
+ /** Change the wallpaper.
+ * @param wallpaper The (local) path to the wallpaper.
+ * @param mode The tiling mode. */
+ virtual void setWallpaper(QString wallpaper, int mode) = 0;
+
+ /** Set color.
+ * @param c The color.
+ * @param isColorA true for foreground and false for background color. */
+ virtual void setColor(const QColor &c, bool isColorA) = 0;
+
+ /** Change the wallpaper in "multi mode". */
+ virtual void changeWallpaper() = 0;
+
+ /** Enable/disable desktop background. */
+ virtual void setBackgroundEnabled(const bool enable) = 0;
+
+ /** Return the current wallpaper for specified desk.
+ * @param desk desktop number, or 0 for the current visible desktop.
+ */
+ virtual QString currentWallpaper( int desk ) = 0;
+
+ /** Return the wallpaper list for specified desk.
+ * @param desk desktop number, or 0 for the current visible desktop.
+ */
+ virtual QStringList wallpaperList(int desk) = 0;
+
+ /** Return the wallpaper files for specified desk.
+ * @param desk desktop number, or 0 for the current visible desktop.
+ */
+ virtual QStringList wallpaperFiles(int desk) = 0;
+};
+
+#endif // __KBackgroundIface_h__
diff --git a/kdesktop/KDesktopIface.h b/kdesktop/KDesktopIface.h
new file mode 100644
index 000000000..bbd1852ab
--- /dev/null
+++ b/kdesktop/KDesktopIface.h
@@ -0,0 +1,113 @@
+
+#ifndef __KDesktopIface_h__
+#define __KDesktopIface_h__
+
+#include <qstringlist.h>
+#include <dcopobject.h>
+#include <dcopref.h>
+
+class KDesktopIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+ /**
+ * @internal
+ */
+ virtual void runAutoStart() = 0;
+
+ /**
+ * Re-arrange the desktop icons.
+ */
+ virtual void rearrangeIcons() = 0;
+ /**
+ * @deprecated
+ */
+ void rearrangeIcons( bool ) { rearrangeIcons(); }
+ /**
+ * Lineup the desktop icons.
+ */
+ virtual void lineupIcons() = 0;
+ /**
+ * Select all icons
+ */
+ virtual void selectAll() = 0;
+ /**
+ * Unselect all icons
+ */
+ virtual void unselectAll() = 0;
+ /**
+ * Refresh all icons
+ */
+ virtual void refreshIcons() = 0;
+ /**
+ * @return the urls of selected icons
+ */
+ virtual QStringList selectedURLs() = 0;
+
+ /**
+ * Re-read KDesktop's configuration
+ */
+ virtual void configure() = 0;
+ /**
+ * Display the "Run Command" dialog (minicli)
+ */
+ virtual void popupExecuteCommand() = 0;
+ /**
+ * Display the "Run Command" dialog (minicli) and prefill
+ * @since 3.4
+ */
+ virtual void popupExecuteCommand(const QString& command) = 0;
+ /**
+ * Get the background dcop interface (KBackgroundIface)
+ */
+ DCOPRef background() { return DCOPRef( "kdesktop", "KBackgroundIface" ); }
+ /**
+ * Get the screensaver dcop interface (KScreensaverIface)
+ */
+ DCOPRef screenSaver() { return DCOPRef( "kdesktop", "KScreensaverIface" ); }
+ /**
+ * Full refresh
+ */
+ virtual void refresh() = 0;
+ /**
+ * Bye bye
+ */
+ virtual void logout() = 0;
+ /**
+ * Returns whether KDesktop uses a virtual root.
+ */
+ virtual bool isVRoot() = 0;
+ /**
+ * Set whether KDesktop should use a virtual root.
+ */
+ virtual void setVRoot( bool enable )= 0;
+ /**
+ * Clears the command history and completion items
+ */
+ virtual void clearCommandHistory() = 0;
+ /**
+ * Returns whether icons are enabled on the desktop
+ */
+ virtual bool isIconsEnabled() = 0;
+ /**
+ * Disable icons on the desktop.
+ */
+ virtual void setIconsEnabled( bool enable )= 0;
+
+ /**
+ * Should be called by any application that wants to tell KDesktop
+ * to switch desktops e.g. the minipager applet on kicker.
+ */
+ virtual void switchDesktops( int delta ) = 0;
+
+ /**
+ * slot for kicker; called when the number or size of panels change the available
+ * space for desktop icons
+ */
+ virtual void desktopIconsAreaChanged(const QRect &area, int screen) = 0;
+};
+
+#endif
+
diff --git a/kdesktop/KScreensaverIface.h b/kdesktop/KScreensaverIface.h
new file mode 100644
index 000000000..0ed26b67a
--- /dev/null
+++ b/kdesktop/KScreensaverIface.h
@@ -0,0 +1,49 @@
+
+#ifndef __KScreensaverIface_h__
+#define __KScreensaverIface_h__
+
+#include <dcopobject.h>
+
+class KScreensaverIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+ /** Lock the screen now even if the screensaver does not lock by default. */
+ virtual void lock() = 0;
+
+ /** Save the screen now. If the user has locking enabled, the screen is
+ * locked also. */
+ virtual void save() = 0;
+
+ /** Quit the screensaver if it is running */
+ virtual void quit() = 0;
+
+ /** Is the screensaver enabled? */
+ virtual bool isEnabled() = 0;
+
+ /**
+ * Enable/disable the screensaver
+ * returns true if the action succeeded
+ */
+ virtual bool enable( bool e ) = 0;
+
+ /** Is the screen currently blanked? */
+ virtual bool isBlanked() = 0;
+
+ /** Reload the screensaver configuration. */
+ virtual void configure() = 0;
+
+ /** Only blank the screen (and possibly lock). Do not use a custom
+ * screen saver in the interest of saving battery.
+ */
+ virtual void setBlankOnly( bool blankOnly ) = 0;
+
+ /***
+ * @internal
+ */
+ virtual void saverLockReady() = 0;
+};
+
+#endif
diff --git a/kdesktop/Makefile.am b/kdesktop/Makefile.am
new file mode 100644
index 000000000..0c1041f19
--- /dev/null
+++ b/kdesktop/Makefile.am
@@ -0,0 +1,71 @@
+## Makefile.am of kdebase/kdesktop
+
+INCLUDES = -I$(top_srcdir)/kcontrol/background -I$(top_srcdir)/libkonq -I$(top_srcdir)/kdmlib $(all_includes)
+kdesktop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kdesktop_la_LIBADD = libkdesktopsettings.la $(top_builddir)/libkonq/libkonq.la $(top_builddir)/kcontrol/background/libbgnd.la $(top_builddir)/kdmlib/libdmctl.la $(LIB_XSS) $(LIB_KUTILS) $(LIB_XCURSOR)
+
+SUBDIRS = . lock pics patterns programs init kwebdesktop
+
+####### Files
+
+bin_PROGRAMS = kcheckrunning
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = kdesktop.la
+noinst_LTLIBRARIES = libkdesktopsettings.la
+
+libkdesktopsettings_la_LDFLAGS = $(all_libraries) -no-undefined
+libkdesktopsettings_la_LIBADD = $(LIB_KDECORE)
+libkdesktopsettings_la_SOURCES = kdesktopsettings.kcfgc klaunchsettings.kcfgc
+
+kdesktop_la_SOURCES = main.cc krootwm.cc xautolock.cc kdiconview.cc desktop.cc \
+ lockeng.cc KDesktopIface.skel \
+ bgmanager.cc init.cc KScreensaverIface.skel \
+ minicli.cpp KBackgroundIface.skel pixmapserver.cc kcustommenu.cc \
+ startupid.cpp minicli_ui.ui xautolock_diy.c xautolock_engine.c \
+ kshadowengine.cpp kshadowsettings.cpp \
+ kdesktopshadowsettings.cpp kfileividesktop.cpp
+
+include_HEADERS = KDesktopIface.h KScreensaverIface.h KBackgroundIface.h
+
+noinst_HEADERS = desktop.h bgmanager.h krootwm.h \
+ xautolock.h lockeng.h init.h minicli.h \
+ pixmapserver.h startupid.h xautolock_c.h
+
+kcheckrunning_SOURCES = kcheckrunning.cpp
+kcheckrunning_LDFLAGS = $(all_libraries)
+kcheckrunning_LDADD = $(LIB_X11)
+
+METASOURCES = AUTO
+
+####### Build rules
+
+# List made with: grep -l kdesktopsettings.h *[pc] | sed -e 's/\.c.*$/.lo: kdesktopsettings.h/'
+bgmanager.lo: kdesktopsettings.h
+desktop.lo: kdesktopsettings.h
+init.lo: kdesktopsettings.h
+kdesktopsettings.lo: kdesktopsettings.h
+kdiconview.lo: kdesktopsettings.h
+krootwm.lo: kdesktopsettings.h
+lockeng.lo: kdesktopsettings.h
+main.lo: kdesktopsettings.h
+minicli.lo: kdesktopsettings.h
+
+# List made with: grep -l klaunchsettings.h *[pc] | sed -e 's/\.c.*$/.lo: klaunchsettings.h/'
+desktop.lo: klaunchsettings.h
+klaunchsettings.lo: klaunchsettings.h
+startupid.lo: klaunchsettings.h
+
+messages: rc.cpp
+ $(EXTRACTRC) lock/*.ui >> rc.cpp
+ $(XGETTEXT) lock/*.cc *.cc *.cpp *.h -o $(podir)/kdesktop.pot
+
+menu_DATA = kdesktop_custom_menu1 kdesktop_custom_menu2
+menudir = $(kde_confdir)
+
+autostart_DATA = kdesktop.desktop
+autostartdir = $(datadir)/autostart
+
+konqservice_DATA = kdesktopSetAsBackground.desktop
+konqservicedir = $(kde_datadir)/konqueror/servicemenus
+
+kde_kcfg_DATA = kdesktop.kcfg klaunch.kcfg
diff --git a/kdesktop/bgmanager.cc b/kdesktop/bgmanager.cc
new file mode 100644
index 000000000..62f97cecc
--- /dev/null
+++ b/kdesktop/bgmanager.cc
@@ -0,0 +1,811 @@
+/* vi: ts=8 sts=4 sw=4
+ * kate: space-indent on; tab-width 8; indent-width 4; indent-mode cstyle;
+ *
+ * This file is part of the KDE project, module kdesktop.
+ * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
+ *
+ * You can Freely distribute this program under the GNU General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#include <config.h>
+#include "bgrender.h"
+#include "bgmanager.h"
+#include "bgdefaults.h"
+#include "kdesktopsettings.h"
+#include "bgsettings.h"
+
+#include <assert.h>
+
+#include <qtimer.h>
+#include <qscrollview.h>
+
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kwin.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kipc.h>
+#include <kpopupmenu.h>
+#include <kwinmodule.h>
+#include <krootpixmap.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#ifndef None
+#define None 0L
+#endif
+
+#include "pixmapserver.h"
+
+template class QPtrVector<KBackgroundRenderer>;
+template class QPtrVector<KBackgroundCacheEntry>;
+template class QMemArray<int>;
+
+static Atom prop_root;
+static bool properties_inited = false;
+
+/**** KBackgroundManager ****/
+
+KBackgroundManager::KBackgroundManager(QWidget *desktop, KWinModule* kwinModule)
+ : DCOPObject("KBackgroundIface")
+{
+ if( !properties_inited )
+ {
+ prop_root = XInternAtom(qt_xdisplay(), "_XROOTPMAP_ID", False);
+ properties_inited = true;
+ }
+ m_bBgInitDone = false;
+ m_bEnabled = true;
+
+ m_pDesktop = desktop;
+ if (desktop == 0L)
+ desktop = QApplication::desktop()->screen();
+
+ m_Renderer.resize( 1 );
+ m_Cache.resize( 1 );
+
+ m_Serial = 0; m_Hash = 0;
+ m_pConfig = KGlobal::config();
+ m_bExport = m_bCommon = m_bInit = false;
+ m_pKwinmodule = kwinModule;
+ m_pPixmapServer = new KPixmapServer();
+ m_xrootpmap = None;
+
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ m_Cache.insert(i, new KBackgroundCacheEntry);
+ m_Cache[i]->pixmap = 0L;
+ m_Cache[i]->hash = 0;
+ m_Cache[i]->exp_from = -1;
+ m_Renderer.insert (i, new KVirtualBGRenderer(i,m_pConfig));
+ connect(m_Renderer[i], SIGNAL(imageDone(int)), SLOT(slotImageDone(int)));
+ m_Renderer[i]->enableTiling( true ); // optimize
+ }
+
+ configure();
+
+ m_pTimer = new QTimer(this);
+ connect(m_pTimer, SIGNAL(timeout()), SLOT(slotTimeout()));
+ m_pTimer->start( 60000 );
+
+ connect(m_pKwinmodule, SIGNAL(currentDesktopChanged(int)),
+ SLOT(slotChangeDesktop(int)));
+ connect(m_pKwinmodule, SIGNAL(numberOfDesktopsChanged(int)),
+ SLOT(slotChangeNumberOfDesktops(int)));
+
+#if (QT_VERSION-0 >= 0x030200)
+ connect( kapp->desktop(), SIGNAL( resized( int )), SLOT( desktopResized())); // RANDR support
+#endif
+}
+
+
+KBackgroundManager::~KBackgroundManager()
+{
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ delete m_Renderer[i];
+
+ //delete m_pConfig; Very bad idea, this is KGlobal::config !
+ delete m_pPixmapServer;
+ delete m_pTimer;
+
+ // clear the Esetroot properties, as the pixmaps they refer to are going away...
+ Pixmap pm = None;
+ Atom type;
+ int format;
+ unsigned long length, after;
+ unsigned char* data_root;
+ if( XGetWindowProperty( qt_xdisplay(), qt_xrootwin(), prop_root, 0L, 1L, False, AnyPropertyType,
+ &type, &format, &length, &after, &data_root) == Success && data_root != NULL )
+ {
+ if (type == XA_PIXMAP)
+ pm = *((Pixmap*)data_root);
+ XFree( data_root );
+ }
+ // only if it's our pixmap
+ if( pm == m_xrootpmap )
+ XDeleteProperty(qt_xdisplay(), qt_xrootwin(), prop_root);
+ m_xrootpmap = None;
+
+ if (m_bExport)
+ return;
+
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ delete m_Cache[i]->pixmap;
+ delete m_Cache[i];
+ }
+}
+
+
+void KBackgroundManager::applyExport(bool exp)
+{
+ if (exp == m_bExport)
+ return;
+
+ // If export mode changed from true -> false, remove all shared pixmaps.
+ // If it changed false -> true force a redraw because the current screen
+ // image might not have an associated pixmap in the cache.
+ if (!exp)
+ {
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ removeCache(i);
+ } else
+ m_Hash = 0;
+
+ m_bExport = exp;
+}
+
+
+void KBackgroundManager::applyCommon(bool common)
+{
+ if (common == m_bCommon)
+ return;
+ m_bCommon = common;
+
+ // If common changed from false -> true, remove all cache entries, except
+ // at index 0 if exports are on.
+ if (m_bCommon)
+ {
+ if (!m_bExport)
+ removeCache(0);
+ for (unsigned i=1; i<m_Cache.size(); i++)
+ removeCache(i);
+ }
+}
+
+
+void KBackgroundManager::applyCache(bool limit, int size)
+{
+ m_bLimitCache = limit;
+ m_CacheLimit = size;
+ freeCache(0);
+}
+
+
+/*
+ * Call this when the configuration has changed.
+ * This method is exported with DCOP.
+ */
+void KBackgroundManager::configure()
+{
+ // Global settings
+ m_pConfig->reparseConfiguration();
+ KDesktopSettings::self()->readConfig();
+
+ // Read individual settings
+ KVirtualBGRenderer *r;
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ r = m_Renderer[i];
+ int ohash = r->hash();
+ r->load(i,false);
+ if ((r->hash() != ohash))
+ removeCache(i);
+ }
+
+ applyCommon(KDesktopSettings::commonDesktop());
+
+ bool limit = KDesktopSettings::limitCache();
+ int size = KDesktopSettings::cacheSize() * 1024;
+ applyCache(limit, size);
+
+ // Repaint desktop
+ slotChangeDesktop(0);
+}
+
+
+int KBackgroundManager::realDesktop()
+{
+ int desk = m_pKwinmodule->currentDesktop();
+ if (desk) desk--;
+ return desk;
+}
+
+
+int KBackgroundManager::effectiveDesktop()
+{
+ return m_bCommon ? 0 : realDesktop();
+}
+
+
+/*
+ * Number of desktops changed
+ */
+void KBackgroundManager::slotChangeNumberOfDesktops(int num)
+{
+ if (m_Renderer.size() == (unsigned) num)
+ return;
+
+ if (m_Renderer.size() > (unsigned) num)
+ {
+ for (unsigned i=num; i<m_Renderer.size(); i++)
+ {
+ if (m_Renderer[i]->isActive())
+ m_Renderer[i]->stop();
+ delete m_Renderer[i];
+ removeCache(i);
+ }
+ for (unsigned i=num; i<m_Renderer.size(); i++)
+ delete m_Cache[i];
+ m_Renderer.resize(num);
+ m_Cache.resize(num);
+ } else
+ {
+ // allocate new renderers and caches
+ int oldsz = m_Renderer.size();
+ m_Renderer.resize(num);
+ m_Cache.resize(num);
+ for (int i=oldsz; i<num; i++)
+ {
+ m_Cache.insert(i, new KBackgroundCacheEntry);
+ m_Cache[i]->pixmap = 0L;
+ m_Cache[i]->hash = 0;
+ m_Cache[i]->exp_from = -1;
+ m_Renderer.insert(i, new KVirtualBGRenderer(i,m_pConfig));
+ connect(m_Renderer[i], SIGNAL(imageDone(int)), SLOT(slotImageDone(int)));
+ m_Renderer[i]->enableTiling( true ); // optimize
+ }
+ }
+}
+
+/*
+ * Call this when the desktop has been changed.
+ * Desk is in KWin convention: [1..desks], instead of [0..desks-1].
+ * 0 repaints the current desktop.
+ */
+void KBackgroundManager::slotChangeDesktop(int desk)
+{
+ if (desk == 0)
+ desk = realDesktop();
+ else
+ desk--;
+
+ // Lazy initialisation of # of desktops
+ if ((unsigned) desk >= m_Renderer.size())
+ slotChangeNumberOfDesktops( m_pKwinmodule->numberOfDesktops() );
+
+ int edesk = effectiveDesktop();
+ m_Serial++;
+
+ // If the background is the same: do nothing
+ if (m_Hash == m_Renderer[edesk]->hash())
+ {
+ exportBackground(m_Current, desk);
+ return;
+ }
+ m_Renderer[edesk]->stop();
+ m_Renderer[edesk]->cleanup();
+
+ // If we have the background already rendered: set it
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (!m_Cache[i]->pixmap)
+ continue;
+ if (m_Cache[i]->hash != m_Renderer[edesk]->hash())
+ continue;
+// kdDebug() << "slotChangeDesktop i=" << i << endl;
+ setPixmap(m_Cache[i]->pixmap, m_Cache[i]->hash, i);
+ m_Cache[i]->atime = m_Serial;
+ exportBackground(i, desk);
+ return;
+ }
+
+ // Do we have this or an identical config already running?
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ if ((m_Renderer[i]->hash() == m_Renderer[edesk]->hash()) &&
+ (m_Renderer[i]->isActive()))
+ return;
+ }
+
+ renderBackground(edesk);
+}
+
+
+/*
+ * Share a desktop pixmap.
+ */
+void KBackgroundManager::exportBackground(int pixmap, int desk)
+{
+ if (!m_bExport || (m_Cache[desk]->exp_from == pixmap))
+ return;
+
+ m_Cache[desk]->exp_from = pixmap;
+ m_pPixmapServer->add(KRootPixmap::pixmapName(desk+1),
+ m_Cache[pixmap]->pixmap);
+ KIPC::sendMessageAll(KIPC::BackgroundChanged, desk+1);
+}
+
+
+/*
+ * Paint the pixmap to the root window.
+ */
+void KBackgroundManager::setPixmap(KPixmap *pm, int hash, int desk)
+{
+ if (m_pDesktop)
+ {
+ QScrollView* sv = dynamic_cast<QScrollView*>( m_pDesktop );
+ if ( sv ) {
+ // Qt eats repaint events in this case :-((
+ sv->viewport()->update();
+ }
+ m_pDesktop->setErasePixmap(*pm);
+ m_pDesktop->repaint();
+ static bool root_cleared = false;
+ if( !root_cleared )
+ { // clear the root window pixmap set by kdm
+ root_cleared = true;
+ QTimer::singleShot( 0, this, SLOT( clearRoot()));
+ // but make the pixmap visible until m_pDesktop is visible
+ QApplication::desktop()->screen()->setErasePixmap(*pm);
+ QApplication::desktop()->screen()->erase();
+ }
+ }
+ else
+ {
+ QApplication::desktop()->screen()->setErasePixmap(*pm);
+ QApplication::desktop()->screen()->erase();
+ }
+
+ // and export it via Esetroot-style for gnome/GTK apps to share in the pretties
+ Pixmap bgPm = pm->handle(); // fetch the actual X handle to it
+ //kdDebug() << "Esetroot compat: setting pixmap to " << bgPm << endl;
+
+ // don't set the ESETROOT_PMAP_ID property - that would result in possible XKillClient()
+ // done on kdesktop
+
+ XChangeProperty(qt_xdisplay(), qt_xrootwin(), prop_root, XA_PIXMAP, 32, PropModeReplace,
+ (unsigned char *) &bgPm, 1);
+ m_xrootpmap = bgPm;
+
+ m_Hash = hash;
+ m_Current = desk;
+}
+
+void KBackgroundManager::clearRoot()
+{
+ QApplication::desktop()->screen()->setErasePixmap( QPixmap());
+ QApplication::desktop()->screen()->erase();
+}
+
+/*
+ * Start the render of a desktop background.
+ */
+void KBackgroundManager::renderBackground(int desk)
+{
+ KVirtualBGRenderer *r = m_Renderer[desk];
+ if (r->isActive())
+ {
+ kdDebug() << "renderer " << desk << " already active" << endl;
+ return;
+ }
+
+ r->start();
+}
+
+
+/*
+ * This slot is called when a renderer is done.
+ */
+void KBackgroundManager::slotImageDone(int desk)
+{
+ KPixmap *pm = new KPixmap();
+ KVirtualBGRenderer *r = m_Renderer[desk];
+ bool do_cleanup = true;
+
+ *pm = r->pixmap();
+ // If current: paint it
+ bool current = (r->hash() == m_Renderer[effectiveDesktop()]->hash());
+ if (current)
+ {
+ setPixmap(pm, r->hash(), desk);
+ if (!m_bBgInitDone)
+ {
+ m_bBgInitDone = true;
+ emit initDone();
+ QTimer::singleShot( 30000, this, SLOT( saveImages()));
+ do_cleanup = false;
+ }
+ }
+ if (m_bExport || !m_bCommon)
+ addCache(pm, r->hash(), desk);
+ else
+ delete pm;
+
+ if (current)
+ exportBackground(desk, realDesktop());
+
+ if( do_cleanup )
+ {
+ r->saveCacheFile();
+ r->cleanup();
+ }
+}
+
+
+void KBackgroundManager::saveImages()
+{
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ m_Renderer[i]->saveCacheFile();
+ m_Renderer[i]->cleanup();
+ }
+}
+
+/*
+ * Size in bytes of a QPixmap. For use in the pixmap cache.
+ */
+int KBackgroundManager::pixmapSize(QPixmap *pm)
+{
+ return (pm->width() * pm->height()) * ((pm->depth() + 7) / 8);
+}
+
+
+/*
+ * Total size of the pixmap cache.
+ */
+int KBackgroundManager::cacheSize()
+{
+ int total = 0;
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (m_Cache[i]->pixmap)
+ total += pixmapSize(m_Cache[i]->pixmap);
+ }
+ return total;
+}
+
+
+/*
+ * Remove an entry from the pixmap cache.
+ */
+void KBackgroundManager::removeCache(int desk)
+{
+ if (m_bExport)
+ m_pPixmapServer->remove(KRootPixmap::pixmapName(desk+1));
+ else
+ delete m_Cache[desk]->pixmap;
+ m_Cache[desk]->pixmap = 0L;
+ m_Cache[desk]->hash = 0;
+ m_Cache[desk]->exp_from = -1;
+ m_Cache[desk]->atime = 0;
+
+ // Remove cache entries pointing to the removed entry
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (m_Cache[i]->exp_from == desk)
+ {
+ assert(m_bExport);
+ m_Cache[i]->exp_from = -1;
+ m_pPixmapServer->remove(KRootPixmap::pixmapName(i+1));
+ }
+ }
+}
+
+
+/*
+ * Try to free up to size bytes from the cache.
+ */
+bool KBackgroundManager::freeCache(int size)
+{
+ if (m_bExport || !m_bLimitCache)
+ return true;
+
+ // If it doesn't fit at all, return now.
+ if (size > m_CacheLimit)
+ return false;
+
+ // If cache is too full, purge it (LRU)
+ while (size+cacheSize() > m_CacheLimit)
+ {
+ int j, min;
+ min = m_Serial+1; j = 0;
+ for (unsigned i=0; i<m_Cache.size(); i++)
+ {
+ if (m_Cache[i]->pixmap && (m_Cache[i]->atime < min))
+ {
+ min = m_Cache[i]->atime;
+ j = i;
+ }
+ }
+ removeCache(j);
+ }
+ return true;
+}
+
+
+/*
+ * Try to add a pixmap to the pixmap cache. We don't use QPixmapCache here
+ * because if we're exporting pixmaps, this needs special care.
+ */
+void KBackgroundManager::addCache(KPixmap *pm, int hash, int desk)
+{
+ if (m_Cache[desk]->pixmap)
+ removeCache(desk);
+
+ if (m_bLimitCache && !m_bExport && !freeCache(pixmapSize(pm)))
+ {
+ // pixmap does not fit in cache
+ delete pm;
+ return;
+ }
+
+ m_Cache[desk]->pixmap = pm;
+ m_Cache[desk]->hash = hash;
+ m_Cache[desk]->atime = m_Serial;
+ m_Cache[desk]->exp_from = -1;
+ exportBackground(desk, desk);
+}
+
+/*
+ * Called every minute to check if we need to rerun a background program.
+ * or change a wallpaper.
+ */
+void KBackgroundManager::slotTimeout()
+{
+ QMemArray<int> running(m_Renderer.size());
+ running.fill(0);
+
+ int NumDesks = m_Renderer.size();
+ if (m_bCommon)
+ NumDesks = 1;
+
+ int edesk = effectiveDesktop();
+
+ for (int i=0; i<NumDesks; i++)
+ {
+ KVirtualBGRenderer *r = m_Renderer[i];
+ bool change = false;
+
+ if (r->needProgramUpdate())
+ {
+ r->programUpdate();
+ change = true;
+ }
+
+ if (r->needWallpaperChange())
+ {
+ r->changeWallpaper();
+ change = true;
+ }
+
+ if (change && (i == edesk))
+ {
+ running[i] = r->hash();
+ r->start();
+ }
+ }
+}
+
+// Return a valid desk number.
+int KBackgroundManager::validateDesk(int desk)
+{
+ if (desk > (int)m_Renderer.size())
+ slotChangeNumberOfDesktops( m_pKwinmodule->numberOfDesktops() );
+
+ if ( (desk <= 0) || (desk > (int)m_Renderer.size()) )
+ return realDesktop();
+
+ return desk - 1;
+}
+
+// DCOP exported
+// Return current wallpaper for specified desk.
+// 0 is for the current visible desktop.
+QString KBackgroundManager::currentWallpaper(int desk)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KBackgroundRenderer *r = m_Renderer[validateDesk(desk)]->renderer(0);
+
+ return r->currentWallpaper();
+}
+
+// DCOP exported
+void KBackgroundManager::changeWallpaper()
+{
+ KVirtualBGRenderer *r = m_Renderer[effectiveDesktop()];
+
+ r->changeWallpaper();
+ slotChangeDesktop(0);
+}
+
+// DCOP exported
+void KBackgroundManager::setExport(int _export)
+{
+ kdDebug() << "KBackgroundManager enabling exports.\n";
+ applyExport(_export);
+ slotChangeDesktop(0);
+}
+
+// DCOP exported
+void KBackgroundManager::setCommon(int common)
+{
+ applyCommon(common);
+ KDesktopSettings::setCommonDesktop( m_bCommon );
+ KDesktopSettings::writeConfig();
+ slotChangeDesktop(0);
+}
+
+// DCOP exported
+void KBackgroundManager::setWallpaper(QString wallpaper, int mode)
+{
+ if (mode < 0 || mode >= KBackgroundSettings::lastWallpaperMode) {
+ kdDebug() << "Invalid background mode " << mode << " passed to " << k_funcinfo << "\n";
+ return;
+ }
+
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ for (unsigned i=0; i < m_Renderer[effectiveDesktop()]->numRenderers(); ++i)
+ {
+ KBackgroundRenderer *r = m_Renderer[effectiveDesktop()]->renderer(i);
+ r->stop();
+ r->setWallpaperMode(mode);
+ r->setMultiWallpaperMode(KBackgroundSettings::NoMulti);
+ r->setWallpaper(wallpaper);
+ r->writeSettings();
+ }
+ slotChangeDesktop(0);
+}
+
+void KBackgroundManager::setWallpaper(QString wallpaper)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KBackgroundRenderer *r = m_Renderer[effectiveDesktop()]->renderer(0);
+ int mode = r->wallpaperMode();
+ if (mode == KBackgroundSettings::NoWallpaper)
+ mode = KBackgroundSettings::Tiled;
+ setWallpaper(wallpaper, mode);
+}
+
+// DCOP exported
+// Returns the filenames of all wallpaper entries for specified desk
+// 0 is for current visible desktop.
+QStringList KBackgroundManager::wallpaperFiles(int desk)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KBackgroundRenderer *r = m_Renderer[validateDesk(desk)]->renderer(0);
+
+ return r->wallpaperFiles();
+}
+
+// DCOP exported
+// Returns the list of wallpaper entries (viewable in background slide
+// show window) for specified desk. 0 is for current visible desktop.
+QStringList KBackgroundManager::wallpaperList(int desk)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ KBackgroundRenderer *r = m_Renderer[validateDesk(desk)]->renderer(0);;
+
+ return r->wallpaperList();
+}
+
+// DCOP exported
+void KBackgroundManager::setCache( int bLimit, int size )
+{
+ applyCache( bLimit, size*1024 );
+ KDesktopSettings::setLimitCache( (bool) bLimit );
+ KDesktopSettings::setCacheSize( size );
+ KDesktopSettings::writeConfig();
+}
+
+// DCOP exported
+void KBackgroundManager::setWallpaper(int desk, QString wallpaper, int mode)
+{
+ if (mode < 0 || mode >= KBackgroundSettings::lastWallpaperMode) {
+ kdDebug() << "Invalid background mode " << mode << " passed to " << k_funcinfo << "\n";
+ return;
+ }
+
+ int sdesk = validateDesk(desk);
+
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ for (unsigned i=0; i < m_Renderer[sdesk]->numRenderers(); ++i)
+ {
+ KBackgroundRenderer *r = m_Renderer[sdesk]->renderer(i);
+
+ setCommon(false); // Force each desktop to have it's own wallpaper
+
+ r->stop();
+ r->setWallpaperMode(mode);
+ r->setMultiWallpaperMode(KBackgroundSettings::NoMulti);
+ r->setWallpaper(wallpaper);
+ r->writeSettings();
+ }
+ slotChangeDesktop(sdesk);
+}
+
+void KBackgroundManager::repaintBackground()
+{
+ if (m_pDesktop)
+ m_pDesktop->repaint();
+ else
+ QApplication::desktop()->screen()->erase();
+}
+
+void KBackgroundManager::desktopResized()
+{
+ for (unsigned i=0; i<m_Renderer.size(); i++)
+ {
+ KVirtualBGRenderer * r = m_Renderer[i];
+ if( r->isActive())
+ r->stop();
+ removeCache(i);
+ // make the renderer update its desktop size
+ r->desktopResized();
+ }
+ m_Hash = 0;
+ if( m_pDesktop )
+ m_pDesktop->resize( kapp->desktop()->size());
+ // Repaint desktop
+ slotChangeDesktop(0);
+}
+
+// DCOP exported
+void KBackgroundManager::setColor(const QColor & c, bool isColorA)
+{
+ //TODO Is the behaviour of this function appropriate for multiple screens?
+ for (unsigned i=0; i < m_Renderer[effectiveDesktop()]->numRenderers(); ++i)
+ {
+ KBackgroundRenderer *r = m_Renderer[effectiveDesktop()]->renderer(i);
+ r->stop();
+
+ if (isColorA)
+ r->setColorA(c);
+ else
+ r->setColorB(c);
+
+ int mode = r->backgroundMode();
+ if (mode == KBackgroundSettings::Program)
+ mode = KBackgroundSettings::Flat;
+
+ if (!isColorA && (mode == KBackgroundSettings::Flat))
+ mode = KBackgroundSettings::VerticalGradient;
+ r->setBackgroundMode(mode);
+
+ r->writeSettings();
+ }
+ slotChangeDesktop(0);
+}
+
+void KBackgroundManager::setBackgroundEnabled( const bool enable )
+{
+ if (m_bEnabled == enable)
+ return;
+
+ m_bEnabled= enable;
+
+ int NumDesks = m_Renderer.size();
+ if (m_bCommon)
+ NumDesks = 1;
+
+ for (int i=0; i<NumDesks; i++)
+ {
+ m_Renderer[i]->setEnabled(enable);
+ }
+ slotChangeDesktop(0);
+}
+
+#include "bgmanager.moc"
diff --git a/kdesktop/bgmanager.h b/kdesktop/bgmanager.h
new file mode 100644
index 000000000..e029cf6cd
--- /dev/null
+++ b/kdesktop/bgmanager.h
@@ -0,0 +1,126 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdesktop.
+ * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
+ *
+ * You can Freely distribute this program under the GNU General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef __BGManager_h_Included__
+#define __BGManager_h_Included__
+
+#include <qstring.h>
+#include <qptrvector.h>
+
+#include <KBackgroundIface.h>
+
+class KConfig;
+class QTimer;
+class QPixmap;
+class KPopupMenu;
+class KWinModule;
+class KPixmap;
+class KVirtualBGRenderer;
+class KPixmapServer;
+
+/**
+ * Internal struct for KBackgroundManager.
+ */
+struct KBackgroundCacheEntry
+{
+ int hash;
+ int atime;
+ int exp_from;
+ KPixmap *pixmap;
+};
+
+
+/**
+ * Background manager for KDE. This class is to be used in kdesktop. Usage is
+ * very simple: instantiate this class once and the desktop background will
+ * be painted automatically from now on.
+ *
+ * The background manager also has a DCOP interface to remotely control its
+ * operation. See KBackgroundIface.h for details.
+ */
+
+class KBackgroundManager
+ : public QObject,
+ virtual public KBackgroundIface
+{
+ Q_OBJECT
+
+public:
+ KBackgroundManager(QWidget *desktop, KWinModule* kwinModule);
+ ~KBackgroundManager();
+
+ void configure();
+ void setCommon(int);
+ bool isCommon() { return m_bCommon; };
+ void setExport(int);
+ bool isExport() { return m_bExport; };
+ void setCache(int, int);
+ void setWallpaper(int desk, QString wallpaper, int mode);
+ void setWallpaper(QString wallpaper, int mode);
+ void setWallpaper(QString wallpaper);
+ void changeWallpaper();
+ QString currentWallpaper(int desk);
+ void setColor(const QColor & c, bool isColorA = true);
+ void setBackgroundEnabled(const bool enable);
+ QStringList wallpaperList(int desk);
+ QStringList wallpaperFiles(int desk);
+
+signals:
+ void initDone();
+
+private slots:
+ void slotTimeout();
+ void slotImageDone(int desk);
+ void slotChangeDesktop(int);
+ void slotChangeNumberOfDesktops(int);
+ void repaintBackground();
+ void desktopResized();
+ void clearRoot();
+ void saveImages();
+
+private:
+ void applyCommon(bool common);
+ void applyExport(bool _export);
+ void applyCache(bool limit, int size);
+
+ int realDesktop();
+ int effectiveDesktop();
+ int validateDesk(int desk);
+
+ void renderBackground(int desk);
+ void exportBackground(int pixmap, int desk);
+ int pixmapSize(QPixmap *pm);
+ int cacheSize();
+ void removeCache(int desk);
+ bool freeCache(int size);
+ void addCache(KPixmap *pm, int hash, int desk);
+ void setPixmap(KPixmap *pm, int hash, int desk);
+
+ bool m_bExport, m_bCommon;
+ bool m_bLimitCache, m_bInit;
+ bool m_bBgInitDone;
+ bool m_bEnabled;
+
+ int m_CacheLimit;
+ int m_Serial, m_Hash, m_Current;
+
+ KConfig *m_pConfig;
+ QWidget *m_pDesktop;
+ QTimer *m_pTimer;
+
+ QPtrVector<KVirtualBGRenderer> m_Renderer;
+ QPtrVector<KBackgroundCacheEntry> m_Cache;
+
+ KWinModule *m_pKwinmodule;
+ KPixmapServer *m_pPixmapServer;
+
+ unsigned long m_xrootpmap;
+};
+
+#endif // __BGManager_h_Included__
diff --git a/kdesktop/configure.in.in b/kdesktop/configure.in.in
new file mode 100644
index 000000000..fcc161c1e
--- /dev/null
+++ b/kdesktop/configure.in.in
@@ -0,0 +1,39 @@
+xss_save_ldflags="$LDFLAGS"
+LDFLAGS="$X_LDFLAGS"
+
+LIB_XSS=
+
+AC_ARG_WITH([xscreensaver],
+ AC_HELP_STRING([--without-xscreensaver], [Disable XScreenSaver support (default: check)]) )
+
+if test "x$with_xscreensaver" != "xno"; then
+ KDE_CHECK_HEADER(X11/extensions/scrnsaver.h,
+ [
+ AC_CHECK_LIB(Xext,XScreenSaverQueryInfo,
+ [
+ AC_DEFINE(HAVE_XSCREENSAVER, 1, [Define if you have the XScreenSaver extension])
+ LIB_XSS="-lXext"
+ ],
+ [
+ ld_shared_flag=
+ xss_save_cxxflags="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $lt_prog_compiler_pic_CXX"
+ KDE_CHECK_COMPILER_FLAG(shared, [ld_shared_flag="-shared"])
+ AC_CHECK_LIB(Xss,XScreenSaverQueryInfo,
+ [
+ AC_DEFINE(HAVE_XSCREENSAVER, 1, [Define if you have the XScreenSaver extension])
+ LIB_XSS="-lXss"
+ ],
+ [],
+ [ $ld_shared_flag $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS ])
+ CXXFLAGS="$xss_save_cxxflags"
+ ],
+ [ $X_PRE_LIBS -lX11 $X_EXTRA_LIBS ])
+ ], [],
+ [
+ #include <X11/Xlib.h>
+ ] )
+fi
+
+AC_SUBST(LIB_XSS)
+LDFLAGS="$xss_save_ldflags"
diff --git a/kdesktop/desktop.cc b/kdesktop/desktop.cc
new file mode 100644
index 000000000..6e2b1e9c0
--- /dev/null
+++ b/kdesktop/desktop.cc
@@ -0,0 +1,986 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include "desktop.h"
+#include "krootwm.h"
+#include "bgmanager.h"
+#include "bgsettings.h"
+#include "startupid.h"
+#include "kdiconview.h"
+#include "minicli.h"
+#include "kdesktopsettings.h"
+#include "klaunchsettings.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <kcolordrag.h>
+#include <kurldrag.h>
+
+#include <qdir.h>
+#include <qevent.h>
+#include <qtooltip.h>
+
+#include <netwm.h>
+#include <dcopclient.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kimageio.h>
+#include <kinputdialog.h>
+#include <kipc.h>
+#include <klocale.h>
+#include <kio/netaccess.h>
+#include <kprocess.h>
+#include <ksycoca.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kglobalaccel.h>
+#include <kwinmodule.h>
+#include <krun.h>
+#include <kwin.h>
+#include <kglobalsettings.h>
+#include <kpopupmenu.h>
+#include <kapplication.h>
+// Create the equivalent of KAccelBase::connectItem
+// and then remove this include and fix reconnects in initRoot() -- ellis
+//#include <kaccelbase.h>
+
+extern int kdesktop_screen_number;
+extern QCString kdesktop_name, kicker_name, kwin_name;
+
+KRootWidget::KRootWidget() : QObject()
+{
+ kapp->desktop()->installEventFilter(this);
+ kapp->desktop()->setAcceptDrops( true );
+}
+
+bool KRootWidget::eventFilter ( QObject *, QEvent * e )
+{
+ if (e->type() == QEvent::MouseButtonPress)
+ {
+ QMouseEvent *me = static_cast<QMouseEvent *>(e);
+ KRootWm::self()->mousePressed( me->globalPos(), me->button() );
+ return true;
+ }
+ else if (e->type() == QEvent::Wheel)
+ {
+ QWheelEvent *we = static_cast<QWheelEvent *>(e);
+ emit wheelRolled(we->delta());
+ return true;
+ }
+ else if ( e->type() == QEvent::DragEnter )
+ {
+ QDragEnterEvent* de = static_cast<QDragEnterEvent *>( e );
+ bool b = !KGlobal::config()->isImmutable() && !KGlobal::dirs()->isRestrictedResource( "wallpaper" );
+
+ bool imageURL = false;
+ if ( KURLDrag::canDecode( de ) )
+ {
+ KURL::List list;
+ KURLDrag::decode( de, list );
+ KURL url = list.first();
+ KMimeType::Ptr mime = KMimeType::findByURL( url );
+ if ( !KImageIO::type( url.path() ).isEmpty() ||
+ KImageIO::isSupported( mime->name(), KImageIO::Reading ) || mime->is( "image/svg+xml" ) )
+ imageURL = true;
+ }
+
+ b = b && ( KColorDrag::canDecode( de ) || QImageDrag::canDecode( de ) || imageURL );
+ de->accept( b );
+ return true;
+ }
+ else if ( e->type() == QEvent::Drop )
+ {
+ QDropEvent* de = static_cast<QDropEvent*>( e );
+ if ( KColorDrag::canDecode( de ) )
+ emit colorDropEvent( de );
+ else if ( QImageDrag::canDecode( de ) )
+ emit imageDropEvent( de );
+ else if ( KURLDrag::canDecode( de ) ) {
+ KURL::List list;
+ KURLDrag::decode( de, list );
+ KURL url = list.first();
+ emit newWallpaper( url );
+ }
+ return true;
+ }
+ return false; // Don't filter.
+}
+
+// -----------------------------------------------------------------------------
+#define DEFAULT_DELETEACTION 1
+
+KDesktop::WheelDirection KDesktop::m_eWheelDirection = KDesktop::m_eDefaultWheelDirection;
+const char* KDesktop::m_wheelDirectionStrings[2] = { "Forward", "Reverse" };
+
+KDesktop::KDesktop( bool x_root_hack, bool wait_for_kded ) :
+ DCOPObject( "KDesktopIface" ),
+ QWidget( 0L, "desktop", WResizeNoErase | ( x_root_hack ? (WStyle_Customize | WStyle_NoBorder) : 0) ),
+ // those two WStyle_ break kdesktop when the root-hack isn't used (no Dnd)
+ startup_id( NULL ), m_waitForKicker(0)
+{
+ m_bWaitForKded = wait_for_kded;
+ m_miniCli = 0; // created on demand
+ keys = 0; // created later
+ KGlobal::locale()->insertCatalogue("kdesktop");
+ KGlobal::locale()->insertCatalogue("libkonq"); // needed for apps using libkonq
+ KGlobal::locale()->insertCatalogue("libdmctl");
+
+ setCaption( "KDE Desktop");
+
+ setAcceptDrops(true); // WStyle_Customize seems to disable that
+ m_pKwinmodule = new KWinModule( this );
+
+ kapp->dcopClient()->setNotifications(true);
+ kapp->dcopClient()->connectDCOPSignal(kicker_name, kicker_name, "desktopIconsAreaChanged(QRect, int)",
+ "KDesktopIface", "desktopIconsAreaChanged(QRect, int)", false);
+
+ // Dont repaint on configuration changes during construction
+ m_bInit = true;
+
+ // It's the child widget that gets the focus, not us
+ setFocusPolicy( NoFocus );
+
+ if ( x_root_hack )
+ {
+ // this is a ugly hack to make Dnd work
+ // Matthias told me that it won't be necessary with kwin
+ // actually my first try with ICCCM (Dirk) :-)
+ unsigned long data[2];
+ data[0] = (unsigned long) 1;
+ data[1] = (unsigned long) 0; // None; (Werner)
+ Atom wm_state = XInternAtom(qt_xdisplay(), "WM_STATE", False);
+ XChangeProperty(qt_xdisplay(), winId(), wm_state, wm_state, 32,
+ PropModeReplace, (unsigned char *)data, 2);
+
+ }
+
+ setGeometry( QApplication::desktop()->geometry() );
+ lower();
+
+ connect( kapp, SIGNAL( shutDown() ),
+ this, SLOT( slotShutdown() ) );
+
+ connect(kapp, SIGNAL(settingsChanged(int)),
+ this, SLOT(slotSettingsChanged(int)));
+ kapp->addKipcEventMask(KIPC::SettingsChanged);
+
+ kapp->addKipcEventMask(KIPC::IconChanged);
+ connect(kapp, SIGNAL(iconChanged(int)), this, SLOT(slotIconChanged(int)));
+
+ connect(KSycoca::self(), SIGNAL(databaseChanged()),
+ this, SLOT(slotDatabaseChanged()));
+
+ m_pIconView = 0;
+ m_pRootWidget = 0;
+ bgMgr = 0;
+ initRoot();
+
+ QTimer::singleShot(0, this, SLOT( slotStart() ));
+
+#if (QT_VERSION-0 >= 0x030200) // XRANDR support
+ connect( kapp->desktop(), SIGNAL( resized( int )), SLOT( desktopResized()));
+#endif
+}
+
+void
+KDesktop::initRoot()
+{
+ Display *dpy = qt_xdisplay();
+ Window root = RootWindow(dpy, kdesktop_screen_number);
+ XDefineCursor(dpy, root, cursor().handle());
+
+ m_bDesktopEnabled = KDesktopSettings::desktopEnabled();
+ if ( !m_bDesktopEnabled && !m_pRootWidget )
+ {
+ hide();
+ delete bgMgr;
+ bgMgr = 0;
+ if ( m_pIconView )
+ m_pIconView->saveIconPositions();
+ delete m_pIconView;
+ m_pIconView = 0;
+
+ { // trigger creation of QToolTipManager, it does XSelectInput() on the root window
+ QWidget w;
+ QToolTip::add( &w, "foo" );
+ }
+ // NOTE: If mouse clicks stop working again, it's most probably something doing XSelectInput()
+ // on the root window after this, and setting it to some fixed value instead of adding its mask.
+ XWindowAttributes attrs;
+ XGetWindowAttributes(dpy, root, &attrs);
+ XSelectInput(dpy, root, attrs.your_event_mask | ButtonPressMask);
+
+ m_pRootWidget = new KRootWidget;
+ connect(m_pRootWidget, SIGNAL(wheelRolled(int)), this, SLOT(slotSwitchDesktops(int)));
+ connect(m_pRootWidget, SIGNAL(colorDropEvent(QDropEvent*)), this, SLOT(handleColorDropEvent(QDropEvent*)) );
+ connect(m_pRootWidget, SIGNAL(imageDropEvent(QDropEvent*)), this, SLOT(handleImageDropEvent(QDropEvent*)) );
+ connect(m_pRootWidget, SIGNAL(newWallpaper(const KURL&)), this, SLOT(slotNewWallpaper(const KURL&)) );
+
+ // Geert Jansen: backgroundmanager belongs here
+ // TODO tell KBackgroundManager if we change widget()
+ bgMgr = new KBackgroundManager( m_pIconView, m_pKwinmodule );
+ bgMgr->setExport(1);
+ connect( bgMgr, SIGNAL( initDone()), SLOT( backgroundInitDone()));
+ if (!m_bInit)
+ {
+ delete KRootWm::self();
+ KRootWm* krootwm = new KRootWm( this ); // handler for root menu (used by kdesktop on RMB click)
+ keys->setSlot("Lock Session", krootwm, SLOT(slotLock()));
+ keys->updateConnections();
+ }
+ }
+ else if (m_bDesktopEnabled && !m_pIconView)
+ {
+ delete bgMgr;
+ bgMgr = 0;
+ delete m_pRootWidget;
+ m_pRootWidget = 0;
+ m_pIconView = new KDIconView( this, 0 );
+ connect( m_pIconView, SIGNAL( imageDropEvent( QDropEvent * ) ),
+ this, SLOT( handleImageDropEvent( QDropEvent * ) ) );
+ connect( m_pIconView, SIGNAL( colorDropEvent( QDropEvent * ) ),
+ this, SLOT( handleColorDropEvent( QDropEvent * ) ) );
+ connect( m_pIconView, SIGNAL( newWallpaper( const KURL & ) ),
+ this, SLOT( slotNewWallpaper( const KURL & ) ) );
+ connect( m_pIconView, SIGNAL( wheelRolled( int ) ),
+ this, SLOT( slotSwitchDesktops( int ) ) );
+
+ // All the QScrollView/QWidget-specific stuff should go here, so that we can use
+ // another qscrollview/widget instead of the iconview and use the same code
+ m_pIconView->setVScrollBarMode( QScrollView::AlwaysOff );
+ m_pIconView->setHScrollBarMode( QScrollView::AlwaysOff );
+ m_pIconView->setDragAutoScroll( false );
+ m_pIconView->setFrameStyle( QFrame::NoFrame );
+ m_pIconView->viewport()->setBackgroundMode( X11ParentRelative );
+ m_pIconView->setFocusPolicy( StrongFocus );
+ m_pIconView->viewport()->setFocusPolicy( StrongFocus );
+ m_pIconView->setGeometry( geometry() );
+ m_pIconView->show();
+
+ // Geert Jansen: backgroundmanager belongs here
+ // TODO tell KBackgroundManager if we change widget()
+ bgMgr = new KBackgroundManager( m_pIconView, m_pKwinmodule );
+ bgMgr->setExport(1);
+ connect( bgMgr, SIGNAL( initDone()), SLOT( backgroundInitDone()));
+
+ // make sure it is initialized before we first call updateWorkArea()
+ m_pIconView->initConfig( m_bInit );
+
+ // set the size of the area for desktop icons placement
+ {
+ QByteArray data, result;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << kdesktop_screen_number;
+ QCString replyType;
+ QRect area;
+
+ if ( kapp->dcopClient()->call(kicker_name, kicker_name, "desktopIconsArea(int)",
+ data, replyType, result, false, 2000) )
+ {
+ QDataStream res(result, IO_ReadOnly);
+ res >> area;
+
+ m_pIconView->updateWorkArea(area);
+ }
+ else
+ if ( m_bInit )
+ {
+ // if we failed to get the information from kicker wait a little - probably
+ // this is the KDE startup and kicker is simply not running yet
+ m_waitForKicker = new QTimer(this);
+ connect(m_waitForKicker, SIGNAL(timeout()), this, SLOT(slotNoKicker()));
+ m_waitForKicker->start(15000, true);
+ }
+ else // we are not called from the ctor, so kicker should already run
+ {
+ area = kwinModule()->workArea(kwinModule()->currentDesktop());
+ m_pIconView->updateWorkArea(area);
+ }
+ }
+
+ if (!m_bInit)
+ {
+ m_pIconView->start();
+ delete KRootWm::self();
+ KRootWm* krootwm = new KRootWm( this ); // handler for root menu (used by kdesktop on RMB click)
+ keys->setSlot("Lock Session", krootwm, SLOT(slotLock()));
+ keys->updateConnections();
+ }
+ } else {
+ DCOPRef r( "ksmserver", "ksmserver" );
+ r.send( "resumeStartup", QCString( "kdesktop" ));
+ }
+
+ KWin::setType( winId(), NET::Desktop );
+ KWin::setState( winId(), NET::SkipPager );
+ KWin::setOnAllDesktops( winId(), true );
+}
+
+void KDesktop::slotNoKicker()
+{
+ kdDebug(1204) << "KDesktop::slotNoKicker ... kicker did not respond" << endl;
+ // up till now, we got no desktopIconsArea from kicker - probably
+ // it's not running, so use the area from KWinModule
+ m_pIconView->updateWorkArea(kwinModule()->workArea(kwinModule()->currentDesktop()));
+}
+
+void
+KDesktop::backgroundInitDone()
+{
+ //kdDebug(1204) << "KDesktop::backgroundInitDone" << endl;
+ // avoid flicker
+ if (m_bDesktopEnabled)
+ {
+ const QPixmap *bg = QApplication::desktop()->screen()->backgroundPixmap();
+ if ( bg )
+ m_pIconView->setErasePixmap( *bg );
+
+ show();
+ kapp->sendPostedEvents();
+ }
+
+ DCOPRef r( "ksmserver", "ksmserver" );
+ r.send( "resumeStartup", QCString( "kdesktop" ));
+}
+
+void
+KDesktop::slotStart()
+{
+ //kdDebug(1204) << "KDesktop::slotStart" << endl;
+ if (!m_bInit) return;
+
+ // In case we started without database
+ KImageIO::registerFormats();
+
+ initConfig();
+
+// if (m_bDesktopEnabled)
+// {
+// // We need to be visible in order to insert icons, even if the background isn't ready yet...
+
+// show();
+// }
+
+ // Now we may react to configuration changes
+ m_bInit = false;
+
+ if (m_pIconView)
+ m_pIconView->start();
+
+ // Global keys
+ keys = new KGlobalAccel( this );
+ (void) new KRootWm( this );
+
+#include "kdesktopbindings.cpp"
+
+ keys->readSettings();
+ keys->updateConnections();
+
+ connect(kapp, SIGNAL(appearanceChanged()), SLOT(slotConfigure()));
+
+ QTimer::singleShot(300, this, SLOT( slotUpAndRunning() ));
+}
+
+void
+KDesktop::runAutoStart()
+{
+ // now let's execute all the stuff in the autostart folder.
+ // the stuff will actually be really executed when the event loop is
+ // entered, since KRun internally uses a QTimer
+ QDir dir( KGlobalSettings::autostartPath() );
+ QStringList entries = dir.entryList( QDir::Files );
+ QStringList::Iterator it = entries.begin();
+ QStringList::Iterator end = entries.end();
+ for (; it != end; ++it )
+ {
+ // Don't execute backup files
+ if ( (*it).right(1) != "~" && (*it).right(4) != ".bak" &&
+ ( (*it)[0] != '%' || (*it).right(1) != "%" ) &&
+ ( (*it)[0] != '#' || (*it).right(1) != "#" ) )
+ {
+ KURL url;
+ url.setPath( dir.absPath() + '/' + (*it) );
+ (void) new KRun( url, 0, true );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+KDesktop::~KDesktop()
+{
+ delete m_miniCli;
+ m_miniCli = 0; // see #120382
+ delete bgMgr;
+ bgMgr = 0;
+ delete startup_id;
+}
+
+// -----------------------------------------------------------------------------
+
+void KDesktop::initConfig()
+{
+ if (m_pIconView)
+ m_pIconView->initConfig( m_bInit );
+
+ if ( keys )
+ {
+ keys->readSettings();
+ keys->updateConnections();
+ }
+
+ KLaunchSettings::self()->readConfig();
+ if( !KLaunchSettings::busyCursor() )
+ {
+ delete startup_id;
+ startup_id = NULL;
+ }
+ else
+ {
+ if( startup_id == NULL )
+ startup_id = new StartupId;
+ startup_id->configure();
+ }
+
+ set_vroot = KDesktopSettings::setVRoot();
+ slotSetVRoot(); // start timer
+
+ m_bWheelSwitchesWorkspace = KDesktopSettings::wheelSwitchesWorkspace();
+
+ const char* forward_string = m_wheelDirectionStrings[Forward];
+ m_eWheelDirection =
+ (KDesktopSettings::wheelDirection() == forward_string) ? Forward : Reverse;
+}
+
+// -----------------------------------------------------------------------------
+
+void KDesktop::slotExecuteCommand()
+{
+ // this function needs to be duplicated since it appears that one
+ // cannot have a 'slot' be a DCOP method. if this changes in the
+ // future, then 'slotExecuteCommand' and 'popupExecuteCommand' can
+ // merge into one slot.
+ popupExecuteCommand();
+}
+
+/*
+ Shows minicli
+ */
+void KDesktop::popupExecuteCommand()
+{
+ popupExecuteCommand("");
+}
+
+void KDesktop::popupExecuteCommand(const QString& command)
+{
+ if (m_bInit)
+ return;
+
+ if (!kapp->authorize("run_command"))
+ return;
+
+ // Created on demand
+ if ( !m_miniCli )
+ {
+ m_miniCli = new Minicli( this );
+ m_miniCli->adjustSize(); // for the centering below
+ }
+
+ if (!command.isEmpty())
+ m_miniCli->setCommand(command);
+
+ // Move minicli to the current desktop
+ NETWinInfo info( qt_xdisplay(), m_miniCli->winId(), qt_xrootwin(), NET::WMDesktop );
+ int currentDesktop = kwinModule()->currentDesktop();
+ if ( info.desktop() != currentDesktop )
+ info.setDesktop( currentDesktop );
+
+ if ( m_miniCli->isVisible() ) {
+ KWin::forceActiveWindow( m_miniCli->winId() );
+ } else {
+ QRect rect = KGlobalSettings::desktopGeometry(QCursor::pos());
+ m_miniCli->move(rect.x() + (rect.width() - m_miniCli->width())/2,
+ rect.y() + (rect.height() - m_miniCli->height())/2);
+ m_miniCli->show(); // non-modal
+ }
+}
+
+void KDesktop::slotSwitchUser()
+{
+ KRootWm::self()->slotSwitchUser();
+}
+
+void KDesktop::slotShowWindowList()
+{
+ KRootWm::self()->slotWindowList();
+}
+
+void KDesktop::slotShowTaskManager()
+{
+ //kdDebug(1204) << "Launching KSysGuard..." << endl;
+ KProcess* p = new KProcess;
+ Q_CHECK_PTR(p);
+
+ *p << "ksysguard";
+ *p << "--showprocesses";
+
+ p->start(KProcess::DontCare);
+
+ delete p;
+}
+
+// -----------------------------------------------------------------------------
+
+void KDesktop::rearrangeIcons()
+{
+ if (m_pIconView)
+ m_pIconView->rearrangeIcons();
+}
+
+void KDesktop::lineupIcons()
+{
+ if (m_pIconView)
+ m_pIconView->lineupIcons();
+}
+
+void KDesktop::selectAll()
+{
+ if (m_pIconView)
+ m_pIconView->selectAll( true );
+}
+
+void KDesktop::unselectAll()
+{
+ if (m_pIconView)
+ m_pIconView->selectAll( false );
+}
+
+QStringList KDesktop::selectedURLs()
+{
+ if (m_pIconView)
+ return m_pIconView->selectedURLs();
+ return QStringList();
+}
+
+void KDesktop::refreshIcons()
+{
+ if (m_pIconView)
+ m_pIconView->refreshIcons();
+}
+
+KActionCollection * KDesktop::actionCollection()
+{
+ if (!m_pIconView)
+ return 0;
+ return m_pIconView->actionCollection();
+}
+
+KURL KDesktop::url() const
+{
+ if (m_pIconView)
+ return m_pIconView->url();
+ return KURL();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDesktop::slotConfigure()
+{
+ configure();
+}
+
+void KDesktop::configure()
+{
+ // re-read configuration and apply it
+ KGlobal::config()->reparseConfiguration();
+ KDesktopSettings::self()->readConfig();
+
+ // If we have done start() already, then re-configure.
+ // Otherwise, start() will call initConfig anyway
+ if (!m_bInit)
+ {
+ initRoot();
+ initConfig();
+ KRootWm::self()->initConfig();
+ }
+
+ if (keys)
+ {
+ keys->readSettings();
+ keys->updateConnections();
+ }
+}
+
+void KDesktop::slotSettingsChanged(int category)
+{
+ //kdDebug(1204) << "KDesktop::slotSettingsChanged" << endl;
+ if (category == KApplication::SETTINGS_PATHS)
+ {
+ kdDebug(1204) << "KDesktop::slotSettingsChanged SETTINGS_PATHS" << endl;
+ if (m_pIconView)
+ m_pIconView->recheckDesktopURL();
+ }
+ else if (category == KApplication::SETTINGS_SHORTCUTS)
+ {
+ kdDebug(1204) << "KDesktop::slotSettingsChanged SETTINGS_SHORTCUTS" << endl;
+ keys->readSettings();
+ keys->updateConnections();
+ }
+}
+
+void KDesktop::slotIconChanged(int group)
+{
+ if ( group == KIcon::Desktop )
+ {
+ kdDebug(1204) << "KDesktop::slotIconChanged" << endl;
+ refresh();
+ }
+}
+
+void KDesktop::slotDatabaseChanged()
+{
+ //kdDebug(1204) << "KDesktop::slotDatabaseChanged" << endl;
+ if (m_bInit) // kded is done, now we can "start" for real
+ slotStart();
+ if (m_pIconView && KSycoca::isChanged("mimetypes"))
+ m_pIconView->refreshMimeTypes();
+}
+
+void KDesktop::refresh()
+{
+ // George Staikos 3/14/01
+ // This bit will just refresh the desktop and icons. Now I have code
+ // in KWin to do a complete refresh so this isn't really needed.
+ // I'll leave it in here incase the plan is changed again
+#if 0
+ m_bNeedRepaint |= 1;
+ updateWorkArea();
+#endif
+ kapp->dcopClient()->send( kwin_name, "", "refresh()", "");
+ refreshIcons();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDesktop::slotSetVRoot()
+{
+ if (!m_pIconView)
+ return;
+
+ if (KWin::windowInfo(winId()).mappingState() == NET::Withdrawn) {
+ QTimer::singleShot(100, this, SLOT(slotSetVRoot()));
+ return;
+ }
+
+ unsigned long rw = RootWindowOfScreen(ScreenOfDisplay(qt_xdisplay(), qt_xscreen()));
+ unsigned long vroot_data[1] = { m_pIconView->viewport()->winId() };
+ static Atom vroot = XInternAtom(qt_xdisplay(), "__SWM_VROOT", False);
+
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ Window top = winId();
+ while (1) {
+ /*int ret = */XQueryTree(qt_xdisplay(), top , &rootReturn, &parentReturn,
+ &children, &numChildren);
+ if (children)
+ XFree((char *)children);
+ if (parentReturn == rw) {
+ break;
+ } else
+ top = parentReturn;
+ }
+ if ( set_vroot )
+ XChangeProperty(qt_xdisplay(), top, vroot, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+ else
+ XDeleteProperty (qt_xdisplay(), top, vroot);
+}
+
+// -----------------------------------------------------------------------------
+
+void KDesktop::slotShutdown()
+{
+ if ( m_pIconView )
+ m_pIconView->saveIconPositions();
+ if ( m_miniCli )
+ m_miniCli->saveConfig();
+}
+
+// don't hide when someone presses Alt-F4 on us
+void KDesktop::closeEvent(QCloseEvent *e)
+{
+ e->ignore();
+}
+
+void KDesktop::desktopIconsAreaChanged(const QRect &area, int screen)
+{
+ // hurra! kicker is alive
+ if ( m_waitForKicker ) m_waitForKicker->stop();
+
+ // -2: all screens
+ // -1: primary screen
+ // else: screen number
+
+ if (screen <= -2)
+ screen = kdesktop_screen_number;
+ else if (screen == -1)
+ screen = kapp->desktop()->primaryScreen();
+
+ // This is pretty broken, mixes Xinerama and non-Xinerama multihead
+ // and generally doesn't seem to be required anyway => ignore screen.
+ if ( /*(screen == kdesktop_screen_number) &&*/ m_pIconView )
+ m_pIconView->updateWorkArea(area);
+}
+
+void KDesktop::slotSwitchDesktops(int delta)
+{
+ if(m_bWheelSwitchesWorkspace && KWin::numberOfDesktops() > 1)
+ {
+ int newDesk, curDesk = KWin::currentDesktop();
+
+ if( (delta < 0 && m_eWheelDirection == Forward) || (delta > 0 && m_eWheelDirection == Reverse) )
+ newDesk = curDesk % KWin::numberOfDesktops() + 1;
+ else
+ newDesk = ( KWin::numberOfDesktops() + curDesk - 2 ) % KWin::numberOfDesktops() + 1;
+
+ KWin::setCurrentDesktop( newDesk );
+ }
+}
+
+void KDesktop::handleColorDropEvent(QDropEvent * e)
+{
+ KPopupMenu popup;
+ popup.insertItem(SmallIconSet("colors"),i18n("Set as Primary Background Color"), 1);
+ popup.insertItem(SmallIconSet("colors"),i18n("Set as Secondary Background Color"), 2);
+ int result = popup.exec(e->pos());
+
+ QColor c;
+ KColorDrag::decode(e, c);
+ switch (result) {
+ case 1: bgMgr->setColor(c, true); break;
+ case 2: bgMgr->setColor(c, false); break;
+ default: return;
+ }
+ bgMgr->setWallpaper(0,0);
+}
+
+void KDesktop::handleImageDropEvent(QDropEvent * e)
+{
+ KPopupMenu popup;
+ if ( m_pIconView )
+ popup.insertItem(SmallIconSet("filesave"),i18n("&Save to Desktop..."), 1);
+ if ( ( m_pIconView && m_pIconView->maySetWallpaper() ) || m_pRootWidget )
+ popup.insertItem(SmallIconSet("background"),i18n("Set as &Wallpaper"), 2);
+ popup.insertSeparator();
+ popup.insertItem(SmallIconSet("cancel"), i18n("&Cancel"));
+ int result = popup.exec(e->pos());
+
+ if (result == 1)
+ {
+ bool ok = true;
+ QString filename = KInputDialog::getText(QString::null, i18n("Enter a name for the image below:"), QString::null, &ok, m_pIconView);
+
+ if (!ok)
+ {
+ return;
+ }
+
+ if (filename.isEmpty())
+ {
+ filename = i18n("image.png");
+ }
+ else if (filename.right(4).lower() != ".png")
+ {
+ filename += ".png";
+ }
+
+ QImage i;
+ QImageDrag::decode(e, i);
+ KTempFile tmpFile(QString::null, filename);
+ i.save(tmpFile.name(), "PNG");
+ // We pass 0 as parent window because passing the desktop is not a good idea
+ KURL src;
+ src.setPath( tmpFile.name() );
+ KURL dest( KDIconView::desktopURL() );
+ dest.addPath( filename );
+ KIO::NetAccess::copy( src, dest, 0 );
+ tmpFile.unlink();
+ }
+ else if (result == 2)
+ {
+ QImage i;
+ QImageDrag::decode(e, i);
+ KTempFile tmpFile(KGlobal::dirs()->saveLocation("wallpaper"), ".png");
+ i.save(tmpFile.name(), "PNG");
+ kdDebug(1204) << "KDesktop::contentsDropEvent " << tmpFile.name() << endl;
+ bgMgr->setWallpaper(tmpFile.name());
+ }
+}
+
+void KDesktop::slotNewWallpaper(const KURL &url)
+{
+ // This is called when a file containing an image is dropped
+ // (called by KonqOperations)
+ if ( url.isLocalFile() )
+ bgMgr->setWallpaper( url.path() );
+ else
+ {
+ // Figure out extension
+ QString fileName = url.fileName();
+ QFileInfo fileInfo( fileName );
+ QString ext = fileInfo.extension();
+ // Store tempfile in a place where it will still be available after a reboot
+ KTempFile tmpFile( KGlobal::dirs()->saveLocation("wallpaper"), "." + ext );
+ KURL localURL; localURL.setPath( tmpFile.name() );
+ // We pass 0 as parent window because passing the desktop is not a good idea
+ KIO::NetAccess::file_copy( url, localURL, -1, true /*overwrite*/ );
+ bgMgr->setWallpaper( localURL.path() );
+ }
+}
+
+// for dcop interface backward compatibility
+void KDesktop::logout()
+{
+ logout( KApplication::ShutdownConfirmDefault,
+ KApplication::ShutdownTypeNone );
+}
+
+void KDesktop::logout( KApplication::ShutdownConfirm confirm,
+ KApplication::ShutdownType sdtype )
+{
+ if( !kapp->requestShutDown( confirm, sdtype ) )
+ // this i18n string is also in kicker/applets/run/runapplet
+ KMessageBox::error( this, i18n("Could not log out properly.\nThe session manager cannot "
+ "be contacted. You can try to force a shutdown by pressing "
+ "Ctrl+Alt+Backspace; note, however, that your current session "
+ "will not be saved with a forced shutdown." ) );
+}
+
+void KDesktop::slotLogout()
+{
+ logout( KApplication::ShutdownConfirmDefault,
+ KApplication::ShutdownTypeDefault );
+}
+
+void KDesktop::slotLogoutNoCnf()
+{
+ logout( KApplication::ShutdownConfirmNo,
+ KApplication::ShutdownTypeNone );
+}
+
+void KDesktop::slotHaltNoCnf()
+{
+ logout( KApplication::ShutdownConfirmNo,
+ KApplication::ShutdownTypeHalt );
+}
+
+void KDesktop::slotRebootNoCnf()
+{
+ logout( KApplication::ShutdownConfirmNo,
+ KApplication::ShutdownTypeReboot );
+}
+
+void KDesktop::setVRoot( bool enable )
+{
+ if ( enable == set_vroot )
+ return;
+
+ set_vroot = enable;
+ kdDebug(1204) << "setVRoot " << enable << endl;
+ KDesktopSettings::setSetVRoot( set_vroot );
+ KDesktopSettings::writeConfig();
+ slotSetVRoot();
+}
+
+void KDesktop::clearCommandHistory()
+{
+ if ( m_miniCli )
+ m_miniCli->clearHistory();
+}
+
+void KDesktop::setIconsEnabled( bool enable )
+{
+ if ( enable == m_bDesktopEnabled )
+ return;
+
+ m_bDesktopEnabled = enable;
+ kdDebug(1204) << "setIcons " << enable << endl;
+ KDesktopSettings::setDesktopEnabled( m_bDesktopEnabled );
+ KDesktopSettings::writeConfig();
+ if (!enable) {
+ delete m_pIconView;
+ m_pIconView = 0;
+ }
+ configure();
+}
+
+void KDesktop::desktopResized()
+{
+ resize(kapp->desktop()->size());
+
+ if ( m_pIconView )
+ {
+ // the sequence of actions is important:
+ // remove all icons, resize desktop, tell kdiconview new iconsArea size
+ // tell kdiconview to reget all icons
+ m_pIconView->slotClear();
+ m_pIconView->resize(kapp->desktop()->size());
+
+ // get new desktopIconsArea from kicker
+ QByteArray data, result;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << kdesktop_screen_number;
+ QCString replyType;
+ QRect area;
+
+ if ( kapp->dcopClient()->call(kicker_name, kicker_name, "desktopIconsArea(int)",
+ data, replyType, result, false, 2000) )
+ {
+ QDataStream res(result, IO_ReadOnly);
+ res >> area;
+ }
+ else
+ area = kwinModule()->workArea(kwinModule()->currentDesktop());
+
+ m_pIconView->updateWorkArea(area);
+ m_pIconView->startDirLister();
+ }
+}
+
+void KDesktop::switchDesktops( int delta )
+{
+ bool old = m_bWheelSwitchesWorkspace;
+ m_bWheelSwitchesWorkspace = true;
+ slotSwitchDesktops(delta);
+ m_bWheelSwitchesWorkspace = old;
+}
+
+bool KDesktop::event(QEvent * e)
+{
+ if ( e->type() == QEvent::WindowDeactivate)
+ {
+ if (m_pIconView)
+ m_pIconView->clearSelection();
+ }
+ return QWidget::event(e);
+}
+
+#include "desktop.moc"
diff --git a/kdesktop/desktop.h b/kdesktop/desktop.h
new file mode 100644
index 000000000..0407fbe4f
--- /dev/null
+++ b/kdesktop/desktop.h
@@ -0,0 +1,212 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __desktop_h__
+#define __desktop_h__
+
+#include "KDesktopIface.h"
+
+#include <qwidget.h>
+#include <qstringlist.h>
+
+#include <kapplication.h> // for logout parameters
+
+class KURL;
+class QCloseEvent;
+class QDropEvent;
+class QPopupMenu;
+class KGlobalAccel;
+class KWinModule;
+class KBackgroundManager;
+class QTimer;
+class StartupId;
+class KDIconView;
+class Minicli;
+class KActionCollection;
+
+class KRootWidget : public QObject
+{
+ Q_OBJECT
+public:
+ KRootWidget();
+ bool eventFilter( QObject *, QEvent * e );
+signals:
+ void wheelRolled( int delta );
+ void colorDropEvent( QDropEvent* e );
+ void imageDropEvent( QDropEvent* e );
+ void newWallpaper( const KURL& url );
+};
+
+/**
+ * KDesktop is the toplevel widget that is the desktop.
+ * It handles the background, the screensaver and all the rest of the global stuff.
+ * The icon view is a child widget of KDesktop.
+ */
+class KDesktop : public QWidget, virtual public KDesktopIface
+{
+ Q_OBJECT
+
+public:
+
+ enum WheelDirection { Forward = 0, Reverse };
+
+ KDesktop(bool x_root_hack, bool wait_for_kded );
+ ~KDesktop();
+
+ // Implementation of the DCOP interface
+ virtual void rearrangeIcons();
+ virtual void lineupIcons();
+ virtual void selectAll();
+ virtual void unselectAll();
+ virtual void refreshIcons();
+ virtual QStringList selectedURLs();
+
+ virtual void configure();
+ virtual void popupExecuteCommand();
+ virtual void popupExecuteCommand(const QString& content);
+ virtual void refresh();
+ virtual void logout();
+ virtual void clearCommandHistory();
+ virtual void runAutoStart();
+
+ virtual void switchDesktops( int delta );
+
+ virtual void desktopIconsAreaChanged(const QRect &area, int screen);
+
+ void logout( KApplication::ShutdownConfirm confirm, KApplication::ShutdownType sdtype );
+
+ KWinModule* kwinModule() const { return m_pKwinmodule; }
+
+ // The action collection of the active widget
+ KActionCollection *actionCollection();
+
+ // The URL (for the File/New menu)
+ KURL url() const;
+
+ // ## hack ##
+ KDIconView *iconView() const { return m_pIconView; }
+
+private slots:
+ /** Background is ready. */
+ void backgroundInitDone();
+
+ /** Activate the desktop. */
+ void slotStart();
+
+ /** Activate crash recovery. */
+ void slotUpAndRunning();
+
+ /** Reconfigures */
+ void slotConfigure();
+
+ /** Show minicli,. the KDE command line interface */
+ void slotExecuteCommand();
+
+ /** Show taskmanager (calls KSysGuard with --showprocesses option) */
+ void slotShowTaskManager();
+
+ void slotShowWindowList();
+
+ void slotSwitchUser();
+
+ void slotLogout();
+ void slotLogoutNoCnf();
+ void slotHaltNoCnf();
+ void slotRebootNoCnf();
+
+ /** Connected to KSycoca */
+ void slotDatabaseChanged();
+
+ void slotShutdown();
+ void slotSettingsChanged(int);
+ void slotIconChanged(int);
+
+ /** set the vroot atom for e.g. xsnow */
+ void slotSetVRoot();
+
+ /** Connected to KDIconView */
+ void handleImageDropEvent( QDropEvent * );
+ void handleColorDropEvent( QDropEvent * );
+ void slotNewWallpaper(const KURL &url);
+
+ /** Connected to KDIconView and KRootWidget */
+ void slotSwitchDesktops(int delta);
+
+ // when there seems to be no kicker, we have to get desktopIconsArea from kwinModule
+ void slotNoKicker();
+
+protected:
+ void initConfig();
+ void initRoot();
+
+ virtual void closeEvent(QCloseEvent *e);
+
+ virtual bool isVRoot() { return set_vroot; }
+ virtual void setVRoot( bool enable );
+
+ virtual bool isIconsEnabled() { return m_bDesktopEnabled; }
+ virtual void setIconsEnabled( bool enable );
+ virtual bool event ( QEvent * e );
+
+private slots:
+ void desktopResized();
+
+private:
+
+ KGlobalAccel *keys;
+
+ KWinModule* m_pKwinmodule;
+
+ KBackgroundManager* bgMgr;
+
+ KDIconView *m_pIconView;
+ KRootWidget *m_pRootWidget;
+
+ Minicli *m_miniCli;
+
+ StartupId* startup_id;
+ bool set_vroot;
+
+ /** Set to true until start() has been called */
+ bool m_bInit;
+
+ /** Wait for kded to finish building database? */
+ bool m_bWaitForKded;
+
+ /** Desktop enabled / disabled **/
+ bool m_bDesktopEnabled;
+
+ /** Whether or not to switch desktops when mouse wheel is rolled */
+ bool m_bWheelSwitchesWorkspace;
+
+ QTimer *m_waitForKicker;
+
+ /** Default mouse wheel direction (Fwd means mwheel up switches to
+ lower desktop)
+ */
+ static const WheelDirection m_eDefaultWheelDirection = Forward;
+
+ /** Mouse wheel/desktop switching direction */
+ static WheelDirection m_eWheelDirection;
+
+ /** Possible values for "kdesktoprc"->"Mouse Buttons"->"WheelDirection" */
+ static const char* m_wheelDirectionStrings[2];
+};
+
+#endif
diff --git a/kdesktop/init.cc b/kdesktop/init.cc
new file mode 100644
index 000000000..c0c2502d5
--- /dev/null
+++ b/kdesktop/init.cc
@@ -0,0 +1,247 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <kstandarddirs.h>
+#include <kdesktopfile.h>
+#include <kglobalsettings.h>
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kdesktopsettings.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ksimpleconfig.h>
+
+// for multihead
+extern int kdesktop_screen_number;
+
+
+/**
+ * Test if a directory exists, create otherwise
+ * @param _name full path of the directory
+ * @param _showMsg show a message box if we created the dir
+ * @return true if the dir was just created (e.g. so that we can populate it)
+ */
+static bool testDir( const QString &_name )
+{
+ DIR *dp;
+ dp = opendir( QFile::encodeName(_name) );
+ if ( dp == NULL )
+ {
+ QString m = _name;
+ if ( m.endsWith( "/" ) )
+ m.truncate( m.length() - 1 );
+ QCString path = QFile::encodeName(m);
+
+ bool ok = ::mkdir( path, S_IRWXU ) == 0;
+ if ( !ok && errno == EEXIST ) {
+ int ret = KMessageBox::warningYesNo( 0, i18n("%1 is a file, but KDE needs it to be a directory; move it to %2.orig and create directory?").arg(m).arg(m), QString::null, i18n("Move It"), i18n("Do Not Move") );
+ if ( ret == KMessageBox::Yes ) {
+ if ( ::rename( path, path + ".orig" ) == 0 ) {
+ ok = ::mkdir( path, S_IRWXU ) == 0;
+ } else {
+ // foo.orig existed already. How likely is that?
+ ok = false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if ( !ok )
+ {
+ KMessageBox::sorry( 0, i18n( "Could not create directory %1; check for permissions or reconfigure the desktop to use another path." ).arg( m ) );
+ return false;
+ }
+ return true;
+ }
+ else // exists already
+ {
+ closedir( dp );
+ return false;
+ }
+}
+
+/**
+ * Copy a standard .directory file to a user's directory
+ * @param fileName destination file name
+ * @param dir destination directory
+ * @param force if false, don't copy if destination file already exists
+ */
+static void copyDirectoryFile(const QString &fileName, const QString& dir, bool force)
+{
+ if (force || !QFile::exists(dir + "/.directory")) {
+ QString cmd = "cp ";
+ cmd += KProcess::quote(locate("data", QString("kdesktop/") + fileName));
+ cmd += " ";
+ cmd += KProcess::quote(dir+"/.directory");
+ system( QFile::encodeName(cmd) );
+ }
+}
+
+static void copyFile( const QString& src, const QString& dest )
+{
+ QCString cmd = "cp ";
+ cmd += QFile::encodeName(KProcess::quote(src));
+ cmd += " ";
+ cmd += QFile::encodeName(KProcess::quote(dest));
+ system( cmd );
+}
+
+static QString realDesktopPath()
+{
+ QString desktopPath = KGlobalSettings::desktopPath();
+ if (kdesktop_screen_number != 0) {
+ QString dn = "Desktop";
+ dn += QString::number(kdesktop_screen_number);
+ desktopPath.replace("Desktop", dn);
+ }
+ return desktopPath;
+}
+
+/**
+ * Copy all links from DesktopLinks/ to the desktop, appropriately renamed
+ * (to the contents of the translated Name field)
+ */
+static void copyDesktopLinks()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("General");
+ if (!config->readBoolEntry("CopyDesktopLinks", true))
+ return;
+
+ QStringList list =
+ KGlobal::dirs()->findAllResources("appdata", "DesktopLinks/*", false, true);
+
+ QString desktopPath = realDesktopPath();
+
+ for (QStringList::ConstIterator it = list.begin(); it != list.end(); it++) {
+ KDesktopFile desk( *it );
+ if (desk.readBoolEntry("Hidden"))
+ continue;
+ copyFile( *it, desktopPath );
+ }
+}
+
+/**
+ * @return true if this is the first time
+ * kdesktop is run for the current release
+ * WARNING : call only once !!! (second call will always return false !)
+ */
+static bool isNewRelease()
+{
+ bool bNewRelease = false;
+
+ int versionMajor = KDesktopSettings::kDEVersionMajor();
+ int versionMinor = KDesktopSettings::kDEVersionMinor();
+ int versionRelease = KDesktopSettings::kDEVersionRelease();
+
+ if( versionMajor < KDE_VERSION_MAJOR )
+ bNewRelease = true;
+ else if( versionMinor < KDE_VERSION_MINOR )
+ bNewRelease = true;
+ else if( versionRelease < KDE_VERSION_RELEASE )
+ bNewRelease = true;
+
+ if( bNewRelease ) {
+ KDesktopSettings::setKDEVersionMajor( KDE_VERSION_MAJOR );
+ KDesktopSettings::setKDEVersionMinor( KDE_VERSION_MINOR );
+ KDesktopSettings::setKDEVersionRelease( KDE_VERSION_RELEASE );
+ KDesktopSettings::writeConfig();
+ }
+
+ return bNewRelease;
+}
+
+/**
+ * Create, if necessary, some directories in user's .kde/,
+ * copy default .directory files there, as well as templates files.
+ * Called by kdesktop on startup.
+ */
+void testLocalInstallation()
+{
+ const bool newRelease = isNewRelease();
+
+ const QString desktopPath = realDesktopPath();
+ const bool emptyDesktop = testDir( desktopPath );
+
+ // Do not force copying that one (it would lose the icon positions)
+ copyDirectoryFile("directory.desktop", desktopPath, false);
+
+ testDir( KGlobalSettings::autostartPath() );
+ // we force the copying in case of a new release, to install new translations....
+ copyDirectoryFile("directory.autostart", KGlobalSettings::autostartPath(), newRelease);
+
+ if (emptyDesktop)
+ copyDesktopLinks();
+
+ // Take care of creating or updating trash.desktop
+ const QString trashDir = KGlobal::dirs()->localxdgdatadir() + "Trash";
+ const bool firstTimeWithNewTrash = !QFile::exists( trashDir );
+ const QString trashDesktopPath = desktopPath + "/trash.desktop";
+ const bool trashDesktopExists = QFile::exists( trashDesktopPath );
+ const bool installNewTrashi18n = newRelease && trashDesktopExists; // not if deleted by user
+ if ( emptyDesktop || firstTimeWithNewTrash || installNewTrashi18n ) {
+ QString oldIcon, oldEmptyIcon;
+ if ( trashDesktopExists ) {
+ KDesktopFile trashDesktop( trashDesktopPath, true );
+ oldIcon = trashDesktop.readIcon();
+ oldEmptyIcon = trashDesktop.readEntry( "EmptyIcon" );
+ }
+ copyFile( locate( "data", "kdesktop/directory.trash" ), trashDesktopPath );
+ if ( trashDesktopExists ) {
+ KDesktopFile trashDesktop( trashDesktopPath );
+ trashDesktop.writeEntry( "Icon", oldIcon );
+ trashDesktop.writeEntry( "EmptyIcon", oldEmptyIcon );
+ trashDesktop.sync();
+ }
+ }
+
+ if ( firstTimeWithNewTrash ) { // migrate pre-kde-3.4 trash contents
+ QByteArray packedArgs;
+ QDataStream stream( packedArgs, IO_WriteOnly );
+ stream << (int)2;
+ KIO::Job* job = KIO::special( "trash:/", packedArgs );
+ (void)KIO::NetAccess::synchronousRun( job, 0 );
+
+ // OK the only thing missing is to convert the icon position...
+ KSimpleConfig cfg( locateLocal("appdata", "IconPositions") );
+ if ( cfg.hasGroup( "IconPosition::Trash" ) && !cfg.hasGroup( "IconPosition::trash.desktop" ) ) {
+ const QMap<QString, QString> entries = cfg.entryMap( "IconPosition::Trash" );
+ cfg.setGroup( "IconPosition::trash.desktop" );
+ for( QMap<QString,QString>::ConstIterator it = entries.begin(); it != entries.end(); ++it ) {
+ cfg.writeEntry( it.key(), it.data() );
+ }
+ }
+ }
+}
+
diff --git a/kdesktop/init.h b/kdesktop/init.h
new file mode 100644
index 000000000..8f23ac1b4
--- /dev/null
+++ b/kdesktop/init.h
@@ -0,0 +1,30 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __init_h
+#define __init_h
+
+/**
+ * Create, if necessary, some directories in user's .kde/,
+ * copy default .directory files there, as well as templates files.
+ * Called by kdesktop on startup.
+ */
+void testLocalInstallation();
+
+#endif
diff --git a/kdesktop/init/Home.desktop b/kdesktop/init/Home.desktop
new file mode 100644
index 000000000..7273aa057
--- /dev/null
+++ b/kdesktop/init/Home.desktop
@@ -0,0 +1,166 @@
+[Desktop Entry]
+Name=Home
+Name[af]=Tuiste
+Name[ar]=المنزل
+Name[az]=Başlanğıc
+Name[be]=Хатняя тэчка
+Name[bg]=Домашна директория
+Name[bn]=ব্যক্তিগত ফোল্ডার
+Name[br]=Er-gêr
+Name[bs]=Početak
+Name[ca]=Inici
+Name[cs]=Můj adresář
+Name[csb]=Dodóm
+Name[cy]=Cartref
+Name[da]=Hjem
+Name[de]=Persönlicher Ordner
+Name[el]=Προσωπικός φάκελος
+Name[eo]=Hejmo
+Name[es]=Personal
+Name[et]=Kodu
+Name[eu]=Etxea
+Name[fa]=آغازه
+Name[fi]=Koti
+Name[fr]=Dossier personnel
+Name[fy]=Thús
+Name[ga]=Baile
+Name[gl]=Persoal
+Name[he]=בית
+Name[hi]=घर
+Name[hr]=Početak
+Name[hu]=Saját könyvtár
+Name[id]=Rumah
+Name[is]=Heimasvæðið þitt
+Name[ja]=ホーム
+Name[ka]=სახლში
+Name[kk]=Мекен
+Name[km]=ផ្ទះ
+Name[ko]=홈
+Name[lo]=ພື້ນທີ່ສ່ວນຕົວ
+Name[lt]=Pradžia
+Name[lv]=Mājas
+Name[mk]=Дома
+Name[mn]=Гэр
+Name[ms]=Laman Utama
+Name[mt]=Direttorju Personali
+Name[nb]=Hjem
+Name[nds]=Tohuus
+Name[ne]=गृह
+Name[nn]=Heim
+Name[nso]=Gae
+Name[oc]=Inici
+Name[pa]=ਘਰ
+Name[pl]=Katalog domowy
+Name[pt]=Pasta Pessoal
+Name[pt_BR]=Pasta do Usuário
+Name[ro]=Acasă
+Name[ru]=Домой
+Name[rw]=Urugo
+Name[se]=Ruoktu
+Name[sk]=Domov
+Name[sl]=Domov
+Name[sr]=Домаће
+Name[sr@Latn]=Domaće
+Name[ss]=Ekhaya
+Name[sv]=Hem
+Name[ta]=தொடக்கம்
+Name[te]=ఇల్లు
+Name[tg]=Компютери Ман
+Name[th]=พื้นที่ส่วนตัว
+Name[tr]=Başlangıç
+Name[tt]=Anabit
+Name[uk]=Домівка
+Name[uz]=Uy
+Name[uz@cyrillic]=Уй
+Name[ven]=Haya
+Name[vi]=Nhà
+Name[wa]=Måjhon
+Name[xh]=Ikhaya
+Name[zh_CN]=主文件夹
+Name[zh_TW]=家目錄
+Name[zu]=Ikhaya
+GenericName=Personal Files
+GenericName[af]=Persoonlike Lêers
+GenericName[ar]=الملفات الشخصية
+GenericName[az]=Şəxsi Fayllar
+GenericName[be]=Персанальныя файлы
+GenericName[bg]=Лични файлове
+GenericName[bn]=ব্যক্তিগত ফাইলসমূহ
+GenericName[br]=Restroù deoc'h
+GenericName[bs]=Osobne datoteke
+GenericName[ca]=Fitxers personals
+GenericName[cs]=Osobní soubory
+GenericName[csb]=Swòje lopczi
+GenericName[cy]=Ffeiliau Personol
+GenericName[da]=Personlige filer
+GenericName[de]=Eigene Dateien
+GenericName[el]=Προσωπικά αρχεία
+GenericName[eo]=Personaj dosieroj
+GenericName[es]=Archivos personales
+GenericName[et]=Isiklikud failid
+GenericName[eu]=Fitxategi pertsonalak
+GenericName[fa]=پرونده‌های شخصی
+GenericName[fi]=Omat tiedostot
+GenericName[fr]=Fichiers personnels
+GenericName[fy]=Persoanlike map
+GenericName[ga]=Comhaid Phearsanta
+GenericName[gl]=Ficheiros Persoais
+GenericName[he]=קבצים אישיים
+GenericName[hi]=निजी फ़ाइलें
+GenericName[hr]=Osobne datoteke
+GenericName[hu]=Személyes fájlok
+GenericName[id]=File Pribadi
+GenericName[is]=Skrárnar þínar
+GenericName[it]=File personali
+GenericName[ja]=個人のファイル
+GenericName[ka]=პირადი საქაღალდეები
+GenericName[kk]=Дербес файлдар
+GenericName[km]=ឯកសារ​ផ្ទាល់​ខ្លួន
+GenericName[ko]=개인적인 파일
+GenericName[lo]=ທີ່ເກັບແຟ້ມແລະເອກະສານສວ່ນຕົວຫລືອື່ນຯ
+GenericName[lt]=Asmeninės bylos
+GenericName[lv]=Personālie Faili
+GenericName[mk]=Лични датотеки
+GenericName[mn]=Өөрийн файлууд
+GenericName[ms]=Fail Peribadi
+GenericName[mt]=Fajls Personali
+GenericName[nb]=Personlige filer
+GenericName[nds]=De egen Dateien
+GenericName[ne]=व्यक्तिगत फाइल
+GenericName[nl]=Persoonlijke map
+GenericName[nn]=Personlege filer
+GenericName[nso]=Difaele tsa Botho
+GenericName[oc]=FiquièRs personals
+GenericName[pa]=ਨਿੱਜੀ ਫਾਇਲ਼ਾਂ
+GenericName[pl]=Pliki osobiste
+GenericName[pt]=Ficheiros Pessoais
+GenericName[pt_BR]=Arquivos Pessoais
+GenericName[ro]=Fișiere personale
+GenericName[ru]=Личные файлы
+GenericName[rw]=Amadosiye Yihariye
+GenericName[se]=Iežat fiillat
+GenericName[sk]=Osobné súbory
+GenericName[sl]=Osebne datoteke
+GenericName[sr]=Лични фајлови
+GenericName[sr@Latn]=Lični fajlovi
+GenericName[sv]=Personliga filer
+GenericName[ta]=சொந்த கோப்புகள்
+GenericName[te]=వ్యక్తిగత దస్త్రాలు
+GenericName[tg]=Файлҳои шахсӣ
+GenericName[th]=แฟ้มส่วนตัว
+GenericName[tr]=Kişisel Dosyalar
+GenericName[tt]=Şäxsi Biremnär
+GenericName[uk]=Особисті файли
+GenericName[uz]=Shaxsiy fayllar
+GenericName[uz@cyrillic]=Шахсий файллар
+GenericName[ven]=Dzifaela dza vhune
+GenericName[vi]=Tập tin Cá nhân
+GenericName[wa]=Fitchîs da vosse
+GenericName[xh]=Iifayile Zobuqu
+GenericName[zh_CN]=个人文件
+GenericName[zh_TW]=個人檔案
+GenericName[zu]=Amafayela Omuntu siqu
+URL=$HOME
+Icon=kfm_home
+Type=Link
+OnlyShowIn=KDE;
diff --git a/kdesktop/init/Makefile.am b/kdesktop/init/Makefile.am
new file mode 100644
index 000000000..8e1895bf4
--- /dev/null
+++ b/kdesktop/init/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = Templates
+
+kdesktop_init_data_DATA = directory.trash directory.autostart directory.templates directory.desktop
+kdesktop_init_datadir = $(kde_datadir)/kdesktop
+
+desktoplink_DATA = Home.desktop System.desktop
+desktoplinkdir = $(kde_datadir)/kdesktop/DesktopLinks
+
diff --git a/kdesktop/init/System.desktop b/kdesktop/init/System.desktop
new file mode 100644
index 000000000..1c4816b57
--- /dev/null
+++ b/kdesktop/init/System.desktop
@@ -0,0 +1,149 @@
+[Desktop Entry]
+Name=System
+Name[af]=Stelsel
+Name[ar]=النظام
+Name[az]=Sistem
+Name[be]=Сістэма
+Name[bg]=Система
+Name[bn]=সিস্টেম
+Name[br]=Reizhiad
+Name[bs]=Sistem
+Name[ca]=Sistema
+Name[cs]=Systém
+Name[csb]=Systema
+Name[cy]=Cysawd
+Name[el]=Σύστημα
+Name[eo]=Sistemo
+Name[es]=Sistema
+Name[et]=Süsteem
+Name[eu]=Sistema
+Name[fa]=سیستم
+Name[fi]=Järjestelmä
+Name[fo]=Kervi
+Name[fr]=Système
+Name[fy]=Systeem
+Name[ga]=Córas
+Name[gl]=Sistema
+Name[he]=מערכת
+Name[hi]=तंत्र
+Name[hr]=Sustav
+Name[hu]=Rendszer
+Name[id]=Sistem
+Name[is]=Kerfi
+Name[it]=Sistema
+Name[ja]=システム
+Name[ka]=სისტემა
+Name[kk]=Жүйелік
+Name[km]=ប្រព័ន្ធ
+Name[ko]=시스템
+Name[lo]=ຈັດການລະບົບ
+Name[lt]=Sistema
+Name[lv]=Sistēma
+Name[mk]=Систем
+Name[mn]=Систем
+Name[ms]=Sistem
+Name[mt]=Sistema
+Name[nds]=Systeem
+Name[ne]=प्रणाली
+Name[nl]=Systeem
+Name[oc]=Sistemo
+Name[pa]=ਸਿਸਟਮ
+Name[pt]=Sistema
+Name[pt_BR]=Sistema
+Name[ro]=Sistem
+Name[ru]=Система
+Name[rw]=Sisitemu
+Name[se]=Vuogádat
+Name[sk]=Systém
+Name[sl]=Sistem
+Name[sr]=Систем
+Name[sr@Latn]=Sistem
+Name[ss]=Umshini
+Name[ta]=அமைப்பு
+Name[te]=వ్యవస్థ
+Name[tg]=Система
+Name[th]=ระบบ
+Name[tr]=Sistem
+Name[tt]=Sistem
+Name[uk]=Система
+Name[uz]=Tizim
+Name[uz@cyrillic]=Тизим
+Name[ven]=Maitele
+Name[vi]=Hệ thống
+Name[wa]=Sistinme
+Name[xh]=Indlela esestyenziswayo
+Name[zh_CN]=系统
+Name[zh_TW]=系統
+Name[zu]=Isistimu
+GenericName=System Locations
+GenericName[af]=Stelsel Liggings
+GenericName[ar]=مواقع النظام
+GenericName[be]=Сістэмныя месцазнаходжанні
+GenericName[bg]=Системни файлове
+GenericName[bn]=সিস্টেম অবস্থানসমূহ
+GenericName[bs]=Sistemske lokacije
+GenericName[ca]=Localitzacions del sistema
+GenericName[cs]=Systémová umístění
+GenericName[csb]=Systemòwé lokalizacëje
+GenericName[da]=System-steder
+GenericName[de]=Systemordner
+GenericName[el]=Τοποθεσίες συστήματος
+GenericName[eo]=Sistemaj lokoj
+GenericName[es]=Ubicaciones del sistema
+GenericName[et]=Süsteemi asukohad
+GenericName[eu]=Sistemaren kokapenak
+GenericName[fa]=محلهای سیستم
+GenericName[fi]=Järjestelmän sijainti
+GenericName[fr]=Emplacements systèmes
+GenericName[fy]=Systeemlokaasjes
+GenericName[gl]=Lugares do Sistema
+GenericName[he]=מיקומי מערכת
+GenericName[hi]=तंत्र स्थान
+GenericName[hr]=Sistemske lokacije
+GenericName[hu]=Rendszerkönyvtárak
+GenericName[is]=Staðsetningar kerfis
+GenericName[it]=Indirizzi di sistema
+GenericName[ja]=システム場所
+GenericName[ka]=სისტემური მისამართები
+GenericName[kk]=Жүйенің орналасуы
+GenericName[km]=ទីតាំង​ប្រព័ន្ធ
+GenericName[ko]=시스템 알림
+GenericName[lt]=Sistemos vietos
+GenericName[lv]=Sistēmas vietas
+GenericName[mk]=Системски локации
+GenericName[ms]=Lokasi Sistem
+GenericName[mt]=System Monitor
+GenericName[nb]=Systemplassar
+GenericName[nds]=Systeemsteden
+GenericName[ne]=प्रणाली स्थान
+GenericName[nl]=Systeemlocaties
+GenericName[nn]=Systemplassar
+GenericName[pa]=ਸਿਸਟਮ ਟਿਕਾਣੇ
+GenericName[pl]=Lokalizacje systemowe
+GenericName[pt]=Locais do Sistema
+GenericName[pt_BR]=Localizações no Sistema
+GenericName[ro]=Locații de sistem
+GenericName[ru]=Системные адреса
+GenericName[rw]=Ahantu ha Sisitemu
+GenericName[se]=Vuogádatbáikkit
+GenericName[sk]=Systémové lokácie
+GenericName[sl]=Sistemske lokacije
+GenericName[sr]=Системске локације
+GenericName[sr@Latn]=Sistemske lokacije
+GenericName[sv]=Systemplatser
+GenericName[ta]=அமைப்பு இடங்கள்
+GenericName[tg]=Ҷойгиршавиҳои система
+GenericName[th]=ที่ตั้งของระบบ
+GenericName[tr]=Sistem Konumları
+GenericName[tt]=Sistem Urınlaşuları
+GenericName[uk]=Системні адреси
+GenericName[uz]=Tizimga tegishli manzillar
+GenericName[uz@cyrillic]=Тизимга тегишли манзиллар
+GenericName[vi]=Đường dẫn Hệ thống
+GenericName[wa]=Plaeces do sistinme
+GenericName[zh_CN]=系统定位
+GenericName[zh_TW]=系統位置
+URL=system:/
+Icon=system
+Type=Link
+OnlyShowIn=KDE;
diff --git a/kdesktop/init/Templates/CAMERA-Device.desktop b/kdesktop/init/Templates/CAMERA-Device.desktop
new file mode 100644
index 000000000..524436e35
--- /dev/null
+++ b/kdesktop/init/Templates/CAMERA-Device.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=camera_mount
+UnmountIcon=camera_unmount
diff --git a/kdesktop/init/Templates/CDROM-Device.desktop b/kdesktop/init/Templates/CDROM-Device.desktop
new file mode 100644
index 000000000..65560072f
--- /dev/null
+++ b/kdesktop/init/Templates/CDROM-Device.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=cdrom_mount
+UnmountIcon=cdrom_unmount
+Actions=Eject;
+X-KDE-Priority=TopLevel
+[Desktop Action Eject]
+Name=Eject
+Name[af]=Uitskiet
+Name[ar]=أقذف
+Name[az]=Çıxart
+Name[be]=Вызваліць
+Name[bg]=Изваждане
+Name[bn]=ইজেক্ট
+Name[br]=Stlepel
+Name[bs]=Izbaci
+Name[ca]=Expulsa
+Name[cs]=Vysunout
+Name[csb]=Wësënie
+Name[cy]=Allfwrw
+Name[da]=Skub ud
+Name[de]=Auswerfen
+Name[el]=Εξαγωγή
+Name[eo]=Eligo
+Name[es]=Expulsar
+Name[et]=Väljastamine
+Name[eu]=Egotzi
+Name[fa]=پس زدن
+Name[fi]=Poista
+Name[fr]=Éjecter
+Name[fy]=Utsmytknop
+Name[ga]=Díchuir
+Name[gl]=Expulsar
+Name[he]=הוצא
+Name[hi]=बाहर
+Name[hr]=Izbaci
+Name[hu]=Kidobás
+Name[is]=Henda út
+Name[it]=Espelli
+Name[ja]=取り出し
+Name[ka]=CD-ს ამოღება
+Name[kk]=Алып-шығару
+Name[km]=ច្រាន​ចេញ
+Name[ko]=꺼내기
+Name[lo]=ເອົາແຜ່ນອອກ
+Name[lt]=Išmesti
+Name[lv]=Izņemt
+Name[mk]=Извади
+Name[mn]=Гаргах
+Name[ms]=Lenting
+Name[mt]=Iftaħ
+Name[nb]=Løs ut
+Name[nds]=Rutsmieten
+Name[ne]=निकाल्नुहोस्
+Name[nl]=Uitwerpen
+Name[nn]=Løys ut
+Name[nso]=Ntsha
+Name[oc]=Expulsa
+Name[pa]=ਬਾਹਰ ਕੱਢੋ
+Name[pl]=Wysuń
+Name[pt]=Ejectar
+Name[pt_BR]=Ejetar
+Name[ro]=Ejectează
+Name[ru]=Извлечь CD
+Name[rw]=Gusohora
+Name[se]=Bálkes olggos
+Name[sk]=Vysunúť
+Name[sl]=Izvrzi
+Name[sr]=Избаци
+Name[sr@Latn]=Izbaci
+Name[ss]=Khafuna
+Name[sv]=Mata ut
+Name[ta]=வெளித்தள்
+Name[te]=ఎజెక్ట్
+Name[tg]=Ихроҷ
+Name[th]=เอาแผ่นออก
+Name[tr]=Çıkart
+Name[tt]=Çığar
+Name[uk]=Виштовхнути
+Name[uz]=Chiqarish
+Name[uz@cyrillic]=Чиқариш
+Name[ven]=Bvisa
+Name[vi]=Đẩy đĩa ra
+Name[wa]=Fé rexhe
+Name[xh]=Khuphela ngaphandle
+Name[zh_CN]=弹出
+Name[zh_TW]=退出
+Name[zu]=Khipha
+Exec=kdeeject %v
diff --git a/kdesktop/init/Templates/CDWRITER-Device.desktop b/kdesktop/init/Templates/CDWRITER-Device.desktop
new file mode 100644
index 000000000..810b71824
--- /dev/null
+++ b/kdesktop/init/Templates/CDWRITER-Device.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=0
+Type=FSDevice
+Icon=cdwriter_mount
+UnmountIcon=cdwriter_unmount
+Actions=Eject;
+X-KDE-Priority=TopLevel
+[Desktop Action Eject]
+Name=Eject
+Name[af]=Uitskiet
+Name[ar]=أقذف
+Name[az]=Çıxart
+Name[be]=Вызваліць
+Name[bg]=Изваждане
+Name[bn]=ইজেক্ট
+Name[br]=Stlepel
+Name[bs]=Izbaci
+Name[ca]=Expulsa
+Name[cs]=Vysunout
+Name[csb]=Wësënie
+Name[cy]=Allfwrw
+Name[da]=Skub ud
+Name[de]=Auswerfen
+Name[el]=Εξαγωγή
+Name[eo]=Eligo
+Name[es]=Expulsar
+Name[et]=Väljastamine
+Name[eu]=Egotzi
+Name[fa]=پس زدن
+Name[fi]=Poista
+Name[fr]=Éjecter
+Name[fy]=Utsmytknop
+Name[ga]=Díchuir
+Name[gl]=Expulsar
+Name[he]=הוצא
+Name[hi]=बाहर
+Name[hr]=Izbaci
+Name[hu]=Kidobás
+Name[is]=Henda út
+Name[it]=Espelli
+Name[ja]=取り出し
+Name[ka]=CD-ს ამოღება
+Name[kk]=Алып-шығару
+Name[km]=ច្រាន​ចេញ
+Name[ko]=꺼내기
+Name[lo]=ເອົາແຜ່ນອອກ
+Name[lt]=Išmesti
+Name[lv]=Izņemt
+Name[mk]=Извади
+Name[mn]=Гаргах
+Name[ms]=Lenting
+Name[mt]=Iftaħ
+Name[nb]=Løs ut
+Name[nds]=Rutsmieten
+Name[ne]=निकाल्नुहोस्
+Name[nl]=Uitwerpen
+Name[nn]=Løys ut
+Name[nso]=Ntsha
+Name[oc]=Expulsa
+Name[pa]=ਬਾਹਰ ਕੱਢੋ
+Name[pl]=Wysuń
+Name[pt]=Ejectar
+Name[pt_BR]=Ejetar
+Name[ro]=Ejectează
+Name[ru]=Извлечь CD
+Name[rw]=Gusohora
+Name[se]=Bálkes olggos
+Name[sk]=Vysunúť
+Name[sl]=Izvrzi
+Name[sr]=Избаци
+Name[sr@Latn]=Izbaci
+Name[ss]=Khafuna
+Name[sv]=Mata ut
+Name[ta]=வெளித்தள்
+Name[te]=ఎజెక్ట్
+Name[tg]=Ихроҷ
+Name[th]=เอาแผ่นออก
+Name[tr]=Çıkart
+Name[tt]=Çığar
+Name[uk]=Виштовхнути
+Name[uz]=Chiqarish
+Name[uz@cyrillic]=Чиқариш
+Name[ven]=Bvisa
+Name[vi]=Đẩy đĩa ra
+Name[wa]=Fé rexhe
+Name[xh]=Khuphela ngaphandle
+Name[zh_CN]=弹出
+Name[zh_TW]=退出
+Name[zu]=Khipha
+Exec=kdeeject %v
diff --git a/kdesktop/init/Templates/DVDROM-Device.desktop b/kdesktop/init/Templates/DVDROM-Device.desktop
new file mode 100644
index 000000000..3d46866be
--- /dev/null
+++ b/kdesktop/init/Templates/DVDROM-Device.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=dvd_mount
+UnmountIcon=dvd_unmount
+Actions=Eject;
+X-KDE-Priority=TopLevel
+[Desktop Action Eject]
+Name=Eject
+Name[af]=Uitskiet
+Name[ar]=أقذف
+Name[az]=Çıxart
+Name[be]=Вызваліць
+Name[bg]=Изваждане
+Name[bn]=ইজেক্ট
+Name[br]=Stlepel
+Name[bs]=Izbaci
+Name[ca]=Expulsa
+Name[cs]=Vysunout
+Name[csb]=Wësënie
+Name[cy]=Allfwrw
+Name[da]=Skub ud
+Name[de]=Auswerfen
+Name[el]=Εξαγωγή
+Name[eo]=Eligo
+Name[es]=Expulsar
+Name[et]=Väljastamine
+Name[eu]=Egotzi
+Name[fa]=پس زدن
+Name[fi]=Poista
+Name[fr]=Éjecter
+Name[fy]=Utsmytknop
+Name[ga]=Díchuir
+Name[gl]=Expulsar
+Name[he]=הוצא
+Name[hi]=बाहर
+Name[hr]=Izbaci
+Name[hu]=Kidobás
+Name[is]=Henda út
+Name[it]=Espelli
+Name[ja]=取り出し
+Name[ka]=CD-ს ამოღება
+Name[kk]=Алып-шығару
+Name[km]=ច្រាន​ចេញ
+Name[ko]=꺼내기
+Name[lo]=ເອົາແຜ່ນອອກ
+Name[lt]=Išmesti
+Name[lv]=Izņemt
+Name[mk]=Извади
+Name[mn]=Гаргах
+Name[ms]=Lenting
+Name[mt]=Iftaħ
+Name[nb]=Løs ut
+Name[nds]=Rutsmieten
+Name[ne]=निकाल्नुहोस्
+Name[nl]=Uitwerpen
+Name[nn]=Løys ut
+Name[nso]=Ntsha
+Name[oc]=Expulsa
+Name[pa]=ਬਾਹਰ ਕੱਢੋ
+Name[pl]=Wysuń
+Name[pt]=Ejectar
+Name[pt_BR]=Ejetar
+Name[ro]=Ejectează
+Name[ru]=Извлечь CD
+Name[rw]=Gusohora
+Name[se]=Bálkes olggos
+Name[sk]=Vysunúť
+Name[sl]=Izvrzi
+Name[sr]=Избаци
+Name[sr@Latn]=Izbaci
+Name[ss]=Khafuna
+Name[sv]=Mata ut
+Name[ta]=வெளித்தள்
+Name[te]=ఎజెక్ట్
+Name[tg]=Ихроҷ
+Name[th]=เอาแผ่นออก
+Name[tr]=Çıkart
+Name[tt]=Çığar
+Name[uk]=Виштовхнути
+Name[uz]=Chiqarish
+Name[uz@cyrillic]=Чиқариш
+Name[ven]=Bvisa
+Name[vi]=Đẩy đĩa ra
+Name[wa]=Fé rexhe
+Name[xh]=Khuphela ngaphandle
+Name[zh_CN]=弹出
+Name[zh_TW]=退出
+Name[zu]=Khipha
+Exec=kdeeject %v
diff --git a/kdesktop/init/Templates/Directory.desktop b/kdesktop/init/Templates/Directory.desktop
new file mode 100644
index 000000000..3ace5a6a4
--- /dev/null
+++ b/kdesktop/init/Templates/Directory.desktop
@@ -0,0 +1,146 @@
+[Desktop Entry]
+Name=Folder...
+Name[af]=Gids...
+Name[ar]=المجلد...
+Name[be]=Тэчка...
+Name[bg]=Директория...
+Name[bn]=ফোল্ডার...
+Name[br]=Renkell ...
+Name[bs]=Direktorij...
+Name[ca]=Carpeta...
+Name[cs]=Složka...
+Name[csb]=Katalog...
+Name[cy]=Plygell...
+Name[da]=Mappe...
+Name[de]=Ordner ...
+Name[el]=Φάκελος...
+Name[eo]=Dosierujo...
+Name[es]=Carpeta...
+Name[et]=Kataloog...
+Name[eu]=Karpeta...
+Name[fa]=پوشه...
+Name[fi]=Kansio...
+Name[fr]=Dossier...
+Name[fy]=Map...
+Name[ga]=Fillteán...
+Name[gl]=Cartafol...
+Name[he]=תיקייה...
+Name[hi]=फ़ोल्डर...
+Name[hr]=Mapa...
+Name[hu]=Könyvtár...
+Name[is]=Mappa...
+Name[it]=Cartella...
+Name[ja]=フォルダ...
+Name[ka]=საქაღალდე...
+Name[kk]=Қапшық...
+Name[km]=ថត...
+Name[ko]=폴더...
+Name[lt]=Aplankas...
+Name[lv]=Mape...
+Name[mk]=Папка...
+Name[mn]=Хавтас...
+Name[mt]=Direttorju...
+Name[nb]=Mappe …
+Name[nds]=Orner...
+Name[ne]=फोल्डर...
+Name[nl]=Map...
+Name[nn]=Mappe …
+Name[pa]=ਫੋਲਡਰ...
+Name[pl]=Katalog...
+Name[pt]=Pasta...
+Name[pt_BR]=Pasta...
+Name[ru]=Папку...
+Name[rw]=Ububiko...
+Name[se]=Máhppa …
+Name[sk]=Priečinok...
+Name[sl]=Mapa ...
+Name[sr]=Фасцикла...
+Name[sr@Latn]=Fascikla...
+Name[sv]=Katalog...
+Name[ta]=அடைவு...
+Name[tg]=Феҳрист...
+Name[th]=โฟลเดอร์...
+Name[tr]=Dizin...
+Name[tt]=Törgäk...
+Name[uk]=Тека...
+Name[uz]=Jild
+Name[uz@cyrillic]=Жилд
+Name[vi]=Thư mục...
+Name[wa]=Ridant...
+Name[zh_CN]=文件夹...
+Name[zh_TW]=資料夾...
+Comment=Enter folder name:
+Comment[af]=Voer gidsnaam in:
+Comment[ar]=أدخل إسم المجلَد:
+Comment[be]=Вызначце назву тэчкі:
+Comment[bg]=Въведете името на директорията:
+Comment[bn]=ফোল্ডারের নাম লিখুন:
+Comment[br]=Roit un anv ar renkell :
+Comment[bs]=Unesite naziv direktorija:
+Comment[ca]=Entra el nom de la carpeta:
+Comment[cs]=Zadejte název složky:
+Comment[csb]=Wpiszë miono katalogù:
+Comment[cy]=Mewnosodwch enw'r plygell:
+Comment[da]=Indtast mappenavn:
+Comment[de]=Ordnernamen eingeben:
+Comment[el]=Δώστε το όνομα του φακέλου:
+Comment[eo]=Enigu novan dosierujonomon:
+Comment[es]=Introduzca el nombre de la carpeta:
+Comment[et]=Sisesta kataloogi nimi:
+Comment[eu]=Sartu karpetaren izena:
+Comment[fa]=نام پوشه را وارد کنید:
+Comment[fi]=Anna kansion nimi:
+Comment[fr]=Donnez le nom du dossier :
+Comment[fy]=Mapname ynfiere:
+Comment[ga]=Iontráil ainm an fhillteáin:
+Comment[gl]=Introduza o nome do cartafol:
+Comment[he]=הזן שם תיקייה:
+Comment[hi]=फ़ोल्डर नाम भरें:
+Comment[hr]=Unesite naziv mape:
+Comment[hu]=A könyvtár neve:
+Comment[is]=Sláðu inn möppunafn:
+Comment[it]=Immetti il nome della cartella:
+Comment[ja]=フォルダ名を入力してください:
+Comment[ka]=შეიყვანეთ საქაღალდის სახელი:
+Comment[kk]=Қапшықты келтіріңіз:
+Comment[km]=បញ្ចូល​ឈ្មោះ​ថត ៖
+Comment[ko]=폴더 이름을 입력하십시오:
+Comment[lt]=Įveskite aplanko vardą:
+Comment[lv]=Ievadiet mapes nosaukumu:
+Comment[mk]=Внесете го името на папката:
+Comment[mn]=Лавлахын нэрийг өг:
+Comment[ms]=Masukkan nama folder:
+Comment[mt]=Daħħal isem id-direttorju:
+Comment[nb]=Nytt mappenavn:
+Comment[nds]=Ornernaam ingeven:
+Comment[ne]=फोल्डर नाम प्रविष्ट गर्नुहोस्:
+Comment[nl]=Mapnaam invoeren:
+Comment[nn]=Nytt mappenamn:
+Comment[pa]=ਫੋਲਡਰ ਨਾਂ ਦਿਓ:
+Comment[pl]=Podaj nazwę katalogu:
+Comment[pt]=Indique o nome da pasta:
+Comment[pt_BR]=Digite o nome da pasta:
+Comment[ro]=Introduceți numele folderului:
+Comment[ru]=Введите имя папки:
+Comment[rw]=Kwinjiza izina ry'ububiko:
+Comment[se]=Bija máhppanama:
+Comment[sk]=Zadajte meno priečinku:
+Comment[sl]=Vnesite ime mape:
+Comment[sr]=Унесите име фасцикле:
+Comment[sr@Latn]=Unesite ime fascikle:
+Comment[sv]=Ange katalognamn:
+Comment[ta]=அடைவின் பெயரை உள்ளிடு:
+Comment[tg]=Номи феҳристро ворид кунед:
+Comment[th]=เติมชื่อโฟลเดอร์:
+Comment[tr]=Dizin adını girin:
+Comment[tt]=Törgäk adın kert:
+Comment[uk]=Введіть назву теки:
+Comment[uz]=Jildning nomini kiriting:
+Comment[uz@cyrillic]=Жилднинг номини киритинг:
+Comment[vi]=Điền tên thư mục:
+Comment[wa]=Dinez l' no do ridant:
+Comment[zh_CN]=输入文件夹名称:
+Comment[zh_TW]=輸入目錄名稱:
+Type=Link
+URL=.source/emptydir
+Icon=folder
diff --git a/kdesktop/init/Templates/Floppy.desktop b/kdesktop/init/Templates/Floppy.desktop
new file mode 100644
index 000000000..ddae9a2c6
--- /dev/null
+++ b/kdesktop/init/Templates/Floppy.desktop
@@ -0,0 +1,78 @@
+[Desktop Action Format]
+Exec=kfloppy %v
+Name=Format
+Name[af]=Formaat
+Name[ar]=الهيئة
+Name[be]=Фармат
+Name[bg]=Формат
+Name[bn]=ফরম্যাট
+Name[br]=Furmadiñ
+Name[cs]=Formát
+Name[csb]=Fòrmat
+Name[cy]=Fformat
+Name[de]=Formatieren
+Name[el]=Μορφοποίηση
+Name[eo]=Formato
+Name[es]=Formato
+Name[et]=Vorming
+Name[eu]=Formatua
+Name[fa]=قالب
+Name[fi]=Formatoi
+Name[fy]=Formattearje
+Name[ga]=Formáid
+Name[gl]=Formato
+Name[he]=אתחל
+Name[hi]=फार्मेट
+Name[hr]=Oblik
+Name[hu]=Formázás
+Name[is]=Snið
+Name[it]=Formatta
+Name[ja]=フォーマット
+Name[ka]=ფორმატი
+Name[kk]=Пішін
+Name[km]=ទ្រង់ទ្រាយ
+Name[ko]=포맷
+Name[lo]=ສູດຄະນິດສານ - K
+Name[lt]=Formatas
+Name[lv]=Formatēt
+Name[mk]=Формат
+Name[mn]=Хэлбэр
+Name[nds]=Formateren
+Name[ne]=ढाँचा
+Name[nl]=Formatteren
+Name[nso]=Thlolego
+Name[pa]=ਫਾਰਮਿਟ
+Name[pt]=Formatar
+Name[pt_BR]=Formato
+Name[ru]=Формат
+Name[rw]=Imiterere
+Name[se]=Formáhtta
+Name[sk]=Formát
+Name[sl]=Oblika
+Name[sr]=Формат
+Name[ss]=Sakhiwo
+Name[ta]=வடிவம்
+Name[te]=ఫార్మెట్
+Name[tg]=Андоза
+Name[th]=รูปแบบ
+Name[tr]=Biçim
+Name[uk]=Формат
+Name[uz]=Format qilish
+Name[uz@cyrillic]=Формат қилиш
+Name[ven]=Tshivhumbeo
+Name[vi]=Định dạng
+Name[wa]=Abwesner
+Name[xh]=Ifomati
+Name[zh_CN]=格式
+Name[zh_TW]=格式化
+Name[zu]=Isakhiwo
+
+[Desktop Entry]
+Actions=Format;
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=3floppy_mount
+UnmountIcon=3floppy_unmount
+X-KDE-Priority=TopLevel
diff --git a/kdesktop/init/Templates/HD.desktop b/kdesktop/init/Templates/HD.desktop
new file mode 100644
index 000000000..78ed614dc
--- /dev/null
+++ b/kdesktop/init/Templates/HD.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=hdd_mount
+UnmountIcon=hdd_unmount
diff --git a/kdesktop/init/Templates/HTMLFile.desktop b/kdesktop/init/Templates/HTMLFile.desktop
new file mode 100644
index 000000000..d2ebe33b0
--- /dev/null
+++ b/kdesktop/init/Templates/HTMLFile.desktop
@@ -0,0 +1,148 @@
+[Desktop Entry]
+Name=HTML File...
+Name[af]=HTML Lêer...
+Name[ar]=ملف لغة علامات النصّ الفائق...
+Name[be]=Файл HTML...
+Name[bg]=HTML файл...
+Name[bn]=HTML ফাইল...
+Name[br]=Restr HTML ...
+Name[bs]=HTML datoteka...
+Name[ca]=Fitxer HTML...
+Name[cs]=HTML soubor...
+Name[csb]=Lopk HTML...
+Name[cy]=Ffeil HTML...
+Name[da]=HTML-fil...
+Name[de]=HTML-Datei ...
+Name[el]=Αρχείο HTML...
+Name[eo]=HTML-dosiero...
+Name[es]=Archivo HTML...
+Name[et]=HTML-fail...
+Name[eu]=HTML fitxategia...
+Name[fa]=پروندۀ‌ زنگام...
+Name[fi]=HTML-tiedosto...
+Name[fr]=Fichier HTML...
+Name[fy]=HTML-triem.......
+Name[ga]=Comhad HTML...
+Name[gl]=Ficheiro HTML...
+Name[he]=קובץ HTML...
+Name[hi]=एचटीएमएल फ़ाइल...
+Name[hr]=HTML datoteka...
+Name[hu]=HTML-fájl...
+Name[is]=HTML skrá...
+Name[it]=File HTML...
+Name[ja]=HTML ファイル...
+Name[ka]=HTML ფაილი...
+Name[kk]=HTML файлы...
+Name[km]=ឯកសារ HTML...
+Name[ko]=HTML 파일
+Name[lt]=HTML byla...
+Name[lv]=HTML Fails...
+Name[mk]=HTML датотека...
+Name[mn]=HTML-Файл...
+Name[ms]=Fail HTML...
+Name[mt]=Fajl HTML...
+Name[nb]=HTML-fil …
+Name[nds]=HTML-Datei...
+Name[ne]=HTML फाइल...
+Name[nl]=HTML-bestand...
+Name[nn]=HTML-fil …
+Name[pa]=HTML ਫਾਇਲ...
+Name[pl]=Plik HTML...
+Name[pt]=Ficheiro HTML...
+Name[pt_BR]=Arquivo HTML...
+Name[ro]=Fișier HTML...
+Name[ru]=Страница HTML...
+Name[rw]=Idosiye HTML...
+Name[se]=HTML-fiila …
+Name[sk]=Súbor HTML...
+Name[sl]=Datoteka HTML ...
+Name[sr]=HTML фајл...
+Name[sr@Latn]=HTML fajl...
+Name[sv]=HTML-fil...
+Name[ta]=HTML கோப்பு...
+Name[te]=హెచ్ టి ఎం ఎల్ దస్త్రం...
+Name[tg]=Файли HTML...
+Name[th]=แฟ้ม HTML...
+Name[tr]=HTML Dosyası...
+Name[tt]=HTML Birem...
+Name[uk]=Файл HTML...
+Name[uz]=HTML-fayli...
+Name[uz@cyrillic]=HTML-файли...
+Name[vi]=Tập tin HTML...
+Name[wa]=Fitchî HTML...
+Name[zh_CN]=HTML 文件...
+Name[zh_TW]=HTML 檔案...
+Comment=Enter HTML filename:
+Comment[af]=Voer HTML lêernaam in:
+Comment[ar]=أدخل إسم ملف لغة علامات النصّ الفائق:
+Comment[be]=Вызначце назву файла HTML:
+Comment[bg]=Въведете името на HTML файла:
+Comment[bn]=HTML ফাইলের নাম:
+Comment[br]=Roit un anv ar restr :
+Comment[bs]=Unesite ime HTML datoteke:
+Comment[ca]=Entra el nom del fitxer HTML:
+Comment[cs]=Zadejte název HTML souboru:
+Comment[csb]=Wpiszë miono lopkù HTML:
+Comment[da]=Indtast HTML-filnavn:
+Comment[de]=Name der HTML-Datei eingeben:
+Comment[el]=Δώστε το όνομα του αρχείου HTML:
+Comment[eo]=Enigu HTML-dosiernomon:
+Comment[es]=Introduzca el nombre del archivo HTML:
+Comment[et]=Sisesta HTML-faili nimi:
+Comment[eu]=Sartu HTML fitxategiaren izena:
+Comment[fa]=نام پروندۀ زنگام را وارد کنید:
+Comment[fi]=Anna HTML-tiedostonimi:
+Comment[fr]=Donnez le nom du fichier HTML :
+Comment[fy]=Namme fan HTML-triem ynfiere:
+Comment[ga]=Iontráil ainm an chomhaid HTML:
+Comment[gl]=Introduza o nome do ficheiro HTML:
+Comment[he]=הזן שם לקובץ ה־HTML:
+Comment[hi]=एचटीएमएल फ़ाइल-नाम भरें:
+Comment[hr]=Unesite naziv HTML datoteke:
+Comment[hu]=A HTML-fájl neve:
+Comment[is]=Sláðu inn HTML skráarnafn:
+Comment[it]=Immetti nome file HTML:
+Comment[ja]=HTML ファイル名を入力:
+Comment[ka]=HTML ფაილის სახელი შეიყვანეთ:
+Comment[kk]=HTML файлын келтіріңіз:
+Comment[km]=បញ្ចូល​ឈ្មោះ​ឯកសារ HTML ៖
+Comment[ko]=HTML 파일 이름을 입력하십시오:
+Comment[lt]=Įveskite HTML bylos vardą:
+Comment[lv]=Ievadiet HTML faila nosaukumu:
+Comment[mk]=Внесете го името на HTML датотеката:
+Comment[ms]=Masukkan nama fail HTML:
+Comment[mt]=Ittajpja isem ta' fajl HTML:
+Comment[nb]=Skriv inn HTML-filnavn:
+Comment[nds]=Naam vun de HTML-Datei ingeven:
+Comment[ne]=HTML फाइलनाम प्रविष्ट गर्नुहोस्:
+Comment[nl]=Naam van HTML-bestand invoeren:
+Comment[nn]=Oppgje HTML-filnamn:
+Comment[pa]=HTML ਫਾਇਲ ਨਾਂ ਦਿਓ:
+Comment[pl]=Podaj nazwę pliku HTML:
+Comment[pt]=Indique o nome do ficheiro HTML:
+Comment[pt_BR]=Insira nome do arquivo HTML:
+Comment[ro]=Introduceți numele fișierului HTML:
+Comment[ru]=Введите имя страницы HTML:
+Comment[rw]=Kwinjiza izinadosiye HTML:
+Comment[se]=Bija HTML-fiilanama:
+Comment[sk]=Zadajte meno súboru HTML:
+Comment[sl]=Vnesite ime datoteke HTML:
+Comment[sr]=Унесите име HTML фајла:
+Comment[sr@Latn]=Unesite ime HTML fajla:
+Comment[sv]=Ange HTML-filnamn:
+Comment[ta]=HTML கோப்பு பெயரை உள்ளிடு:
+Comment[te]=హెచ్ టి ఎం ఎల్ దస్త్రం పేరును వ్రాయండి:
+Comment[tg]=Номи файли HTML-ро ворид кунед:
+Comment[th]=เติมชื่อแฟ้ม HTML:
+Comment[tr]=HTML dosyasını girin:
+Comment[tt]=HTML-birem adın kert:
+Comment[uk]=Введіть назву файла HTML:
+Comment[uz]=HTML-faylning nomini kiriting:
+Comment[uz@cyrillic]=HTML-файлнинг номини киритинг:
+Comment[vi]=Điền tên tập tin HTML:
+Comment[wa]=Dinez l' no do fitchî HTML:
+Comment[zh_CN]=输入 HTML 文件名:
+Comment[zh_TW]=輸入 HTML 檔案名稱:
+Type=Link
+URL=.source/HTMLFile.html
+Icon=html
diff --git a/kdesktop/init/Templates/HTMLFile.html b/kdesktop/init/Templates/HTMLFile.html
new file mode 100644
index 000000000..c217ab3fc
--- /dev/null
+++ b/kdesktop/init/Templates/HTMLFile.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title></title>
+ <meta content="">
+ <style></style>
+ </head>
+ <body></body>
+</html> \ No newline at end of file
diff --git a/kdesktop/init/Templates/MO-Device.desktop b/kdesktop/init/Templates/MO-Device.desktop
new file mode 100644
index 000000000..7ad78fd18
--- /dev/null
+++ b/kdesktop/init/Templates/MO-Device.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=mo_mount
+UnmountIcon=mo_unmount
diff --git a/kdesktop/init/Templates/Makefile.am b/kdesktop/init/Templates/Makefile.am
new file mode 100644
index 000000000..b05dfcbd1
--- /dev/null
+++ b/kdesktop/init/Templates/Makefile.am
@@ -0,0 +1,21 @@
+
+# The links (that contain translations)
+templ_DATA = linkProgram.desktop \
+ linkURL.desktop linkFloppy.desktop linkHD.desktop linkCDROM.desktop \
+ Directory.desktop TextFile.desktop HTMLFile.desktop linkZIP.desktop \
+ linkDVDROM.desktop linkCAMERA.desktop linkNFS.desktop linkCDWRITER.desktop \
+ linkMO.desktop
+
+templdir = $(kde_templatesdir)
+
+# The source files (the actual templates)
+sources_DATA = Program.desktop \
+ URL.desktop Floppy.desktop HD.desktop CDROM-Device.desktop \
+ TextFile.txt HTMLFile.html ZIP-Device.desktop DVDROM-Device.desktop \
+ CAMERA-Device.desktop NFS.desktop CDWRITER-Device.desktop \
+ MO-Device.desktop
+
+sourcesdir = $(kde_templatesdir)/.source
+
+install-data-hook:
+ $(mkinstalldirs) $(DESTDIR)$(sourcesdir)/emptydir
diff --git a/kdesktop/init/Templates/NFS.desktop b/kdesktop/init/Templates/NFS.desktop
new file mode 100644
index 000000000..dcfc043d4
--- /dev/null
+++ b/kdesktop/init/Templates/NFS.desktop
@@ -0,0 +1,7 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=nfs_mount
+UnmountIcon=nfs_unmount
diff --git a/kdesktop/init/Templates/Program.desktop b/kdesktop/init/Templates/Program.desktop
new file mode 100644
index 000000000..263e1a155
--- /dev/null
+++ b/kdesktop/init/Templates/Program.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Exec=
+Icon=exec
+Path=
+Terminal=false
+Type=Application
diff --git a/kdesktop/init/Templates/TextFile.desktop b/kdesktop/init/Templates/TextFile.desktop
new file mode 100644
index 000000000..3c371d42c
--- /dev/null
+++ b/kdesktop/init/Templates/TextFile.desktop
@@ -0,0 +1,148 @@
+[Desktop Entry]
+Name=Text File...
+Name[af]=Teks Lêer...
+Name[ar]=ملف نصي...
+Name[be]=Тэкставы файл...
+Name[bg]=Текстов файл...
+Name[bn]=টেক্সট ফাইল...
+Name[br]=Restr skrid ...
+Name[bs]=Tekst datoteka...
+Name[ca]=Fitxer de text...
+Name[cs]=Textový soubor...
+Name[csb]=Tekstowi lopk...
+Name[cy]=Ffeil Testun...
+Name[da]=Tekstfil...
+Name[de]=Textdatei ...
+Name[el]=Αρχείο κειμένου...
+Name[eo]=Tekstdosiero...
+Name[es]=Archivo de texto...
+Name[et]=Tekstifail...
+Name[eu]=Testu fitxategia...
+Name[fa]=پروندۀ متنی...
+Name[fi]=Tekstitiedosto...
+Name[fr]=Fichier texte...
+Name[fy]=Teksttriem......
+Name[ga]=Téacschomhad...
+Name[gl]=Ficheiro de Texto...
+Name[he]=קובץ טקסט...
+Name[hi]=पाठ फ़ाइल...
+Name[hr]=Tekstualna datoteka...
+Name[hu]=Szöveges fájl...
+Name[is]=Textaskrá...
+Name[it]=File di testo...
+Name[ja]=テキストファイル...
+Name[ka]=ტექსტური ფაილი...
+Name[kk]=Мәтін файлы...
+Name[km]=ឯកសារ​អត្ថបទ...
+Name[ko]=텍스트 파일...
+Name[lt]=Teksto byla...
+Name[lv]=Teksta Fails...
+Name[mk]=Текстуална датотека...
+Name[mn]=Текст файл...
+Name[ms]=Fail Teks...
+Name[mt]=Fajl ta' test...
+Name[nb]=Tekstfil …
+Name[nds]=Textdatei...
+Name[ne]=पाठ फाइल...
+Name[nl]=Tekstbestand...
+Name[nn]=Tekstfil …
+Name[pa]=ਪਾਠ ਫਾਇਲ...
+Name[pl]=Plik tekstowy...
+Name[pt]=Ficheiro de Texto...
+Name[pt_BR]=Arquivo Texto...
+Name[ro]=Fișier text...
+Name[ru]=Текстовый файл...
+Name[rw]= Idosiye Mwandiko...
+Name[se]=Teakstafiila …
+Name[sk]=Textový súbor...
+Name[sl]=Besedilna datoteka ...
+Name[sr]=Текстуални фајл...
+Name[sr@Latn]=Tekstualni fajl...
+Name[sv]=Textfil...
+Name[ta]=உரைக் கோப்பு
+Name[te]=వచన దస్త్రం...
+Name[tg]=Файли матнӣ...
+Name[th]=แฟ้มข้อความ...
+Name[tr]=Metin Dosyası...
+Name[tt]=Mäten Bireme...
+Name[uk]=Текстовий файл...
+Name[uz]=Matn fayli...
+Name[uz@cyrillic]=Матн файли...
+Name[vi]=Tập tin Văn bản...
+Name[wa]=Fitchî tecse...
+Name[zh_CN]=文本文件...
+Name[zh_TW]=文字檔案...
+Comment=Enter text filename:
+Comment[af]=Voer teks lêernaam in:
+Comment[ar]=أدخل اسم الملف النصي:
+Comment[be]=Вызначце назву тэкставага файла:
+Comment[bg]=Въведете име на текстовия файл:
+Comment[bn]=টেক্সট ফাইলের নাম:
+Comment[br]=Roit un anv ar restr skrid :
+Comment[bs]=Unesite ime tekst datoteke:
+Comment[ca]=Entra el nom del fitxer de text:
+Comment[cs]=Zadejte název textového souboru:
+Comment[csb]=Wpiszë miono tekstowégò lopkù:
+Comment[da]=Indtast tekstfilnavn:
+Comment[de]=Name der Textdatei eingeben:
+Comment[el]=Δώστε το όνομα του αρχείου κειμένου:
+Comment[eo]=Enigu la tekstodosieran nomon:
+Comment[es]=Introduzca el nombre del archivo de texto:
+Comment[et]=Sisesta tekstifaili nimi:
+Comment[eu]=Sartu testu fitxategiaren izena
+Comment[fa]=نام پروندۀ‌ متنی را وارد کنید:
+Comment[fi]=Anna tekstitiedoston nimi:
+Comment[fr]=Donnez le nom du fichier de texte :
+Comment[fy]=Namme fan teksttriem ynfiere:
+Comment[ga]=Iontráil ainm an téacschomhaid:
+Comment[gl]=Introduza o nome do ficheiro de texto:
+Comment[he]=הזן שם לקובץ הטקסט:
+Comment[hi]=पाठ फ़ाइल-नाम भरें:
+Comment[hr]=Upišite naziv tekstualne datoteke:
+Comment[hu]=A szöveges fájl neve:
+Comment[is]=Sláðu inn nafn á textaskrá:
+Comment[it]=Immetti nome file di testo:
+Comment[ja]=テキストファイル名を入力:
+Comment[ka]=შეიყვანეთ ტექსტური ფაილის სახელი:
+Comment[kk]=Мәтін файлын келтіріңіз:
+Comment[km]=បញ្ចូល​ឈ្មោះ​ឯកសារ​អត្ថបទ ៖
+Comment[ko]=텍스트 파일 이름을 입력하십시오:
+Comment[lt]=Įveskite teksto bylos vardą:
+Comment[lv]=Ievadiet teksta faila nosaukumu:
+Comment[mk]=Внесете го името на текстуалната датотека:
+Comment[ms]=Masukkan nama fail teks:
+Comment[mt]=Ittajpja isem ta' fajl b'test:
+Comment[nb]=Skriv inn navnet på tekstfila:
+Comment[nds]=Naam vun de Textdatei ingeven:
+Comment[ne]=पाठ फाइलनाम प्रविष्ट गर्नुहोस्:
+Comment[nl]=Naam van tekstbestand invoeren:
+Comment[nn]=Oppgje tekstfilnamn:
+Comment[pa]=ਪਾਠ ਫਾਇਲ ਨਾਂ ਦਿਓ:
+Comment[pl]=Podaj nazwę pliku tekstowego:
+Comment[pt]=Indique o nome do ficheiro de texto:
+Comment[pt_BR]=Insira nome do arquivo de texto:
+Comment[ro]=Introduceți numele fișierului text:
+Comment[ru]=Введите имя тестового файла:
+Comment[rw]=Kwinjiza izinadosiye mwandiko:
+Comment[se]=Bija teakstafiilanama:
+Comment[sk]=Zadajte meno textového súboru:
+Comment[sl]=Vnesite ime besedilne datoteke:
+Comment[sr]=Унесите име текстуалног фајла:
+Comment[sr@Latn]=Unesite ime tekstualnog fajla:
+Comment[sv]=Ange textfilnamn:
+Comment[ta]=உரை கோப்பு பெயரை உள்ளிடு:
+Comment[te]=వచన దస్త్రం పేరును వ్రాయండి:
+Comment[tg]=Номи файли матнро ворид кунед:
+Comment[th]=เติมชื่อแฟ้มข้อความ:
+Comment[tr]=Metin dosya adını girin:
+Comment[tt]=Mäten-birem adın kert:
+Comment[uk]=Введіть назву текстового файла:
+Comment[uz]=Matn faylining nomini kiriting:
+Comment[uz@cyrillic]=Матн файлининг номини киритинг:
+Comment[vi]=Điền tên tập tin văn bản:
+Comment[wa]=Dinez l' no do fitchî tecse:
+Comment[zh_CN]=输入文本文件名:
+Comment[zh_TW]=輸入純文字檔案名稱:
+Type=Link
+URL=.source/TextFile.txt
+Icon=txt
diff --git a/kdesktop/init/Templates/TextFile.txt b/kdesktop/init/Templates/TextFile.txt
new file mode 100644
index 000000000..8d1c8b69c
--- /dev/null
+++ b/kdesktop/init/Templates/TextFile.txt
@@ -0,0 +1 @@
+
diff --git a/kdesktop/init/Templates/URL.desktop b/kdesktop/init/Templates/URL.desktop
new file mode 100644
index 000000000..968859c37
--- /dev/null
+++ b/kdesktop/init/Templates/URL.desktop
@@ -0,0 +1,3 @@
+[Desktop Entry]
+URL=
+Type=Link
diff --git a/kdesktop/init/Templates/ZIP-Device.desktop b/kdesktop/init/Templates/ZIP-Device.desktop
new file mode 100644
index 000000000..f51641275
--- /dev/null
+++ b/kdesktop/init/Templates/ZIP-Device.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+MountPoint=
+Dev=
+ReadOnly=false
+Type=FSDevice
+Icon=zip_mount
+UnmountIcon=zip_unmount
+Actions=Eject;
+X-KDE-Priority=TopLevel
+[Desktop Action Eject]
+Name=Eject
+Name[af]=Uitskiet
+Name[ar]=أقذف
+Name[az]=Çıxart
+Name[be]=Вызваліць
+Name[bg]=Изваждане
+Name[bn]=ইজেক্ট
+Name[br]=Stlepel
+Name[bs]=Izbaci
+Name[ca]=Expulsa
+Name[cs]=Vysunout
+Name[csb]=Wësënie
+Name[cy]=Allfwrw
+Name[da]=Skub ud
+Name[de]=Auswerfen
+Name[el]=Εξαγωγή
+Name[eo]=Eligo
+Name[es]=Expulsar
+Name[et]=Väljastamine
+Name[eu]=Egotzi
+Name[fa]=پس زدن
+Name[fi]=Poista
+Name[fr]=Éjecter
+Name[fy]=Utsmytknop
+Name[ga]=Díchuir
+Name[gl]=Expulsar
+Name[he]=הוצא
+Name[hi]=बाहर
+Name[hr]=Izbaci
+Name[hu]=Kidobás
+Name[is]=Henda út
+Name[it]=Espelli
+Name[ja]=取り出し
+Name[ka]=CD-ს ამოღება
+Name[kk]=Алып-шығару
+Name[km]=ច្រាន​ចេញ
+Name[ko]=꺼내기
+Name[lo]=ເອົາແຜ່ນອອກ
+Name[lt]=Išmesti
+Name[lv]=Izņemt
+Name[mk]=Извади
+Name[mn]=Гаргах
+Name[ms]=Lenting
+Name[mt]=Iftaħ
+Name[nb]=Løs ut
+Name[nds]=Rutsmieten
+Name[ne]=निकाल्नुहोस्
+Name[nl]=Uitwerpen
+Name[nn]=Løys ut
+Name[nso]=Ntsha
+Name[oc]=Expulsa
+Name[pa]=ਬਾਹਰ ਕੱਢੋ
+Name[pl]=Wysuń
+Name[pt]=Ejectar
+Name[pt_BR]=Ejetar
+Name[ro]=Ejectează
+Name[ru]=Извлечь CD
+Name[rw]=Gusohora
+Name[se]=Bálkes olggos
+Name[sk]=Vysunúť
+Name[sl]=Izvrzi
+Name[sr]=Избаци
+Name[sr@Latn]=Izbaci
+Name[ss]=Khafuna
+Name[sv]=Mata ut
+Name[ta]=வெளித்தள்
+Name[te]=ఎజెక్ట్
+Name[tg]=Ихроҷ
+Name[th]=เอาแผ่นออก
+Name[tr]=Çıkart
+Name[tt]=Çığar
+Name[uk]=Виштовхнути
+Name[uz]=Chiqarish
+Name[uz@cyrillic]=Чиқариш
+Name[ven]=Bvisa
+Name[vi]=Đẩy đĩa ra
+Name[wa]=Fé rexhe
+Name[xh]=Khuphela ngaphandle
+Name[zh_CN]=弹出
+Name[zh_TW]=退出
+Name[zu]=Khipha
+Exec=kdeeject %v
diff --git a/kdesktop/init/Templates/linkCAMERA.desktop b/kdesktop/init/Templates/linkCAMERA.desktop
new file mode 100644
index 000000000..5d9dc9be1
--- /dev/null
+++ b/kdesktop/init/Templates/linkCAMERA.desktop
@@ -0,0 +1,150 @@
+[Desktop Entry]
+Name=Camera Device...
+Name[af]=Kamera Toestel...
+Name[ar]=جهاز الكاميرا...
+Name[be]=Камера...
+Name[bg]=Фотоапарат...
+Name[bn]=ক্যমেরা ডিভাইস...
+Name[br]=Trobarzhell ar gamera ...
+Name[bs]=Kamera uređaj...
+Name[ca]=Dispositiu de càmera...
+Name[cs]=Kamera...
+Name[csb]=Òdjimkòwô kaméra...
+Name[cy]=Dyfais Camera...
+Name[da]=Kamera-enhed...
+Name[de]=Kamera ...
+Name[el]=Συσκευή κάμερας...
+Name[eo]=kamero-aparato...
+Name[es]=Cámara...
+Name[et]=Kaameraseade
+Name[eu]=Kamera...
+Name[fa]=دستگاه دوربین...
+Name[fi]=Kamerat...
+Name[fr]=Appareil photo
+Name[fy]=Kamera...
+Name[ga]=Gléas Ceamara...
+Name[gl]=Dispositivo de Cámara...
+Name[he]=התקן מצלמה...
+Name[hi]=कैमरा उपकरण...
+Name[hr]=Kamera...
+Name[hu]=Fényképezőgép...
+Name[is]=Myndavél...
+Name[it]=Dispositivo macchina fotografica...
+Name[ja]=カメラデバイス...
+Name[ka]=კამერის მოწყობილობა
+Name[kk]=Фотокамера құрылғысы...
+Name[km]=ឧបករណ៍​ម៉ាស៊ីន​ថត...
+Name[ko]=카메라 장치...
+Name[lt]=Kameros įrenginys...
+Name[lv]=Kameras iekārta...
+Name[mk]=Камера...
+Name[mn]=Камерын Төхөөрөмж...
+Name[ms]=Peranti Kamera...
+Name[mt]=Kamera...
+Name[nb]=Kameraenhet …
+Name[nds]=Kamera...
+Name[ne]=क्यामेरा यन्त्र...
+Name[nl]=Camera...
+Name[nn]=Kameraeining …
+Name[pa]=ਕੈਮਰਾ ਜੰਤਰ...
+Name[pl]=Aparat fotograficzny...
+Name[pt]=Máquina Fotográfica...
+Name[pt_BR]=Dispositivo de Câmera...
+Name[ro]=Dispozitiv foto...
+Name[ru]=Камера...
+Name[rw]=Apareye Kamera...
+Name[se]=Govvenapperáhttaovttadat …
+Name[sk]=Zariadenie digitálneho fotoaparátu...
+Name[sl]=Naprava kamere ...
+Name[sr]=Камера...
+Name[sr@Latn]=Kamera...
+Name[sv]=Kameraenhet...
+Name[ta]=புகைப்பட கருவி சாதனங்கள்
+Name[te]=కెమెరా పరికరం...
+Name[tg]=Дастгоҳи камера...
+Name[th]=อุปกรณ์กล้อง...
+Name[tr]=Kamera Aygıtı...
+Name[tt]=kamera Cıhazı...
+Name[uk]=Пристрій фотоапарата...
+Name[uz]=Fotoaparat uskunasi...
+Name[uz@cyrillic]=Фотоапарат ускунаси...
+Name[vi]=Máy ảnh số...
+Name[wa]=Éndjin camera...
+Name[zh_CN]=相机设备...
+Name[zh_TW]=照相機設備...
+Comment=New camera
+Comment[af]=Nuwe kamera
+Comment[ar]=كاميرا جديدة
+Comment[be]=Новая камера
+Comment[bg]=Нов фотоапарат
+Comment[bn]=নতুন ক্যামেরা
+Comment[br]=Kamera nevez
+Comment[bs]=Nova kamera
+Comment[ca]=Càmera nova
+Comment[cs]=Nová kamera
+Comment[csb]=Nowô òdjimkòwô kaméra
+Comment[cy]=Camera Newydd
+Comment[da]=Nyt kamera
+Comment[de]=Neue Kamera
+Comment[el]=Νέα κάμερα
+Comment[eo]=Nova kamero
+Comment[es]=Nueva cámara
+Comment[et]=Uus kaamera
+Comment[eu]=Kamera berria
+Comment[fa]=دوربین جدید
+Comment[fi]=Uusi kamera
+Comment[fr]=Nouvel appareil photo
+Comment[fy]=Nije kamera
+Comment[ga]=Ceamara nua
+Comment[gl]=Nova cámara
+Comment[he]=מצלמה חדשה
+Comment[hi]=नया कैमरा
+Comment[hr]=Nova kamera
+Comment[hu]=Új fényképezőgép
+Comment[is]=Ný myndavél
+Comment[it]=Nuova macchina fotografica
+Comment[ja]=新しいカメラ
+Comment[ka]=ახალი კამერა
+Comment[kk]=Жаңа фотокамера
+Comment[km]=ម៉ាស៊ីន​ថត​ថ្មី
+Comment[ko]=새 카메라
+Comment[lt]=Nauja kamera
+Comment[lv]=Jauna kamera
+Comment[mk]=Нова камера
+Comment[mn]=Шинэ камер
+Comment[ms]=Kamera baru
+Comment[mt]=Kamera ġdida
+Comment[nb]=Nytt kamera
+Comment[nds]=Niege Kamera
+Comment[ne]=नयाँ क्यामेरा
+Comment[nl]=Nieuwe camera
+Comment[nn]=Nytt kamera
+Comment[pa]=ਨਵਾਂ ਕੈਮਰਾ
+Comment[pl]=Nowy aparat fotograficzny
+Comment[pt]=Nova máquina fotográfica
+Comment[pt_BR]=Nova câmera
+Comment[ro]=Aparat foto nou
+Comment[ru]=Ссылка на устройство цифровой камеры
+Comment[rw]=Kamera nshya
+Comment[se]=Ođđa govvenapperáhtta
+Comment[sk]=Nový digitálny fotoaparát
+Comment[sl]=Nov fotoaparat
+Comment[sr]=Нова камера
+Comment[sr@Latn]=Nova kamera
+Comment[sv]=Ny kamera
+Comment[ta]=புதிய புகைப்பட கருவி
+Comment[te]=కొత్త కెమెరా
+Comment[tg]=Камераи нав
+Comment[th]=เพิ่มกล้องใหม่
+Comment[tr]=Yeni kamera
+Comment[tt]=Yaña kamera
+Comment[uk]=Новий фотоапарат
+Comment[uz]=Yangi fotoaparat
+Comment[uz@cyrillic]=Янги фотоапарат
+Comment[vi]=Tạo máy ảnh số mới
+Comment[wa]=Novele camera
+Comment[zh_CN]=新建相机
+Comment[zh_TW]=新增照相機
+Type=Link
+URL=.source/CAMERA-Device.desktop
+Icon=camera_unmount
diff --git a/kdesktop/init/Templates/linkCDROM.desktop b/kdesktop/init/Templates/linkCDROM.desktop
new file mode 100644
index 000000000..b895fe79b
--- /dev/null
+++ b/kdesktop/init/Templates/linkCDROM.desktop
@@ -0,0 +1,150 @@
+[Desktop Entry]
+Name=CD-ROM Device...
+Name[af]=CD-ROM Toestel
+Name[ar]=جهاز الأقراص المدمجة...
+Name[be]=Прылада CD-ROM...
+Name[bg]=CD-ROM...
+Name[bn]=সিডি-রম ডিভাইস...
+Name[br]=Trobarzhell CD-ROM ...
+Name[bs]=CD-ROM uređaj...
+Name[ca]=Dispositiu CD-ROM...
+Name[cs]=Jednotka CD-ROM...
+Name[csb]=Nëk CD-ROM...
+Name[cy]=Dyfais CD-ROM...
+Name[da]=Cd-rom-enhed...
+Name[de]=CD-ROM-Laufwerk ...
+Name[el]=Συσκευή CD-ROM...
+Name[eo]=Lumdiskingo...
+Name[es]=Unidad de CD-ROM...
+Name[et]=CD-ROM seade...
+Name[eu]=CD-ROM gailua...
+Name[fa]=دستگاه CD-ROM...
+Name[fi]=CD-ROM-laitteet...
+Name[fr]=Lecteur de CD-ROM...
+Name[fy]=kompaktskiifstasjon ...
+Name[ga]=Gléas CD-ROM...
+Name[gl]=Dispositivo de CD-ROM...
+Name[he]=התקן תקליטור...
+Name[hi]=सीडी-रोम उपकरण...
+Name[hr]=CD/DVD-ROM uređaj...
+Name[hu]=CD-meghajtó...
+Name[is]=Geisladrif...
+Name[it]=Dispositivo CD-ROM...
+Name[ja]=CD-ROM デバイス...
+Name[ka]=CD-ROM მოწყობილობა
+Name[kk]=CD-ROM құрылғысы...
+Name[km]=ឧបករណ៍ CD-ROM...
+Name[ko]=CD-ROM 장치...
+Name[lt]=CD-ROM įrenginys...
+Name[lv]=CD-ROM Iekārta...
+Name[mk]=CD-ROM Уред...
+Name[mn]=КД-ROM төхөөрөмж...
+Name[ms]=Peranti CD-ROM...
+Name[mt]=CDROM...
+Name[nb]=CD-ROM-enhet …
+Name[nds]=CD-ROM-Reedschap...
+Name[ne]=CD-ROM यन्त्र...
+Name[nl]=CD-romspeler...
+Name[nn]=CD-ROM-eining …
+Name[pa]=CD-ROM ਜੰਤਰ...
+Name[pl]=Urządzenie CD-ROM...
+Name[pt]=Dispositivo de CD-ROM...
+Name[pt_BR]=Dispositivo de CD-ROM...
+Name[ro]=Dispozitiv CD-ROM...
+Name[ru]=CD-ROM...
+Name[rw]=Apareye CD-ROM...
+Name[se]=CD-ROM-ovttadat …
+Name[sk]=Zariadenie CD-ROM...
+Name[sl]=Naprava CD-ROM ...
+Name[sr]=CD/DVD-ROM уређај...
+Name[sr@Latn]=CD/DVD-ROM uređaj...
+Name[sv]=Cdrom-enhet...
+Name[ta]=CD-ROM சாதனம்...
+Name[te]=సీడి-రామ్ పరికరం...
+Name[tg]=Дастгоҳи CD-ROM...
+Name[th]=อุปกรณ์ซีดีรอม
+Name[tr]=CD-ROM Aygıtı...
+Name[tt]=CD-ROM Cıhazı...
+Name[uk]=Пристрій CD-ROM...
+Name[uz]=Kompakt-disk uskunasi...
+Name[uz@cyrillic]=Компакт-диск ускунаси...
+Name[vi]=Thiết bị đọc đĩa CD-ROM...
+Name[wa]=Éndjin léjheu di plakes lazer...
+Name[zh_CN]=CD-ROM 设备...
+Name[zh_TW]=光碟機設備
+Comment=New CD-ROM Device
+Comment[af]=Nuwe CD-ROM Toestel
+Comment[ar]=جهاز أقراص مدمجة جديد
+Comment[be]=Новая прылада CD-ROM
+Comment[bg]=Ново устройство CD-ROM
+Comment[bn]=নতুন সিডি-রম ডিভাইস
+Comment[br]=Trobarzhell CD-ROM Nevez
+Comment[bs]=Novi CD/DVD-ROM uređaj
+Comment[ca]=Dispositiu CD-ROM nou
+Comment[cs]=Nová jednotka CD-ROM
+Comment[csb]=Nowi nëk CD
+Comment[cy]=Dyfais CD-ROM Newydd
+Comment[da]=Ny cd-rom-enhed
+Comment[de]=Neues CD-ROM-Laufwerk
+Comment[el]=Νέα συσκευή CD-ROM
+Comment[eo]=Nova lumdiskingo...
+Comment[es]=Nueva unidad de CD-ROM
+Comment[et]=Uus CD-ROM seade
+Comment[eu]=CD-ROM gailu berria
+Comment[fa]=دستگاه CD-ROM جدید
+Comment[fi]=Uusi CD/DVD-ROM -laite
+Comment[fr]=Nouveau lecteur de CD-ROM
+Comment[fy]=Nije kompaktskiifstasjon
+Comment[ga]=Gléas nua CD-ROM
+Comment[gl]=Novo Dispositivo de CD-ROM
+Comment[he]=התקן תקליטור חדש
+Comment[hi]=नया सीडी-रोम उपकरण
+Comment[hr]=Novi CD/DVD-ROM uređaj
+Comment[hu]=Új CD-meghajtó
+Comment[is]=Nýtt geisladrif
+Comment[it]=Nuovo dispositivo CD-ROM
+Comment[ja]=新規 CD-ROM デバイス
+Comment[ka]=ახალი CD-ROM მოწყობილობა
+Comment[kk]=Жаңа CD-ROM құрылғысы
+Comment[km]=ឧបករណ៍ CD-ROM ថ្មី
+Comment[ko]=새 CD-ROM 장치
+Comment[lt]=Naujas CD-ROM įrenginys
+Comment[lv]=Jauna CD-ROM Iekārta
+Comment[mk]=Нов CD-ROM уред
+Comment[mn]=Шинэ КД-ROM төхөөрөмж
+Comment[ms]=Peranti CD-ROM Baru
+Comment[mt]=CD-ROM ġdid
+Comment[nb]=Ny CD-ROM-enhet
+Comment[nds]=Niege CD-ROM-Reedschap
+Comment[ne]=नयाँ CD-ROM यन्त्र
+Comment[nl]=Nieuwe cd-romspeler
+Comment[nn]=Ny CD-ROM-eining
+Comment[pa]=ਨਵਾਂ CD-ROM ਜੰਤਰ
+Comment[pl]=Nowe urządzenie CD-ROM
+Comment[pt]=Novo Dispositivo de CD-ROM
+Comment[pt_BR]=Novo dispositivo de CD-ROM
+Comment[ro]=Dispozitiv CD-ROM nou
+Comment[ru]=Ссылка на устройство CD-ROM
+Comment[rw]=Apareye CD-ROM Nshya
+Comment[se]=Ođđa CD-ROM-ovttadat
+Comment[sk]=Nové zariadenie CD-ROM
+Comment[sl]=Nova naprava CD-ROM
+Comment[sr]=Нови CD/DVD-ROM уређај
+Comment[sr@Latn]=Novi CD/DVD-ROM uređaj
+Comment[sv]=Ny cdrom-enhet
+Comment[ta]=புதிய CD-ROM சாதனம்
+Comment[te]=కొత్త సీడి-రామ్ పరికరం
+Comment[tg]=Дастгоҳи нави CD-ROM
+Comment[th]=กำหนดอุปกรณ์ซีดีใหม่
+Comment[tr]=Yeni CD-ROM Aygıtı
+Comment[tt]=Yaña CD-ROM Cıhazı
+Comment[uk]=Новий пристрій CD-ROM
+Comment[uz]=Yangi kompakt-disk uskunasi
+Comment[uz@cyrillic]=Янги компакт-диск ускунаси
+Comment[vi]=Tạo CD-ROM mới
+Comment[wa]=Novea éndjin léjheu di plakes lazer
+Comment[zh_CN]=新建 CD-ROM 设备
+Comment[zh_TW]=新光碟機設備
+Type=Link
+URL=.source/CDROM-Device.desktop
+Icon=cdrom_unmount
diff --git a/kdesktop/init/Templates/linkCDWRITER.desktop b/kdesktop/init/Templates/linkCDWRITER.desktop
new file mode 100644
index 000000000..8a080c55a
--- /dev/null
+++ b/kdesktop/init/Templates/linkCDWRITER.desktop
@@ -0,0 +1,150 @@
+[Desktop Entry]
+Name=CDWRITER Device...
+Name[af]=CD Skrywer Toestel
+Name[ar]=جهاز تسجيل الأقراص المدمجة...
+Name[be]=Прылада CDWRITER...
+Name[bg]=CDWRITER...
+Name[bn]=সিডি-রাইটার ডিভাইস...
+Name[br]=Trobarzhell an engraver CD ...
+Name[bs]=CD pržilica...
+Name[ca]=Dispositiu CDWRITER...
+Name[cs]=Vypalovačka CD...
+Name[csb]=Wëpôlôrz CD...
+Name[cy]=Dyfais CDWRITER...
+Name[da]=Cd-skriver enhed...
+Name[de]=CD-Brenner ...
+Name[el]=Συσκευή CDWRITER...
+Name[eo]=Lumdiska skribilo...
+Name[es]=Grabadora de CD...
+Name[et]=CD-kirjutaja...
+Name[eu]=CDWRITER gailua...
+Name[fa]=دستگاه CDWRITER...
+Name[fi]=CDWRITER-laite...
+Name[fr]=Graveur de CD-ROM...
+Name[fy]=kompaktskiifstasjon...
+Name[ga]=Gléas CDWRITER...
+Name[gl]=Dispositivo CDWRITER...
+Name[he]=התקן צורב...
+Name[hi]=सीडी-राइटर उपकरण...
+Name[hr]=CD/DVD pržilica...
+Name[hu]=CD-író...
+Name[is]=Geisladiskaskrifari...
+Name[it]=Masterizzatore...
+Name[ja]=CD ライターデバイス...
+Name[ka]=CDWRITER მოწყობილობა
+Name[kk]=CDWRITER құрылғысы...
+Name[km]=ឧបករណ៍ CDWRITER...
+Name[ko]=CDWRITER 장치...
+Name[lt]=CDWRITER įrenginys...
+Name[lv]=CD rakstīšanas iekārta...
+Name[mk]=CDWRITER Уред...
+Name[mn]=КД бичигч төхөөрөмж
+Name[ms]=Peranti CDWRITER...
+Name[mt]=CDWRITER...
+Name[nb]=CD-brenner-enhet
+Name[nds]=CD-Brenner...
+Name[ne]=CDWRITER यन्त्र...
+Name[nl]=CD-writer...
+Name[nn]=CD-brennareining …
+Name[pa]=CDWRITER ਜੰਤਰ...
+Name[pl]=Nagrywarka CD...
+Name[pt]=Gravador de CDs...
+Name[pt_BR]=Dispositivo de Gravação de CD...
+Name[ro]=Dispozitiv CD-Writer...
+Name[ru]=Пишущий CD-ROM...
+Name[rw]=Apareye MWANDIKA-CD...
+Name[se]=CDWRITER-ovttadat …
+Name[sk]=Zariadenie CDWRITER...
+Name[sl]=Naprava CDWRITER ...
+Name[sr]=CD/DVD резач...
+Name[sr@Latn]=CD/DVD rezač...
+Name[sv]=Cd-brännarenhet...
+Name[ta]=CDWRITER சாதனம்
+Name[te]=సీడి వ్రైటర్ పరికరం...
+Name[tg]=Дастгоҳи CDWRITER...
+Name[th]=อุปกรณ์เขียนซีดี...
+Name[tr]=CD Yazıcı Aygıtı...
+Name[tt]=CD-Yazğıç Cıhazı...
+Name[uk]=Пристрій CDWRITER...
+Name[uz]=Kompakt-disk yozuvchi uskuna...
+Name[uz@cyrillic]=Компакт-диск ёзувчи ускуна...
+Name[vi]=Thiết bị ghi đĩa CD...
+Name[wa]=Éndjin broûleu di plakes lazer...
+Name[zh_CN]=刻录机设备...
+Name[zh_TW]=光碟燒錄機設備
+Comment=New CDWRITER Device
+Comment[af]=Nuwe CD Skrywer Toestel
+Comment[ar]=جهاز تسجيل أقراص مدمجة جديد
+Comment[be]=Новая прылада CDWRITER
+Comment[bg]=Ново устройство CDWRITER
+Comment[bn]=নতুন সিডি-রাইটার ডিভাইস
+Comment[br]=Trobarzhell CDSKRIVER nevez
+Comment[bs]=Nova CD pržilica
+Comment[ca]=Dispositiu CDWRITER nou
+Comment[cs]=Nová vypalovačka CD
+Comment[csb]=Nowi wëpôlôrz CD
+Comment[cy]=Dyfais CDWRITER Newydd
+Comment[da]=Ny cd-skriver enhed
+Comment[de]=Neuer CD-Brenner
+Comment[el]=Νέα συσκευή CDWRITER
+Comment[eo]=Nova lumdisk-skribilo
+Comment[es]=Nueva grabadora de CD
+Comment[et]=Uus CD-kirjutaja
+Comment[eu]=CDWRITER gailu berria
+Comment[fa]=دستگاه CDWRITER جدید
+Comment[fi]=Uusi CDWRITER-laite
+Comment[fr]=Nouveau graveur de CD-ROM
+Comment[fy]=Nije kompaktskiifstasjon
+Comment[ga]=Gléas CDWRITER Nua
+Comment[gl]=Novo Dispositivo CDWRITER
+Comment[he]=התקן צורב חדש
+Comment[hi]=नया सीडी-राइटर उपकरण
+Comment[hr]=Nova CD/DVD pržilica
+Comment[hu]=Új CD-író
+Comment[is]=Nýr geisladiskaskrifari
+Comment[it]=Nuovo masterizzatore
+Comment[ja]=新規 CD ライターデバイス
+Comment[ka]=ახალი CDWRITER მოწყობილობა
+Comment[kk]=Жаңа CDWRITER құрылғысы
+Comment[km]=ឧបករណ៍ CDWRITER ថ្មី
+Comment[ko]=새 CDWRITER 장치
+Comment[lt]=Naujas CDWRITER įrenginys
+Comment[lv]=Jauna CD rakstīšanas iekārta
+Comment[mk]=Нов CDWRITER уред
+Comment[mn]=Шинэ КД бичигч төхөөрөмж
+Comment[ms]=Peranti CDWRITER Baru
+Comment[mt]=Apparat CDWRITER ġdid
+Comment[nb]=Ny CD-brenner-enhet
+Comment[nds]=Niegen CD-Brenner
+Comment[ne]=नयाँ CDWRITER यन्त्र
+Comment[nl]=Nieuwe CD-writer
+Comment[nn]=Ny CD-brennareining
+Comment[pa]=ਨਵਾਂ CDWRITER ਜੰਤਰ
+Comment[pl]=Nowa nagrywarka CD
+Comment[pt]=Novo Gravador de CDs
+Comment[pt_BR]=Novo dispositivo de Gravação de CD
+Comment[ro]=Dispozitiv CD-Writer nou
+Comment[ru]=Ссылка на устройство пишущего CD-ROM
+Comment[rw]=Apareye MWANDIKA-CD Nshya
+Comment[se]=Ođđa CDWRITER-ovttadat
+Comment[sk]=Nové zariadenie CDWRITER
+Comment[sl]=Nova naprava CDWRITER
+Comment[sr]=Нови CD/DVD резач
+Comment[sr@Latn]=Novi CD/DVD rezač
+Comment[sv]=Ny cd-brännarenhet
+Comment[ta]=புது CDWRITER சாதனம்
+Comment[te]=కొత్త సీడి వ్రైటర్ పరికరం
+Comment[tg]=Дастгоҳ нави CDWRITER
+Comment[th]=กำหนดอุปกรณ์เขียนซีดีใหม่
+Comment[tr]=Yeni CD Yazıcı Aygıtı
+Comment[tt]=Yaña CD-Yazğıç Cıhazı
+Comment[uk]=Новий пристрій CDWRITER
+Comment[uz]=Yangi kompakt-disk yozuvchi uskuna
+Comment[uz@cyrillic]=Янги компакт-диск ёзувчи ускуна
+Comment[vi]=Tạo thiết bị ghi CD mới
+Comment[wa]=Novea éndjin broûleu di plakes lazer
+Comment[zh_CN]=新建刻录机设备
+Comment[zh_TW]=新光碟燒錄機設備
+Type=Link
+URL=.source/CDWRITER-Device.desktop
+Icon=cdwriter_unmount
diff --git a/kdesktop/init/Templates/linkDVDROM.desktop b/kdesktop/init/Templates/linkDVDROM.desktop
new file mode 100644
index 000000000..e65875b9d
--- /dev/null
+++ b/kdesktop/init/Templates/linkDVDROM.desktop
@@ -0,0 +1,150 @@
+[Desktop Entry]
+Name=DVD-ROM Device...
+Name[af]=DVD-ROM Toestel
+Name[ar]=جهاز قارئ أقراص رقمية مرئية...
+Name[be]=Прылада DVD-ROM...
+Name[bg]=DVD-ROM...
+Name[bn]=ডিভিডি-রম ডিভাইস...
+Name[br]=Trobarzhell DVD-ROM ...
+Name[bs]=DVD-ROM uređaj...
+Name[ca]=Dispositiu DVD-ROM...
+Name[cs]=Jednotka DVD-ROM...
+Name[csb]=Nëk DVD-ROM...
+Name[cy]=Dyfais DVD-ROM...
+Name[da]=Dvd-rom-enhed...
+Name[de]=DVD-ROM-Laufwerk ...
+Name[el]=Συσκευή DVD-ROM...
+Name[eo]=DVDdiskingo...
+Name[es]=Unidad de DVD-ROM...
+Name[et]=DVD-ROM seade...
+Name[eu]=DVD-ROM gailua...
+Name[fa]=دستگاه DVD-ROM...
+Name[fi]=DVD-ROM-laite
+Name[fr]=Lecteur de DVD-ROM...
+Name[fy]=Dûbelskiifstasjon
+Name[ga]=Gléas DVD-ROM...
+Name[gl]=Dispositivo DVD-ROM...
+Name[he]=התקן DVD...
+Name[hi]=डीवीडी-रोम उपकरण...
+Name[hr]=CD/DVD-ROM uređaj...
+Name[hu]=DVD-meghajtó...
+Name[is]=DVD-ROM-drif...
+Name[it]=Dispositivo DVD-ROM...
+Name[ja]=DVD-ROM デバイス...
+Name[ka]=DVD-ROM მოწყობილობა
+Name[kk]=DVD-ROM құрылғысы...
+Name[km]=ឧបករណ៍ DVD-ROM...
+Name[ko]=DVD-ROM 장치...
+Name[lt]=DVD-ROM įrenginys...
+Name[lv]=DVD-ROM Iekārta...
+Name[mk]=DVD-ROM Уред...
+Name[mn]=DVD-ROM төхөөрөмж...
+Name[ms]=Peranti DVD-ROM...
+Name[mt]=DVD-ROM...
+Name[nb]=DVD-ROM-enhet …
+Name[nds]=DVD-ROM-Reedschap...
+Name[ne]=DVD-ROM यन्त्र...
+Name[nl]=DVD-romspeler...
+Name[nn]=DVD-ROM-eining …
+Name[pa]=DVD-ROM ਜੰਤਰ...
+Name[pl]=Urządzenie DVD-ROM...
+Name[pt]=Leitor de DVD-ROMs...
+Name[pt_BR]=Dispositivo de DVD-ROM...
+Name[ro]=Dispozitiv DVD-ROM...
+Name[ru]=DVD-ROM...
+Name[rw]=Apareye DVD-ROM Nshya...
+Name[se]=DVD-ROM-ovttadat …
+Name[sk]=Zariadenie DVD-ROM...
+Name[sl]=Naprava DVD-ROM ...
+Name[sr]=CD/DVD-ROM уређај...
+Name[sr@Latn]=CD/DVD-ROM uređaj...
+Name[sv]=Dvdrom-enhet...
+Name[ta]=டிவிடிராம் சாதனம்
+Name[te]=డివిడి-రామ్ పరికరం...
+Name[tg]=Дастгоҳи DVD-ROM...
+Name[th]=อุปกรณ์ดีวีดีรอม...
+Name[tr]=CD/DVD-ROM Aygıtı...
+Name[tt]=DVD-ROM Cıhazı...
+Name[uk]=Пристрій DVD-ROM...
+Name[uz]=DVD-ROM uskunasi...
+Name[uz@cyrillic]=DVD-ROM ускунаси...
+Name[vi]=Thiết bị đọc đĩa DVD-ROM...
+Name[wa]=Éndjin léjheu di plakes lazer DVD...
+Name[zh_CN]=DVD-ROM 设备...
+Name[zh_TW]=DVD-ROM 設備...
+Comment=New DVD-ROM Device
+Comment[af]=Nuwe DVD-ROM Toestel
+Comment[ar]=جهاز قارئ أقراص رقمية مرئية جديد
+Comment[be]=Новая прылада DVD-ROM
+Comment[bg]=Ново устройство DVD-ROM
+Comment[bn]=নতুন ডিভিডি-রম ডিভাইস
+Comment[br]=Trobarzhell DVD-ROM Nevez
+Comment[bs]=Novi DVD-ROM uređaj
+Comment[ca]=Dispositiu DVD-ROM nou
+Comment[cs]=Nová jednotka DVD-ROM
+Comment[csb]=Nowi nëk DVD-ROM
+Comment[cy]=Dyfais DVD-ROM Newydd
+Comment[da]=Ny dvd-rom enhed
+Comment[de]=Neues DVD-ROM-Laufwerk
+Comment[el]=Νέα συσκευή DVD-ROM
+Comment[eo]=Nova DVDdiskingo...
+Comment[es]=Nueva unidad de DVD-ROM
+Comment[et]=Uus DVD-ROM seade
+Comment[eu]=DVD-ROM gailu berria
+Comment[fa]=دستگاه DVD-ROM جدید
+Comment[fi]=Uusi DVD-ROM-laite
+Comment[fr]=Nouveau lecteur de DVD-ROM
+Comment[fy]=Nije dûbelskiifstasjon
+Comment[ga]=Gléas nua DVD-ROM
+Comment[gl]=Novo Dispositivo DVD-ROM
+Comment[he]=התקן DVD חדש
+Comment[hi]=नया डीवीडी-रोम उपकरण
+Comment[hr]=Novi CD/DVD-ROM uređaj
+Comment[hu]=Új DVD-meghajtó
+Comment[is]=Nýtt DVD-ROM-drif
+Comment[it]=Nuovo dispositivo DVD-ROM
+Comment[ja]=新規 DVD-ROM デバイス
+Comment[ka]=ახალი DVD-ROM მოწყობილობა
+Comment[kk]=Жаңа DVD-ROM құрылғысы
+Comment[km]=ឧបករណ៍ DVD-ROM ថ្មី
+Comment[ko]=새 DVD-ROM 장치
+Comment[lt]=Naujas DVD-ROM įrenginys
+Comment[lv]=Jauna DVD-ROM Iekārta
+Comment[mk]=Нов DVD-ROM уред
+Comment[mn]=Шинэ DVD-төхөөрөмж
+Comment[ms]=Peranti DVD-ROM Baru
+Comment[mt]=DVD-ROM ġdid
+Comment[nb]=Ny DVD-ROM-enhet
+Comment[nds]=Niege DVD-ROM-Reedschap
+Comment[ne]=नयाँ DVD-ROM यन्त्र
+Comment[nl]=Nieuwe DVD-romspeler
+Comment[nn]=Ny DVD-ROM-eining
+Comment[pa]=ਨਵਾਂ DVD-ROM ਜੰਤਰ
+Comment[pl]=Nowe urządzenie DVD-ROM...
+Comment[pt]=Novo leitor de DVD-ROMs
+Comment[pt_BR]=Novo dispositivo de DVD-ROM
+Comment[ro]=Dispozitiv DVD-ROM nou
+Comment[ru]=Ссылка на устройство DVD-ROM
+Comment[rw]=Apareye DVD-ROOM Nshya
+Comment[se]=Ođđa DVD-ROM-ovttadat
+Comment[sk]=Nové zariadenie DVD-ROM
+Comment[sl]=Nova naprava DVD-ROM
+Comment[sr]=Нови CD/DVD-ROM уређај
+Comment[sr@Latn]=Novi CD/DVD-ROM uređaj
+Comment[sv]=Ny dvdrom-enhet
+Comment[ta]=புது DVD-ROM சாதனம்
+Comment[te]=కొత్త డివిడి-రామ్ పరికరం
+Comment[tg]=Дастгоҳи нави DVD-ROM
+Comment[th]=กำหนดอุปกรณ์ซีดี/ดีวีดีรอมใหม่
+Comment[tr]=Yeni DVD-ROM Aygıtı
+Comment[tt]=Yaña DVD-ROM Cıhazı
+Comment[uk]=Новий пристрій DVD-ROM
+Comment[uz]=Yangi DVD uskunasi
+Comment[uz@cyrillic]=Янги DVD ускунаси
+Comment[vi]=Tạo DVD-ROM mới
+Comment[wa]=Novea éndjin léjheu di plakes lazer DVD
+Comment[zh_CN]=新建 DVD-ROM 设备
+Comment[zh_TW]=新 DVD-ROM 設備
+Type=Link
+URL=.source/DVDROM-Device.desktop
+Icon=dvd_unmount
diff --git a/kdesktop/init/Templates/linkFloppy.desktop b/kdesktop/init/Templates/linkFloppy.desktop
new file mode 100644
index 000000000..2a86dd575
--- /dev/null
+++ b/kdesktop/init/Templates/linkFloppy.desktop
@@ -0,0 +1,158 @@
+[Desktop Entry]
+Name=Floppy Device...
+Name[af]=Sagteskyf Toestel...
+Name[ar]=جهاز أقراص مرنة...
+Name[be]=Дыскета...
+Name[bg]=Флопи...
+Name[bn]=ফ্লপি ডিভাইস...
+Name[br]=Trobarzhell Pladennig ...
+Name[bs]=Disketni uređaj...
+Name[ca]=Dispositiu de disquet...
+Name[cs]=Disketová jednotka...
+Name[csb]=Nëk disczétków...
+Name[cy]=Dyfais Disg Meddal...
+Name[da]=Floppy-enhed...
+Name[de]=Diskettenlaufwerk ...
+Name[el]=Συσκευή δισκέτας...
+Name[eo]=Disketingo...
+Name[es]=Unidad de disquetes...
+Name[et]=Flopiseade...
+Name[eu]=Diskete gailua...
+Name[fa]=دستگاه فلاپی...
+Name[fi]=Levykeasema...
+Name[fr]=Lecteur de disquettes...
+Name[fy]=Slappe skiifstasjon...
+Name[ga]=Gléas Diosca Flapach...
+Name[gl]=Dispositivo de Disquete...
+Name[he]=התקן תקליטון...
+Name[hi]=फ़्लॉपी उपकरण...
+Name[hr]=Disketni uređaj...
+Name[hu]=Floppy-meghajtó...
+Name[is]=Disklingadrif...
+Name[it]=Dispositivo dischetti...
+Name[ja]=フロッピーデバイス...
+Name[ka]=დრეკადი დისკის წამყვანი
+Name[kk]=Иілгіш диск...
+Name[km]=ដ្រាយ​ថាស​ទន់...
+Name[ko]=플로피 장치...
+Name[lt]=Diskelių įrenginys...
+Name[lv]=Diskešu Iekārta...
+Name[mk]=Дискетна единица...
+Name[mn]=Уян диск...
+Name[ms]=Peranti Liut...
+Name[mt]=Floppy...
+Name[nb]=Diskettenhet …
+Name[nds]=Diskett-Reedschap...
+Name[ne]=फ्लपी यन्त्र...
+Name[nl]=Diskettestation...
+Name[nn]=Disketteining …
+Name[pa]=ਫਲਾਪੀ ਜੰਤਰ...
+Name[pl]=Stacja dyskietek...
+Name[pt]=Leitor de Disquetes...
+Name[pt_BR]=Dispositivo de disquete...
+Name[ro]=Dispozitiv Floppy...
+Name[ru]=Дисковод...
+Name[rw]=Apareye Disikete...
+Name[se]=Dibmaskearroovttadat …
+Name[sk]=Disketová mechanika...
+Name[sl]=Disketna naprava ...
+Name[sr]=Флопи уређај...
+Name[sr@Latn]=Flopi uređaj...
+Name[sv]=Diskettenhet...
+Name[ta]=நெகிழ்வட்டு சாதனம்...
+Name[te]=ఫ్లాపీ పరికరం...
+Name[tg]=Дастгоҳи Floppy...
+Name[th]=อุปกรณ์ฟลอปปี้...
+Name[tr]=Disket Aygıtı...
+Name[tt]=Floppy Cıhazı...
+Name[uk]=Пристрій гнучкого диска...
+Name[uz]=Disket uskunasi...
+Name[uz@cyrillic]=Дискет ускунаси...
+Name[vi]=Ổ mềm...
+Name[wa]=Éndjin léjheu di plaketes...
+Name[zh_CN]=软驱设备...
+Name[zh_TW]=軟碟設備...
+Comment=New Floppy Device
+Comment[af]=Nuwe Sagteskyf Toestel
+Comment[ar]=جهاز أقراص مرنة جديد
+Comment[az]=Yeni Disket Avadanlığı
+Comment[be]=Новая дыскета
+Comment[bg]=Ново флопи-дисково устройство
+Comment[bn]=নতুন ফ্লপি ডিভাইস
+Comment[br]=Trobarzhell Bladennig Nevez
+Comment[bs]=Novi disketni uređaj
+Comment[ca]=Dispositiu de disquet nou
+Comment[cs]=Nová disketová jednotka
+Comment[csb]=Nowi nëk disczétków
+Comment[cy]=Dyfais Disg Meddal Newydd
+Comment[da]=Ny floppy-enhed
+Comment[de]=Neues Diskettenlaufwerk
+Comment[el]=Νέα συσκευή δισκέτας
+Comment[eo]=Nova disketa ingo
+Comment[es]=Nueva unidad de disquetes
+Comment[et]=Uus flopiseade
+Comment[eu]=Diskete gailu berria
+Comment[fa]=دستگاه فلاپی جدید
+Comment[fi]=Uusi levykeasema
+Comment[fr]=Nouveau lecteur de disquettes
+Comment[fy]=Nije slappe skiifstasjon
+Comment[ga]=Gléas nua diosca flapach
+Comment[gl]=Nova Disqueteira
+Comment[he]=התקן תקליטון חדש
+Comment[hi]=नया फ़्लॉपी उपकरण
+Comment[hr]=Novi disketni uređaj
+Comment[hu]=Új floppy-meghajtó
+Comment[id]=Divais Floppy baru
+Comment[is]=Nýtt disklingadrif
+Comment[it]=Nuovo dispositivo dischetti
+Comment[ja]=新規フロッピーディスク
+Comment[ka]=ახალი დრეკადი დისკის წამყვანი
+Comment[kk]=Жаңа иілгіш диск құрылғысы
+Comment[km]=ឧបករណ៍​ថាស​ទន់​ថ្មី
+Comment[ko]=새 플로피 장치
+Comment[lo]=ກຳນົດອັຸປະກອນຟອບປີ້ໃຫມ่
+Comment[lt]=Naujas diskelių įrenginys
+Comment[lv]=Jauna Diskešu iekārta
+Comment[mk]=Нова дискетна единица
+Comment[mn]=Шинэ уян диск хөтлөгч
+Comment[ms]=Peranti Liut Baru
+Comment[mt]=Apparat floppy ġdid
+Comment[nb]=Ny diskettenhet
+Comment[nds]=Niege Diskettreedschap
+Comment[ne]=नयाँ फ्लपी यन्त्र
+Comment[nl]=Nieuw diskettestation
+Comment[nn]=Ny disketteining
+Comment[nso]=Leano le Leswa la Floopy
+Comment[oc]=Dispositiu de disquet nou
+Comment[pa]=ਨਵਾਂ ਫਲਾਪੀ ਜੰਤਰ
+Comment[pl]=Nowa stacja dyskietek
+Comment[pt]=Novo leitor de disquetes
+Comment[pt_BR]=Novo dispositivo de disquete
+Comment[ro]=Dispozitiv Floppy nou
+Comment[ru]=Ссылка на устройство дисковода
+Comment[rw]=Apareye Disikete Nshya
+Comment[se]=Ođđa dibmaskearroovttadat
+Comment[sk]=Nová disketová mechanika
+Comment[sl]=Nova disketna naprava
+Comment[sr]=Нови флопи уређај
+Comment[sr@Latn]=Novi flopi uređaj
+Comment[sv]=Ny diskettenhet
+Comment[ta]=புது நெகிழ்வட்டு சாதனம்
+Comment[te]=కొత్త ఫ్లాపీ పరికరం
+Comment[tg]=Дастгоҳи нави Floppy
+Comment[th]=กำหนดอุปกรณ์ฟล็อปปีใหม่
+Comment[tr]=Yeni Disket Aygıtı
+Comment[tt]=Yaña Floppy Cıhazı
+Comment[uk]=Новий пристрій гнучкого диска
+Comment[uz]=Yangi disket uskunasi
+Comment[uz@cyrillic]=Янги дискет ускунаси
+Comment[ven]=Maano maswa a Floppy
+Comment[vi]=Tạo ổ mềm mới
+Comment[wa]=Novea éndjin léjheu di plaketes...
+Comment[xh]=Icebo Elitsha le Floppy
+Comment[zh_CN]=新建软驱设备
+Comment[zh_TW]=新軟碟設備
+Comment[zu]=Ithuluzi le-Floppy elisha
+Type=Link
+URL=.source/Floppy.desktop
+Icon=3floppy_unmount
diff --git a/kdesktop/init/Templates/linkHD.desktop b/kdesktop/init/Templates/linkHD.desktop
new file mode 100644
index 000000000..43a5ba482
--- /dev/null
+++ b/kdesktop/init/Templates/linkHD.desktop
@@ -0,0 +1,157 @@
+[Desktop Entry]
+Name=Hard Disc Device...
+Name[af]=Hardeskyf Toestel...
+Name[ar]=جهاز القرص الصلب...
+Name[be]=Раздзел жорсткага дыска...
+Name[bg]=Твърд диск...
+Name[bn]=হার্ড ডিস্ক ডিভাইস...
+Name[br]=Trobarzhell Bladenn ...
+Name[bs]=Hard disk uređaj...
+Name[ca]=Dispositius de disc dur...
+Name[cs]=Pevný disk...
+Name[csb]=Cwiardi disk...
+Name[cy]=Dyfais Disg Caled...
+Name[da]=Harddisk-enhed...
+Name[de]=Festplatte ...
+Name[el]=Συσκευή σκληρού δίσκου...
+Name[eo]=Fiksdiskingo...
+Name[es]=Disco duro...
+Name[et]=Kõvaketas...
+Name[eu]=Diska gogorra...
+Name[fa]=دستگاه دیسک سخت...
+Name[fi]=Kiintolevy...
+Name[fr]=Disque dur...
+Name[fy]=Fêste skiif...
+Name[ga]=Gléas Diosca Crua...
+Name[gl]=Dispositivo de Disco Duro...
+Name[he]=התקן כונן קשיח...
+Name[hi]=हार्ड डिस्क उपकरण...
+Name[hr]=Tvrdi disk...
+Name[hu]=Merevlemez-partíció...
+Name[is]=Harður diskur...
+Name[it]=Disco rigido...
+Name[ja]=ハードディスクデバイス...
+Name[ka]=ხისტი დისკი...
+Name[kk]=Қатқыл диск...
+Name[km]=ឧបករណ៍​ថាស​រឹង...
+Name[ko]=하드 디스크 장치...
+Name[lt]=Kietojo disko įrenginys...
+Name[lv]=Cietais Disks...
+Name[mk]=Тврд диск...
+Name[mn]=Хатуу диск...
+Name[ms]=Peranti Cakera Keras...
+Name[mt]=Ħard disk...
+Name[nb]=Harddisk …
+Name[nds]=Fastplaat...
+Name[ne]=हार्डडिस्क यन्त्र...
+Name[nl]=Harde Schijf...
+Name[nn]=Harddisk …
+Name[pa]=ਹਾਰਡ-ਡਿਸਕ ਜੰਤਰ...
+Name[pl]=Twardy dysk...
+Name[pt]=Disco Rígido...
+Name[pt_BR]=Disco rígido...
+Name[ro]=Dispozitiv Hard Disc...
+Name[ru]=Жёсткий диск...
+Name[rw]=Ububiko Disiki...
+Name[se]=Garraskearru-ovttadat …
+Name[sk]=Pevný disk...
+Name[sl]=Naprava trdega diska ...
+Name[sr]=Хард диск...
+Name[sr@Latn]=Hard disk...
+Name[sv]=Hårddisk...
+Name[ta]=வட்டு
+Name[te]=హార్డ్ డిస్క్ పరికరం...
+Name[tg]=Дастгоҳи Диски Сахти...
+Name[th]=อุปกรณ์ฮาร์ดดิสก์...
+Name[tr]=Sabit Disk Aygıtı...
+Name[tt]=Eçke Disk Cıhazı...
+Name[uk]=Пристрій жорсткого диска...
+Name[uz]=Qattiq disk uskunasi...
+Name[uz@cyrillic]=Қаттиқ диск ускунаси...
+Name[vi]=Ổ cứng...
+Name[wa]=Éndjin di deure plake...
+Name[zh_CN]=硬盘设备...
+Name[zh_TW]=硬碟設備...
+Comment=New Hard Disc
+Comment[af]=Nuwe Hardeskyf
+Comment[ar]=قرص صلب جديد
+Comment[az]=Yeni Sabit Disk
+Comment[be]=Новы раздзел жорсткага дыска
+Comment[bg]=Нов твърд диск
+Comment[bn]=নতুন হার্ড ডিস্ক
+Comment[br]=Trobarzhell Bladenn Nevez
+Comment[bs]=Novi hard disk
+Comment[ca]=Disc dur nou
+Comment[cs]=Nový pevný disk
+Comment[csb]=Nowi cwiardi disk
+Comment[cy]=Disg Caled Newydd
+Comment[da]=Ny harddisk
+Comment[de]=Neue Festplatte
+Comment[el]=Νέος σκληρός δίσκος
+Comment[en_GB]=New Hard Disk
+Comment[eo]=Nova fiksdisko
+Comment[es]=Nuevo disco duro
+Comment[et]=Uus kõvaketas
+Comment[eu]=Disko gogor berria
+Comment[fa]=دیسک سخت جدید
+Comment[fi]=Uusi kiintolevy
+Comment[fr]=Nouveau disque dur
+Comment[fy]=Nije Fêste skiif
+Comment[ga]=Diosca crua nua
+Comment[gl]=Novo Disco Duro
+Comment[he]=כונן קשיח חדש
+Comment[hi]=नया हार्ड डिस्क
+Comment[hr]=Novi tvrdi disk
+Comment[hu]=Új merevlemez-partíció
+Comment[is]=Nýr harður diskur
+Comment[it]=Nuovo disco rigido
+Comment[ja]=新規ハードディスク
+Comment[ka]=ახალი ხისტი დისკი
+Comment[kk]=Жаңа қатқыл дискі
+Comment[km]=ថាស​រឹង​ថ្មី
+Comment[ko]=새 하드 디스크
+Comment[lo]=ກຳນົດອຸປະກອນຮາດດີສໃຫ່ມ
+Comment[lt]=Naujas kietas diskas
+Comment[lv]=Jauns Cietais Disks
+Comment[mk]=Нов тврд диск
+Comment[mn]=Шинэ хатуу диск
+Comment[ms]=Cakera Keras Baru
+Comment[mt]=Ħard disk ġdid
+Comment[nb]=Ny harddisk
+Comment[nds]=Niege Fastplaat
+Comment[ne]=नयाँ हार्डडिस्क
+Comment[nl]=Nieuwe harde schijf
+Comment[nn]=Ny harddisk
+Comment[nso]=Hard Disc ye Ntshwa
+Comment[pa]=ਨਵੀਂ ਹਾਰਡ-ਡਿਸਕ
+Comment[pl]=Nowy twardy dysk
+Comment[pt]=Novo Disco Rígido
+Comment[pt_BR]=Novo disco rígido
+Comment[ro]=Hard Disc nou
+Comment[ru]=Ссылка на устройство жёсткого диска
+Comment[rw]=Ububiko Disiki Bushya
+Comment[se]=Ođđa garraskearru
+Comment[sk]=Nový pevný disk
+Comment[sl]=Nov trdi disk
+Comment[sr]=Нови хард диск
+Comment[sr@Latn]=Novi hard disk
+Comment[sv]=Ny hårddisk
+Comment[ta]=புது வன் தகடு
+Comment[te]=కొత్త హార్డ్ డిస్క్
+Comment[tg]=Диски Сахти нав
+Comment[th]=กำหนดอุปกรณ์ฮาร์ดดิสก์ใหม่
+Comment[tr]=Yeni Sabit Disk
+Comment[tt]=Yaña Qatı Disk
+Comment[uk]=Новий жорсткий диск
+Comment[uz]=Yangi qattiq disk uskunasi
+Comment[uz@cyrillic]=Янги қаттиқ диск ускунаси
+Comment[ven]=Disiki ntswa yo khwathaho
+Comment[vi]=Tạo ổ cứng mới
+Comment[wa]=Novea éndjin di deure plake
+Comment[xh]=Hard Disc Entsha
+Comment[zh_CN]=新建硬盘
+Comment[zh_TW]=新硬碟設備
+Comment[zu]=I-diski Elukhuni Entsha
+Type=Link
+URL=.source/HD.desktop
+Icon=hdd_unmount
diff --git a/kdesktop/init/Templates/linkMO.desktop b/kdesktop/init/Templates/linkMO.desktop
new file mode 100644
index 000000000..44f801e5e
--- /dev/null
+++ b/kdesktop/init/Templates/linkMO.desktop
@@ -0,0 +1,150 @@
+[Desktop Entry]
+Name=MO Device...
+Name[af]=MO Toestel...
+Name[ar]=جهاز MO...
+Name[be]=Прылада MO...
+Name[bg]=MO...
+Name[bn]=MO ডিভাইস...
+Name[br]=Trobarzhell MO ...
+Name[bs]=MO uređaj...
+Name[ca]=Dispositiu MO...
+Name[cs]=MO zařízení...
+Name[csb]=Nëk MO...
+Name[cy]=Dyfais MO...
+Name[da]=MO-enhed...
+Name[de]=MO-Laufwerk ...
+Name[el]=Συσκευή MO...
+Name[eo]=Magnetdiskingo...
+Name[es]=Dispositivo de MO...
+Name[et]=MO seade...
+Name[eu]=MO gailua...
+Name[fa]=دستگاه MO...
+Name[fi]=MO-laite...
+Name[fr]=Périphérique MO...
+Name[fy]=Magnetyske skiif stasjon...
+Name[ga]=Gléas MO...
+Name[gl]=Dispositivo MO...
+Name[he]=התקן MO...
+Name[hi]=एमओ उपकरण...
+Name[hr]=MO uređaj...
+Name[hu]=Magnetooptikai eszköz...
+Name[is]=MO tæki...
+Name[it]=Dispositivo MO...
+Name[ja]=MO デバイス...
+Name[ka]=MO მოწყობილობა
+Name[kk]=Магнитооптик құрылғысы...
+Name[km]=ឧបករណ៍ MO...
+Name[ko]=MO 장치...
+Name[lt]=MO įrenginys...
+Name[lv]=MO Iekārta...
+Name[mk]=MO Уред...
+Name[mn]=MO Төхөөрөмж...
+Name[ms]=Peranti MO...
+Name[mt]=Apparat MO...
+Name[nb]=MO-enhet …
+Name[nds]=MO-Reedschap...
+Name[ne]=MO यन्त्र...
+Name[nl]=MO-apparaat...
+Name[nn]=MO-eining …
+Name[pa]=MO ਜੰਤਰ...
+Name[pl]=Napęd magnetooptyczny...
+Name[pt]=Dispositivo MO...
+Name[pt_BR]=Dispositivo MO...
+Name[ro]=Dispozitiv MO...
+Name[ru]=Магнитооптическое устройство...
+Name[rw]=Apareye MO...
+Name[se]=MO-ovttadat …
+Name[sk]=Disk MO...
+Name[sl]=MO naprava ...
+Name[sr]=МО уређај...
+Name[sr@Latn]=MO uređaj...
+Name[sv]=Magneto-optisk enhet...
+Name[ta]=MO சாதனம்...
+Name[te]=ఎంఓ పరికరం...
+Name[tg]=Дастгоҳи MO...
+Name[th]=อุปกรณ์ MO
+Name[tr]=MO Aygıtı...
+Name[tt]=MO Cıhazı...
+Name[uk]=Пристрій MO...
+Name[uz]=MO uskunasi
+Name[uz@cyrillic]=MO ускунаси
+Name[vi]=Thiết bị MO...
+Name[wa]=Éndjin MO...
+Name[zh_CN]=MO 设备...
+Name[zh_TW]=MO 設備...
+Comment=New MO Device
+Comment[af]=Nuwe MO Toestel
+Comment[ar]=جهاز MO جديد
+Comment[be]=Новая прылада MO
+Comment[bg]=Ново устройство MO
+Comment[bn]=নতুন MO ডিভাইস
+Comment[br]=Trobarzhell MO nevez
+Comment[bs]=Novi MO uređaj
+Comment[ca]=Dispositiu MO nou
+Comment[cs]=Nová MO mechanika
+Comment[csb]=Nowi nëk MO
+Comment[cy]=Dyfais MO Newydd
+Comment[da]=Ny MO-enhed
+Comment[de]=Neues MO-Laufwerk
+Comment[el]=Νέα συσκευή MO
+Comment[eo]=Nova magnetdiskingo
+Comment[es]=Nuevo dispositivo de MO
+Comment[et]=Uus MO seade
+Comment[eu]=MO gailu berria
+Comment[fa]=دستگاه MO جدید
+Comment[fi]=Uusi MO-laite
+Comment[fr]=Nouveau périphérique MO
+Comment[fy]=Nije magnetyske skiif stasjon
+Comment[ga]=Gléas MO Nua
+Comment[gl]=Novo Dispositivo MO
+Comment[he]=התקן MO חדש
+Comment[hi]=नया एमओ उपकरण
+Comment[hr]=Novi MO uređaj
+Comment[hu]=Új magnetooptikai eszköz
+Comment[is]=Nýtt MO tæki
+Comment[it]=Nuovo dispositivo MO
+Comment[ja]=新規 MO デバイス
+Comment[ka]=ახალი MO მოწყობილობა
+Comment[kk]=Жаңа магнитооптик құрылғысы
+Comment[km]=ឧបករណ៍ MO ថ្មី
+Comment[ko]=새 MO 장치
+Comment[lt]=Naujas MO įrenginys
+Comment[lv]=Jauna MO iekārta
+Comment[mk]=Нов MO уред
+Comment[mn]=Шинэ MO төхөөрөмж
+Comment[ms]=Peranti MO Baru
+Comment[mt]=Apparat MO ġdid
+Comment[nb]=Ny MO-enhet
+Comment[nds]=Niege MO-Reedschap
+Comment[ne]=नयाँ MO यन्त्र
+Comment[nl]=Nieuw MO-aparaat
+Comment[nn]=Ny MO-eining
+Comment[pa]=ਨਵਾਂ MO ਜੰਤਰ
+Comment[pl]=Nowy napęd magnetooptyczny
+Comment[pt]=Novo Dispositivo MO
+Comment[pt_BR]=Novo dispositivo MO
+Comment[ro]=Dispozitiv MO nou
+Comment[ru]=Ссылка на магнитооптическое устройство
+Comment[rw]= Apareye MO Nshya
+Comment[se]=Ođđa MO-ovttadat
+Comment[sk]=Nové zariadenie MO
+Comment[sl]=Nova MO naprava
+Comment[sr]=Нови МО уређај
+Comment[sr@Latn]=Novi MO uređaj
+Comment[sv]=Ny magneto-optisk enhet
+Comment[ta]=புது MO சாதனம்
+Comment[te]=కొత్త ఎంఓ పరికరం
+Comment[tg]=Дастгоҳи нави MO
+Comment[th]=กำหนดอุปกรณ์ MO ใหม่
+Comment[tr]=Yeni MO Aygıtı
+Comment[tt]=Yaña MO Cıhazı
+Comment[uk]=Новий пристрій MO
+Comment[uz]=Yangi MO uskunasi
+Comment[uz@cyrillic]=Янги MO ускунаси
+Comment[vi]=Tạo MO mới
+Comment[wa]=Novea éndjin MO
+Comment[zh_CN]=新建 MO 设备
+Comment[zh_TW]=新 MO 設備
+Type=Link
+URL=.source/MO-Device.desktop
+Icon=mo_unmount
diff --git a/kdesktop/init/Templates/linkNFS.desktop b/kdesktop/init/Templates/linkNFS.desktop
new file mode 100644
index 000000000..a7952c33f
--- /dev/null
+++ b/kdesktop/init/Templates/linkNFS.desktop
@@ -0,0 +1,91 @@
+[Desktop Entry]
+Name=NFS...
+Name[ar]=نظام ملفات الشبكة (NFS)...
+Name[bn]=এন-এফ-এস (NFS)...
+Name[br]=NFS ...
+Name[de]=NFS ...
+Name[hi]=एनएफ़एस...
+Name[hu]=NFS-megosztás...
+Name[nb]=NFS …
+Name[nn]=NFS …
+Name[ru]=Диск NFS...
+Name[se]=NFS …
+Name[sl]=NFS ...
+Name[te]=ఎన్ ఎఫ్ ఎస్...
+Name[th]=การเชื่อมโยง NFS...
+Comment=New NFS Link
+Comment[af]=Nuwe NFS Skakel
+Comment[ar]=رابط NFS جديد
+Comment[be]=Новая спасылка на NFS
+Comment[bg]=Нова връзка NFS
+Comment[bn]=নতুন এন-এফ-এস লিঙ্ক
+Comment[br]=Liamm NFS Nevez
+Comment[bs]=Novi NFS link
+Comment[ca]=Enllaç NFS nou
+Comment[cs]=Nový NFS odkaz
+Comment[csb]=Nowi lënk do NFS
+Comment[cy]=Cyswllt NFS Newydd
+Comment[da]=Nyt NFS-link
+Comment[de]=Neue NFS-Verknüpfung
+Comment[el]=Νέος δεσμός NFS
+Comment[eo]=Nova NFS-ligo
+Comment[es]=Nuevo enlace NFS
+Comment[et]=Uus NFS viit
+Comment[eu]=NFS esteka berria
+Comment[fa]=پیوند NFS جدید
+Comment[fi]=Uusi NFS-linkki
+Comment[fr]=Nouveau lien NFS
+Comment[fy]=Nije NFS-Keppeling
+Comment[ga]=Nasc nua NFS
+Comment[gl]=Nova Ligazón NFS
+Comment[he]=קישור NFS חדש
+Comment[hi]=नया एनएफ़एस लिंक
+Comment[hr]=Nova NFS veza
+Comment[hu]=Új NFS-link
+Comment[is]=Ný NFS tenging
+Comment[it]=Nuovo collegamento NFS
+Comment[ja]=新規 NFS リンク
+Comment[ka]=ახალი NFS ბმული
+Comment[kk]=Жаңа NFS сілтемесі
+Comment[km]=តំណ NFS ថ្មី
+Comment[ko]=새 NFS 연결
+Comment[lt]=Nauja NFS nuoroda
+Comment[lv]=Jauna NFS saite
+Comment[mk]=Нова NFS врска
+Comment[mn]=Шинэ NFS холбоос
+Comment[ms]=Pautan NFS Baru
+Comment[mt]=Link ġdid għal NFS
+Comment[nb]=Ny NFS-lenke
+Comment[nds]=Niegen NFS-Link
+Comment[ne]=नयाँ NFS लिङ्क
+Comment[nl]=Nieuwe NFS-koppeling
+Comment[nn]=Ny NFS-lenkje
+Comment[pa]=ਨਵਾਂ NFS ਸੰਬੰਧ
+Comment[pl]=Nowy skrót do NFS...
+Comment[pt]=Nova ligação NFS
+Comment[pt_BR]=Novo Link NFS
+Comment[ro]=Legătură NFS nouă
+Comment[ru]=Ссылка на диск NFS
+Comment[rw]= Ihuza NFS Rishya
+Comment[se]=Ođđa NFS-liŋka
+Comment[sk]=Nový odkaz NFS
+Comment[sl]=Nova povezava NFS
+Comment[sr]=Нова NFS веза
+Comment[sr@Latn]=Nova NFS veza
+Comment[sv]=Ny NFS-länk
+Comment[ta]=புது NFS இணைப்பு
+Comment[te]=కొత్త ఎన్ ఎఫ్ ఎస్ లింక్
+Comment[tg]=NFS-и пайванди нав
+Comment[th]=สร้างการเชื่อมโยง NFS ใหม่
+Comment[tr]=Yeni NFS Bağlantısı
+Comment[tt]=NFS öçen Yaña Bäy
+Comment[uk]=Нове посилання NFS
+Comment[uz]=NFS bilan yangi bogʻ
+Comment[uz@cyrillic]=NFS билан янги боғ
+Comment[vi]=Tạo liên kết NFS mới
+Comment[wa]=Novea loyén NFS
+Comment[zh_CN]=新建 NFS 链接
+Comment[zh_TW]=新 NFS 鏈結
+Type=Link
+URL=.source/NFS.desktop
+Icon=nfs_unmount
diff --git a/kdesktop/init/Templates/linkProgram.desktop b/kdesktop/init/Templates/linkProgram.desktop
new file mode 100644
index 000000000..867e9e380
--- /dev/null
+++ b/kdesktop/init/Templates/linkProgram.desktop
@@ -0,0 +1,153 @@
+[Desktop Entry]
+Name=Link to Application...
+Name[af]=Skakel na Program...
+Name[ar]=رابط لتطبيق...
+Name[be]=Спасылка на праграму...
+Name[bg]=Връзка към програма...
+Name[bn]=অ্যাপলিকেশন-এ লিঙ্ক...
+Name[br]=Liamm ouzh un arload ...
+Name[bs]=Veza do programa...
+Name[ca]=Enllaç a aplicació...
+Name[cs]=Odkaz na aplikaci...
+Name[csb]=Lënk do programë...
+Name[cy]=Cyswllt i Gymhwysiad...
+Name[da]=Link til program...
+Name[de]=Verknüpfung zu Programm ...
+Name[el]=Δεσμός με εφαρμογή...
+Name[eo]=Ligo al aplikaĵo...
+Name[es]=Enlace a aplicación...
+Name[et]=Viit rakendusele...
+Name[eu]=Esteka aplikazioari...
+Name[fa]=پیوند به کاربرد...
+Name[fi]=Linkki sovellukseen...
+Name[fr]=Lien vers une application...
+Name[fy]=Keppeling nei tappasing...
+Name[ga]=Nasc go Feidhmchlár...
+Name[gl]=Ligazón a unha Aplicación...
+Name[he]=קישור ליישום...
+Name[hi]=अनुप्रयोग को लिंक...
+Name[hr]=Veza s aplikacijom...
+Name[hu]=Alkalmazásra mutató link...
+Name[is]=Tengja við forrit...
+Name[it]=Collegamento ad un'applicazione...
+Name[ja]=アプリケーションへのリンク...
+Name[ka]=პროგრამის ბმული...
+Name[kk]=Қолданбаға сілтеме...
+Name[km]=តំណ​ទៅ​កម្មវិធី...
+Name[ko]=프로그램으로 향한 연결...
+Name[lt]=Programos nuoroda...
+Name[lv]=Saite uz Aplikāciju...
+Name[mk]=Врска до апликација...
+Name[mn]=Програмтай холбох...
+Name[ms]=Paut ke Aplikasi...
+Name[mt]=Link għal programm...
+Name[nb]=Lenke til program …
+Name[nds]=Link na'n Programm...
+Name[ne]=अनुप्रयोगमा लिङ्क गर्नुहोस्...
+Name[nl]=Koppeling naar toepassing...
+Name[nn]=Lenkje til program …
+Name[pa]=ਕਾਰਜ ਨਾਲ ਸੰਬੰਧ...
+Name[pl]=Skrót do programu...
+Name[pt]=Atalho para Aplicação...
+Name[pt_BR]=Link para Aplicativo...
+Name[ro]=Legătură către aplicație...
+Name[ru]=Ссылка на приложение...
+Name[rw]=Ihuza kuri Porogaramu...
+Name[se]=Liŋka prográmmii …
+Name[sk]=Odkaz na aplikáciu...
+Name[sl]=Povezava do programa ...
+Name[sr]=Веза ка програму...
+Name[sr@Latn]=Veza ka programu...
+Name[sv]=Länk till program...
+Name[ta]=விண்ணப்பத்துக்கு இணை...
+Name[tg]=Пайванд ба барномаи...
+Name[th]=เชื่อมโยงไปยังแอพพลิเคชัน...
+Name[tr]=Uygulamaya Bağlantı...
+Name[tt]=Yazılımğa Bäy...
+Name[uk]=Посилання на програму...
+Name[uz]=Dastur bilan bogʻ...
+Name[uz@cyrillic]=Дастур билан боғ...
+Name[vi]=Liên kết tới một Chương trình...
+Name[wa]=Loyén viè on programe...
+Name[zh_CN]=应用程序链接...
+Name[zh_TW]=應用程式連結...
+Comment=New Link to Application
+Comment[af]=Nuwe Skakel na Aansoek
+Comment[ar]=إرتباط جديد بتطبيق
+Comment[be]=Новая спасылка на праграму
+Comment[bg]=Нова връзка към програма
+Comment[bn]=অ্যাপলিকেশন-এ নতুন লিঙ্ক
+Comment[br]=Liamm nevez ouzh un arload ...
+Comment[bs]=Nova veza do programa
+Comment[ca]=Nou enllaç a l'aplicació
+Comment[cs]=Nový odkaz na aplikaci
+Comment[csb]=Nowi lënk do programë
+Comment[cy]=Cyswllt Newydd i Gymhwysiad
+Comment[da]=Nyt link til program
+Comment[de]=Neue Verknüpfung mit Programm
+Comment[el]=Νέος δεσμός με εφαρμογή
+Comment[eo]=Nova ligo al aplikaĵo
+Comment[es]=Nuevo enlace a aplicación
+Comment[et]=Uus viit rakendusele
+Comment[eu]=Aplikazioarekiko esteka berria
+Comment[fa]=پیوند جدید به کاربرد
+Comment[fi]=Uusi linkki sovellukseen
+Comment[fr]=Nouveau lien vers une application
+Comment[fy]=Nije keppeling naar toepassing
+Comment[ga]=Nasc nua go feidhmchlár
+Comment[gl]=Nova Ligazón a unha Aplicación
+Comment[he]=קישור חדש ליישום
+Comment[hi]=अनुप्रयोग को नई लिंक
+Comment[hr]=Nova veza s aplikacijom
+Comment[hu]=Alkalmazásra mutató új link
+Comment[is]=Nýtt tengi við forrit
+Comment[it]=Nuovo collegamento ad un'applicazione
+Comment[ja]=新規アプリケーションリンク
+Comment[ka]=პროგრამის ახალი ბმული
+Comment[kk]=Қолданбаға жаңа сілтеме
+Comment[km]=តំណ​ថ្មី​ទៅ​កម្មវិធី
+Comment[ko]=프로그램으로 향한 새 연결
+Comment[lo]=ສ້າງລິ້ງໄປຍັງແອບພີເຄຊັ້ນໃຫມ່
+Comment[lt]=Nauja programos nuoroda
+Comment[lv]=Jauna Saite uz Aplikāciju
+Comment[mk]=Нова врска до апликација
+Comment[mn]=програмтай шинээр холбох
+Comment[ms]=Pautan Baru ke Aplikasi
+Comment[mt]=Link ġdid ġħal programm
+Comment[nb]=Ny lenke til program
+Comment[nds]=Niegen Link na'n Programm
+Comment[ne]=अनुप्रयोगमा नयाँ लिङ्क गर्नुहोस्
+Comment[nl]=Nieuwe koppeling naar toepassing
+Comment[nn]=Ny lenkje til program
+Comment[nso]=Kgokaganyo ye Ntshwa go Tshomiso
+Comment[pa]=ਕਾਰਜ ਨਾਲ ਨਵਾਂ ਸੰਬੰਧ
+Comment[pl]=Nowy skrót do programu
+Comment[pt]=Novo Atalho para Aplicação
+Comment[pt_BR]=Novo link para Aplicativo
+Comment[ro]=Legătură nouă către aplicație
+Comment[ru]=Новая ссылка на приложение
+Comment[rw]=Ihuza Rishya kuri Porogaramu
+Comment[se]=Ođđa liŋka prográmmii
+Comment[sk]=Nový odkaz na aplikáciu
+Comment[sl]=Nova povezava do programa
+Comment[sr]=Нова веза ка програму
+Comment[sr@Latn]=Nova veza ka programu
+Comment[sv]=Ny länk till program
+Comment[ta]=பயன்பாட்டுக்கான புதிய இணைப்பு
+Comment[tg]=Пайванди нав ба барнома
+Comment[th]=สร้างการเชื่อมโยงใหม่ไปยังแอพพลิเคชัน
+Comment[tr]=Uygulamaya Yeni Bağlantı
+Comment[tt]=Yazılım öçen Yaña Bäy
+Comment[uk]=Нове посилання на програму
+Comment[uz]=Dastur bilan yangi bogʻ
+Comment[uz@cyrillic]=Дастур билан янги боғ
+Comment[ven]=Thumanyo ntswa kha apulifikhesheni
+Comment[vi]=Tạo liên kết mới tới một chương trình
+Comment[wa]=Novea loyén viè on programe
+Comment[xh]=Ikhonkco Elitsha Lwesicelo
+Comment[zh_CN]=新建应用程序链接
+Comment[zh_TW]=新建應用程式連結
+Comment[zu]=Isixhumanisi esisha esiya kumyaleli
+Icon=exec
+Type=Link
+URL=.source/Program.desktop
diff --git a/kdesktop/init/Templates/linkURL.desktop b/kdesktop/init/Templates/linkURL.desktop
new file mode 100644
index 000000000..df71e95c2
--- /dev/null
+++ b/kdesktop/init/Templates/linkURL.desktop
@@ -0,0 +1,153 @@
+[Desktop Entry]
+Name=Link to Location (URL)...
+Name[af]=Skakel na Ligging (URL)...
+Name[ar]=رابط لموقع...
+Name[be]=Спасылка на месцазнаходжанне (URL)...
+Name[bg]=Връзка към адрес...
+Name[bn]=ইউ-আর-এল অবস্থানে লিঙ্ক...
+Name[br]=Liamm ouzh ul lec'hiadur (URL) ...
+Name[bs]=Veza do lokacije (URL)...
+Name[ca]=Enllaç al localitzador (URL)...
+Name[cs]=Odkaz na umístění (URL)...
+Name[csb]=Lënk do adresë (URL)...
+Name[cy]=Cyswllt i Leoliad (URL)...
+Name[da]=Internetlink (URL)...
+Name[de]=Verknüpfung zu Adresse (URL) ...
+Name[el]=Δεσμός με τοποθεσία (URL)...
+Name[eo]=Ligo al situo (URL)...
+Name[es]=Enlace a dirección (URL)...
+Name[et]=Viit asukohale (URL)...
+Name[eu]=Esteka kokapenari (URL)...
+Name[fa]=پیوند به محل )نشانی وب(...
+Name[fi]=Linkki sijaintiin (URL)...
+Name[fr]=Lien vers une URL...
+Name[fy]=Keppeling nei lokaasje (URL-adres)...
+Name[ga]=Nasc le Suíomh (URL)...
+Name[gl]=Ligazón a un Sítio (URL)...
+Name[he]=קישור למיקום (URL)...
+Name[hi]=स्थान (यूआरएल) को लिंक...
+Name[hr]=Veza s lokacijom (URL)...
+Name[hu]=Internet-cím (URL)...
+Name[is]=Staðsetningartengill...
+Name[it]=Collegamento ad un indirizzo (URL)...
+Name[ja]=場所へのリンク (URL)
+Name[ka]=ადგილმდებარეობის ბმული (URL)...
+Name[kk]=URL-адреске сілтеме...
+Name[km]=តំណ​ទៅ​ទីតាំង (URL)...
+Name[ko]=위치로 향한 연결 (URL)...
+Name[lt]=Adreso nuoroda (URL)...
+Name[lv]=Saite uz Vietu (URL)...
+Name[mk]=Врска до локација (URL)...
+Name[mn]=Хаягтай (URL) холбох...
+Name[ms]=Paut ke Aplikasi (URL)...
+Name[mt]=Link għal lokazzjoni (URL)...
+Name[nb]=Lenke til nettadresse (URL) …
+Name[nds]=Link na'n Oort (URL)...
+Name[ne]=स्थानमा लिङ्क गर्नुहोस् (यूआरएल)...
+Name[nl]=Koppeling naar locatie (URL-adres)...
+Name[nn]=Lenkje til nettadresse (URL) …
+Name[pa]=ਸਥਿਤੀ (URL) ਨਾਲ ਸੰਬੰਧ...
+Name[pl]=Skrót do adresu (URL)...
+Name[pt]=Atalho para Localização (URL)...
+Name[pt_BR]=Link para Localização (URL)...
+Name[ro]=Legătură către locație (URL)...
+Name[ru]=Адрес Интернета...
+Name[rw]=Ihuza ku ndangahantu (URL)...
+Name[se]=Liŋka fierpmádatčujuhussii (URL) …
+Name[sk]=Odkaz na umiestnenie (URL)...
+Name[sl]=Povezava do lokacije (URL) ...
+Name[sr]=Веза ка локацији (URL)...
+Name[sr@Latn]=Veza ka lokaciji (URL)...
+Name[sv]=Länk till plats (URL)...
+Name[ta]=இடத்திற்கு இணை (URL)...
+Name[tg]=Пайванд ба макони (URL)...
+Name[th]=เชื่อมโยงไปยังตำแหน่ง (URL)...
+Name[tr]=Konuma (URL) Bağlantı...
+Name[tt]=Urınlaşu öçen Bäy (URL)...
+Name[uk]=Посилання до адреси (URL)...
+Name[uz]=Mavzu bilan bogʻ (URL)...
+Name[uz@cyrillic]=Мавзу билан боғ (URL)...
+Name[vi]=Liên kết tới trang mạng (URL)...
+Name[wa]=Loyén viè ene plaece (URL)...
+Name[zh_CN]=到位置(URL)的链接...
+Name[zh_TW]=到位置的連結(URL)
+Comment=Enter link to location (URL):
+Comment[af]=Invoer skakel na ligging (Url):
+Comment[ar]=أدخل رابط لموقع:
+Comment[be]=Вызначце спасылку на месцазнаходжанне (URL):
+Comment[bg]=Въведете връзката към адреса:
+Comment[bn]=লিঙ্কের অবস্থান:
+Comment[br]=Roit al liamm ouzh ul lec'hiadur (URL) :
+Comment[bs]=Unesite vezu do lokacije (URL):
+Comment[ca]=Entreu un enllaç al localitzador (URL):
+Comment[cs]=Zadejte odkaz na umístění (URL):
+Comment[csb]=Nowi lënk do internetowi adresë (URL):
+Comment[cy]=Mewnosodwch cyswllt i leoliad (URL):
+Comment[da]=Indtast internetlink (URL):
+Comment[de]=Verknüpfung mit Adresse (URL) eingeben:
+Comment[el]=Δώστε δεσμό στην τοποθεσία (URL):
+Comment[eo]=Enigu ligon al situo (URL):
+Comment[es]=Introduzca el enlace a la dirección (URL):
+Comment[et]=Sisesta viit asukohale (URL):
+Comment[eu]=Sartu kokapenarekiko (URL) esteka:
+Comment[fa]=پیوند به محل )نشانی وب( را وارد کنید:
+Comment[fi]=Anna linkki sijaintiin (URL):
+Comment[fr]=Nouveau lien vers une URL :
+Comment[fy]=Keppeling nei lokaasje ynfiere (URL-adres):
+Comment[ga]=Iontráil nasc le suíomh (URL):
+Comment[gl]=Introduza a ligazón á localización (URL):
+Comment[he]=הזן את הקישור למיקום (URL):
+Comment[hi]=स्थान (यूआरएल) को लिंक भरें:
+Comment[hr]=Nova veza s lokacijom (URL)
+Comment[hu]=Adja meg az internet-címet (URL-t):
+Comment[is]=Gefðu upp slóð að staðsetningu:
+Comment[it]=Immetti collegamento all'indirizzo (URL):
+Comment[ja]=新規の場所へのリンク(URL):
+Comment[ka]=შეიყვანეთ პროგრამის ბმული ბმული (URL)
+Comment[kk]=URL-адресін келтіріңіз:
+Comment[km]=បញ្ចូល​តំណ​ទៅ​ទីតាំង (URL) ៖
+Comment[ko]=연결할 위치(URL)를 입력하십시오:
+Comment[lo]=ສ້າງລິໄປຍັງຕຳແຫນ່ງ (URL) ໃຫ່ມ
+Comment[lt]=Nauja adreso nuoroda (URL)
+Comment[lv]=Jauna Saite uz Vietu (URL):
+Comment[mk]=Внесете врска до локацијата (URL):
+Comment[mn]=Холбох хаяг (URL) өгөх:
+Comment[ms]=Masukkan pautan ke lokasi (URL):
+Comment[mt]=Link ġdid għal lokazzjoni (URL)
+Comment[nb]=Ny lenke til en nettadresse:
+Comment[nds]=Link na'n Oort (URL) ingeven:
+Comment[ne]=स्थानमा प्रविष्टि लिङ्क गर्नुहोस् (यूआरएल):
+Comment[nl]=Koppeling naar locatie invoeren (URL-adres):
+Comment[nn]=Ny lenkje til Internettadresse:
+Comment[nso]=Tsenya sekgokaganyi go tulo (URL):
+Comment[pa]=ਸਥਿਤੀ (URL) ਨਾਲ ਸੰਬੰਧ ਦਿਓ:
+Comment[pl]=Nowy skrót do adresu internetowego (URL):
+Comment[pt]=Indique o atalho para a localização (URL):
+Comment[pt_BR]=Digite o link para a localização (URL):
+Comment[ro]=Introduceți legătura către locație (URL):
+Comment[ru]=Адрес в Интернете:
+Comment[rw]=Kwinjiza ihuza ku ndangahantu (URL):
+Comment[se]=Bija liŋkka fierpmádatčujuhussii (URL):
+Comment[sk]=Zadajte odkaz na umiestnenie (URL):
+Comment[sl]=Vnesite povezavo do mesta (URL):
+Comment[sr]=Унесите везу ка локацији (URL):
+Comment[sr@Latn]=Unesite vezu ka lokaciji (URL):
+Comment[sv]=Ange länk till plats (URL):
+Comment[ta]=இடத்திற்கான இணைப்பை உள்ளிடு (URL):
+Comment[tg]=Бадарғаро ба адреси (URL) ворид кунед:
+Comment[th]=สร้างการเชื่อมโยงไปยังตำแหน่ง (URL) ใหม่
+Comment[tr]=Konuma bağlantıyı girin:
+Comment[tt]=Urınlaşu bäyen kertü (URL):
+Comment[uk]=Введіть посилання до адреси (URL):
+Comment[uz]=Mavzuga bogʻni (URL) kiriting:
+Comment[uz@cyrillic]=Мавзуга боғни (URL) киритинг:
+Comment[ven]=Dzhenisani vhukwamani kha fhethu (URL):
+Comment[vi]=Nhập liên kết tới trang mạng:
+Comment[wa]=Novea loyén viè ene plaece (URL):
+Comment[xh]=Ngenisa ikhonkco kwindawo ekuyo (URL):
+Comment[zh_CN]=输入到位置(URL)的链接:
+Comment[zh_TW]=輸入到位置的連結(URL):
+Comment[zu]=Ngenisa isixhumanisi esiya endaweni (URL):
+URL=.source/URL.desktop
+Type=Link
+Icon=www
diff --git a/kdesktop/init/Templates/linkZIP.desktop b/kdesktop/init/Templates/linkZIP.desktop
new file mode 100644
index 000000000..9ef9eaee9
--- /dev/null
+++ b/kdesktop/init/Templates/linkZIP.desktop
@@ -0,0 +1,150 @@
+[Desktop Entry]
+Name=ZIP Device...
+Name[af]=ZIP Toestel...
+Name[ar]=جهاز ZIP...
+Name[be]=Прылада ZIP...
+Name[bg]=ZIP...
+Name[bn]=ZIP ডিভাইস...
+Name[br]=Trobarzhell ZIP ...
+Name[bs]=ZIP uređaj...
+Name[ca]=Dispositiu ZIP...
+Name[cs]=ZIP jednotka...
+Name[csb]=Nëk ZIP...
+Name[cy]=Dyfais ZIP...
+Name[da]=ZIP-enhed...
+Name[de]=ZIP-Laufwerk ...
+Name[el]=Συσκευή ZIP...
+Name[eo]=ZIP-ingo...
+Name[es]=Unidad ZIP...
+Name[et]=ZIP seade...
+Name[eu]=ZIP gailua...
+Name[fa]=دستگاه ZIP...
+Name[fi]=ZIP-laite...
+Name[fr]=Lecteur ZIP...
+Name[fy]=ZIP-apparaat...
+Name[ga]=Gléas Zip...
+Name[gl]=Dispositivo Zip...
+Name[he]=התקן ZIP...
+Name[hi]=जिप उपकरण...
+Name[hr]=ZIP uređaj...
+Name[hu]=ZIP-meghajtó...
+Name[is]=ZIP-drif...
+Name[it]=Dispositivo ZIP...
+Name[ja]=ZIP デバイス...
+Name[ka]=ZIP მოწყობილობა...
+Name[kk]=ZIP құрылғысы...
+Name[km]=ឧបករណ៍ ZIP...
+Name[ko]=ZIP 장치...
+Name[lt]=ZIP įrenginys...
+Name[lv]=ZIP Iekārta...
+Name[mk]=ZIP Уред...
+Name[mn]=ZIP Төхөөрөмж..
+Name[ms]=Peranti ZIP...
+Name[mt]=Apparat ZIP
+Name[nb]=ZIP-enhet …
+Name[nds]=ZIP-Reedschap...
+Name[ne]=ZIP यन्त्र...
+Name[nl]=ZIP-apparaat...
+Name[nn]=ZIP-eining …
+Name[pa]=ZIP ਜੰਤਰ...
+Name[pl]=Napęd ZIP...
+Name[pt]=Dispositivo ZIP...
+Name[pt_BR]=Dispositivo ZIP...
+Name[ro]=Dispozitiv ZIP...
+Name[ru]=ZIP...
+Name[rw]=Apareye ZIPU...
+Name[se]=ZIP-Ovttadat …
+Name[sk]=Mechanika ZIP...
+Name[sl]=Naprava ZIP ...
+Name[sr]=ZIP Уређај...
+Name[sr@Latn]=ZIP Uređaj...
+Name[sv]=Zip-enhet...
+Name[ta]=ZIP சாதனங்கள்
+Name[te]=జిప్ పరికరం...
+Name[tg]=Дастгоҳи ZIP...
+Name[th]=อุปกรณ์ ZIP...
+Name[tr]=ZIP Aygıtı...
+Name[tt]=ZIP Cıhazı...
+Name[uk]=Пристрій ZIP...
+Name[uz]=ZIP uskunasi...
+Name[uz@cyrillic]=ZIP ускунаси...
+Name[vi]=Ổ ZIP...
+Name[wa]=Éndjin léjheu di plaketes ZIP...
+Name[zh_CN]=ZIP 设备...
+Name[zh_TW]=ZIP 設備...
+Comment=New ZIP Device
+Comment[af]=Nuwe ZIP Toestel...
+Comment[ar]=جهاز ZIP جديد
+Comment[be]=Новая прылада ZIP
+Comment[bg]=Ново устройство ZIP
+Comment[bn]=নতুন ZIP ডিভাইস
+Comment[br]=Trobarzhell ZIP Nevez
+Comment[bs]=Novi ZIP uređaj
+Comment[ca]=Dispositiu ZIP nou
+Comment[cs]=Nová ZIP jednotka
+Comment[csb]=Nowi nëk ZIP
+Comment[cy]=Dyfais ZIP Newydd
+Comment[da]=Ny ZIP-enhed
+Comment[de]=Neues ZIP-Laufwerk
+Comment[el]=Νέα συσκευή ZIP
+Comment[eo]=Nova ZIP-ingo
+Comment[es]=Nueva unidad ZIP
+Comment[et]=Uus ZIP seade
+Comment[eu]=ZIP gailu berria
+Comment[fa]=دستگاه ZIP جدید
+Comment[fi]=Uusi ZIP-laite
+Comment[fr]=Nouveau lecteur ZIP
+Comment[fy]=Nije ZIP-apparaat
+Comment[ga]=Gléas Nua Zip
+Comment[gl]=Novo Dispositivo Zip
+Comment[he]=התקן ZIP חדש
+Comment[hi]=नया जिप उपकरण
+Comment[hr]=Novi ZIP uređaj
+Comment[hu]=Új ZIP-lemezes meghajtó
+Comment[is]=Nýtt ZIP-drif
+Comment[it]=Nuovo dispositivo ZIP
+Comment[ja]=新規 ZIP デバイス
+Comment[ka]=ახალი ZIP მოწყობილობა
+Comment[kk]=Жаңа ZIP құрылғысы
+Comment[km]=ឧបករណ៍ ZIP ថ្មី
+Comment[ko]=새 ZIP 장치
+Comment[lt]=Naujas ZIP įrenginys
+Comment[lv]=Jauna ZIP iekārta
+Comment[mk]=Нов ZIP уред
+Comment[mn]=Шинэ ZIP Төхөөрөмж..
+Comment[ms]=Peranti ZIP Baru
+Comment[mt]=Apparat ZIP ġdid
+Comment[nb]=Ny ZIP-enhet
+Comment[nds]=Niege ZIP-Reedschap
+Comment[ne]=नयाँ ZIP यन्त्र
+Comment[nl]=Nieuw ZIP-apparaat
+Comment[nn]=Ny ZIP-eining
+Comment[pa]=ਨਵਾਂ ZIP ਜੰਤਰ
+Comment[pl]=Nowy napęd ZIP
+Comment[pt]=Novo Dispositivo ZIP
+Comment[pt_BR]=Novo Dispositivo ZIP
+Comment[ro]=Dispozitiv ZIP nou
+Comment[ru]=Ссылка на устройство ZIP
+Comment[rw]=Apareye ZIP Nshya
+Comment[se]=Ođđa ZIP-ovttadat …
+Comment[sk]=Nové zariadenie ZIP
+Comment[sl]=Nova naprava ZIP
+Comment[sr]=Нови ZIP уређај
+Comment[sr@Latn]=Novi ZIP uređaj
+Comment[sv]=Ny Zip-enhet
+Comment[ta]=புதிய ZIP சாதனம்
+Comment[te]=కొత్త జిప్ పరికరం
+Comment[tg]=Дастгоҳи нави ZIP
+Comment[th]=กำหนดอุปกรณ์ ZIP ตัวใหม่
+Comment[tr]=Yeni ZIP Aygıtı
+Comment[tt]=Yaña ZIP Cıhazı
+Comment[uk]=Новий пристрій ZIP
+Comment[uz]=Yangi ZIP uskunasi
+Comment[uz@cyrillic]=Янги ZIP ускунаси
+Comment[vi]=Tạo ổ ZIP mới
+Comment[wa]=Novea éndjin léjheu di plaketes ZIP
+Comment[zh_CN]=新建 ZIP 设备
+Comment[zh_TW]=新 ZIP 設備
+Type=Link
+URL=.source/ZIP-Device.desktop
+Icon=zip_unmount
diff --git a/kdesktop/init/directory.autostart b/kdesktop/init/directory.autostart
new file mode 100644
index 000000000..d63845aed
--- /dev/null
+++ b/kdesktop/init/directory.autostart
@@ -0,0 +1,68 @@
+[Desktop Entry]
+Type=Directory
+Name=Autostart
+Name[af]=Outomatiese begin
+Name[ar]=بدء تشغيل تلقائي
+Name[az]=Öz-Özünə Başlama
+Name[be]=Аўтазапуск
+Name[bg]=Автоматично стартиране
+Name[bn]=অটো-স্টার্ট
+Name[br]=Emloc'h
+Name[ca]=Autoengega
+Name[csb]=Aùtosztart
+Name[cy]=Hunan-gychwyn
+Name[el]=Αυτόματη Έναρξη
+Name[eo]=Aŭtolanĉo
+Name[es]=Inicio automático
+Name[eu]=Autoabiatu
+Name[fa]=خودآغاز
+Name[fi]=Käynnistä
+Name[fr]=Démarrage automatique
+Name[fy]=Automatysk Begjinne
+Name[ga]=Tús uathoibríoch
+Name[gl]=Autoinício
+Name[he]=הפעלה אוטומטית
+Name[hi]=स्वतःप्रारंभ
+Name[hr]=Automatsko pokretanje
+Name[hu]=Automatikus indítás
+Name[is]=Sjálfræsing
+Name[it]=Avvio automatico
+Name[ja]=自動起動
+Name[ka]=ავტოგაშვება
+Name[kk]=Автобастау
+Name[km]=ចាប់ផ្ដើម​ស្វ័យប្រវត្តិ
+Name[lo]=ເລິ່ມອັດໂນມັດ
+Name[lt]=Autostartas
+Name[lv]=Autostarts
+Name[mk]=Автостарт
+Name[mn]=Автомат эхлэгч
+Name[ms]=Automula
+Name[mt]=Awto-bidu
+Name[ne]=स्वत: सुरु
+Name[nso]=Thomo yago Itirisa
+Name[pa]=ਸਵੈ-ਚਾਲਤ
+Name[pt]=Arranque
+Name[pt_BR]=Inicialização Automática
+Name[ru]=Автозапуск
+Name[se]=Autoálggaheapmi
+Name[sk]=Autoštart
+Name[sl]=Samodejni zagon
+Name[sr]=Аутоматско покретање
+Name[sr@Latn]=Automatsko pokretanje
+Name[ta]=தானாகதுவக்கு
+Name[te]=స్వయంచాలన
+Name[tg]=Сар кунии автоматикӣ
+Name[th]=เริ่มอัตโนมัติ
+Name[tr]=Otomatik Başlat
+Name[tt]=Üze Cibäreläse
+Name[uk]=Автостарт
+Name[uz]=Avto-boshlash
+Name[uz@cyrillic]=Авто-бошлаш
+Name[ven]=Thoma
+Name[vi]=Tự khởi động
+Name[wa]=Enonde tot seu
+Name[xh]=Isiqalo esizenzekelayo
+Name[zh_CN]=自动启动
+Name[zh_TW]=自動啟動
+Name[zu]=Ukuqala ngokuzenzekela
+
diff --git a/kdesktop/init/directory.desktop b/kdesktop/init/directory.desktop
new file mode 100644
index 000000000..2269e69dd
--- /dev/null
+++ b/kdesktop/init/directory.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Type=Directory
+BgImage=
+Icon=desktop
+Name=Desktop
+Name[af]=Werkskerm
+Name[ar]=سطح المكتب
+Name[az]=Masa Üstü
+Name[be]=Працоўны стол
+Name[bg]=Работен плот
+Name[bn]=ডেস্কটপ
+Name[br]=Gorretaol
+Name[bs]=Radna površina
+Name[ca]=Escriptori
+Name[cs]=Pracovní plocha
+Name[csb]=Pùlt
+Name[cy]=Penbwrdd
+Name[de]=Arbeitsfläche
+Name[el]=Επιφάνεια εργασίας
+Name[eo]=Tabulo
+Name[es]=Escritorio
+Name[et]=Töölaud
+Name[eu]=Mahaigaina
+Name[fa]=رومیزی
+Name[fi]=Työpöytä
+Name[fo]=Skriviborð
+Name[fr]=Bureau
+Name[fy]=Buroblêd
+Name[ga]=Deasc
+Name[gl]=Escritorio
+Name[he]=שולחן עבודה
+Name[hi]=डेस्कटॉप
+Name[hr]=Radna površina
+Name[hsb]=Dźěłowy powjerch
+Name[hu]=Munkaasztal
+Name[is]=Skjáborð
+Name[ja]=デスクトップ
+Name[ka]=სამუშაო დაფა
+Name[kk]=Жұмыс үстелі
+Name[km]=ផ្ទៃតុ
+Name[ko]=데스크톱
+Name[lo]=ພື້ນທີ່ເຮັດວງກ
+Name[lt]=Darbastalis
+Name[lv]=Darbvirsma
+Name[mk]=Работна површина
+Name[mn]=Ажлын тавцан
+Name[ms]=Ruang Kerja
+Name[nb]=Skrivebord
+Name[nds]=Schriefdisch
+Name[ne]=डेस्कटप
+Name[nl]=Bureaublad
+Name[nn]=Skrivebord
+Name[oc]=BurèU
+Name[pa]=ਵੇਹੜਾ
+Name[pl]=Pulpit
+Name[pt]=Ambiente de Trabalho
+Name[pt_BR]=Área de Trabalho
+Name[ru]=Рабочий стол
+Name[rw]=Ibiro
+Name[se]=Čállinbeavdi
+Name[sk]=Plocha
+Name[sl]=Namizje
+Name[sr]=Радна површина
+Name[sr@Latn]=Radna površina
+Name[ss]=Desktop
+Name[sv]=Skrivbord
+Name[ta]=மேல்மேசை
+Name[te]=రంగస్ఠలం
+Name[tg]=Мизи корӣ
+Name[th]=พื้นที่ทำงาน
+Name[tr]=Masaüstü
+Name[tt]=Östäl
+Name[uk]=Стільниця
+Name[uz]=Ish stoli
+Name[uz@cyrillic]=Иш столи
+Name[ven]=Desikithopo
+Name[vi]=Màn hình nền
+Name[wa]=Sicribanne
+Name[zh_CN]=桌面
+Name[zh_TW]=桌面
+
diff --git a/kdesktop/init/directory.templates b/kdesktop/init/directory.templates
new file mode 100644
index 000000000..d77fa5cb6
--- /dev/null
+++ b/kdesktop/init/directory.templates
@@ -0,0 +1,78 @@
+[Desktop Entry]
+Type=Directory
+Name=Templates
+Name[af]=Voorbeelde
+Name[ar]=القوالب
+Name[az]=Nümunələr
+Name[be]=Шаблоны
+Name[bg]=Шаблони
+Name[bn]=টেমপ্লেট
+Name[br]=Patromoù
+Name[bs]=Šabloni
+Name[ca]=Plantilles
+Name[cs]=Šablony
+Name[csb]=Mùstrë
+Name[cy]=Patrymluniau
+Name[da]=Skabeloner
+Name[de]=Vorlagen
+Name[el]=Πρότυπα
+Name[eo]=Ŝablonoj
+Name[es]=Plantillas
+Name[et]=Mallid
+Name[eu]=Txantiloiak
+Name[fa]=الگوها
+Name[fi]=Pohjat
+Name[fr]=Modèles
+Name[fy]=Sjabloanen
+Name[ga]=Teimpléid
+Name[gl]=Modelos
+Name[he]=תבניות
+Name[hi]=टैम्प्लेट्स
+Name[hr]=Predlošci
+Name[hu]=Sablonok
+Name[is]=Snið
+Name[it]=Modelli
+Name[ja]=テンプレート
+Name[ka]=ნიმუშები
+Name[kk]=Үлгілер
+Name[km]=ពុម្ព
+Name[lo]=ຕົ້ນແບບ
+Name[lt]=Šablonai
+Name[lv]=Šabloni
+Name[mk]=Шаблони
+Name[mn]=Шаблом
+Name[ms]=Templat
+Name[mt]=Mudelli
+Name[nb]=Maler
+Name[nds]=Vörlagen
+Name[ne]=टेम्प्लेट
+Name[nl]=Sjablonen
+Name[nn]=Malar
+Name[nso]=Dipapiso
+Name[pa]=ਨਮੂਨਾ
+Name[pl]=Wzorce
+Name[pt]=Modelos
+Name[pt_BR]=Modelos
+Name[ro]=Modele
+Name[ru]=Шаблоны
+Name[se]=Mállet
+Name[sk]=Šablóny
+Name[sl]=Predloge
+Name[sr]=Шаблони
+Name[sr@Latn]=Šabloni
+Name[sv]=Mallar
+Name[ta]=வார்ப்புருக்கள்
+Name[te]=టెంప్లెటులు
+Name[tg]=Намунаҳо
+Name[th]=ต้นแบบ
+Name[tr]=Şablonlar
+Name[tt]=Ürçetmä
+Name[uk]=Шаблони
+Name[uz]=Namunalar
+Name[uz@cyrillic]=Намуналар
+Name[vi]=Tiêu bản
+Name[wa]=Modeles
+Name[zh_CN]=模板
+Name[zh_TW]=範本
+Name[zu]=Ama-Templates
+
diff --git a/kdesktop/init/directory.trash b/kdesktop/init/directory.trash
new file mode 100644
index 000000000..83b69240b
--- /dev/null
+++ b/kdesktop/init/directory.trash
@@ -0,0 +1,160 @@
+[Desktop Entry]
+Type=Link
+URL=trash:/
+Encoding=UTF-8
+Icon=trashcan_full
+EmptyIcon=trashcan_empty
+Name=Trash
+Name[af]=Gemors
+Name[ar]=سلة النفايات
+Name[az]=Zibil
+Name[be]=Сметніца
+Name[bg]=Кошче
+Name[bn]=আবর্জনা
+Name[br]=Pod-lastez
+Name[bs]=Smeće
+Name[ca]=Paperera
+Name[cs]=Koš
+Name[csb]=Kòsz
+Name[cy]=Sbwriel
+Name[da]=Affald
+Name[de]=Mülleimer
+Name[el]=Κάδος απορριμμάτων
+Name[en_GB]=Wastebin
+Name[eo]=Rubujo
+Name[es]=Papelera
+Name[et]=Prügikast
+Name[eu]=Zaborra
+Name[fa]=زباله
+Name[fi]=Roskakori
+Name[fr]=Corbeille
+Name[fy]=Jiskefet
+Name[ga]=Bruscar
+Name[gl]=Lixo
+Name[he]=אשפה
+Name[hi]=रद्दी
+Name[hr]=Otpad
+Name[hsb]=Papjernik
+Name[hu]=Szemétkosár
+Name[is]=Rusl
+Name[it]=Cestino
+Name[ja]=ごみ箱
+Name[ka]=ურნა
+Name[kk]=Өшірілгендер
+Name[km]=ធុងសំរាម
+Name[lo]=ຖັງຂີ້ເຫຍື່ອ
+Name[lt]=Šiukšliadėžė
+Name[lv]=Miskaste
+Name[mk]=Корпа
+Name[mn]=Хогийн сав
+Name[ms]=Sampah
+Name[mt]=Skart
+Name[nb]=Papirkurv
+Name[nds]=Affalltünn
+Name[ne]=रद्दीटोकरी
+Name[nl]=Prullenbak
+Name[nn]=Papirkorg
+Name[nso]=Seswaraditlakala
+Name[pa]=ਰੱਦੀ
+Name[pl]=Kosz
+Name[pt]=Lixo
+Name[pt_BR]=Lixo
+Name[ro]=Gunoi
+Name[ru]=Корзина
+Name[se]=Ruskalihtti
+Name[sk]=Kôš
+Name[sl]=Smeti
+Name[sr]=Смеће
+Name[sr@Latn]=Smeće
+Name[sv]=Skräp
+Name[ta]=குப்பை
+Name[te]=చెత్త బుట్ట
+Name[tg]=Ахлотдон
+Name[th]=ถังขยะ
+Name[tr]=Çöp
+Name[tt]=Çüplek
+Name[uk]=Смітник
+Name[uz]=Chiqindilar qutisi
+Name[uz@cyrillic]=Чиқиндилар қутиси
+Name[ven]=Tshikha
+Name[vi]=Thùng rác
+Name[wa]=Batch
+Name[xh]=Inkukumo
+Name[zh_CN]=回收站
+Name[zh_TW]=資源回收桶
+Name[zu]=Izibi
+Comment=Contains removed files
+Comment[af]=Bevat verwyder lêers
+Comment[ar]=تحتوي على الملفات المحذوفة
+Comment[az]=Silinmiş faylları daxil edir
+Comment[be]=Утрымлівае выдаленыя файлы
+Comment[bg]=Изтрити файлове
+Comment[bn]=মুছে ফেলা ফাইল থাকে
+Comment[bs]=Sadrži izbrisane datoteke
+Comment[ca]=Conté els fitxers esborrats
+Comment[cs]=Obsahuje odstraněné soubory
+Comment[csb]=Zamëkô w se remniãté lopczi
+Comment[cy]=Yn cynnwys ffeiliau sydd wedi eu gwaredu
+Comment[da]=Indeholder fjernede filer
+Comment[de]=Enthält gelöschte Dateien
+Comment[el]=Περιέχει σβησμένα αρχεία
+Comment[eo]=Enhavas forigitajn dosierojn
+Comment[es]=Contiene archivos borrados
+Comment[et]=Sisaldab eemaldatud faile
+Comment[eu]=Kendutako fitxategiak dauzka
+Comment[fa]=شامل پرونده‌های حذف‌شده
+Comment[fi]=Sisältää poistettuja tiedostoja
+Comment[fr]=Contient les fichiers supprimés
+Comment[fy]=Befettet fuortsmieten triemmen
+Comment[gl]=Contén ficheiros borrados
+Comment[he]=מכילה קבצים שהוסרו
+Comment[hi]=मिटाई गई फ़ाइलों को रखता है
+Comment[hr]=Sadrži izbrisane datoteke
+Comment[hu]=Itt találhatók a törölt fájlok
+Comment[is]=Inniheldur fjarlægðar skrár
+Comment[it]=Contiene i file cestinati
+Comment[ja]=削除されたファイルを保持しています
+Comment[ka]=შეიცავს წაშლილ ფაილებს
+Comment[kk]=Өшірілген файлдар үшін
+Comment[km]=ផ្ទុក​ឯកសារ​ដែល​បាន​យកចេញ
+Comment[lo]=ທີ່ສຳລັບເກັບແຟ້ມຂອງເຈົ້າທີ່ຕ້ອງການລືບ
+Comment[lt]=Čia yra ištrintos bylos
+Comment[lv]=Satur aizvāktos failus
+Comment[mk]=Содржи отстранети датотеки
+Comment[mn]=Усгагдсан файлууд агуулагдана
+Comment[ms]=Mengandungi fail yang dibuang
+Comment[mt]=Fih fajls mormija
+Comment[nb]=Inneholder slettede filer
+Comment[nds]=Dor sünd wegdaan Dateien binnen
+Comment[ne]=हटाएका फाइल समावेश गर्छ
+Comment[nl]=Bevat de verwijderde bestanden
+Comment[nn]=Inneheld sletta filer
+Comment[nso]=Ena le difaele tseo di tlositswego
+Comment[pa]=ਹਟਾਈਆਂ ਫਾਇਲ਼ਾਂ ਰੱਖਦਾ ਹੈ
+Comment[pl]=Zawiera usunięte pliki
+Comment[pt]=Contém os ficheiros apagados
+Comment[pt_BR]=Contém arquivos removidos
+Comment[ro]=Conține fișiere șterse
+Comment[ru]=Содержит удалённые файлы
+Comment[se]=Dáppe leat bálkestuvvon fiillat
+Comment[sk]=Obsahuje zmazané súbory
+Comment[sl]=Vsebuje odstranjene datoteke
+Comment[sr]=Садржи уклоњене фајлове
+Comment[sr@Latn]=Sadrži uklonjene fajlove
+Comment[sv]=Innehåller borttagna filer
+Comment[ta]=நீக்கப்பட்ட கோப்புகள் உள்ளது
+Comment[tg]=Файлҳои нобудшуда дорад
+Comment[th]=ที่สำหรับเก็บแฟ้มที่คุณต้องการลบ
+Comment[tr]=Silinmiş dosyaları içerir
+Comment[tt]=Beterelgän biremnär yatu urını
+Comment[uk]=Містить вилучені файли
+Comment[uz]=Olib tashlangan fayllardan iborat
+Comment[uz@cyrillic]=Олиб ташланган файллардан иборат
+Comment[ven]=Ina faela dzo bviswaho
+Comment[vi]=Chứa tập tin đã vứt
+Comment[wa]=I gn a des fitchîs oistés
+Comment[xh]=Iqulathe iifayile ezisusiweyo
+Comment[zh_CN]=保存临时删除的文件
+Comment[zh_TW]=包含刪除的檔案
+Comment[zu]=Iqukethe amafayela agudluziwe
+OnlyShowIn=KDE
diff --git a/kdesktop/kcheckrunning.cpp b/kdesktop/kcheckrunning.cpp
new file mode 100644
index 000000000..eaf8b9ebb
--- /dev/null
+++ b/kdesktop/kcheckrunning.cpp
@@ -0,0 +1,29 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Lubos Lunak <l.lunak@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <X11/Xlib.h>
+
+int main()
+ {
+ Display* dpy = XOpenDisplay( NULL );
+ if( dpy == NULL )
+ return 1;
+ Atom atom = XInternAtom( dpy, "_KDE_RUNNING", False );
+ return XGetSelectionOwner( dpy, atom ) != None ? 0 : 1;
+ }
diff --git a/kdesktop/kcustommenu.cc b/kdesktop/kcustommenu.cc
new file mode 100644
index 000000000..675dab098
--- /dev/null
+++ b/kdesktop/kcustommenu.cc
@@ -0,0 +1,111 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qimage.h>
+#include <qregexp.h>
+
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+
+#include "kcustommenu.h"
+
+class KCustomMenu::KCustomMenuPrivate
+{
+public:
+ QMap<int,KService::Ptr> entryMap;
+};
+
+KCustomMenu::KCustomMenu(const QString &configfile, QWidget *parent)
+ : QPopupMenu(parent, "kcustom_menu")
+{
+ d = new KCustomMenuPrivate;
+
+ KConfig cfg(configfile, true, false);
+ int count = cfg.readNumEntry("NrOfItems");
+ for(int i = 0; i < count; i++)
+ {
+ QString entry = cfg.readEntry(QString("Item%1").arg(i+1));
+ if (entry.isEmpty())
+ continue;
+
+ // Try KSycoca first.
+ KService::Ptr menuItem = KService::serviceByDesktopPath( entry );
+ if (!menuItem)
+ menuItem = KService::serviceByDesktopName( entry );
+ if (!menuItem)
+ menuItem = new KService( entry );
+
+ if (!menuItem->isValid())
+ continue;
+
+ insertMenuItem( menuItem, -1 );
+ }
+ connect(this, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
+}
+
+KCustomMenu::~KCustomMenu()
+{
+ delete d;
+}
+
+void
+KCustomMenu::slotActivated(int id)
+{
+ KService::Ptr s = d->entryMap[id];
+ if (!s)
+ return;
+ kapp->startServiceByDesktopPath(s->desktopEntryPath());
+}
+
+// The following is copied from kicker's PanelServiceMenu
+void
+KCustomMenu::insertMenuItem(KService::Ptr & s, int nId, int nIndex/*= -1*/)
+{
+ QString serviceName = s->name();
+
+ // item names may contain ampersands. To avoid them being converted
+ // to accelators, replace them with two ampersands.
+ serviceName.replace("&", "&&");
+
+ QPixmap normal = KGlobal::instance()->iconLoader()->loadIcon(s->icon(), KIcon::Small,
+ 0, KIcon::DefaultState, 0L, true);
+ QPixmap active = KGlobal::instance()->iconLoader()->loadIcon(s->icon(), KIcon::Small,
+ 0, KIcon::ActiveState, 0L, true);
+ // make sure they are not larger than 16x16
+ if (normal.width() > 16 || normal.height() > 16) {
+ QImage tmp = normal.convertToImage();
+ tmp = tmp.smoothScale(16, 16);
+ normal.convertFromImage(tmp);
+ }
+ if (active.width() > 16 || active.height() > 16) {
+ QImage tmp = active.convertToImage();
+ tmp = tmp.smoothScale(16, 16);
+ active.convertFromImage(tmp);
+ }
+
+ QIconSet iconset;
+ iconset.setPixmap(normal, QIconSet::Small, QIconSet::Normal);
+ iconset.setPixmap(active, QIconSet::Small, QIconSet::Active);
+
+ int newId = insertItem(iconset, serviceName, nId, nIndex);
+ d->entryMap.insert(newId, s);
+}
+
+#include "kcustommenu.moc"
diff --git a/kdesktop/kcustommenu.h b/kdesktop/kcustommenu.h
new file mode 100644
index 000000000..3a678ae7a
--- /dev/null
+++ b/kdesktop/kcustommenu.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kcustommenu_h__
+#define __kcustommenu_h__
+
+#include <qpopupmenu.h>
+#include <kservice.h>
+
+/*
+ * This class provides a Popup Menu with programs that can be executed and
+ * that reads its configuration from a config file.
+ */
+class KCustomMenu : public QPopupMenu
+{
+ Q_OBJECT
+public:
+ /**
+ * Create a custome menu described by @p configfile.
+ */
+ KCustomMenu(const QString &configfile, QWidget *parent=0);
+
+ /**
+ * Destructor
+ */
+ ~KCustomMenu();
+
+protected slots:
+ void slotActivated(int id);
+
+protected:
+ void insertMenuItem(KService::Ptr &s, int nId, int nIndex = -1);
+
+private:
+ class KCustomMenuPrivate;
+ KCustomMenuPrivate *d;
+};
+
+
+#endif
diff --git a/kdesktop/kdesktop.desktop b/kdesktop/kdesktop.desktop
new file mode 100644
index 000000000..7da10e945
--- /dev/null
+++ b/kdesktop/kdesktop.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+Exec=kdesktop
+X-DCOP-ServiceType=wait
+Name=KDE Desktop
+Name[af]=KDE Werkskerm
+Name[ar]=سطح المكتب KDE
+Name[az]=KDE Masa üstü
+Name[be]=Працоўны стол KDE
+Name[bn]=কে.ডি.ই. ডেস্কটপ
+Name[br]=Burev KDE
+Name[bs]=KDE radna površina
+Name[ca]=Escriptori KDE
+Name[cs]=Pracovní plocha KDE
+Name[csb]=Pùlt KDE
+Name[cy]=Penbwrdd KDE
+Name[da]=KDE-desktop
+Name[de]=KDE-Arbeitsfläche
+Name[el]=Επιφάνεια εργασίας του KDE
+Name[eo]=KDE Labortablo
+Name[es]=Escritorio de KDE
+Name[et]=KDE töölaud
+Name[eu]=KDE mahaigaina
+Name[fa]=رومیزی KDE
+Name[fi]=KDE-työpöytä
+Name[fr]=Bureau de KDE
+Name[fy]=KDE Buroblêd
+Name[ga]=Deasc KDE
+Name[gl]=Escritório de KDE
+Name[he]=שולחן העבודה של KDE
+Name[hi]=केडीई डेस्कटॉप
+Name[hr]=KDE radna površina
+Name[hu]=Munkaasztal
+Name[id]=Desktop KDE
+Name[is]=KDE skjáborð
+Name[it]=Desktop KDE
+Name[ja]=KDE デスクトップ
+Name[ka]=KDE სამუშაო დაფა
+Name[kk]=KDE үстелі
+Name[km]=ផ្ទៃតុ KDE
+Name[ko]=데스크톱
+Name[lo]=ພື້ນທີ່ທຳງານ KDE
+Name[lt]=KDE Darbastalis
+Name[lv]=KDE Darbvirsma
+Name[mk]=KDE Десктоп
+Name[mn]=КДЭ-Ажлын тавцан
+Name[ms]=Desktop KDE
+Name[mt]=Desktop KDE
+Name[nb]=KDE Skrivebord
+Name[nds]=KDE-Schriefdisch
+Name[ne]=KDE डेस्कटप
+Name[nl]=KDE Bureaublad
+Name[nn]=KDE-skrivebord
+Name[nso]=Desktop ya KDE
+Name[pa]=KDE ਵੇਹੜਾ
+Name[pl]=Pulpit KDE
+Name[pt]=Ecrã do KDE
+Name[pt_BR]=Área de Trabalho KDE
+Name[ro]=Ecran KDE
+Name[ru]=Рабочий стол KDE
+Name[rw]=KDE Ibiro
+Name[se]=KDE-čallinbeavdi
+Name[sk]=Pracovná plocha
+Name[sl]=Namizje KDE
+Name[sr]=KDE радна површина
+Name[sr@Latn]=KDE radna površina
+Name[sv]=KDE-skrivbord
+Name[ta]=KDE மேல்மேசை
+Name[te]=కెడిఈ రంగస్థలం
+Name[tg]=Мизи Кории KDE
+Name[th]=พื้นที่ทำงาน KDE
+Name[tr]=KDE Masaüstü
+Name[tt]=KDE Östäl
+Name[uk]=Стільниця KDE
+Name[uz]=KDE ish stoli
+Name[uz@cyrillic]=KDE иш столи
+Name[ven]=Desikithopo ya KDE
+Name[vi]=Môi trường KDE
+Name[wa]=Sicribanne KDE
+Name[zh_CN]=KDE 桌面
+Name[zh_TW]=KDE 桌面
+Name[zu]=I-Desktop ye-KDE
+Type=Service
+X-KDE-StartupNotify=false
+OnlyShowIn=KDE;
+X-KDE-autostart-phase=0
diff --git a/kdesktop/kdesktop.kcfg b/kdesktop/kdesktop.kcfg
new file mode 100644
index 000000000..597377661
--- /dev/null
+++ b/kdesktop/kdesktop.kcfg
@@ -0,0 +1,370 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile arg="true" />
+
+ <group name="Background Common">
+ <entry key="CommonDesktop" type="Bool">
+ <default>true</default>
+ <label>Common settings for all desktops</label>
+ <whatsthis>If you want the same background settings to be applied to all desktops enable this option.</whatsthis>
+ </entry>
+ <entry key="CommonScreen" type="Bool">
+ <default>true</default>
+ <label>Common settings for all screens</label>
+ <whatsthis>If you want the same background settings to be applied to all screens enable this option.</whatsthis>
+ </entry>
+ <entry key="DrawBackgroundPerScreen" type="Bool">
+ <default>false</default>
+ <label>Draw backgrounds per screen</label>
+ <whatsthis>If you want to draw to each screen separately in xinerama mode enable this option.</whatsthis>
+ </entry>
+ <entry key="LimitCache" type="Bool">
+ <default>false</default>
+ <label>Limit background cache</label>
+ <whatsthis>Enable this option if you want to limit the cache size for the background.</whatsthis>
+ </entry>
+ <entry key="CacheSize" type="Int">
+ <default>2048</default>
+ <label>Background cache size</label>
+ <whatsthis>Here you can enter how much memory KDE should use for caching the background(s). If you have different backgrounds for the different desktops caching can make switching desktops smoother at the expense of higher memory use.</whatsthis>
+ </entry>
+ </group>
+ <group name="General">
+ <entry name="DesktopEnabled" key="Enabled" type="Bool">
+ <default>true</default>
+ <label>Show icons on desktop</label>
+ <whatsthis>Uncheck this option if you do not want to have icons on the desktop. Without icons the desktop will be somewhat faster but you will no longer be able to drag files to the desktop.</whatsthis>
+ </entry>
+ <entry key="SetVRoot" type="Bool">
+ <default>false</default>
+ <label>Allow programs in desktop window</label>
+ <whatsthis>Check this option if you want to run X11 programs that draw into the desktop such as xsnow, xpenguin or xmountain. If you have problems with applications like netscape that check the root window for running instances, disable this option.</whatsthis>
+ </entry>
+ <entry key="CopyDesktopLinks" type="Bool">
+ <default>true</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- init.cc:138 -->
+ <!-- if (!config->readBoolEntry("CopyDesktopLinks", true)) -->
+ </entry>
+ <entry key="AutoLineUpIcons" type="Bool">
+ <default>false</default>
+ <label>Automatically line up icons</label>
+ <whatsthis>Check this option if you want to see your icons automatically aligned to the grid when you move them.</whatsthis>
+ </entry>
+ <entry key="SortDirectoriesFirst" type="Bool">
+ <default>true</default>
+ <label>Sort directories first</label>
+ <whatsthis></whatsthis>
+ <!-- krootwm.cc:251 -->
+ <!-- aSortDirsFirst->setChecked( kconfig->readBoolEntry("SortDirectoriesFirst", true)); -->
+ <!-- krootwm.cc:496 -->
+ <!-- config->writeEntry( "SortDirectoriesFirst", b ); -->
+ </entry>
+ </group>
+ <group name="Mouse Buttons">
+ <entry key="WheelSwitchesWorkspace" type="Bool">
+ <default>false</default>
+ <label>Mouse wheel over desktop background switches desktop</label>
+ <whatsthis>You can switch between the virtual desktops by using the mouse wheel over the desktop background.</whatsthis>
+ </entry>
+ <entry key="WheelDirection" type="String">
+ <default>Forward</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- desktop.cc:397 -->
+ <!-- (config->readEntry("WheelDirection", default_dir_string) == forward_string) ? Forward : Reverse; -->
+ </entry>
+ <entry key="TerminalApplication" type="Path">
+ <default>konsole</default>
+ <label>Terminal application</label>
+ <whatsthis>Defines which terminal application is used.</whatsthis>
+ </entry>
+ <entry key="Left" type="String">
+ <default></default>
+ <label>Left Mouse Button Action</label>
+ <whatsthis>You can choose what happens when you click the left button of your pointing device on the desktop.</whatsthis>
+ </entry>
+ <entry key="Middle" type="String">
+ <default>WindowListMenu</default>
+ <label>Middle Mouse Button Action</label>
+ <whatsthis>You can choose what happens when you click the middle button of your pointing device on the desktop.</whatsthis>
+ </entry>
+ <entry key="Right" type="String">
+ <default>DesktopMenu</default>
+ <label>Right Mouse Button Action</label>
+ <whatsthis>You can choose what happens when you click the right button of your pointing device on the desktop.</whatsthis>
+ </entry>
+ </group>
+ <group name="Version">
+ <entry key="KDEVersionMajor" type="Int">
+ <default>0</default>
+ <label>KDE major version number</label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="KDEVersionMinor" type="Int">
+ <default>0</default>
+ <label>KDE minor version number</label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="KDEVersionRelease" type="Int">
+ <default>0</default>
+ <label>KDE release version number</label>
+ <whatsthis></whatsthis>
+ </entry>
+ </group>
+ <group name="FMSettings">
+ <entry key="NormalTextColor" type="Color"> <!--SHARED-->
+ <default>Qt::white</default>
+ <label>Normal text color used for icon labels</label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="ItemTextBackground" type="Color"> <!--SHARED-->
+ <label>Background color used for icon labels</label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="ShadowEnabled" type="Bool">
+ <default>true</default>
+ <label>Enable text shadow</label>
+ <whatsthis>Check here to enable a shadow outline around the desktop font. This also improves the readability of the desktop text against backgrounds of a similar color.</whatsthis>
+ </entry>
+ <entry key="ShadowParameters" type="String">
+ <default>0,0,4.0,120.0,2,1,1,0,0,0</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- kdesktopshadowsettings.cpp:84 -->
+ <!-- fromString(config->readEntry(SHADOW_CONFIG_ENTRY)); -->
+ </entry>
+ </group>
+ <group name="Desktop Icons">
+ <entry key="ShowHidden" type="Bool">
+ <default>false</default>
+ <label>Show hidden files</label>
+ <whatsthis><p>If you check this option, any files in your desktop directory that begin with a period (.) will be shown. Usually, such files contain configuration information, and remain hidden from view.</p>\n<p>For example, files which are named \".directory\" are plain text files which contain information for Konqueror, such as the icon to use in displaying a directory, the order in which files should be sorted, etc. You should not change or delete these files unless you know what you are doing.</p></whatsthis>
+ </entry>
+ <entry key="VertAlign" type="Bool">
+ <default>true</default>
+ <label>Align direction</label>
+ <whatsthis>If this is enabled, icons are aligned vertically, otherwise horizontally.</whatsthis>
+ </entry>
+ <entry key="Preview" type="StringList">
+ <default></default>
+ <label>Show Icon Previews For</label>
+ <whatsthis>Select for which types of files you want to enable preview images.</whatsthis>
+ </entry>
+ <entry key="SortCriterion" type="Int">
+<!--
+ <entry key="SortCriterion" type="Enum">
+ <choices>
+ <choice name="NameCaseSensitive" />
+ <choice name="NameCaseInsensitive" />
+ <choice name="Size" />
+ <choice name="Type" />
+ <choice name="Date" />
+ </choices>
+-->
+ <default>0</default>
+ <label>Sort criterion</label>
+ <whatsthis>Sets the sort criterion. Possible choices are NameCaseSensitive = 0, NameCaseInsensitive = 1, Size = 2, Type = 3, Date = 4.</whatsthis>
+ </entry>
+ <entry key="DirectoriesFirst" type="Bool">
+ <default>true</default>
+ <label>Sort directories first</label>
+ <whatsthis>Enable this to place directories in front of the sorted list, otherwise they are amongst the files.</whatsthis>
+ </entry>
+ <entry key="LockIcons" type="Bool">
+ <default>false</default>
+ <label>Lock in Place</label>
+ <whatsthis>Check this option if you want to keep your icons from moving.</whatsthis>
+ </entry>
+
+ <entry key="AlwaysFirstItems" type="StringList">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- kdiconview.cc:254 -->
+ <!-- m_itemsAlwaysFirst = config->readListEntry("AlwaysFirstItems"); // Distributor plug-in -->
+ </entry>
+ </group>
+ <group name="Media">
+ <entry name="MediaEnabled" key="enabled" type="Bool">
+ <default>false</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- kdiconview.cc:258 -->
+ <!-- m_enableMedia=config->readBoolEntry("enabled",false); -->
+ </entry>
+ <entry key="exclude" type="String">
+ <default>media/hdd_mounted,media/hdd_unmounted,media/floppy_unmounted,media/cdrom_unmounted,media/floppy5_unmounted</default>
+ <label>Device Types to exclude</label>
+ <whatsthis>The device types which you do not want to see on the desktop.</whatsthis>
+ <!-- kdiconview.cc:261 -->
+ <!-- QString tmpList=config->readEntry("exclude","media/hdd_mounted,media/hdd_unmounted,media/floppy_unmounted,media/cdrom_unmounted,media/floppy5_unmounted"); -->
+ </entry>
+ </group>
+ <group name="KDE">
+ <entry key="macStyle" type="Bool">
+ <default>false</default>
+ <label>Current application's menu bar (Mac OS-style)</label>
+ <whatsthis>If this option is selected, applications will not have their menu bar attached to their own window anymore. Instead, there is one menu bar at the top of the screen which shows the menus of the currently active application. You might recognize this behavior from Mac OS.</whatsthis>
+ </entry>
+ </group>
+ <group name="Menubar">
+ <entry key="ShowMenubar" type="Bool">
+ <default>false</default>
+ <label>Desktop menu bar</label>
+ <whatsthis>If this option is selected, there is one menu bar at the top of the screen which shows the desktop menus.</whatsthis>
+ </entry>
+ </group>
+ <group name="ScreenSaver">
+ <entry name="ScreenSaverEnabled" key="Enabled" type="Bool">
+ <default>false</default>
+ <label>Enable screen saver</label>
+ <whatsthis>Enables the screen saver.</whatsthis>
+ </entry>
+ <entry key="Timeout" type="Int">
+ <default>300</default>
+ <label>Screen saver timeout</label>
+ <whatsthis>Sets the seconds after which the screen saver is started.</whatsthis>
+ </entry>
+ <entry name="DpmsDependent" key="DPMS-dependent" type="Bool">
+ <default>true</default>
+ <label>Suspend screen saver when DPMS kicks in</label>
+ <whatsthis>Usually the screen saver is suspended when display power saving kicks in,
+ as nothing can be seen on the screen anyway, obviously. However, some screen savers
+ actually perform useful computations, so it is not desirable to suspend them.</whatsthis>
+ </entry>
+ <entry key="ActionTopLeft" type="Int">
+ <default>0</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="ActionTopRight" type="Int">
+ <default>0</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="ActionBottomLeft" type="Int">
+ <default>0</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="ActionBottomRight" type="Int">
+ <default>0</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ </entry>
+ <entry key="Lock" type="Bool">
+ <default>false</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:308 -->
+ <!-- if(config.readBoolEntry("Lock", false)) -->
+ </entry>
+ <entry key="LockGrace" type="Int">
+ <default>5000</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:310 -->
+ <!-- mLockGrace = config.readNumEntry("LockGrace", LOCK_GRACE_DEFAULT); -->
+ </entry>
+ <entry key="AutoLogout" type="Bool">
+ <default>false</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:319 -->
+ <!-- if (config.readBoolEntry("AutoLogout", false)) -->
+ </entry>
+ <entry key="AutoLogoutTimeout" type="Int">
+ <default>600</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:322 -->
+ <!-- mAutoLogoutTimeout = config.readNumEntry("AutoLogoutTimeout", AUTOLOGOUT_DEFAULT); -->
+ </entry>
+ <entry key="Priority" type="Int">
+ <default>19</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:332 -->
+ <!-- mPriority = config.readNumEntry("Priority", 19); -->
+ </entry>
+ <entry key="Saver" type="String">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:336 -->
+ <!-- mSaver = config.readEntry("Saver"); -->
+ </entry>
+ <entry key="PluginsUnlock" type="StringList">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:342 -->
+ <!-- mPlugins = config.readListEntry("PluginsUnlock"); -->
+ </entry>
+ <entry key="PluginOptions" type="StringList">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- /home/paco/cvsroot/kdebase/kdesktop/lock/lockprocess.cc:345 -->
+ <!-- mPluginOptions = config.readListEntry("PluginOptions"); -->
+ </entry>
+ </group>
+ <group name="MiniCli">
+ <entry key="History" type="PathList">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- minicli.cpp:191 -->
+ <!-- QStringList histList = config->readPathListEntry("History"); -->
+ <!-- minicli.cpp:242 -->
+ <!-- config->writePathEntry( "History", m_dlg->cbCommand->historyItems() ); -->
+ </entry>
+ <entry key="HistoryLength" type="Int">
+ <default>50</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- minicli.cpp:192 -->
+ <!-- int maxHistory = config->readNumEntry("HistoryLength", 50); -->
+ </entry>
+ <entry key="TerminalApps" type="PathList">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- minicli.cpp:193 -->
+ <!-- m_terminalAppList = config->readPathListEntry("TerminalApps"); -->
+ <!-- minicli.cpp:243 -->
+ <!-- config->writePathEntry( "TerminalApps", m_terminalAppList ); -->
+ </entry>
+ <entry key="CompletionItems" type="PathList">
+ <default></default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- minicli.cpp:204 -->
+ <!-- QStringList compList = config->readPathListEntry("CompletionItems"); -->
+ <!-- minicli.cpp:244 -->
+ <!-- config->writePathEntry( "CompletionItems", m_dlg->cbCommand->completionObject()->items() ); -->
+ </entry>
+ <entry key="CompletionMode" type="Int">
+ <default code="true">KGlobalSettings::completionMode()</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- minicli.cpp:210 -->
+ <!-- int mode = config->readNumEntry( "CompletionMode", KGlobalSettings::completionMode() ); -->
+ <!-- minicli.cpp:252 -->
+ <!-- config->writeEntry( "CompletionMode", m_dlg->cbCommand->completionMode() ); -->
+ </entry>
+ <entry key="MaxUsernameCompletions" type="Int">
+ <default>30</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- minicli.cpp:220 -->
+ <!-- int maxEntries = config->readNumEntry("MaxUsernameCompletions", 30); -->
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdesktop/kdesktopSetAsBackground.desktop b/kdesktop/kdesktopSetAsBackground.desktop
new file mode 100644
index 000000000..0579fc013
--- /dev/null
+++ b/kdesktop/kdesktopSetAsBackground.desktop
@@ -0,0 +1,210 @@
+[Desktop Entry]
+ServiceTypes=image/*
+Actions=setAsBackground;tileAsBackground;
+X-KDE-Submenu=Set as Background
+X-KDE-Submenu[af]=Stel as agtergrond
+X-KDE-Submenu[be]=Зрабіць фонавым малюнкам
+X-KDE-Submenu[bg]=Установяване като фон
+X-KDE-Submenu[bn]=পশ্চাদ্‌পট হিসাবে বেছে নাও
+X-KDE-Submenu[bs]=Postavi kao pozadinu
+X-KDE-Submenu[ca]=Estableix com a fons
+X-KDE-Submenu[cs]=Nastavit jako pozadí
+X-KDE-Submenu[csb]=Ùstôwi jakno spòdlé
+X-KDE-Submenu[da]=Sæt som baggrund
+X-KDE-Submenu[de]=Als Hintergrund setzen
+X-KDE-Submenu[el]=Ορισμός ως ταπετσαρία
+X-KDE-Submenu[eo]=Agordu kiel fono
+X-KDE-Submenu[es]=Establecer como fondo
+X-KDE-Submenu[et]=Sea taustapildiks
+X-KDE-Submenu[eu]=Ezarri atzeko plano gisa
+X-KDE-Submenu[fa]=تنظیم به عنوان زمینه
+X-KDE-Submenu[fi]=Aseta taustakuvaksi
+X-KDE-Submenu[fr]=Définir comme arrière-plan
+X-KDE-Submenu[fy]=As eftergrûn brûke
+X-KDE-Submenu[gl]=Pór como Fondo de Escritório
+X-KDE-Submenu[he]=קבע כרקע
+X-KDE-Submenu[hr]=Postavi kao pozadinu
+X-KDE-Submenu[hu]=Beállítás háttérképnek
+X-KDE-Submenu[is]=Setja sem bakgrunn
+X-KDE-Submenu[it]=Imposta come sfondo
+X-KDE-Submenu[ja]=背景としてセット
+X-KDE-Submenu[kk]=Ая ретінде орнату
+X-KDE-Submenu[km]=កំណត់​ជា​ផ្ទៃខាងក្រោយ
+X-KDE-Submenu[lt]=Nustatyti fonu
+X-KDE-Submenu[mk]=Постави како подлога
+X-KDE-Submenu[nb]=Sett som bakgrunn
+X-KDE-Submenu[nds]=As Achtergrund fastleggen
+X-KDE-Submenu[ne]=पृष्ठभूमिको रुपमा सेट गर्छ
+X-KDE-Submenu[nl]=Als achtergrond gebruiken
+X-KDE-Submenu[nn]=Bruk som bakgrunn
+X-KDE-Submenu[pa]=ਪਿੱਠਭੂਮੀ ਬਣਾਓ
+X-KDE-Submenu[pl]=Ustaw jako tło
+X-KDE-Submenu[pt]=Colocar como Fundo
+X-KDE-Submenu[pt_BR]=Configurar como Plano de fundo
+X-KDE-Submenu[ro]=Setează ca fundal
+X-KDE-Submenu[ru]=Сделать фоновым рисунком
+X-KDE-Submenu[se]=Geavat duogášgovvan
+X-KDE-Submenu[sk]=Nastaviť ako pozadie
+X-KDE-Submenu[sl]=Nastavi kot ozadje
+X-KDE-Submenu[sr]=Постави као позадину
+X-KDE-Submenu[sr@Latn]=Postavi kao pozadinu
+X-KDE-Submenu[sv]=Använd som bakgrund
+X-KDE-Submenu[th]=ตั้งให้เป็นพื้นหลัง
+X-KDE-Submenu[tr]=Masaüstü Arkaplanı Yap
+X-KDE-Submenu[uk]=Встановити як тло
+X-KDE-Submenu[uz]=Ish stoliga qoʻyish
+X-KDE-Submenu[uz@cyrillic]=Иш столига қўйиш
+X-KDE-Submenu[vi]=Đặt làm Hình nền
+X-KDE-Submenu[wa]=Mete come fond d' waitroûle
+X-KDE-Submenu[zh_CN]=设为背景
+X-KDE-Submenu[zh_TW]=設為背景
+
+[Desktop Action setAsBackground]
+Name=Centered
+Name[af]=Gesentreer
+Name[ar]=مركز
+Name[be]=Пасярэдзіне
+Name[bg]=Центрирано
+Name[bn]=মাঝামাঝি
+Name[br]=Kreizennet
+Name[bs]=Centrirano
+Name[ca]=Centrat
+Name[cs]=Na střed
+Name[csb]=Na westrzódkù
+Name[cy]=Canoledig
+Name[da]=Centreret
+Name[de]=Zentriert
+Name[el]=Κεντράρισμα
+Name[en_GB]=Centred
+Name[eo]=Meza
+Name[es]=Centrado
+Name[et]=Tsentreeritud
+Name[eu]=Erdiratua
+Name[fa]=مرکزی
+Name[fi]=Keskitetty
+Name[fr]=Centré
+Name[fy]=sintraal setten
+Name[ga]=Láraithe
+Name[gl]=Centrado
+Name[he]=ממורכז
+Name[hi]=बीचों-बीच
+Name[hr]=Sredinom
+Name[hu]=Középre igazítva
+Name[is]=Miðjað
+Name[it]=Centrato
+Name[ja]=中央
+Name[ka]=ცენტრზე
+Name[kk]=Ортаға
+Name[km]=កណ្ដាល
+Name[lt]=Centruota
+Name[lv]=Centrēts
+Name[mk]=Центриран
+Name[ms]=Tengah
+Name[mt]=Iċċentrat
+Name[nb]=Sentrert
+Name[nds]=In de Merrn
+Name[ne]=केन्द्रित
+Name[nl]=Gecentreerd
+Name[nn]=Sentrert
+Name[pa]=ਕੇਂਦਰੀ
+Name[pl]=Wyśrodkowane
+Name[pt]=Centrado
+Name[pt_BR]=Centralizado
+Name[ro]=Centrat
+Name[ru]=По центру
+Name[rw]=Biri hagati
+Name[se]=Guovdut
+Name[sk]=V strede
+Name[sl]=Usrediščeno
+Name[sr]=Центрирано
+Name[sr@Latn]=Centrirano
+Name[sv]=Centrerad
+Name[ta]=மைய
+Name[te]=మద్యన
+Name[tg]=Марказӣ
+Name[th]=จัดกลาง
+Name[tr]=Uzat
+Name[tt]=Üzäkläşep
+Name[uk]=По центру
+Name[uz]=Markazda
+Name[uz@cyrillic]=Марказда
+Name[vi]=Giữa
+Name[wa]=Å mitan
+Name[zh_CN]=居中
+Name[zh_TW]=置中
+Icon=background
+Exec=dcop kdesktop KBackgroundIface setWallpaper %u 6
+
+[Desktop Action tileAsBackground]
+Name=Tiled
+Name[af]=Geteël
+Name[ar]=مبلّط
+Name[be]=Расцягнутае
+Name[bg]=Каскадно
+Name[bn]=টাইল করা
+Name[br]=Teolet
+Name[bs]=Popločano
+Name[ca]=Repetit
+Name[cs]=Dlaždice
+Name[csb]=Kachelkòwóné
+Name[cy]=Teiledig
+Name[da]=Fliselagt
+Name[de]=Gekachelt
+Name[el]=Σε παράθεση
+Name[eo]=kahela
+Name[es]=Mosaico
+Name[et]=Paanidena
+Name[eu]=Mosaikoa
+Name[fa]=کاشی‌شده
+Name[fi]=Vierekkäin
+Name[fr]=Mosaïque
+Name[fy]=Tegele
+Name[ga]=Tilithe
+Name[gl]=Mosaico
+Name[he]=פרוש
+Name[hi]=चटाई-दार
+Name[hr]=Popločeno
+Name[hu]=Mozaikszerűen
+Name[is]=Flísað
+Name[it]=Ripetuto
+Name[ja]=タイル状
+Name[ka]=მოზაიკა
+Name[kk]=Қатарлап
+Name[km]=ក្បឿង
+Name[lt]=Iškloti
+Name[mk]=Поплочен
+Name[ms]=Berjubin
+Name[mt]=Madum
+Name[nb]=Flislagt
+Name[nds]=Kachelt
+Name[ne]=टायल गरिएको
+Name[nl]=Tegels
+Name[nn]=Jamsides
+Name[pa]=ਤਣਿਆ
+Name[pl]=Kafelkowane
+Name[pt]=Mosaico
+Name[pt_BR]=Ladrilhado
+Name[ro]=Mozaic
+Name[ru]=Черепицей
+Name[rw]=Byudukaro
+Name[se]=Bálddalaga
+Name[sk]=Dlaždice
+Name[sl]=Razdeljeno
+Name[sr]=Поређано
+Name[sr@Latn]=Poređano
+Name[sv]=Sida vid sida
+Name[ta]=பிண்ணனி
+Name[te]=పలకలుగా
+Name[tg]=Тахтасангӣ
+Name[th]=ปูทั้งหน้าจอ
+Name[tr]=Sırala
+Name[tt]=Bülengän
+Name[uk]=Плиткою
+Name[uz]=Kafel
+Name[uz@cyrillic]=Кафель
+Name[vi]=Xếp ngói
+Name[wa]=A schaeyes
+Name[zh_CN]=平铺
+Name[zh_TW]=拼貼
+Icon=background
+Exec=dcop kdesktop KBackgroundIface setWallpaper %u 2
diff --git a/kdesktop/kdesktop_custom_menu1 b/kdesktop/kdesktop_custom_menu1
new file mode 100644
index 000000000..f0466b886
--- /dev/null
+++ b/kdesktop/kdesktop_custom_menu1
@@ -0,0 +1,2 @@
+NrOfItems=1
+Item1=konsole
diff --git a/kdesktop/kdesktop_custom_menu2 b/kdesktop/kdesktop_custom_menu2
new file mode 100644
index 000000000..2073a0d77
--- /dev/null
+++ b/kdesktop/kdesktop_custom_menu2
@@ -0,0 +1,2 @@
+NrOfItems=1
+Item1=xterm
diff --git a/kdesktop/kdesktopbindings.cpp b/kdesktop/kdesktopbindings.cpp
new file mode 100644
index 000000000..c50eb7c30
--- /dev/null
+++ b/kdesktop/kdesktopbindings.cpp
@@ -0,0 +1,47 @@
+#ifndef NOSLOTS
+# define DEF( name, key3, key4, fnSlot ) \
+ keys->insert( name, i18n(name), QString::null, key3, key4, this, SLOT(fnSlot) )
+# define DEF2( name, key3, key4, receiver, slot ) \
+ keys->insert( name, i18n(name), QString::null, key3, key4, receiver, slot );
+#else
+# define DEF( name, key3, key4, fnSlot ) \
+ keys->insert( name, i18n(name), QString::null, key3, key4 )
+# define DEF2( name, key3, key4, receiver, slot ) \
+ keys->insert( name, i18n(name), QString::null, key3, key4 )
+#endif
+#define WIN KKey::QtWIN
+
+ keys->insert( "Program:kdesktop", i18n("Desktop") );
+
+#ifndef NOSLOTS
+ if (kapp->authorize("run_command"))
+ {
+#endif
+ DEF( I18N_NOOP("Run Command"), ALT+Qt::Key_F2, WIN+Qt::Key_Return, slotExecuteCommand() );
+#ifndef NOSLOTS
+ }
+#endif
+ DEF( I18N_NOOP("Show Taskmanager"), CTRL+Qt::Key_Escape, WIN+CTRL+Qt::Key_Pause, slotShowTaskManager() );
+ DEF( I18N_NOOP("Show Window List"), ALT+Qt::Key_F5, WIN+Qt::Key_0, slotShowWindowList() );
+ DEF( I18N_NOOP("Switch User"), ALT+CTRL+Qt::Key_Insert, WIN+Qt::Key_Insert, slotSwitchUser() );
+#ifndef NOSLOTS
+ if (kapp->authorize("lock_screen"))
+ {
+#endif
+ DEF2( I18N_NOOP("Lock Session"), ALT+CTRL+Qt::Key_L, WIN+Qt::Key_ScrollLock, KRootWm::self(), SLOT(slotLock()) );
+#ifndef NOSLOTS
+ }
+ if (kapp->authorize("logout"))
+ {
+#endif
+ DEF( I18N_NOOP("Log Out"), ALT+CTRL+Qt::Key_Delete, WIN+Qt::Key_Escape, slotLogout() );
+ DEF( I18N_NOOP("Log Out Without Confirmation"), ALT+CTRL+SHIFT+Qt::Key_Delete, WIN+SHIFT+Qt::Key_Escape, slotLogoutNoCnf() );
+ DEF( I18N_NOOP("Halt without Confirmation"), ALT+CTRL+SHIFT+Qt::Key_PageDown, WIN+CTRL+SHIFT+Qt::Key_PageDown, slotHaltNoCnf() );
+ DEF( I18N_NOOP("Reboot without Confirmation"), ALT+CTRL+SHIFT+Qt::Key_PageUp, WIN+CTRL+SHIFT+Qt::Key_PageUp, slotRebootNoCnf() );
+#ifndef NOSLOTS
+ }
+#endif
+
+#undef DEF
+#undef DEF2
+#undef WIN
diff --git a/kdesktop/kdesktopsettings.kcfgc b/kdesktop/kdesktopsettings.kcfgc
new file mode 100644
index 000000000..f3577d133
--- /dev/null
+++ b/kdesktop/kdesktopsettings.kcfgc
@@ -0,0 +1,4 @@
+File=kdesktop.kcfg
+ClassName=KDesktopSettings
+Singleton=true
+Mutators=true
diff --git a/kdesktop/kdesktopshadowsettings.cpp b/kdesktop/kdesktopshadowsettings.cpp
new file mode 100644
index 000000000..8ebdc89a8
--- /dev/null
+++ b/kdesktop/kdesktopshadowsettings.cpp
@@ -0,0 +1,92 @@
+/* This file is proposed to be part of the KDE base.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow
+ * algorithm (currently used)
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <qcolor.h>
+#include <kdebug.h>
+#include "kdesktopshadowsettings.h"
+
+
+//#define DEBUG
+
+KDesktopShadowSettings::KDesktopShadowSettings(KConfig *cfg) :
+ KShadowSettings(),
+ m_textColor(QColor(255,255,255)),
+ _UID(0L)
+{
+ setConfig(cfg);
+}
+
+KDesktopShadowSettings::~KDesktopShadowSettings()
+{
+}
+
+/**
+ *
+ */
+void KDesktopShadowSettings::setUID(unsigned long val)
+{
+ if (val == 0L || val == _UID)
+ _UID++;
+ else
+ _UID = val;
+}
+
+unsigned long KDesktopShadowSettings::UID()
+{
+ return _UID;
+}
+
+/**
+ * Loads a new configuration
+ */
+void KDesktopShadowSettings::setConfig(KConfig *val)
+{
+ config = val;
+
+ if (val == NULL)
+ return;
+
+ // increment the UID so the items will rebuild their
+ // pixmaps
+ setUID();
+
+ config->setGroup("FMSettings");
+ m_textColor = config->readColorEntry("NormalTextColor", &Qt::white);
+ m_bgColor = config->readColorEntry("ItemTextBackground");
+ m_isEnabled = config->readBoolEntry("ShadowEnabled", true);
+
+#ifdef DEBUG
+ // debug
+ kdDebug(1204) << "setConfig()" << endl;
+#endif
+
+ if (config->hasKey(SHADOW_CONFIG_ENTRY))
+ fromString(config->readEntry(SHADOW_CONFIG_ENTRY));
+
+#ifdef DEBUG
+ // debug
+ kdDebug(1204) << " \t" << SHADOW_TEXT_COLOR << "=" << m_textColor << endl;
+ kdDebug(1204) << " \t" << SHADOW_TEXT_BACKGROUND << "=" << m_bgColor << endl;
+ kdDebug(1204) << " \t" << toString() << endl;
+#endif
+}
diff --git a/kdesktop/kdesktopshadowsettings.h b/kdesktop/kdesktopshadowsettings.h
new file mode 100644
index 000000000..7ee3b1451
--- /dev/null
+++ b/kdesktop/kdesktopshadowsettings.h
@@ -0,0 +1,117 @@
+/* This file is proposed to be part of the KDE base.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow
+ * algorithm (currently used)
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef __FX_DATA_DESKTOP
+#define __FX_DATA_DESKTOP
+
+#include <qcolor.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+
+#include <kshadowsettings.h>
+
+#define FX_GROUP "FX"
+
+#define ALGO_KEY "Shadow.Algorithm"
+#define MULT_KEY "Shadow.MultiplicationFactor"
+#define OPAC_KEY "Shadow.MaxOpacity"
+#define OFSX_KEY "Shadow.OffsetX"
+#define OFSY_KEY "Shadow.OffsetY"
+#define THIK_KEY "Shadow.Thickness"
+#define SELT_KEY "Shadow.SelectionType"
+
+/**
+ * This implementation of FxData will read a the default configuration
+ * file. The values used for shadow are frouped under "FX".
+ *
+ * The values are:
+ * Shadow.Algorithm: the algorithm used for making the sahdow
+ * Shadow.Scale the normailsation factor for veraging the sum
+ * Shadow.MaxOpacity the maximum allowable opacity (255 = 100%opaque)
+ * Shadow.OffsetX the X-coordinate offset (0 centered)
+ * Shadow.OffsetY the Y-coordinate offset (0 centered)
+ * Shadow.Thickness the shadow thickness (usually 3-5 px)
+ * Shadow.SelectionType the selection type - inverse video or use
+ * the selection colours.
+ *
+ * 06-Feb-03: Added simple UID algorithm
+ *
+ */
+class KDesktopShadowSettings : public KShadowSettings
+{
+ public:
+ /**
+ * Constructor
+ * @param cfg the configuration file
+ */
+ KDesktopShadowSettings(KConfig *cfg = NULL);
+
+ virtual ~KDesktopShadowSettings();
+
+ /**
+ * Sets a specific configuration file after the object's creation
+ * @param config new configuration object
+ */
+ void setConfig(KConfig *);
+
+ /**
+ * Returns the text color as definied in the configuraiton
+ * @return the text color as definied in the configuraiton
+ */
+ QColor &textColor(){ return m_textColor; };
+
+ /**
+ * Returns the shadow color as definied in the configuraiton
+ * @return the shadow color as definied in the configuraiton
+ */
+ QColor &bgColor() { return m_bgColor; };
+
+ /**
+ * Returns true if the shadow engine is enabled.
+ * @return true if the shadow engine is enabled.
+ */
+ bool isEnabled() { return m_isEnabled; };
+
+ /**
+ * Returns an UID for shadow rebuilding purposes
+ * @return an UID for shadow rebuilding purposes
+ */
+ unsigned long UID();
+
+ /**
+ * (Re)sets an UID for shadow rebuilding purposes
+ * @param the new UID (if 0/default, increments the stored UID)
+ */
+ void setUID(unsigned long val = 0L);
+
+ private:
+ KConfig *config;
+ QColor m_textColor;
+ QColor m_bgColor;
+ bool m_isEnabled;
+
+ // uid of the object. Use this to determine the oportunity of a new
+ // rebuild.
+ unsigned long _UID;
+};
+
+#endif
diff --git a/kdesktop/kdiconview.cc b/kdesktop/kdiconview.cc
new file mode 100644
index 000000000..f9ca6c446
--- /dev/null
+++ b/kdesktop/kdiconview.cc
@@ -0,0 +1,1668 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000, 2001 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kdiconview.h"
+#include "krootwm.h"
+#include "desktop.h"
+#include "kdesktopsettings.h"
+
+#include <kio/paste.h>
+#include <kaccel.h>
+#include <kapplication.h>
+#include <kcolordrag.h>
+#include <kdebug.h>
+#include <kdesktopfile.h>
+#include <kdirlister.h>
+#include <kglobalsettings.h>
+#include <kpropertiesdialog.h>
+#include <klocale.h>
+#include <konqbookmarkmanager.h>
+#include <konq_defaults.h>
+#include <konq_drag.h>
+#include <konq_operations.h>
+#include <konq_popupmenu.h>
+#include <konq_settings.h>
+#include <konq_undo.h>
+#include <kprotocolinfo.h>
+#include <kstdaction.h>
+#include <kstandarddirs.h>
+#include <kurldrag.h>
+#include <kwin.h>
+#include <kwinmodule.h>
+
+#include <fixx11h.h>
+
+#include <qclipboard.h>
+#include <qdir.h>
+#include <qevent.h>
+#include <qregexp.h>
+
+#include <unistd.h>
+
+#include "kshadowengine.h"
+#include "kdesktopshadowsettings.h"
+#include "kfileividesktop.h"
+
+// for multihead
+extern int kdesktop_screen_number;
+
+// -----------------------------------------------------------------------------
+
+QRect KDIconView::desktopRect()
+{
+ return ( kdesktop_screen_number == 0 )
+ ? QApplication::desktop()->geometry() // simple case, or xinerama
+ : QApplication::desktop()->screenGeometry( kdesktop_screen_number ); // multi-head
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::saveIconPosition(KSimpleConfig *config, int x, int y)
+{
+ // save the icon position in absolute coordinates
+ config->writeEntry("Xabs", x);
+ config->writeEntry("Yabs", y);
+
+ // save also mentioning desktop size
+ QRect desk = desktopRect();
+ QString sizeStr = QString( "_%1x%2" ).arg(desk.width()).arg(desk.height());
+
+ config->writeEntry("Xabs" + sizeStr, x);
+ config->writeEntry("Yabs" + sizeStr, y);
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::readIconPosition(KSimpleConfig *config, int &x, int &y)
+{
+ // check if we have the position for the current desktop size
+ QRect desk = desktopRect();
+ QString sizeStr = QString( "_%1x%2" ).arg(desk.width()).arg(desk.height());
+
+ x = config->readNumEntry("Xabs" + sizeStr, -99999);
+
+ if ( x != -99999 )
+ y = config->readNumEntry("Yabs" + sizeStr);
+ else
+ {
+ // not found; use the resolution independent position
+ x = config->readNumEntry("Xabs", -99999);
+
+ if ( x != -99999 )
+ y = config->readNumEntry("Yabs");
+ else // for compatibility, read the old iconArea-relative-position
+ {
+ // problem here: when reading a position before we know the correct
+ // desktopIconsArea, the relative position do not make sense
+ // workaround: use desktopRect() as the allowed size
+
+ QRect desk = desktopRect();
+ QString X_w = QString("X %1").arg(desk.width() );
+ QString Y_h = QString("Y %1").arg(desk.height());
+
+ x = config->readNumEntry(X_w, -99999);
+ if ( x != -99999 ) x = config->readNumEntry("X");
+ if ( x < 0 ) x += desk.width();
+
+ y = config->readNumEntry(Y_h, -99999);
+ if ( y != -99999 ) y = config->readNumEntry("Y");
+ if ( y < 0 ) y += desk.height();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+KDIconView::KDIconView( QWidget *parent, const char* name )
+ : KonqIconViewWidget( parent, name, WResizeNoErase, true ),
+ m_actionCollection( this, "KDIconView::m_actionCollection" ),
+ m_accel( 0L ),
+ m_bNeedRepaint( false ),
+ m_bNeedSave( false ),
+ m_autoAlign( false ),
+ m_hasExistingPos( false ),
+ m_bEditableDesktopIcons( kapp->authorize("editable_desktop_icons") ),
+ m_bShowDot( false ),
+ m_bVertAlign( true ),
+ m_dirLister( 0L ),
+ m_mergeDirs(),
+ m_dotDirectory( 0L ),
+ m_lastDeletedIconPos(),
+ m_eSortCriterion( NameCaseInsensitive ),
+ m_bSortDirectoriesFirst( true ),
+ m_itemsAlwaysFirst(),
+ m_gotIconsArea(false)
+{
+ setResizeMode( Fixed );
+ setIconArea( desktopRect() ); // the default is the whole desktop
+
+ // Initialise the shadow data objects...
+ m_shadowEngine = new KShadowEngine(new KDesktopShadowSettings(KGlobal::config()));
+
+ connect( QApplication::clipboard(), SIGNAL(dataChanged()),
+ this, SLOT(slotClipboardDataChanged()) );
+
+ setURL( desktopURL() ); // sets m_url
+
+ m_desktopDirs = KGlobal::dirs()->findDirs( "appdata", "Desktop" );
+ initDotDirectories();
+
+ connect( this, SIGNAL( executed( QIconViewItem * ) ),
+ SLOT( slotExecuted( QIconViewItem * ) ) );
+ connect( this, SIGNAL( returnPressed( QIconViewItem * ) ),
+ SLOT( slotReturnPressed( QIconViewItem * ) ) );
+ connect( this, SIGNAL( mouseButtonPressed(int, QIconViewItem*, const QPoint&)),
+ SLOT( slotMouseButtonPressed(int, QIconViewItem*, const QPoint&)) );
+ connect( this, SIGNAL( mouseButtonClicked(int, QIconViewItem*, const QPoint&)),
+ SLOT( slotMouseButtonClickedKDesktop(int, QIconViewItem*, const QPoint&)) );
+ connect( this, SIGNAL( contextMenuRequested(QIconViewItem*, const QPoint&)),
+ SLOT( slotContextMenuRequested(QIconViewItem*, const QPoint&)) );
+
+ connect( this, SIGNAL( enableAction( const char * , bool ) ),
+ SLOT( slotEnableAction( const char * , bool ) ) );
+
+ // Hack: KonqIconViewWidget::slotItemRenamed is not virtual :-(
+ disconnect( this, SIGNAL(itemRenamed(QIconViewItem *, const QString &)),
+ this, SLOT(slotItemRenamed(QIconViewItem *, const QString &)) );
+ connect( this, SIGNAL(itemRenamed(QIconViewItem *, const QString &)),
+ this, SLOT(slotItemRenamed(QIconViewItem *, const QString &)) );
+
+ if (!m_bEditableDesktopIcons)
+ {
+ setItemsMovable(false);
+ setAcceptDrops(false);
+ viewport()->setAcceptDrops(false);
+ }
+}
+
+KDIconView::~KDIconView()
+{
+ if (m_dotDirectory && !m_bEditableDesktopIcons)
+ m_dotDirectory->rollback(false); // Don't save positions
+
+ delete m_dotDirectory;
+ delete m_dirLister;
+ delete m_shadowEngine;
+}
+
+void KDIconView::initDotDirectories()
+{
+ QStringList dirs = m_desktopDirs;
+ KURL u = desktopURL();
+ if (u.isLocalFile())
+ dirs.prepend(u.path());
+
+ QString prefix = iconPositionGroupPrefix();
+ QString dotFileName = locateLocal("appdata", "IconPositions");
+ if (kdesktop_screen_number != 0)
+ dotFileName += "_Desktop" + QString::number(kdesktop_screen_number);
+
+ if (m_dotDirectory && !m_bEditableDesktopIcons)
+ m_dotDirectory->rollback(false); // Don't save positions
+
+ delete m_dotDirectory;
+
+ m_dotDirectory = new KSimpleConfig( dotFileName );
+ // If we don't allow editable desktop icons, empty m_dotDirectory
+ if (!m_bEditableDesktopIcons)
+ {
+ QStringList groups = m_dotDirectory->groupList();
+ QStringList::ConstIterator gIt = groups.begin();
+ QStringList::ConstIterator gEnd = groups.end();
+ for (; gIt != gEnd; ++gIt )
+ {
+ m_dotDirectory->deleteGroup(*gIt, true);
+ }
+ }
+ QRect desk = desktopRect();
+ QString X_w = QString( "X %1" ).arg( desk.width() );
+ QString Y_h = QString( "Y %1" ).arg( desk.height() );
+ for ( QStringList::ConstIterator it = dirs.begin() ; it != dirs.end() ; ++it )
+ {
+ kdDebug(1204) << "KDIconView::initDotDirectories found dir " << *it << endl;
+ QString dotFileName = *it + "/.directory";
+
+ if (QFile::exists(dotFileName))
+ {
+ KSimpleConfig dotDir(dotFileName, true); // Read only
+
+ QStringList groups = dotDir.groupList();
+ QStringList::ConstIterator gIt = groups.begin();
+ QStringList::ConstIterator gEnd = groups.end();
+ for (; gIt != gEnd; ++gIt )
+ {
+ if ( (*gIt).startsWith(prefix) )
+ {
+ dotDir.setGroup( *gIt );
+ m_dotDirectory->setGroup( *gIt );
+
+ if (!m_dotDirectory->hasKey( X_w ))
+ {
+ int x,y;
+ readIconPosition(&dotDir, x, y);
+ m_dotDirectory->writeEntry( X_w, x );
+ m_dotDirectory->writeEntry( Y_h, y ); // Not persistant!
+ }
+ }
+ }
+ }
+ }
+}
+
+void KDIconView::initConfig( bool init )
+{
+ //kdDebug() << "initConfig " << init << endl;
+
+ if ( !init ) {
+ KonqFMSettings::reparseConfiguration();
+ KDesktopSettings::self()->readConfig();
+ }
+
+ KConfig * config = KGlobal::config();
+
+ if ( !init ) {
+ KDesktopShadowSettings *shadowSettings = static_cast<KDesktopShadowSettings *>(m_shadowEngine->shadowSettings());
+ shadowSettings->setConfig(config);
+ }
+
+ setMaySetWallpaper(!config->isImmutable() && !KGlobal::dirs()->isRestrictedResource("wallpaper"));
+ m_bShowDot = KDesktopSettings::showHidden();
+ m_bVertAlign = KDesktopSettings::vertAlign();
+ QStringList oldPreview = previewSettings();
+ setPreviewSettings( KDesktopSettings::preview() );
+
+ // read arrange configuration
+ m_eSortCriterion = (SortCriterion)KDesktopSettings::sortCriterion();
+ m_bSortDirectoriesFirst = KDesktopSettings::directoriesFirst();
+ m_itemsAlwaysFirst = KDesktopSettings::alwaysFirstItems(); // Distributor plug-in
+
+ if (KProtocolInfo::isKnownProtocol(QString::fromLatin1("media")))
+ m_enableMedia=KDesktopSettings::mediaEnabled();
+ else
+ m_enableMedia=false;
+ QString tmpList=KDesktopSettings::exclude();
+ kdDebug(1204)<<"m_excludeList"<<tmpList<<endl;
+ m_excludedMedia=QStringList::split(",",tmpList,false);
+ kdDebug(1204)<<" m_excludeList / item count:" <<m_excludedMedia.count()<<endl;
+ if ( m_dirLister ) // only when called while running - not on first startup
+ {
+ configureMedia();
+ m_dirLister->setShowingDotFiles( m_bShowDot );
+ m_dirLister->emitChanges();
+ }
+
+ setArrangement(m_bVertAlign ? TopToBottom : LeftToRight);
+
+ if ( KonqIconViewWidget::initConfig( init ) )
+ lineupIcons(); // called if the font changed.
+
+ setAutoArrange( false );
+
+ if ( previewSettings().count() )
+ {
+ for ( QStringList::ConstIterator it = oldPreview.begin(); it != oldPreview.end(); ++it)
+ if ( !previewSettings().contains( *it ) ){
+ kdDebug(1204) << "Disabling preview for " << *it << endl;
+ if ( *it == "audio/" )
+ disableSoundPreviews();
+ else
+ {
+ KService::Ptr serv = KService::serviceByDesktopName( *it );
+ Q_ASSERT( serv != 0L );
+ if ( serv )
+ {
+ setIcons( iconSize( ), serv->property("MimeTypes").toStringList() /* revert no-longer wanted previews to icons */ );
+ }
+ }
+ }
+ startImagePreview( QStringList(), true );
+ }
+ else
+ {
+ stopImagePreview();
+ setIcons( iconSize(), "*" /* stopImagePreview */ );
+ }
+
+ if ( !init )
+ updateContents();
+}
+
+void KDIconView::start()
+{
+ // We can only start once
+ Q_ASSERT(!m_dirLister);
+ if (m_dirLister)
+ return;
+
+ kdDebug(1204) << "KDIconView::start" << endl;
+
+ // Create the directory lister
+ m_dirLister = new KDirLister();
+
+ m_bNeedSave = false;
+
+ connect( m_dirLister, SIGNAL( clear() ), this, SLOT( slotClear() ) );
+ connect( m_dirLister, SIGNAL( started(const KURL&) ),
+ this, SLOT( slotStarted(const KURL&) ) );
+ connect( m_dirLister, SIGNAL( completed() ), this, SLOT( slotCompleted() ) );
+ connect( m_dirLister, SIGNAL( newItems( const KFileItemList & ) ),
+ this, SLOT( slotNewItems( const KFileItemList & ) ) );
+ connect( m_dirLister, SIGNAL( deleteItem( KFileItem * ) ),
+ this, SLOT( slotDeleteItem( KFileItem * ) ) );
+ connect( m_dirLister, SIGNAL( refreshItems( const KFileItemList & ) ),
+ this, SLOT( slotRefreshItems( const KFileItemList & ) ) );
+
+ // Start the directory lister !
+ m_dirLister->setShowingDotFiles( m_bShowDot );
+ kapp->allowURLAction("list", KURL(), url());
+ startDirLister();
+ createActions();
+}
+
+void KDIconView::configureMedia()
+{
+ kdDebug(1204) << "***********KDIconView::configureMedia() " <<endl;
+ m_dirLister->setMimeExcludeFilter(m_excludedMedia);
+ m_dirLister->emitChanges();
+ updateContents();
+ if (m_enableMedia)
+ {
+ for (KURL::List::Iterator it1=m_mergeDirs.begin();it1!=m_mergeDirs.end();++it1)
+ {
+ if ((*it1).url()=="media:/") return;
+ }
+ m_mergeDirs.append(KURL("media:/"));
+ m_dirLister->openURL(KURL("media:/"),true);
+ }
+ else
+ {
+ for (KURL::List::Iterator it2=m_mergeDirs.begin();it2!=m_mergeDirs.end();++it2)
+ {
+ if ((*it2).url()=="media:/")
+ {
+ delete m_dirLister;
+ m_dirLister=0;
+ start();
+// m_mergeDirs.remove(it2);
+// m_dirLister->stop("media");
+ return;
+ }
+
+ }
+ return;
+ }
+
+}
+
+void KDIconView::createActions()
+{
+ if (m_bEditableDesktopIcons)
+ {
+ KAction *undo = KStdAction::undo( KonqUndoManager::self(), SLOT( undo() ), &m_actionCollection, "undo" );
+ connect( KonqUndoManager::self(), SIGNAL( undoAvailable( bool ) ),
+ undo, SLOT( setEnabled( bool ) ) );
+ connect( KonqUndoManager::self(), SIGNAL( undoTextChanged( const QString & ) ),
+ undo, SLOT( setText( const QString & ) ) );
+ undo->setEnabled( KonqUndoManager::self()->undoAvailable() );
+
+ KAction* paCut = KStdAction::cut( this, SLOT( slotCut() ), &m_actionCollection, "cut" );
+ KShortcut cutShortCut = paCut->shortcut();
+ cutShortCut.remove( KKey( SHIFT + Key_Delete ) ); // used for deleting files
+ paCut->setShortcut( cutShortCut );
+
+ KStdAction::copy( this, SLOT( slotCopy() ), &m_actionCollection, "copy" );
+ KStdAction::paste( this, SLOT( slotPaste() ), &m_actionCollection, "paste" );
+ KAction *pasteTo = KStdAction::paste( this, SLOT( slotPopupPasteTo() ), &m_actionCollection, "pasteto" );
+ pasteTo->setEnabled( false ); // only enabled during popupMenu()
+
+ KShortcut reloadShortcut = KStdAccel::shortcut(KStdAccel::Reload);
+ new KAction( i18n( "&Reload" ), "reload", reloadShortcut, this, SLOT( refreshIcons() ), &m_actionCollection, "reload" );
+
+ (void) new KAction( i18n( "&Rename" ), /*"editrename",*/ Key_F2, this, SLOT( renameSelectedItem() ), &m_actionCollection, "rename" );
+ (void) new KAction( i18n( "&Properties" ), ALT+Key_Return, this, SLOT( slotProperties() ), &m_actionCollection, "properties" );
+ KAction* trash = new KAction( i18n( "&Move to Trash" ), "edittrash", Key_Delete, &m_actionCollection, "trash" );
+ connect( trash, SIGNAL( activated( KAction::ActivationReason, Qt::ButtonState ) ),
+ this, SLOT( slotTrashActivated( KAction::ActivationReason, Qt::ButtonState ) ) );
+
+ KConfig config("kdeglobals", true, false);
+ config.setGroup( "KDE" );
+ (void) new KAction( i18n( "&Delete" ), "editdelete", SHIFT+Key_Delete, this, SLOT( slotDelete() ), &m_actionCollection, "del" );
+
+ // Initial state of the actions (cut/copy/paste/...)
+ slotSelectionChanged();
+ //init paste action
+ slotClipboardDataChanged();
+ }
+}
+
+void KDIconView::rearrangeIcons( SortCriterion sc, bool bSortDirectoriesFirst )
+{
+ m_eSortCriterion = sc;
+ m_bSortDirectoriesFirst = bSortDirectoriesFirst;
+ rearrangeIcons();
+}
+
+void KDIconView::rearrangeIcons()
+{
+ setupSortKeys();
+ sort(); // calls arrangeItemsInGrid() which does not honor iconArea()
+
+ if ( m_autoAlign )
+ lineupIcons( m_bVertAlign ? QIconView::TopToBottom : QIconView::LeftToRight ); // also saves position
+ else
+ {
+ KonqIconViewWidget::lineupIcons(m_bVertAlign ? QIconView::TopToBottom : QIconView::LeftToRight);
+ saveIconPositions();
+ }
+}
+
+void KDIconView::lineupIcons()
+{
+ if ( !m_gotIconsArea ) return;
+ KonqIconViewWidget::lineupIcons();
+ saveIconPositions();
+}
+
+void KDIconView::setAutoAlign( bool b )
+{
+ m_autoAlign = b;
+
+ // Auto line-up icons
+ if ( b ) {
+ lineupIcons();
+ connect( this, SIGNAL( iconMoved() ),
+ this, SLOT( lineupIcons() ) );
+ }
+ else {
+ // change maxItemWidth, because when grid-align was active, it changed this for the grid
+ int sz = iconSize() ? iconSize() : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ setMaxItemWidth( QMAX( QMAX( sz, previewIconSize( iconSize() ) ), KonqFMSettings::settings()->iconTextWidth() ) );
+ setFont( font() ); // Force calcRect()
+
+ disconnect( this, SIGNAL( iconMoved() ),
+ this, SLOT( lineupIcons() ) );
+ }
+}
+
+void KDIconView::startDirLister()
+{
+ // if desktop is resized before start() is called (XRandr)
+ if (!m_dirLister) return;
+
+ m_dirLister->openURL( url() );
+
+ // Gather the list of directories to merge into the desktop
+ // (the main URL is desktopURL(), no need for it in the m_mergeDirs list)
+ m_mergeDirs.clear();
+ for ( QStringList::ConstIterator it = m_desktopDirs.begin() ; it != m_desktopDirs.end() ; ++it )
+ {
+ kdDebug(1204) << "KDIconView::desktopResized found merge dir " << *it << endl;
+ KURL u;
+ u.setPath( *it );
+ m_mergeDirs.append( u );
+ // And start listing this dir right now
+ kapp->allowURLAction("list", KURL(), u);
+ m_dirLister->openURL( u, true );
+ }
+ configureMedia();
+}
+
+void KDIconView::lineupIcons(QIconView::Arrangement align)
+{
+ m_bVertAlign = ( align == QIconView::TopToBottom );
+ setArrangement( m_bVertAlign ? TopToBottom : LeftToRight );
+
+ if ( m_autoAlign )
+ {
+ KonqIconViewWidget::lineupIcons( align );
+ saveIconPositions();
+ }
+ else
+ rearrangeIcons(); // also saves the position
+
+ KDesktopSettings::setVertAlign( m_bVertAlign );
+ KDesktopSettings::writeConfig();
+}
+
+// Only used for DCOP
+QStringList KDIconView::selectedURLs()
+{
+ QStringList seq;
+
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ if ( it->isSelected() ) {
+ KFileItem *fItem = ((KFileIVI *)it)->item();
+ seq.append( fItem->url().url() ); // copy the URL
+ }
+
+ return seq;
+}
+
+void KDIconView::recheckDesktopURL()
+{
+ // Did someone change the path to the desktop ?
+ kdDebug(1204) << desktopURL().url() << endl;
+ kdDebug(1204) << url().url() << endl;
+ if ( desktopURL() != url() )
+ {
+ kdDebug(1204) << "Desktop path changed from " << url().url() <<
+ " to " << desktopURL().url() << endl;
+ setURL( desktopURL() ); // sets m_url
+ initDotDirectories();
+ m_dirLister->openURL( url() );
+ }
+}
+
+KURL KDIconView::desktopURL()
+{
+ // Support both paths and URLs
+ QString desktopPath = KGlobalSettings::desktopPath();
+ if (kdesktop_screen_number != 0) {
+ QString dn = "Desktop";
+ dn += QString::number(kdesktop_screen_number);
+ desktopPath.replace("Desktop", dn);
+ }
+
+ KURL desktopURL;
+ if (desktopPath[0] == '/')
+ desktopURL.setPath(desktopPath);
+ else
+ desktopURL = desktopPath;
+
+ Q_ASSERT( desktopURL.isValid() );
+ if ( !desktopURL.isValid() ) { // should never happen
+ KURL u;
+ u.setPath( QDir::homeDirPath() + "/" + "Desktop" + "/" );
+ return u;
+ }
+
+ return desktopURL;
+}
+
+void KDIconView::contentsMousePressEvent( QMouseEvent *e )
+{
+ if (!m_dirLister) return;
+ //kdDebug(1204) << "KDIconView::contentsMousePressEvent" << endl;
+ // QIconView, as of Qt 2.2, doesn't emit mouseButtonPressed for LMB on background
+ if ( e->button() == LeftButton && KRootWm::self()->hasLeftButtonMenu() )
+ {
+ QIconViewItem *item = findItem( e->pos() );
+ if ( !item )
+ {
+ // Left click menu
+ KRootWm::self()->mousePressed( e->globalPos(), e->button() );
+ return;
+ }
+ }
+ KonqIconViewWidget::contentsMousePressEvent( e );
+}
+
+void KDIconView::mousePressEvent( QMouseEvent *e )
+{
+ KRootWm::self()->mousePressed( e->globalPos(), e->button() );
+}
+
+void KDIconView::wheelEvent( QWheelEvent* e )
+{
+ if (!m_dirLister) return;
+ //kdDebug(1204) << "KDIconView::wheelEvent" << endl;
+
+ QIconViewItem *item = findItem( e->pos() );
+ if ( !item )
+ {
+ emit wheelRolled( e->delta() );
+ return;
+ }
+
+ KonqIconViewWidget::wheelEvent( e );
+}
+
+void KDIconView::slotProperties()
+{
+ KFileItemList selectedFiles = selectedFileItems();
+
+ if( selectedFiles.isEmpty() )
+ return;
+
+ (void) new KPropertiesDialog( selectedFiles );
+}
+
+void KDIconView::slotContextMenuRequested(QIconViewItem *_item, const QPoint& _global)
+{
+ if (_item)
+ {
+ ((KFileIVI*)_item)->setSelected( true );
+ popupMenu( _global, selectedFileItems() );
+ }
+}
+
+void KDIconView::slotMouseButtonPressed(int _button, QIconViewItem* _item, const QPoint& _global)
+{
+ //kdDebug(1204) << "KDIconView::slotMouseButtonPressed" << endl;
+ if (!m_dirLister) return;
+ m_lastDeletedIconPos = QPoint(); // user action -> not renaming an icon
+ if(!_item)
+ KRootWm::self()->mousePressed( _global, _button );
+}
+
+void KDIconView::slotMouseButtonClickedKDesktop(int _button, QIconViewItem* _item, const QPoint&)
+{
+ if (!m_dirLister) return;
+ //kdDebug(1204) << "KDIconView::slotMouseButtonClickedKDesktop" << endl;
+ if ( _item && _button == MidButton )
+ slotExecuted(_item);
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotReturnPressed( QIconViewItem *item )
+{
+ if (item && item->isSelected())
+ slotExecuted(item);
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotExecuted( QIconViewItem *item )
+{
+ kapp->propagateSessionManager();
+ m_lastDeletedIconPos = QPoint(); // user action -> not renaming an icon
+ if (item) {
+ visualActivate(item);
+ ((KFileIVI*)item)->returnPressed();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotCut()
+{
+ cutSelection();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotCopy()
+{
+ copySelection();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotPaste()
+{
+ KonqOperations::doPaste(this, url(), KRootWm::self()->desktopMenuPosition());
+}
+
+void KDIconView::slotPopupPasteTo()
+{
+ Q_ASSERT( !m_popupURL.isEmpty() );
+ if ( !m_popupURL.isEmpty() )
+ paste( m_popupURL );
+}
+
+/**
+ * The files on the desktop come from a variety of sources.
+ * If an attempt is made to delete a .desktop file that does
+ * not originate from the users own Desktop directory then
+ * a .desktop file with "Hidden=true" is written to the users
+ * own Desktop directory to hide the file.
+ *
+ * Returns true if all selected items have been deleted.
+ * Returns false if there are selected items remaining that
+ * still need to be deleted in a regular fashion.
+ */
+bool KDIconView::deleteGlobalDesktopFiles()
+{
+ KURL desktop_URL = desktopURL();
+ if (!desktop_URL.isLocalFile())
+ return false; // Dunno how to do this.
+
+ QString desktopPath = desktop_URL.path();
+
+ bool itemsLeft = false;
+ QIconViewItem *it = 0;
+ QIconViewItem *nextIt = firstItem();
+ for (; (it = nextIt); )
+ {
+ nextIt = it->nextItem();
+ if ( !it->isSelected() )
+ continue;
+
+ KFileItem *fItem = ((KFileIVI *)it)->item();
+ if (fItem->url().path().startsWith(desktopPath))
+ {
+ itemsLeft = true;
+ continue; // File is in users own Desktop directory
+ }
+
+ if (!isDesktopFile(fItem))
+ {
+ itemsLeft = true;
+ continue; // Not a .desktop file
+ }
+
+ KDesktopFile df(desktopPath + fItem->url().fileName());
+ df.writeEntry("Hidden", true);
+ df.sync();
+
+ delete it;
+ }
+ return !itemsLeft;
+}
+
+void KDIconView::slotTrashActivated( KAction::ActivationReason reason, Qt::ButtonState state )
+{
+ if (deleteGlobalDesktopFiles())
+ return; // All items deleted
+
+ if ( reason == KAction::PopupMenuActivation && ( state & Qt::ShiftButton ) )
+ KonqOperations::del(this, KonqOperations::DEL, selectedUrls());
+ else
+ KonqOperations::del(this, KonqOperations::TRASH, selectedUrls());
+}
+
+void KDIconView::slotDelete()
+{
+ if (deleteGlobalDesktopFiles())
+ return; // All items deleted
+ KonqOperations::del(this, KonqOperations::DEL, selectedUrls());
+}
+
+// -----------------------------------------------------------------------------
+
+// This method is called when right-clicking over one or more items
+// Not to be confused with the global popup-menu, KRootWm, when doing RMB on the desktop
+void KDIconView::popupMenu( const QPoint &_global, const KFileItemList& _items )
+{
+ if (!kapp->authorize("action/kdesktop_rmb")) return;
+ if (!m_dirLister) return;
+ if ( _items.count() == 1 )
+ m_popupURL = _items.getFirst()->url();
+
+ KAction* pasteTo = m_actionCollection.action( "pasteto" );
+ if (pasteTo)
+ pasteTo->setEnabled( m_actionCollection.action( "paste" )->isEnabled() );
+
+ bool hasMediaFiles = false;
+ KFileItemListIterator it(_items);
+ for (; it.current() && !hasMediaFiles; ++it) {
+ hasMediaFiles = it.current()->url().protocol() == "media";
+ }
+
+ KParts::BrowserExtension::PopupFlags itemFlags = KParts::BrowserExtension::DefaultPopupItems;
+ if ( hasMediaFiles )
+ itemFlags |= KParts::BrowserExtension::NoDeletion;
+ KonqPopupMenu * popupMenu = new KonqPopupMenu( KonqBookmarkManager::self(), _items,
+ url(),
+ m_actionCollection,
+ KRootWm::self()->newMenu(),
+ this,
+ KonqPopupMenu::ShowProperties | KonqPopupMenu::ShowNewWindow,
+ itemFlags );
+
+ popupMenu->exec( _global );
+ delete popupMenu;
+ m_popupURL = KURL();
+ if (pasteTo)
+ pasteTo->setEnabled( false );
+}
+
+void KDIconView::slotNewMenuActivated()
+{
+ //kdDebug(1204) << "KDIconView::slotNewMenuActivated" << endl;
+ // New / <template> was chosen, a new file is going to appear soon,
+ // make it appear at the position of the popupmenu.
+ m_nextItemPos = KRootWm::self()->desktopMenuPosition();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotEnableAction( const char * name, bool enabled )
+{
+ //kdDebug(1204) << "slotEnableAction " << name << " enabled=" << enabled << endl;
+ QCString sName( name );
+ // No such actions here... konqpopupmenu provides them.
+ if ( sName == "properties" || sName == "editMimeType" )
+ return;
+
+ KAction * act = m_actionCollection.action( sName.data() );
+ if (act)
+ act->setEnabled( enabled );
+}
+
+// -----------------------------------------------------------------------------
+
+// Straight from kpropsdlg :)
+bool KDIconView::isDesktopFile( KFileItem * _item ) const
+{
+ // only local files
+ if ( !_item->isLocalFile() )
+ return false;
+
+ // only regular files
+ if ( !S_ISREG( _item->mode() ) )
+ return false;
+
+ QString t( _item->url().path() );
+
+ // only if readable
+ if ( access( QFile::encodeName(t), R_OK ) != 0 )
+ return false;
+
+ // return true if desktop file
+ return ( _item->mimetype() == QString::fromLatin1("application/x-desktop") );
+}
+
+QString KDIconView::stripDesktopExtension( const QString & text )
+{
+ if (text.right(7) == QString::fromLatin1(".kdelnk"))
+ return text.left(text.length() - 7);
+ else if (text.right(8) == QString::fromLatin1(".desktop"))
+ return text.left(text.length() - 8);
+ return text;
+}
+
+bool KDIconView::makeFriendlyText( KFileIVI *fileIVI )
+{
+ KFileItem *item = fileIVI->item();
+ QString desktopFile;
+ if ( item->isDir() && item->isLocalFile() )
+ {
+ KURL u( item->url() );
+ u.addPath( ".directory" );
+ // using KStandardDirs as this one checks for path being
+ // a file instead of a directory
+ if ( KStandardDirs::exists( u.path() ) )
+ desktopFile = u.path();
+ }
+ else if ( isDesktopFile( item ) )
+ {
+ desktopFile = item->url().path();
+ }
+
+ if ( !desktopFile.isEmpty() )
+ {
+ KSimpleConfig cfg( desktopFile, true );
+ cfg.setDesktopGroup();
+ if (cfg.readBoolEntry("Hidden"))
+ return false;
+
+ if (cfg.readBoolEntry( "NoDisplay", false ))
+ return false;
+
+ QStringList tmpList;
+ if (cfg.hasKey("OnlyShowIn"))
+ {
+ if (!cfg.readListEntry("OnlyShowIn", ';').contains("KDE"))
+ return false;
+ }
+ if (cfg.hasKey("NotShowIn"))
+ {
+ if (cfg.readListEntry("NotShowIn", ';').contains("KDE"))
+ return false;
+ }
+ if (cfg.hasKey("TryExec"))
+ {
+ if (KStandardDirs::findExe( cfg.readEntry( "TryExec" ) ).isEmpty())
+ return false;
+ }
+
+ QString name = cfg.readEntry("Name");
+ if ( !name.isEmpty() )
+ fileIVI->setText( name );
+ else
+ // For compatibility
+ fileIVI->setText( stripDesktopExtension( fileIVI->text() ) );
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotClear()
+{
+ clear();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotNewItems( const KFileItemList & entries )
+{
+ bool firstRun = (count() == 0); // no icons yet, this seems to be the initial loading
+
+ // delay updates until all new items have been created
+ setUpdatesEnabled( false );
+ QRect area = iconArea();
+ setIconArea( QRect( 0, 0, -1, -1 ) );
+
+ QString desktopPath;
+ KURL desktop_URL = desktopURL();
+ if (desktop_URL.isLocalFile())
+ desktopPath = desktop_URL.path();
+ // We have new items, so we'll need to repaint in slotCompleted
+ m_bNeedRepaint = true;
+ kdDebug(1214) << "KDIconView::slotNewItems count=" << entries.count() << endl;
+ KFileItemListIterator it(entries);
+ KFileIVI* fileIVI = 0L;
+ for (; it.current(); ++it)
+ {
+ KURL url = it.current()->url();
+ if (!desktopPath.isEmpty() && url.isLocalFile() && !url.path().startsWith(desktopPath))
+ {
+ QString fileName = url.fileName();
+ if (QFile::exists(desktopPath + fileName))
+ continue; // Don't duplicate entry
+
+ QString mostLocal = locate("appdata", "Desktop/"+fileName);
+ if (!mostLocal.isEmpty() && (mostLocal != url.path()))
+ continue; // Don't duplicate entry
+ }
+
+ // No delayed mimetype determination on the desktop
+ it.current()->determineMimeType();
+ fileIVI = new KFileIVIDesktop( this, it.current(), iconSize(), m_shadowEngine );
+ if (!makeFriendlyText( fileIVI ))
+ {
+ delete fileIVI;
+ continue;
+ }
+
+ kdDebug(1214) << " slotNewItems: " << url.url() << " text: " << fileIVI->text() << endl;
+ fileIVI->setRenameEnabled( false );
+
+ if ( !m_nextItemPos.isNull() ) // position remembered from e.g. RMB-popupmenu position, when doing New/...
+ {
+ kdDebug(1214) << "slotNewItems : using popupmenu position " << m_nextItemPos.x() << "," << m_nextItemPos.y() << endl;
+ fileIVI->move( m_nextItemPos.x(), m_nextItemPos.y() );
+ m_nextItemPos = QPoint();
+ }
+ else
+ {
+ kdDebug(1214) << "slotNewItems : trying to read position from .directory file"<<endl;
+ QString group = iconPositionGroupPrefix();
+ QString filename = url.fileName();
+ if ( filename.endsWith(".part") && !m_dotDirectory->hasGroup( group + filename ) )
+ filename = filename.left( filename.length() - 5 );
+ group.append( filename );
+ kdDebug(1214) << "slotNewItems : looking for group " << group << endl;
+ if ( m_dotDirectory->hasGroup( group ) )
+ {
+ m_dotDirectory->setGroup( group );
+ m_hasExistingPos = true;
+ int x,y;
+ readIconPosition(m_dotDirectory, x, y);
+
+ kdDebug(1214)<<"slotNewItems() x: "<<x<<" y: "<<y<<endl;
+
+ QRect oldPos = fileIVI->rect();
+ fileIVI->move( x, y );
+ if ( !firstRun && !isFreePosition( fileIVI ) ) // if we can't put it there, then let QIconView decide
+ {
+ kdDebug(1214)<<"slotNewItems() pos was not free :-("<<endl;
+ fileIVI->move( oldPos.x(), oldPos.y() );
+ m_dotDirectory->deleteGroup( group );
+ m_bNeedSave = true;
+ }
+ else
+ {
+ kdDebug(1214)<<"Using saved position"<<endl;
+ }
+ }
+ else
+ {
+ // Not found, we'll need to save the new pos
+ kdDebug(1214)<<"slotNewItems(): New item without position information, try to find a sane location"<<endl;
+
+ moveToFreePosition(fileIVI);
+
+ m_bNeedSave = true;
+ }
+ }
+ }
+
+ setIconArea( area );
+
+ // align on grid
+ if ( m_autoAlign )
+ lineupIcons();
+
+ setUpdatesEnabled( true );
+}
+
+// -----------------------------------------------------------------------------
+
+// see also KonqKfmIconView::slotRefreshItems
+void KDIconView::slotRefreshItems( const KFileItemList & entries )
+{
+ kdDebug(1204) << "KDIconView::slotRefreshItems" << endl;
+ bool bNeedPreviewJob = false;
+ KFileItemListIterator rit(entries);
+ for (; rit.current(); ++rit)
+ {
+ bool found = false;
+ QIconViewItem *it = firstItem();
+ for ( ; it ; it = it->nextItem() )
+ {
+ KFileIVI * fileIVI = static_cast<KFileIVI *>(it);
+ if ( fileIVI->item() == rit.current() ) // compare the pointers
+ {
+ kdDebug(1204) << "KDIconView::slotRefreshItems refreshing icon " << fileIVI->item()->url().url() << endl;
+ found = true;
+ fileIVI->setText( rit.current()->text() );
+ if (!makeFriendlyText( fileIVI ))
+ {
+ delete fileIVI;
+ break;
+ }
+ if ( fileIVI->isThumbnail() ) {
+ bNeedPreviewJob = true;
+ fileIVI->invalidateThumbnail();
+ }
+ else
+ fileIVI->refreshIcon( true );
+ if ( rit.current()->isMimeTypeKnown() )
+ fileIVI->setMouseOverAnimation( rit.current()->iconName() );
+ break;
+ }
+ }
+ if ( !found )
+ kdDebug(1204) << "Item not found: " << rit.current()->url().url() << endl;
+ }
+ if ( bNeedPreviewJob && previewSettings().count() )
+ {
+ startImagePreview( QStringList(), false );
+ }
+ else
+ {
+ // In case we replace a big icon with a small one, need to repaint.
+ updateContents();
+ // Can't do that with m_bNeedRepaint since slotCompleted isn't called
+ m_bNeedRepaint = false;
+ }
+}
+
+
+void KDIconView::refreshIcons()
+{
+ QIconViewItem *it = firstItem();
+ for ( ; it ; it = it->nextItem() )
+ {
+ KFileIVI * fileIVI = static_cast<KFileIVI *>(it);
+ fileIVI->item()->refresh();
+ fileIVI->refreshIcon( true );
+ makeFriendlyText( fileIVI );
+ }
+}
+
+
+void KDIconView::FilesAdded( const KURL & directory )
+{
+ if ( directory.path().length() <= 1 && directory.protocol() == "trash" )
+ refreshTrashIcon();
+}
+
+void KDIconView::FilesRemoved( const KURL::List & fileList )
+{
+ if ( !fileList.isEmpty() ) {
+ const KURL url = fileList.first();
+ if ( url.protocol() == "trash" )
+ refreshTrashIcon();
+ }
+}
+
+void KDIconView::refreshTrashIcon()
+{
+ QIconViewItem *it = firstItem();
+ for ( ; it ; it = it->nextItem() )
+ {
+ KFileIVI * fileIVI = static_cast<KFileIVI *>(it);
+ KFileItem* item = fileIVI->item();
+ if ( isDesktopFile( item ) ) {
+ KSimpleConfig cfg( item->url().path(), true );
+ cfg.setDesktopGroup();
+ if ( cfg.readEntry( "Type" ) == "Link" &&
+ cfg.readEntry( "URL" ) == "trash:/" ) {
+ fileIVI->refreshIcon( true );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotDeleteItem( KFileItem * _fileitem )
+{
+ kdDebug(1204) << "KDIconView::slotDeleteItems" << endl;
+ // we need to find out the KFileIVI containing the fileitem
+ QIconViewItem *it = firstItem();
+ while ( it ) {
+ KFileIVI * fileIVI = static_cast<KFileIVI *>(it);
+ if ( fileIVI->item() == _fileitem ) { // compare the pointers
+ // Delete this item.
+ //kdDebug(1204) << fileIVI->text() << endl;
+
+ QString group = iconPositionGroupPrefix();
+ group.append( fileIVI->item()->url().fileName() );
+ if ( m_dotDirectory->hasGroup( group ) )
+ m_dotDirectory->deleteGroup( group );
+
+ m_lastDeletedIconPos = fileIVI->pos();
+ delete fileIVI;
+ break;
+ }
+ it = it->nextItem();
+ }
+ m_bNeedRepaint = true;
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::slotStarted( const KURL& _url )
+{
+ kdDebug(1204) << "KDIconView::slotStarted url: " << _url.url() << " url().url(): "<<url().url()<<endl;
+}
+
+void KDIconView::slotCompleted()
+{
+ // Root item ? Store in konqiconviewwidget (used for drops onto the background, for instance)
+ if ( m_dirLister->rootItem() )
+ setRootItem( m_dirLister->rootItem() );
+
+ if ( previewSettings().count() )
+ startImagePreview( QStringList(), true );
+ else
+ {
+ stopImagePreview();
+ setIcons( iconSize(), "*" /* stopImagePreview */ );
+ }
+
+ // during first run need to rearrange all icons so default config settings will be used
+ kdDebug(1204)<<"slotCompleted() m_hasExistingPos: "<<(m_hasExistingPos?(int)1:(int)0)<<endl;
+ if (!m_hasExistingPos)
+ rearrangeIcons();
+
+// kdDebug(1204) << "KDIconView::slotCompleted save:" << m_bNeedSave << " repaint:" << m_bNeedRepaint << endl;
+ if ( m_bNeedSave )
+ {
+ // Done here because we want to align icons only once initially, and each time new icons appear.
+ // This MUST precede the call to saveIconPositions().
+ emit iconMoved();
+ saveIconPositions();
+ m_hasExistingPos = true; // if we didn't have positions, we have now.
+ m_bNeedSave = false;
+ }
+ if ( m_bNeedRepaint )
+ {
+ viewport()->repaint();
+ m_bNeedRepaint = false;
+ }
+}
+
+void KDIconView::slotClipboardDataChanged()
+{
+ // This is very related to KonqDirPart::slotClipboardDataChanged
+
+ KURL::List lst;
+ QMimeSource *data = QApplication::clipboard()->data();
+ if ( data->provides( "application/x-kde-cutselection" ) && data->provides( "text/uri-list" ) )
+ if ( KonqDrag::decodeIsCutSelection( data ) )
+ (void) KURLDrag::decode( data, lst );
+
+ disableIcons( lst );
+
+ QString actionText = KIO::pasteActionText();
+ bool paste = !actionText.isEmpty();
+ if ( paste ) {
+ KAction* pasteAction = m_actionCollection.action( "paste" );
+ if ( pasteAction )
+ pasteAction->setText( actionText );
+ }
+ slotEnableAction( "paste", paste );
+}
+
+void KDIconView::renameDesktopFile(const QString &path, const QString &name)
+{
+ KDesktopFile cfg( path, false );
+
+ // if we don't have the desktop entry group, then we assume that
+ // it's not a config file (and we don't nuke it!)
+ if ( !cfg.hasGroup( "Desktop Entry" ) )
+ return;
+
+ if ( cfg.readName() == name )
+ return;
+
+ cfg.writeEntry( "Name", name, true, false, false );
+ cfg.writeEntry( "Name", name, true, false, true );
+ cfg.sync();
+}
+
+void KDIconView::slotItemRenamed(QIconViewItem* _item, const QString &name)
+{
+ kdDebug(1204) << "KDIconView::slotItemRenamed(item, \"" << name << "\" )" << endl;
+ QString newName(name);
+ if ( _item)
+ {
+ KFileIVI *fileItem = static_cast< KFileIVI* >( _item );
+ //save position of item renamed
+ m_lastDeletedIconPos = fileItem->pos();
+ if ( fileItem->item() && !fileItem->item()->isLink() )
+ {
+ QString desktopFile( fileItem->item()->url().path() );
+ if (!desktopFile.isEmpty())
+ {
+ // first and foremost, we make sure that this is a .desktop file
+ // before we write anything to it
+ KMimeType::Ptr type = KMimeType::findByURL( fileItem->item()->url() );
+ bool bDesktopFile = false;
+
+ if (type->name() == "application/x-desktop")
+ {
+ bDesktopFile = true;
+ if (!newName.endsWith(".desktop"))
+ newName += ".desktop";
+ }
+ else if(type->name() == "inode/directory") {
+ desktopFile += "/.directory";
+ bDesktopFile = true;
+ }
+
+ if (QFile(desktopFile).exists() && bDesktopFile)
+ {
+ renameDesktopFile(desktopFile, name);
+ return;
+ }
+ }
+ }
+ }
+ KonqIconViewWidget::slotItemRenamed(_item, newName);
+}
+
+void KDIconView::slotAboutToCreate(const QPoint &pos, const QValueList<KIO::CopyInfo> &files)
+{
+ if (pos.isNull())
+ return;
+
+ if (m_dropPos != pos)
+ {
+ m_dropPos = pos;
+ m_lastDropPos = pos;
+ }
+
+ QString dir = url().path(-1); // Strip trailing /
+
+ QValueList<KIO::CopyInfo>::ConstIterator it = files.begin();
+ int gridX = gridXValue();
+ int gridY = 120; // 120 pixels should be enough for everyone (tm)
+
+ for ( ; it!= files.end() ; ++it )
+ {
+ kdDebug(1214) << "KDIconView::saveFuturePosition x=" << m_lastDropPos.x() << " y=" << m_lastDropPos.y() << " filename=" << (*it).uDest.prettyURL() << endl;
+ if ((*it).uDest.isLocalFile() && ((*it).uDest.directory() == dir))
+ {
+ m_dotDirectory->setGroup( iconPositionGroupPrefix() + (*it).uDest.fileName() );
+ saveIconPosition(m_dotDirectory, m_lastDropPos.x(), m_lastDropPos.y());
+ int dX = m_lastDropPos.x() - m_dropPos.x();
+ int dY = m_lastDropPos.y() - m_dropPos.y();
+ if ((QABS(dX) > QABS(dY)) || (m_lastDropPos.x() + 2*gridX > width()))
+ m_lastDropPos = QPoint(m_dropPos.x(), m_lastDropPos.y() + gridY);
+ else
+ m_lastDropPos = QPoint(m_lastDropPos.x() + gridX, m_lastDropPos.y());
+ }
+ }
+ m_dotDirectory->sync();
+}
+
+// -----------------------------------------------------------------------------
+
+void KDIconView::showEvent( QShowEvent *e )
+{
+ //HACK to avoid QIconView calling arrangeItemsInGrid (Simon)
+ //EVEN MORE HACK: unfortunately, QScrollView has no concept of
+ //TopToBottom, therefore, it always adds LeftToRight. So, if any of
+ //the icons have a setting, we'll use QScrollView.. but otherwise,
+ //we use the iconview
+ //kdDebug(1204)<<"showEvent() m_hasExistingPos: "<<(m_hasExistingPos?(int)1:(int)0)<<endl;
+ if (m_hasExistingPos)
+ QScrollView::showEvent( e );
+ else
+ KIconView::showEvent( e );
+}
+
+void KDIconView::contentsDropEvent( QDropEvent * e )
+{
+ kdDebug(1204)<<"void KDIconView::contentsDropEvent( QDropEvent * e )\n";
+ // mind: if it's a filedrag which itself is an image, libkonq is called. There's a popup for drops as well
+ // that contains the same line "Set as Wallpaper" in void KonqOperations::asyncDrop
+ bool isColorDrag = KColorDrag::canDecode(e);
+ bool isImageDrag = QImageDrag::canDecode(e);
+ bool isUrlDrag = KURLDrag::canDecode(e);
+
+ bool isImmutable = KGlobal::config()->isImmutable();
+
+ if ( (isColorDrag || isImageDrag) && !isUrlDrag ) {
+ // Hack to clear the drag shape
+ bool bMovable = itemsMovable();
+ bool bSignals = signalsBlocked();
+ setItemsMovable(false);
+ blockSignals(true);
+ KIconView::contentsDropEvent( e );
+ blockSignals(bSignals);
+ setItemsMovable(bMovable);
+ // End hack
+
+ if ( !isImmutable ) // just ignore event in kiosk-mode
+ {
+ if ( isColorDrag)
+ emit colorDropEvent( e );
+ else if (isImageDrag)
+ emit imageDropEvent( e );
+ }
+ } else {
+ setLastIconPosition( e->pos() );
+ KonqIconViewWidget::contentsDropEvent( e );
+ }
+
+ // Check if any items have been moved outside the desktop area.
+ // If we find any, move them right back in there. (#40418)
+ QRect desk = desktopRect();
+ bool adjustedAnyItems = false;
+ for( QIconViewItem *item = firstItem(); item; item = item->nextItem() )
+ {
+ if( !desk.contains( item->rect(), true ))
+ {
+ QRect r = item->rect();
+
+ if( r.top() < 0 )
+ r.moveTop( 0 );
+ if( r.bottom() > rect().bottom() )
+ r.moveBottom( rect().bottom() );
+ if( r.left() < 0 )
+ r.moveLeft( 0 );
+ if( r.right() > rect().right() )
+ r.moveRight( rect().right() );
+
+ item->move( r.x(), r.y() );
+ adjustedAnyItems = true;
+ }
+ }
+ if( adjustedAnyItems )
+ {
+ // Make sure the viewport isn't unnecessarily resized by now,
+ // then schedule a repaint to remove any garbage pixels.
+ resizeContents( width(), height() );
+ viewport()->update();
+ }
+
+ if (QIconDrag::canDecode(e)) {
+ emit iconMoved();
+ if ( !m_autoAlign ) // if autoAlign, positions were saved in lineupIcons
+ saveIconPositions();
+ }
+}
+
+// don't scroll when someone uses his nifty mouse wheel
+void KDIconView::viewportWheelEvent( QWheelEvent * e )
+{
+ e->accept();
+}
+
+void KDIconView::updateWorkArea( const QRect &wr )
+{
+ m_gotIconsArea = true; // now we have it!
+
+ if ( iconArea() == wr ) return; // nothing changed; avoid repaint/saveIconPosition ...
+
+ QRect oldArea = iconArea();
+ setIconArea( wr );
+
+ kdDebug(1204) << "KDIconView::updateWorkArea wr: " << wr.x() << "," << wr.y()
+ << " " << wr.width() << "x" << wr.height() << endl;
+ kdDebug(1204) << " oldArea: " << oldArea.x() << "," << oldArea.y()
+ << " " << oldArea.width() << "x" << oldArea.height() << endl;
+
+ if ( m_autoAlign )
+ lineupIcons();
+ else {
+ bool needRepaint = false;
+ QIconViewItem* item;
+ int dx, dy;
+
+ dx = wr.left() - oldArea.left();
+ dy = wr.top() - oldArea.top();
+
+ if ( dx != 0 || dy != 0 ) {
+ if ( (dx > 0) || (dy > 0) ) // the iconArea was shifted right/down; less space now
+ for ( item = firstItem(); item; item = item->nextItem() ) {
+ // check if there is any item inside the now unavailable area
+ // If so, we have to move _all_ items
+ // If not, we don't have to move any item (avoids bug:117868)
+ if ( (item->x() < wr.x()) || (item->y() < wr.y()) ) {
+ needRepaint = true;
+ break;
+ }
+ }
+ else // the iconArea was shifted left/up; more space now - use it
+ needRepaint = true;
+
+ if ( needRepaint )
+ for ( item = firstItem(); item; item = item->nextItem() )
+ item->moveBy( dx, dy );
+ }
+
+ for ( item = firstItem(); item; item = item->nextItem() ) {
+ QRect r( item->rect() );
+ int dx = 0, dy = 0;
+ if ( r.bottom() > wr.bottom() )
+ dy = wr.bottom() - r.bottom() - 1;
+ if ( r.right() > wr.right() )
+ dx = wr.right() - r.right() - 1;
+ if ( dx != 0 || dy != 0 ) {
+ needRepaint = true;
+ item->moveBy( dx, dy );
+ }
+ }
+ if ( needRepaint ) {
+ viewport()->repaint( FALSE );
+ repaint( FALSE );
+ saveIconPositions();
+ }
+ }
+}
+
+void KDIconView::setupSortKeys()
+{
+ // can't use sorting in KFileIVI::setKey()
+ setProperty("sortDirectoriesFirst", QVariant(false, 0));
+
+ for (QIconViewItem *it = firstItem(); it; it = it->nextItem())
+ {
+ QString strKey;
+
+ if (!m_itemsAlwaysFirst.isEmpty())
+ {
+ QString strFileName = static_cast<KFileIVI *>( it )->item()->url().fileName();
+ int nFind = m_itemsAlwaysFirst.findIndex(strFileName);
+ if (nFind >= 0)
+ strKey = "0" + QString::number(nFind);
+ }
+
+ if (strKey.isEmpty())
+ {
+ switch (m_eSortCriterion)
+ {
+ case NameCaseSensitive:
+ strKey = it->text();
+ break;
+ case NameCaseInsensitive:
+ strKey = it->text().lower();
+ break;
+ case Size:
+ strKey = KIO::number(static_cast<KFileIVI *>( it )->item()->size()).rightJustify(20, '0');
+ break;
+ case Type:
+ // Sort by Type + Name (#17014)
+ strKey = static_cast<KFileIVI *>( it )->item()->mimetype() + '~' + it->text().lower();
+ break;
+ case Date:
+ QDateTime dayt;
+ dayt.setTime_t( static_cast<KFileIVI *>( it )->
+ item()->time( KIO::UDS_MODIFICATION_TIME ) );
+ strKey = dayt.toString( "yyyyMMddhhmmss" );
+ break;
+ }
+
+ if (m_bSortDirectoriesFirst)
+ {
+ if (S_ISDIR(static_cast<KFileIVI *>( it )->item()->mode()))
+ strKey.prepend(sortDirection() ? '1' : '2');
+ else
+ strKey.prepend(sortDirection() ? '2' : '1' );
+ }
+ else
+ strKey.prepend('1');
+ }
+
+ it->setKey(strKey);
+ }
+}
+
+bool KDIconView::isFreePosition( const QIconViewItem *item ) const
+{
+ QRect r = item->rect();
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ {
+ if ( !it->rect().isValid() || it == item )
+ continue;
+
+ if ( it->intersects( r ) )
+ return false;
+ }
+
+ return true;
+}
+
+bool KDIconView::isFreePosition( const QIconViewItem *item ,const QRect& rect) const
+{
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ {
+ if ( !rect.isValid() || it == item )
+ continue;
+
+ if ( it->intersects( rect ) )
+ return false;
+ }
+
+ return true;
+}
+
+void KDIconView::setLastIconPosition( const QPoint &_pos )
+{
+ m_lastDeletedIconPos = _pos;
+}
+
+void KDIconView::moveToFreePosition(QIconViewItem *item )
+{
+ bool success;
+ // It may be that a file has been renamed. In this case,
+ // m_lastDeletedIconPos is the position to use for this "apparently new" item.
+ // (We rely on deleteItem being now emitted before newItems).
+ if ( !m_lastDeletedIconPos.isNull() )
+ // Problem is: I'd like to compare those two file's attributes
+ // (size, creation time, modification time... etc.) but since renaming
+ // is done by kpropsdlg, all of those can have changed (and creation time
+ // is different since the new file is a copy!)
+ {
+ kdDebug(1214) << "Moving " << item->text() << " to position of last deleted icon." << endl;
+ item->move( m_lastDeletedIconPos );
+ m_lastDeletedIconPos = QPoint();
+ return;
+ }
+
+ //try to find a free place to put the item, honouring the m_bVertAlign property
+ QRect rect=item->rect();
+ if (m_bVertAlign)
+ {
+ kdDebug(1214)<<"moveToFreePosition for vertical alignment"<<endl;
+
+ rect.moveTopLeft(QPoint(spacing(),spacing()));
+ do
+ {
+ success=false;
+ while (rect.bottom()<height())
+ {
+ if (!isFreePosition(item,rect))
+ {
+ rect.moveBy(0,rect.height()+spacing());
+ }
+ else
+ {
+ success=true;
+ break;
+ }
+ }
+
+ if (!success)
+ {
+ rect.moveTopLeft(QPoint(rect.right()+spacing(),spacing()));
+ } else break;
+ }
+ while (item->rect().right()<width());
+ if (success)
+ item->move(rect.x(),rect.y());
+ else
+ item->move(width()-spacing()-item->rect().width(),height()-spacing()-item->rect().height());
+
+ }
+
+}
+
+
+void KDIconView::saveIconPositions()
+{
+ kdDebug(1214) << "KDIconView::saveIconPositions" << endl;
+
+ if (!m_bEditableDesktopIcons)
+ return; // Don't save position
+
+ QString prefix = iconPositionGroupPrefix();
+ QIconViewItem *it = firstItem();
+ if ( !it )
+ return; // No more icons. Maybe we're closing and they've been removed already
+
+ while ( it )
+ {
+ KFileIVI *ivi = static_cast<KFileIVI *>( it );
+ KFileItem *item = ivi->item();
+
+ m_dotDirectory->setGroup( prefix + item->url().fileName() );
+ kdDebug(1214) << "KDIconView::saveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl;
+ saveIconPosition(m_dotDirectory, it->x(), it->y());
+
+ it = it->nextItem();
+ }
+
+ m_dotDirectory->sync();
+}
+
+#include "kdiconview.moc"
diff --git a/kdesktop/kdiconview.h b/kdesktop/kdiconview.h
new file mode 100644
index 000000000..a92d39712
--- /dev/null
+++ b/kdesktop/kdiconview.h
@@ -0,0 +1,256 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000, 2001 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef kdiconview_h
+#define kdiconview_h
+
+#include <konq_iconviewwidget.h>
+#include <kaction.h>
+#include <kfileitem.h>
+#include <kdirnotify.h>
+
+class KDirLister;
+class KonqSettings;
+class KSimpleConfig;
+class KAccel;
+class KShadowEngine;
+class KDesktopShadowSettings;
+
+/**
+ * This class is KDesktop's icon view.
+ * The icon view is a child widget of the KDesktop widget.
+ *
+ * Added shadow capability by Laur Ivan (C) 2003
+ * The shadow is supported by the new KFileIVIDesktop objects
+ * which replace KFileIVI objects.
+ */
+class KDIconView : public KonqIconViewWidget, public KDirNotify
+{
+ Q_OBJECT
+
+public:
+ KDIconView( QWidget *parent, const char* name = 0L );
+ ~KDIconView();
+
+ virtual void initConfig( bool init );
+ void configureMedia();
+ /**
+ * Start listing
+ */
+ void start();
+
+ KActionCollection *actionCollection() { return &m_actionCollection; }
+
+ enum SortCriterion {
+ NameCaseSensitive = 0, NameCaseInsensitive, Size, Type, Date };
+
+ void rearrangeIcons( SortCriterion sc, bool bSortDirectoriesFirst);
+
+ /**
+ * Re-arrange the desktop icons without confirmation.
+ */
+ void rearrangeIcons();
+
+ void lineupIcons(QIconView::Arrangement);
+
+ void setAutoAlign( bool b );
+
+ QStringList selectedURLs();
+
+ /**
+ * Save the icon positions
+ */
+ void saveIconPositions();
+
+ /**
+ * Check if the URL to the desktop has changed
+ */
+ void recheckDesktopURL();
+
+ /**
+ * Called when the desktop icons area has changed
+ */
+ void updateWorkArea( const QRect &wr );
+
+ /**
+ * Reimplemented from KonqIconViewWidget (for image drops)
+ */
+ virtual void setWallpaper(const KURL &url) { emit newWallpaper( url ); }
+ void setLastIconPosition( const QPoint & );
+
+ static KURL desktopURL();
+
+ /// KDirNotify interface, for trash:/
+ virtual void FilesAdded( const KURL & directory );
+ virtual void FilesRemoved( const KURL::List & fileList );
+ virtual void FilesChanged( const KURL::List & ) {}
+
+ void startDirLister();
+
+protected slots:
+
+ // slots connected to the icon view
+ void slotReturnPressed( QIconViewItem *item );
+ void slotExecuted( QIconViewItem *item );
+ void slotMouseButtonPressed(int _button, QIconViewItem* _item, const QPoint& _global);
+ void slotMouseButtonClickedKDesktop(int _button, QIconViewItem* _item, const QPoint& _global);
+ void slotContextMenuRequested(QIconViewItem* _item, const QPoint& _global);
+ void slotEnableAction( const char * name, bool enabled );
+ void slotAboutToCreate(const QPoint &pos, const QValueList<KIO::CopyInfo> &files);
+
+ void slotItemRenamed(QIconViewItem*, const QString &name);
+
+ // slots connected to the directory lister
+ void slotStarted( const KURL& url );
+ void slotCompleted();
+ void slotNewItems( const KFileItemList& );
+ void slotDeleteItem( KFileItem * );
+ void slotRefreshItems( const KFileItemList& );
+
+ // slots connected to the popupmenu (actions)
+ void slotCut();
+ void slotCopy();
+ void slotTrashActivated( KAction::ActivationReason reason, Qt::ButtonState state );
+ void slotDelete();
+ void slotPopupPasteTo();
+ void slotProperties();
+
+ void slotClipboardDataChanged();
+
+ void slotNewMenuActivated();
+
+ // For communication with KDesktop
+signals:
+ void colorDropEvent( QDropEvent *e );
+ void imageDropEvent( QDropEvent *e );
+ void newWallpaper( const KURL & );
+ void iconMoved();
+ void wheelRolled( int delta );
+
+public slots:
+ /**
+ * Lineup the desktop icons.
+ */
+ void lineupIcons();
+ void slotPaste(); // for krootwm
+ void slotClear();
+ void refreshIcons();
+
+
+protected:
+ void createActions();
+ void setupSortKeys();
+ void initDotDirectories();
+
+ bool makeFriendlyText( KFileIVI *fileIVI );
+ static QString stripDesktopExtension( const QString & text );
+ bool isDesktopFile( KFileItem * _item ) const;
+ bool isFreePosition( const QIconViewItem *item ) const;
+ bool isFreePosition( const QIconViewItem *item, const QRect& rect ) const;
+ void moveToFreePosition(QIconViewItem *item );
+
+ bool deleteGlobalDesktopFiles();
+
+ static void renameDesktopFile(const QString &path, const QString &name);
+
+ void popupMenu( const QPoint &_global, const KFileItemList& _items );
+ virtual void showEvent( QShowEvent *e );
+ virtual void contentsDropEvent( QDropEvent *e );
+ virtual void viewportWheelEvent( QWheelEvent * );
+ virtual void contentsMousePressEvent( QMouseEvent *e );
+ virtual void mousePressEvent( QMouseEvent *e );
+ virtual void wheelEvent( QWheelEvent* e );
+
+private:
+ void refreshTrashIcon();
+
+ static QRect desktopRect();
+ static void saveIconPosition(KSimpleConfig *config, int x, int y);
+ static void readIconPosition(KSimpleConfig *config, int &x, int &y);
+
+ /** Our action collection, parent of all our actions */
+ KActionCollection m_actionCollection;
+
+ /** KAccel object, to make the actions shortcuts work */
+ KAccel *m_accel;
+
+ bool m_bNeedRepaint;
+ bool m_bNeedSave;
+ bool m_autoAlign;
+
+ /** true if even one icon has an icon-position entry in the .directory */
+ bool m_hasExistingPos;
+
+ /** whether the user may move/edit/remove desktop icons */
+ bool m_bEditableDesktopIcons;
+
+ /** Show dot files ? */
+ bool m_bShowDot;
+
+ /** Vertical or Horizontal align of icons on desktop */
+ bool m_bVertAlign;
+
+ /** The directory lister - created only in start() */
+ KDirLister* m_dirLister;
+
+ /** The list of urls to be merged into the desktop, in addition to desktopURL */
+ KURL::List m_mergeDirs;
+
+ /** The list of dirs to be merged into the desktop, in addition to desktopURL **/
+ QStringList m_desktopDirs;
+
+ /** The desktop's .directory, used for storing icon positions */
+ KSimpleConfig *m_dotDirectory;
+
+ /** Position of last deleted icon - used when renaming a file */
+ QPoint m_lastDeletedIconPos;
+
+ /** Sorting */
+ SortCriterion m_eSortCriterion;
+ bool m_bSortDirectoriesFirst;
+ QStringList m_itemsAlwaysFirst;
+
+ /**
+ * The shadow object
+ */
+ KShadowEngine *m_shadowEngine;
+
+ /** Position where to move the next item.
+ * It is set to the KRootWm position when "new file" is chosen. */
+ QPoint m_nextItemPos;
+
+ /** Position where the last drop occurred */
+ QPoint m_dropPos;
+
+ /** Position for the last dropped item */
+ QPoint m_lastDropPos;
+
+ /** URL of the items which is being RMB'ed - when only one */
+ KURL m_popupURL;
+
+ /** media list management */
+ bool m_enableMedia;
+ QStringList m_excludedMedia;
+
+ // did we already get the correct desktopIconsArea (from kicker)
+ // needed when we want to line up icons on a grid
+ bool m_gotIconsArea;
+};
+
+#endif
diff --git a/kdesktop/kfileividesktop.cpp b/kdesktop/kfileividesktop.cpp
new file mode 100644
index 000000000..28bf51105
--- /dev/null
+++ b/kdesktop/kfileividesktop.cpp
@@ -0,0 +1,255 @@
+/* This file is proposed to be part of the KDE base.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow
+ * algorithm (currently used)
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+
+#include <qcolor.h>
+#include <qpalette.h>
+#include <qstring.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <kwordwrap.h>
+#include <kiconview.h>
+#include <kdebug.h>
+
+#include <kshadowengine.h>
+#include "kdesktopshadowsettings.h"
+#include "kfileividesktop.h"
+
+//#define DEBUG
+
+/* Changelog:
+ */
+
+KFileIVIDesktop::KFileIVIDesktop(KonqIconViewWidget *iconview, KFileItem* fileitem,
+ int size, KShadowEngine *shadow) :
+ KFileIVI(iconview, fileitem, size),
+ m_selectedImage(0L),
+ m_normalImage(0L),
+ _selectedUID(0),
+ _normalUID(0)
+{
+ m_shadow = shadow;
+ oldText = "";
+
+ calcRect( text() ); // recalculate rect including shadow
+}
+
+KFileIVIDesktop::~KFileIVIDesktop()
+{
+ delete m_selectedImage;
+ delete m_normalImage;
+}
+
+void KFileIVIDesktop::calcRect( const QString& _text )
+{
+ KIconViewItem::calcRect( _text );
+
+ if ( !iconView() || !m_shadow ||
+ !wordWrap() || !( static_cast<KDesktopShadowSettings *>
+ ( m_shadow->shadowSettings() ) )->isEnabled() )
+ return;
+
+ int spread = shadowThickness();
+ QRect itemTextRect = textRect();
+ QRect itemRect = rect();
+
+ itemTextRect.setBottom( itemTextRect.bottom() + spread );
+ itemTextRect.setRight( itemTextRect.right() + spread );
+ itemRect.setBottom( itemRect.bottom() + spread );
+ itemRect.setRight( itemRect.right() + spread );
+
+ setTextRect( itemTextRect );
+ setItemRect( itemRect );
+}
+
+void KFileIVIDesktop::paintItem( QPainter *p, const QColorGroup &cg)
+{
+ QColorGroup colors = updateColors(cg);
+
+ QIconView* view = iconView();
+ Q_ASSERT( view );
+
+ if ( !view )
+ return;
+
+ if ( !wordWrap() )
+ return;
+
+ p->save();
+
+ // draw the pixmap as in KIconViewItem::paintItem(...)
+ paintPixmap(p, colors);
+
+ //
+ // Paint the text as shadowed if the shadow is available
+ //
+ if (m_shadow != 0L && (static_cast<KDesktopShadowSettings *> (m_shadow->shadowSettings()))->isEnabled())
+ drawShadowedText(p, colors);
+ else {
+ paintFontUpdate(p);
+ paintText(p, colors);
+ }
+
+ p->restore();
+
+ paintOverlay(p);
+}
+
+bool KFileIVIDesktop::shouldUpdateShadow(bool selected)
+{
+ unsigned long uid = (static_cast<KDesktopShadowSettings *> (m_shadow->shadowSettings()))->UID();
+ QString wrapped = wordWrap()->wrappedString();
+
+ if (wrapped != oldText){
+ oldText = wrapped;
+ _selectedUID = _normalUID = 0;
+ }
+
+ if (selected == true)
+ return (uid != _selectedUID);
+ else
+ return (uid != _normalUID);
+
+ return false;
+}
+
+void KFileIVIDesktop::paintFocus( QPainter *p, const QColorGroup &cg )
+{
+ if ( !iconView() )
+ return;
+
+ if ( !m_shadow || !wordWrap() ||
+ !( static_cast<KDesktopShadowSettings *>
+ ( m_shadow->shadowSettings() ) )->isEnabled() ) {
+ QIconViewItem::paintFocus( p, cg );
+ return;
+ }
+
+ int spread = shadowThickness();
+
+ iconView()->style().drawPrimitive( QStyle::PE_FocusRect, p,
+ QRect( textRect( false ).x(), textRect( false ).y(),
+ textRect( false ).width() - spread,
+ textRect( false ).height() - spread + 1 ),
+ cg,
+ isSelected() ? QStyle::Style_FocusAtBorder : QStyle::Style_Default,
+ QStyleOption( isSelected() ? cg.highlight() : cg.base() ) );
+
+ if ( this != iconView()->currentItem() ) {
+ iconView()->style().drawPrimitive( QStyle::PE_FocusRect, p,
+ QRect( pixmapRect( false ).x(), pixmapRect( false ).y(),
+ pixmapRect( false ).width(), pixmapRect( false ).height() ),
+ cg, QStyle::Style_Default, QStyleOption( cg.base() ) );
+ }
+}
+
+
+void KFileIVIDesktop::drawShadowedText( QPainter *p, const QColorGroup &cg )
+{
+ int textX = textRect( FALSE ).x() + 2;
+ int textY = textRect( FALSE ).y();
+ int align = ((KIconView *) iconView())->itemTextPos() == QIconView::Bottom
+ ? AlignHCenter : AlignAuto;
+ bool rebuild = shouldUpdateShadow(isSelected());
+
+ KDesktopShadowSettings *settings = (KDesktopShadowSettings *) (m_shadow->shadowSettings());
+
+ unsigned long uid = settings->UID();
+
+ p->setFont(iconView()->font());
+ paintFontUpdate(p);
+ QColor shadow;
+ QColor text;
+ int spread = shadowThickness();
+
+ if ( isSelected() && settings->selectionType() != KShadowSettings::InverseVideoOnSelection ) {
+ // select using a filled rect
+ text = cg.highlightedText();
+ QRect rect = textRect( false );
+ rect.setRight( rect.right() - spread );
+ rect.setBottom( rect.bottom() - spread + 1 );
+ p->fillRect( rect, cg.highlight() );
+ }
+ else {
+ // use shadow
+ if ( isSelected() ) {
+ // inverse text and shadow colors
+ shadow = settings->textColor();
+ text = settings->bgColor();
+ if ( rebuild ) {
+ setSelectedImage( buildShadow( p, align, shadow ) );
+ _selectedUID = uid;
+ }
+ }
+ else {
+ text = settings->textColor();
+ shadow = ( settings->bgColor().isValid() ) ? settings->bgColor() :
+ ( qGray( text.rgb() ) > 127 ) ? black : white;
+ if (rebuild) {
+ setNormalImage(buildShadow(p, align, shadow));
+ _normalUID = uid;
+ }
+ }
+
+ // draw the shadow
+ int shadowX = textX - spread + settings->offsetX();
+ int shadowY = textY - spread + settings->offsetY();
+
+ p->drawImage(shadowX, shadowY,
+ (isSelected()) ? *selectedImage() : *normalImage(),
+ 0, 0, -1, -1, DITHER_FLAGS);
+ }
+
+ // draw the text
+ p->setPen(text);
+ wordWrap()->drawText( p, textX, textY, align | KWordWrap::Truncate );
+}
+
+
+QImage *KFileIVIDesktop::buildShadow( QPainter *p, const int align,
+ QColor &shadowColor )
+{
+ QPainter pixPainter;
+ int spread = shadowThickness();
+
+ QPixmap textPixmap(textRect( FALSE ).width() + spread * 2 + 2,
+ textRect( FALSE ).height() + spread * 2 + 2);
+
+ textPixmap.fill(QColor(0,0,0));
+ textPixmap.setMask( textPixmap.createHeuristicMask(TRUE) );
+
+ pixPainter.begin(&textPixmap);
+ pixPainter.setPen(white); // get the pen from the root painter
+ pixPainter.setFont(p->font()); // get the font from the root painter
+ wordWrap()->drawText( &pixPainter, spread, spread, align | KWordWrap::Truncate );
+ pixPainter.end();
+
+ return new QImage(m_shadow->makeShadow(textPixmap, shadowColor));
+}
+
+int KFileIVIDesktop::shadowThickness() const
+{
+ return ( ( m_shadow->shadowSettings()->thickness() + 1 ) >> 1 ) + 1;
+}
+
diff --git a/kdesktop/kfileividesktop.h b/kdesktop/kfileividesktop.h
new file mode 100644
index 000000000..0fb764cd0
--- /dev/null
+++ b/kdesktop/kfileividesktop.h
@@ -0,0 +1,127 @@
+/* This file is proposed to be part of the KDE base.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow
+ * algorithm (currently used)
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KFILE_IVI_DESKTOP
+#define KFILE_IVI_DESKTOP
+
+#include <qcolor.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qstring.h>
+#include <kfileivi.h>
+
+/*
+ * The dither flags used to display the shadow image
+ */
+#define DITHER_FLAGS (Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::AvoidDither)
+
+
+class QFont;
+class KShadowEngine;
+
+/**
+ * This class replaces KFileIVI in the desktop only.
+ * If the shadow object is NULL, then the class should behave almost identical
+ * to its parent.
+ * @since 3.2
+ */
+class KFileIVIDesktop : public KFileIVI
+{
+ public:
+ /**
+ * Constructor. It replicates the KFileIVI constructor and adds an
+ * optional shadow object.
+ * @param iconview the parent (iconview)
+ * @param fileitem the item theis object is supposed to draw
+ * @param size the default size of the drawn object
+ * @param shadow reference to the shadow object
+ */
+ KFileIVIDesktop(KonqIconViewWidget *iconview, KFileItem* fileitem, int
+ size, KShadowEngine *shadow = 0L);
+
+ /**
+ * Default destructor. Doesn't really do anything.
+ */
+ ~KFileIVIDesktop();
+
+ protected:
+ /**
+ * Reimplements KIconView::calcRect to take the shadow metrics
+ * into account
+ */
+ virtual void calcRect( const QString& _text );
+
+ /**
+ * Paints this item. Takes care of using the normal or alpha
+ * blending methods depending on the configuration.
+ * @param p the painter for drawing the item
+ * @param cg the base color group
+ */
+ virtual void paintItem(QPainter *p, const QColorGroup &cg);
+
+ /**
+ * Reimplements QIconView::paintFocus() to take the shadow
+ * metrics into account();
+ */
+ virtual void paintFocus( QPainter *p, const QColorGroup &cg );
+
+ /**
+ * Draws the shadow text.
+ * @param p the painter for drawing the item
+ * @param cg the base color group
+ */
+ virtual void drawShadowedText(QPainter *p, const QColorGroup &cg);
+
+ /**
+ * Builds the shadow. As the algorithm is pretty slow (at pixel level),
+ * This method is triggered only if the configuration has changed.
+ * @param p the painter for drawing the item
+ * @param align the shadow alignment
+ * @param shadowColor the shadow color
+ */
+ virtual QImage *buildShadow(QPainter *p, const int align, QColor &shadowColor);
+
+ protected:
+ void setNormalImage(QImage *newImage) { delete m_normalImage; m_normalImage = newImage; };
+ void setSelectedImage(QImage *newImage) { delete m_selectedImage; m_selectedImage = newImage; };
+
+ QImage *normalImage() { return m_normalImage; };
+ QImage *selectedImage() { return m_selectedImage; };
+
+ private:
+ bool shouldUpdateShadow(bool selected);
+ int shadowThickness() const;
+
+ KShadowEngine *m_shadow;
+
+ QImage *m_selectedImage;
+ QImage *m_normalImage;
+
+ QString oldText;
+
+ unsigned long _selectedUID;
+ unsigned long _normalUID;
+
+};
+
+#endif
diff --git a/kdesktop/klaunch.kcfg b/kdesktop/klaunch.kcfg
new file mode 100644
index 000000000..29418f827
--- /dev/null
+++ b/kdesktop/klaunch.kcfg
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="klaunchrc" />
+ <!-- generated by KConfig XTraKtor -->
+
+ <group name="BusyCursorSettings">
+ <entry key="Timeout" type="Int">
+ <default>30</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- startupid.cpp:58 -->
+ <!-- startup_info.setTimeout( c.readUnsignedNumEntry( "Timeout", 30 )); -->
+ </entry>
+ <entry key="Blinking" type="Bool">
+ <default>false</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- startupid.cpp:59 -->
+ <!-- blinking = c.readBoolEntry( "Blinking", false ); -->
+ </entry>
+ <entry key="Bouncing" type="Bool">
+ <default>true</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- startupid.cpp:60 -->
+ <!-- bouncing = c.readBoolEntry( "Bouncing", true ); -->
+ </entry>
+ </group>
+ <group name="FeedbackStyle">
+ <entry key="BusyCursor" type="Bool">
+ <default>true</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdesktop/klaunchsettings.kcfgc b/kdesktop/klaunchsettings.kcfgc
new file mode 100644
index 000000000..0cf4f73eb
--- /dev/null
+++ b/kdesktop/klaunchsettings.kcfgc
@@ -0,0 +1,4 @@
+File=klaunch.kcfg
+ClassName=KLaunchSettings
+Singleton=true
+Mutators=true
diff --git a/kdesktop/krootwm.cc b/kdesktop/krootwm.cc
new file mode 100644
index 000000000..51586f878
--- /dev/null
+++ b/kdesktop/krootwm.cc
@@ -0,0 +1,859 @@
+/*
+ * krootwm.cc Part of the KDE project.
+ *
+ * Copyright (C) 1997 Matthias Ettrich
+ * (C) 1997 Torben Weis, weis@kde.org
+ * (C) 1998 S.u.S.E. weis@suse.de
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <kstandarddirs.h>
+#include <kpopupmenu.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcmultidialog.h>
+#include <kbookmarkmenu.h>
+#include <konqbookmarkmanager.h>
+#include <klocale.h>
+#include <knewmenu.h>
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <khelpmenu.h>
+#include <kdebug.h>
+#include <kwindowlistmenu.h>
+#include <kwin.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kuser.h>
+#include <qfile.h>
+
+#include "krootwm.h"
+#include "kdiconview.h"
+#include "desktop.h"
+#include "kcustommenu.h"
+#include "kdesktopsettings.h"
+
+#include <netwm.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include <dmctl.h>
+
+KRootWm * KRootWm::s_rootWm = 0;
+
+extern QCString kdesktop_name, kicker_name, kwin_name;
+
+KRootWm::KRootWm(KDesktop* _desktop) : QObject(_desktop)
+{
+ s_rootWm = this;
+ m_actionCollection = new KActionCollection(_desktop, this, "KRootWm::m_actionCollection");
+ m_pDesktop = _desktop;
+ m_bDesktopEnabled = (m_pDesktop->iconView() != 0);
+ customMenu1 = 0;
+ customMenu2 = 0;
+ m_configDialog = 0;
+
+
+ // Creates the new menu
+ menuBar = 0; // no menubar yet
+ menuNew = 0;
+ if (m_bDesktopEnabled && kapp->authorize("editable_desktop_icons"))
+ {
+ menuNew = new KNewMenu( m_actionCollection, "new_menu" );
+ connect(menuNew->popupMenu(), SIGNAL( aboutToShow() ),
+ this, SLOT( slotFileNewAboutToShow() ) );
+ connect( menuNew, SIGNAL( activated() ),
+ m_pDesktop->iconView(), SLOT( slotNewMenuActivated() ) );
+ }
+
+ if (kapp->authorizeKAction("bookmarks"))
+ {
+ bookmarks = new KActionMenu( i18n("Bookmarks"), "bookmark", m_actionCollection, "bookmarks" );
+ // The KBookmarkMenu is needed to fill the Bookmarks menu in the desktop menubar.
+ bookmarkMenu = new KBookmarkMenu( KonqBookmarkManager::self(), new KBookmarkOwner(),
+ bookmarks->popupMenu(),
+ m_actionCollection,
+ true, false );
+ }
+ else
+ {
+ bookmarks = 0;
+ bookmarkMenu = 0;
+ }
+
+ // The windowList and desktop menus can be part of a menubar (Mac style)
+ // so we create them here
+ desktopMenu = new QPopupMenu;
+ windowListMenu = new KWindowListMenu;
+ connect( windowListMenu, SIGNAL( aboutToShow() ),
+ this, SLOT( slotWindowListAboutToShow() ) );
+
+ // Create the actions
+#if 0
+ if (m_bDesktopEnabled)
+ {
+ // Don't do that! One action in two parent collections means some invalid write
+ // during the second ~KActionCollection.
+ KAction *action = m_pDesktop->actionCollection()->action( "paste" );
+ if (action)
+ m_actionCollection->insert( action );
+ action = m_pDesktop->actionCollection()->action( "undo" );
+ if (action)
+ m_actionCollection->insert( action );
+ }
+#endif
+
+ if (kapp->authorize("run_command"))
+ {
+ new KAction(i18n("Run Command..."), "run", 0, m_pDesktop, SLOT( slotExecuteCommand() ), m_actionCollection, "exec" );
+ }
+ if (!KGlobal::config()->isImmutable())
+ {
+ new KAction(i18n("Configure Desktop..."), "configure", 0, this, SLOT( slotConfigureDesktop() ),
+ m_actionCollection, "configdesktop" );
+ new KAction(i18n("Disable Desktop Menu"), 0, this, SLOT( slotToggleDesktopMenu() ),
+ m_actionCollection, "togglemenubar" );
+ }
+
+ new KAction(i18n("Unclutter Windows"), 0, this, SLOT( slotUnclutterWindows() ),
+ m_actionCollection, "unclutter" );
+ new KAction(i18n("Cascade Windows"), 0, this, SLOT( slotCascadeWindows() ),
+ m_actionCollection, "cascade" );
+
+ // arrange menu actions
+ if (m_bDesktopEnabled && kapp->authorize("editable_desktop_icons"))
+ {
+ new KAction(i18n("By Name (Case Sensitive)"), 0, this, SLOT( slotArrangeByNameCS() ),
+ m_actionCollection, "sort_ncs");
+ new KAction(i18n("By Name (Case Insensitive)"), 0, this, SLOT( slotArrangeByNameCI() ),
+ m_actionCollection, "sort_nci");
+ new KAction(i18n("By Size"), 0, this, SLOT( slotArrangeBySize() ),
+ m_actionCollection, "sort_size");
+ new KAction(i18n("By Type"), 0, this, SLOT( slotArrangeByType() ),
+ m_actionCollection, "sort_type");
+ new KAction(i18n("By Date"), 0, this, SLOT( slotArrangeByDate() ),
+ m_actionCollection, "sort_date");
+
+ KToggleAction *aSortDirsFirst = new KToggleAction( i18n("Directories First"), 0, m_actionCollection, "sort_directoriesfirst" );
+ connect( aSortDirsFirst, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotToggleDirFirst( bool ) ) );
+ new KAction(i18n("Line Up Horizontally"), 0,
+ this, SLOT( slotLineupIconsHoriz() ),
+ m_actionCollection, "lineupHoriz" );
+ new KAction(i18n("Line Up Vertically"), 0,
+ this, SLOT( slotLineupIconsVert() ),
+ m_actionCollection, "lineupVert" );
+ KToggleAction *aAutoAlign = new KToggleAction(i18n("Align to Grid"), 0,
+ m_actionCollection, "realign" );
+ connect( aAutoAlign, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotToggleAutoAlign( bool ) ) );
+ KToggleAction *aLockIcons = new KToggleAction(i18n("Lock in Place"), 0, m_actionCollection, "lock_icons");
+ connect( aLockIcons, SIGNAL( toggled( bool ) ),
+ this, SLOT( slotToggleLockIcons( bool ) ) );
+ }
+ if (m_bDesktopEnabled)
+ {
+ new KAction(i18n("Refresh Desktop"), "desktop", 0, this, SLOT( slotRefreshDesktop() ),
+ m_actionCollection, "refresh" );
+ }
+ // Icons in sync with kicker
+ if (kapp->authorize("lock_screen"))
+ {
+ new KAction(i18n("Lock Session"), "lock", 0, this, SLOT( slotLock() ),
+ m_actionCollection, "lock" );
+ }
+ if (kapp->authorize("logout"))
+ {
+ new KAction(i18n("Log Out \"%1\"...").arg(KUser().loginName()), "exit", 0,
+ this, SLOT( slotLogout() ), m_actionCollection, "logout" );
+ }
+
+ if (kapp->authorize("start_new_session") && DM().isSwitchable())
+ {
+ new KAction(i18n("Start New Session"), "fork", 0, this,
+ SLOT( slotNewSession() ), m_actionCollection, "newsession" );
+ if (kapp->authorize("lock_screen"))
+ {
+ new KAction(i18n("Lock Current && Start New Session"), "lock", 0, this,
+ SLOT( slotLockNNewSession() ), m_actionCollection, "lockNnewsession" );
+ }
+ }
+
+ initConfig();
+}
+
+KRootWm::~KRootWm()
+{
+ delete m_actionCollection;
+ delete desktopMenu;
+ delete windowListMenu;
+}
+
+void KRootWm::initConfig()
+{
+// kdDebug() << "KRootWm::initConfig" << endl;
+
+ // parse the configuration
+ m_bGlobalMenuBar = KDesktopSettings::macStyle();
+ m_bShowMenuBar = m_bGlobalMenuBar || KDesktopSettings::showMenubar();
+
+ static const int choiceCount = 7;
+ // read configuration for clicks on root window
+ static const char * const s_choices[choiceCount] = { "", "WindowListMenu", "DesktopMenu", "AppMenu", "CustomMenu1", "CustomMenu2", "BookmarksMenu" };
+ leftButtonChoice = middleButtonChoice = rightButtonChoice = NOTHING;
+ QString s = KDesktopSettings::left();
+ for ( int c = 0 ; c < choiceCount ; c ++ )
+ if (s == s_choices[c])
+ { leftButtonChoice = (menuChoice) c; break; }
+ s = KDesktopSettings::middle();
+ for ( int c = 0 ; c < choiceCount ; c ++ )
+ if (s == s_choices[c])
+ { middleButtonChoice = (menuChoice) c; break; }
+ s = KDesktopSettings::right();
+ for ( int c = 0 ; c < choiceCount ; c ++ )
+ if (s == s_choices[c])
+ { rightButtonChoice = (menuChoice) c; break; }
+
+ // Read configuration for icons alignment
+ if ( m_bDesktopEnabled ) {
+ m_pDesktop->iconView()->setAutoAlign( KDesktopSettings::autoLineUpIcons() );
+ if ( kapp->authorize( "editable_desktop_icons" ) ) {
+ m_pDesktop->iconView()->setItemsMovable( !KDesktopSettings::lockIcons() );
+ KToggleAction *aLockIcons = static_cast<KToggleAction*>(m_actionCollection->action("lock_icons"));
+ if (aLockIcons)
+ aLockIcons->setChecked( KDesktopSettings::lockIcons() );
+ }
+ KToggleAction *aAutoAlign = static_cast<KToggleAction*>(m_actionCollection->action("realign"));
+ if (aAutoAlign)
+ aAutoAlign->setChecked( KDesktopSettings::autoLineUpIcons() );
+ KToggleAction *aSortDirsFirst = static_cast<KToggleAction*>(m_actionCollection->action("sort_directoriesfirst"));
+ if (aSortDirsFirst)
+ aSortDirsFirst->setChecked( KDesktopSettings::sortDirectoriesFirst() );
+ }
+
+ buildMenus();
+}
+
+void KRootWm::buildMenus()
+{
+// kdDebug() << "KRootWm::buildMenus" << endl;
+
+ delete menuBar;
+ menuBar = 0;
+
+ delete customMenu1;
+ customMenu1 = 0;
+ delete customMenu2;
+ customMenu2 = 0;
+
+ if (m_bShowMenuBar)
+ {
+// kdDebug() << "showMenuBar" << endl;
+ menuBar = new KMenuBar;
+ menuBar->setCaption("KDE Desktop");
+ }
+
+ // create Arrange menu
+ QPopupMenu *pArrangeMenu = 0;
+ QPopupMenu *pLineupMenu = 0;
+ KAction *action;
+ help = new KHelpMenu(0, 0, false);
+ help->menu()->removeItem( KHelpMenu::menuAboutApp );
+
+ if (m_bDesktopEnabled && m_actionCollection->action("realign"))
+ {
+ pArrangeMenu = new QPopupMenu;
+ m_actionCollection->action("sort_ncs")->plug( pArrangeMenu );
+ m_actionCollection->action("sort_nci")->plug( pArrangeMenu );
+ m_actionCollection->action("sort_size")->plug( pArrangeMenu );
+ m_actionCollection->action("sort_type")->plug( pArrangeMenu );
+ m_actionCollection->action("sort_date" )->plug( pArrangeMenu );
+ pArrangeMenu->insertSeparator();
+ m_actionCollection->action("sort_directoriesfirst")->plug( pArrangeMenu );
+
+ pLineupMenu = new QPopupMenu;
+ m_actionCollection->action( "lineupHoriz" )->plug( pLineupMenu );
+ m_actionCollection->action( "lineupVert" )->plug( pLineupMenu );
+ pLineupMenu->insertSeparator();
+ m_actionCollection->action( "realign" )->plug( pLineupMenu );
+ }
+
+ sessionsMenu = 0;
+ if (m_actionCollection->action("newsession"))
+ {
+ sessionsMenu = new QPopupMenu;
+ connect( sessionsMenu, SIGNAL(aboutToShow()), SLOT(slotPopulateSessions()) );
+ connect( sessionsMenu, SIGNAL(activated(int)), SLOT(slotSessionActivated(int)) );
+ }
+
+ if (menuBar) {
+ bool needSeparator = false;
+ file = new QPopupMenu;
+
+ action = m_actionCollection->action("exec");
+ if (action)
+ {
+ action->plug( file );
+ file->insertSeparator();
+ }
+
+ action = m_actionCollection->action("lock");
+ if (action)
+ action->plug( file );
+
+ action = m_actionCollection->action("logout");
+ if (action)
+ action->plug( file );
+
+ desk = new QPopupMenu;
+
+ if (m_bDesktopEnabled)
+ {
+ m_actionCollection->action("unclutter")->plug( desk );
+ m_actionCollection->action("cascade")->plug( desk );
+ desk->insertSeparator();
+
+ if (pArrangeMenu)
+ desk->insertItem(i18n("Sort Icons"), pArrangeMenu);
+ if (pLineupMenu)
+ desk->insertItem(i18n("Line Up Icons"), pLineupMenu );
+
+ m_actionCollection->action("refresh")->plug( desk );
+ needSeparator = true;
+ }
+ action = m_actionCollection->action("configdesktop");
+ if (action)
+ {
+ if (needSeparator)
+ desk->insertSeparator();
+ action->plug( desk );
+ needSeparator = true;
+ }
+
+ action = m_actionCollection->action("togglemenubar");
+ if (action)
+ {
+ if (needSeparator)
+ desk->insertSeparator();
+ action->plug( desk );
+ action->setText(i18n("Disable Desktop Menu"));
+ }
+ }
+ else
+ {
+ action = m_actionCollection->action("togglemenubar");
+ if (action)
+ action->setText(i18n("Enable Desktop Menu"));
+ }
+
+ desktopMenu->clear();
+ desktopMenu->disconnect( this );
+ bool needSeparator = false;
+
+ if (menuNew)
+ {
+ menuNew->plug( desktopMenu );
+ needSeparator = true;
+ }
+
+#if 0
+ if (bookmarks)
+ {
+ bookmarks->plug( desktopMenu );
+ needSeparator = true;
+ }
+#endif
+
+ action = m_actionCollection->action("exec");
+ if (action)
+ {
+ action->plug( desktopMenu );
+ needSeparator = true;
+ }
+
+ if (needSeparator)
+ {
+ desktopMenu->insertSeparator();
+ needSeparator = false;
+ }
+
+ if (m_bDesktopEnabled)
+ {
+ action = m_pDesktop->actionCollection()->action( "undo" );
+ if (action)
+ action->plug( desktopMenu );
+ action = m_pDesktop->actionCollection()->action( "paste" );
+ if (action)
+ action->plug( desktopMenu );
+ desktopMenu->insertSeparator();
+ }
+
+ if (m_bDesktopEnabled && m_actionCollection->action("realign"))
+ {
+ QPopupMenu* pIconOperationsMenu = new QPopupMenu;
+
+ pIconOperationsMenu->insertItem(i18n("Sort Icons"), pArrangeMenu);
+ pIconOperationsMenu->insertSeparator();
+ m_actionCollection->action( "lineupHoriz" )->plug( pIconOperationsMenu );
+ m_actionCollection->action( "lineupVert" )->plug( pIconOperationsMenu );
+ pIconOperationsMenu->insertSeparator();
+ m_actionCollection->action( "realign" )->plug( pIconOperationsMenu );
+ KAction *aLockIcons = m_actionCollection->action( "lock_icons" );
+ if ( aLockIcons )
+ aLockIcons->plug( pIconOperationsMenu );
+
+ desktopMenu->insertItem(SmallIconSet("icons"), i18n("Icons"), pIconOperationsMenu);
+ }
+
+ QPopupMenu* pWindowOperationsMenu = new QPopupMenu;
+ m_actionCollection->action("cascade")->plug( pWindowOperationsMenu );
+ m_actionCollection->action("unclutter")->plug( pWindowOperationsMenu );
+ desktopMenu->insertItem(SmallIconSet("window_list"), i18n("Windows"), pWindowOperationsMenu);
+
+ if (m_bDesktopEnabled)
+ {
+ m_actionCollection->action("refresh")->plug( desktopMenu );
+ }
+
+ action = m_actionCollection->action("configdesktop");
+ if (action)
+ {
+ action->plug( desktopMenu );
+ }
+ int lastSep = desktopMenu->insertSeparator();
+
+ if (sessionsMenu && kapp->authorize("switch_user"))
+ {
+ desktopMenu->insertItem(SmallIconSet("switchuser" ), i18n("Switch User"), sessionsMenu);
+ needSeparator = true;
+ }
+
+ action = m_actionCollection->action("lock");
+ if (action)
+ {
+ action->plug( desktopMenu );
+ needSeparator = true;
+ }
+
+ action = m_actionCollection->action("logout");
+ if (action)
+ {
+ action->plug( desktopMenu );
+ needSeparator = true;
+ }
+
+ if (!needSeparator)
+ {
+ desktopMenu->removeItem(lastSep);
+ }
+
+ connect( desktopMenu, SIGNAL( aboutToShow() ), this, SLOT( slotFileNewAboutToShow() ) );
+
+ if (menuBar) {
+ menuBar->insertItem(i18n("File"), file);
+ if (sessionsMenu)
+ {
+ menuBar->insertItem(i18n("Sessions"), sessionsMenu);
+ }
+ if (menuNew)
+ {
+ menuBar->insertItem(i18n("New"), menuNew->popupMenu());
+ }
+ if (bookmarks)
+ {
+ menuBar->insertItem(i18n("Bookmarks"), bookmarks->popupMenu());
+ }
+ menuBar->insertItem(i18n("Desktop"), desk);
+ menuBar->insertItem(i18n("Windows"), windowListMenu);
+ menuBar->insertItem(i18n("Help"), help->menu());
+
+ menuBar->setTopLevelMenu( true );
+ menuBar->show(); // we need to call show() as we delayed the creation with the timer
+ }
+}
+
+void KRootWm::slotToggleDirFirst( bool b )
+{
+ KDesktopSettings::setSortDirectoriesFirst( b );
+ KDesktopSettings::writeConfig();
+}
+
+void KRootWm::slotToggleAutoAlign( bool b )
+{
+ KDesktopSettings::setAutoLineUpIcons( b );
+ KDesktopSettings::writeConfig();
+
+ // Auto line-up icons
+ m_pDesktop->iconView()->setAutoAlign( b );
+}
+
+void KRootWm::slotFileNewAboutToShow()
+{
+ if (menuNew)
+ {
+// kdDebug() << " KRootWm:: (" << this << ") slotFileNewAboutToShow() menuNew=" << menuNew << endl;
+ // As requested by KNewMenu :
+ menuNew->slotCheckUpToDate();
+ // And set the files that the menu apply on :
+ menuNew->setPopupFiles( m_pDesktop->url() );
+ }
+}
+
+void KRootWm::slotWindowListAboutToShow()
+{
+ windowListMenu->init();
+}
+
+void KRootWm::activateMenu( menuChoice choice, const QPoint& global )
+{
+ switch ( choice )
+ {
+ case SESSIONSMENU:
+ if (sessionsMenu)
+ sessionsMenu->popup(global);
+ break;
+ case WINDOWLISTMENU:
+ windowListMenu->popup(global);
+ break;
+ case DESKTOPMENU:
+ m_desktopMenuPosition = global; // for KDIconView::slotPaste
+ desktopMenu->popup(global);
+ break;
+ case BOOKMARKSMENU:
+ if (bookmarks)
+ bookmarks->popup(global);
+ break;
+ case APPMENU:
+ {
+ // This allows the menu to disappear when clicking on the background another time
+ XUngrabPointer(qt_xdisplay(), CurrentTime);
+ XSync(qt_xdisplay(), False);
+
+ // Ask kicker to showup the menu
+ DCOPRef( kicker_name, kicker_name ).send( "popupKMenu", global );
+ break;
+ }
+ case CUSTOMMENU1:
+ if (!customMenu1)
+ customMenu1 = new KCustomMenu("kdesktop_custom_menu1");
+ customMenu1->popup(global);
+ break;
+ case CUSTOMMENU2:
+ if (!customMenu2)
+ customMenu2 = new KCustomMenu("kdesktop_custom_menu2");
+ customMenu2->popup(global);
+ break;
+ case NOTHING:
+ default:
+ break;
+ }
+}
+
+void KRootWm::mousePressed( const QPoint& _global, int _button )
+{
+ if (!desktopMenu) return; // initialisation not yet done
+ switch ( _button ) {
+ case LeftButton:
+ if ( m_bShowMenuBar && menuBar )
+ menuBar->raise();
+ activateMenu( leftButtonChoice, _global );
+ break;
+ case MidButton:
+ activateMenu( middleButtonChoice, _global );
+ break;
+ case RightButton:
+ if (!kapp->authorize("action/kdesktop_rmb")) return;
+ activateMenu( rightButtonChoice, _global );
+ break;
+ default:
+ // nothing
+ break;
+ }
+}
+
+void KRootWm::slotWindowList() {
+// kdDebug() << "KRootWm::slotWindowList" << endl;
+// Popup at the center of the screen, this is from keyboard shortcut.
+ QDesktopWidget* desktop = KApplication::desktop();
+ QRect r = desktop->screenGeometry( desktop->screenNumber(QCursor::pos()));
+ windowListMenu->init();
+ disconnect( windowListMenu, SIGNAL( aboutToShow() ),
+ this, SLOT( slotWindowListAboutToShow() ) ); // avoid calling init() twice
+ // windowListMenu->rect() is not valid before showing, use sizeHint()
+ windowListMenu->popup(r.center() - QRect( QPoint( 0, 0 ), windowListMenu->sizeHint()).center());
+ windowListMenu->selectActiveWindow(); // make the popup more useful
+ connect( windowListMenu, SIGNAL( aboutToShow() ),
+ this, SLOT( slotWindowListAboutToShow() ) );
+}
+
+void KRootWm::slotSwitchUser() {
+// kdDebug() << "KRootWm::slotSwitchUser" << endl;
+ if (!sessionsMenu)
+ return;
+ QDesktopWidget* desktop = KApplication::desktop();
+ QRect r = desktop->screenGeometry( desktop->screenNumber(QCursor::pos()));
+ slotPopulateSessions();
+ disconnect( sessionsMenu, SIGNAL( aboutToShow() ),
+ this, SLOT( slotPopulateSessions() ) ); // avoid calling init() twice
+ sessionsMenu->popup(r.center() - QRect( QPoint( 0, 0 ), sessionsMenu->sizeHint()).center());
+ connect( sessionsMenu, SIGNAL( aboutToShow() ),
+ SLOT( slotPopulateSessions() ) );
+}
+
+void KRootWm::slotArrangeByNameCS()
+{
+ if (m_bDesktopEnabled)
+ {
+ bool b = static_cast<KToggleAction *>(m_actionCollection->action("sort_directoriesfirst"))->isChecked();
+ m_pDesktop->iconView()->rearrangeIcons( KDIconView::NameCaseSensitive, b);
+ }
+}
+
+void KRootWm::slotArrangeByNameCI()
+{
+ if (m_bDesktopEnabled)
+ {
+ bool b = static_cast<KToggleAction *>(m_actionCollection->action("sort_directoriesfirst"))->isChecked();
+ m_pDesktop->iconView()->rearrangeIcons( KDIconView::NameCaseInsensitive, b);
+ }
+}
+
+void KRootWm::slotArrangeBySize()
+{
+ if (m_bDesktopEnabled)
+ {
+ bool b = static_cast<KToggleAction *>(m_actionCollection->action("sort_directoriesfirst"))->isChecked();
+ m_pDesktop->iconView()->rearrangeIcons( KDIconView::Size, b);
+ }
+}
+
+void KRootWm::slotArrangeByDate()
+{
+ if (m_bDesktopEnabled)
+ {
+ bool b = static_cast<KToggleAction *>( m_actionCollection->action( "sort_directoriesfirst" ) )->isChecked();
+ m_pDesktop->iconView()->rearrangeIcons( KDIconView::Date, b );
+ }
+}
+
+void KRootWm::slotArrangeByType()
+{
+ if (m_bDesktopEnabled)
+ {
+ bool b = static_cast<KToggleAction *>(m_actionCollection->action("sort_directoriesfirst"))->isChecked();
+ m_pDesktop->iconView()->rearrangeIcons( KDIconView::Type, b);
+ }
+}
+
+void KRootWm::slotLineupIconsHoriz() {
+ if (m_bDesktopEnabled)
+ {
+ m_pDesktop->iconView()->lineupIcons(QIconView::LeftToRight);
+ }
+}
+
+void KRootWm::slotLineupIconsVert() {
+ if (m_bDesktopEnabled)
+ {
+ m_pDesktop->iconView()->lineupIcons(QIconView::TopToBottom);
+ }
+}
+
+void KRootWm::slotLineupIcons() {
+ if (m_bDesktopEnabled)
+ {
+ m_pDesktop->iconView()->lineupIcons();
+ }
+}
+
+void KRootWm::slotToggleLockIcons( bool lock )
+{
+ if (m_bDesktopEnabled)
+ {
+ m_pDesktop->iconView()->setItemsMovable( !lock );
+ KDesktopSettings::setLockIcons( lock );
+ KDesktopSettings::writeConfig();
+ }
+}
+
+void KRootWm::slotRefreshDesktop() {
+ if (m_bDesktopEnabled)
+ {
+ m_pDesktop->refresh();
+ }
+}
+
+QStringList KRootWm::configModules() {
+ QStringList args;
+ args << "kde-background.desktop" << "kde-desktopbehavior.desktop" << "kde-desktop.desktop"
+ << "kde-screensaver.desktop" << "kde-display.desktop";
+ return args;
+}
+
+void KRootWm::slotConfigureDesktop() {
+ if (!m_configDialog)
+ {
+ m_configDialog = new KCMultiDialog( (QWidget*)0, "configureDialog" );
+ connect(m_configDialog, SIGNAL(finished()), this, SLOT(slotConfigClosed()));
+
+ QStringList modules = configModules();
+ for (QStringList::const_iterator it = modules.constBegin(); it != modules.constEnd(); ++it)
+ {
+ if (kapp->authorizeControlModule(*it))
+ {
+ m_configDialog->addModule(*it);
+ }
+ }
+ }
+
+ KWin::setOnDesktop(m_configDialog->winId(), KWin::currentDesktop());
+ m_configDialog->show();
+ m_configDialog->raise();
+}
+
+void KRootWm::slotConfigClosed()
+{
+ m_configDialog->delayedDestruct();
+ m_configDialog = 0;
+}
+
+void KRootWm::slotToggleDesktopMenu()
+{
+ KDesktopSettings::setShowMenubar( !(m_bShowMenuBar && menuBar) );
+ KDesktopSettings::writeConfig();
+
+ QByteArray data;
+ kapp->dcopClient()->send( kdesktop_name, "KDesktopIface", "configure()", data);
+ // for the standalone menubar setting
+ kapp->dcopClient()->send( "menuapplet*", "menuapplet", "configure()", data );
+ kapp->dcopClient()->send( kicker_name, kicker_name, "configureMenubar()", data );
+ kapp->dcopClient()->send( "kwin*", "", "reconfigure()", data );
+}
+
+
+void KRootWm::slotUnclutterWindows()
+{
+ kapp->dcopClient()->send(kwin_name, "KWinInterface", "unclutterDesktop()", "");
+}
+
+
+void KRootWm::slotCascadeWindows() {
+ kapp->dcopClient()->send(kwin_name, "KWinInterface", "cascadeDesktop()", "");
+}
+
+
+void KRootWm::slotLock() {
+ kapp->dcopClient()->send(kdesktop_name, "KScreensaverIface", "lock()", "");
+}
+
+
+void KRootWm::slotLogout() {
+ m_pDesktop->logout(KApplication::ShutdownConfirmDefault, KApplication::ShutdownTypeDefault);
+}
+
+void KRootWm::slotPopulateSessions()
+{
+ KAction *action;
+ int p;
+ DM dm;
+
+ sessionsMenu->clear();
+ action = m_actionCollection->action("newsession");
+ if (action && (p = dm.numReserve()) >= 0)
+ {
+ action->plug( sessionsMenu );
+ action->setEnabled( p );
+ action = m_actionCollection->action("lockNnewsession");
+ if (action)
+ {
+ action->plug( sessionsMenu );
+ action->setEnabled( p );
+ }
+ sessionsMenu->insertSeparator();
+ }
+ SessList sess;
+ if (dm.localSessions( sess ))
+ for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ int id = sessionsMenu->insertItem( DM::sess2Str( *it ), (*it).vt );
+ if (!(*it).vt)
+ sessionsMenu->setItemEnabled( id, false );
+ if ((*it).self)
+ sessionsMenu->setItemChecked( id, true );
+ }
+}
+
+void KRootWm::slotSessionActivated( int ent )
+{
+ if (ent > 0 && !sessionsMenu->isItemChecked( ent ))
+ DM().lockSwitchVT( ent );
+}
+
+void KRootWm::slotNewSession()
+{
+ doNewSession( false );
+}
+
+void KRootWm::slotLockNNewSession()
+{
+ doNewSession( true );
+}
+
+void KRootWm::doNewSession( bool lock )
+{
+ int result = KMessageBox::warningContinueCancel(
+ m_pDesktop,
+ i18n("<p>You have chosen to open another desktop session.<br>"
+ "The current session will be hidden "
+ "and a new login screen will be displayed.<br>"
+ "An F-key is assigned to each session; "
+ "F%1 is usually assigned to the first session, "
+ "F%2 to the second session and so on. "
+ "You can switch between sessions by pressing "
+ "Ctrl, Alt and the appropriate F-key at the same time. "
+ "Additionally, the KDE Panel and Desktop menus have "
+ "actions for switching between sessions.</p>")
+ .arg(7).arg(8),
+ i18n("Warning - New Session"),
+ KGuiItem(i18n("&Start New Session"), "fork"),
+ ":confirmNewSession",
+ KMessageBox::PlainCaption | KMessageBox::Notify);
+
+ if (result==KMessageBox::Cancel)
+ return;
+
+ if (lock)
+ slotLock();
+
+ DM().startReserve();
+}
+
+void KRootWm::slotMenuItemActivated(int /* item */ )
+{
+}
+
+#include "krootwm.moc"
diff --git a/kdesktop/krootwm.h b/kdesktop/krootwm.h
new file mode 100644
index 000000000..9231b4bb6
--- /dev/null
+++ b/kdesktop/krootwm.h
@@ -0,0 +1,175 @@
+/*
+ * krootwm.h Part of the KDE project.
+ *
+ * Copyright (C) 1997 Matthias Ettrich
+ * (C) 1997 Torben Weis, weis@kde.org
+ * (C) 1998 S.u.S.E, weis@suse.de
+ *
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __krootwm_h__
+#define __krootwm_h__
+
+#include <qpixmap.h>
+#include <qobject.h>
+
+// we need Window but do not want to include X.h since it
+// #defines way too many constants
+typedef unsigned long XID;
+typedef XID Window;
+
+class KMenuBar;
+class KDesktop;
+class QPopupMenu;
+class KCMultiDialog;
+class KNewMenu;
+class KWinModule;
+class KBookmarkMenu;
+class KHelpMenu;
+class KActionCollection;
+class KActionMenu;
+class KWindowListMenu;
+
+enum {
+ ITEM_HELP=100,
+ ITEM_PASTE,
+ ITEM_EXECUTE,
+ ITEM_CONFIGURE_BACKGROUND,
+ ITEM_CONFIGURE_ICONS,
+ ITEM_UNCLUTTER_WINDOWS,
+ ITEM_CASCADE_WINDOWS,
+ ITEM_ARRANGE_ICONS,
+ ITEM_LOCK_SCREEN,
+ ITEM_LOGOUT
+};
+
+/**
+ * This class is the handler for the menus (root popup menu and desktop menubar)
+ */
+class KRootWm: public QObject {
+ Q_OBJECT
+
+public:
+ KRootWm(KDesktop*);
+ ~KRootWm();
+
+ void mousePressed( const QPoint& _global, int _button );
+ bool hasLeftButtonMenu() { return leftButtonChoice != NOTHING; }
+
+ /**
+ * Return the unique KRootWm instance
+ */
+ static KRootWm * self() { return s_rootWm; }
+
+ /**
+ * share this with desktop.cc
+ */
+ KNewMenu * newMenu() const { return menuNew; }
+
+ /**
+ * The position of the (usually RMB) click that opened the 'desktop' menu
+ */
+ QPoint desktopMenuPosition() const { return m_desktopMenuPosition; }
+
+ /**
+ * Read and apply configuration
+ */
+ void initConfig();
+
+ /**
+ * List of config modules used by Configure Desktop
+ */
+ static QStringList configModules();
+
+public slots:
+ void slotArrangeByNameCS();
+ void slotArrangeByNameCI();
+ void slotArrangeBySize();
+ void slotArrangeByType();
+ void slotArrangeByDate();
+ void slotLineupIconsHoriz();
+ void slotLineupIconsVert();
+ void slotLineupIcons();
+ void slotRefreshDesktop();
+ void slotConfigureDesktop();
+ void slotToggleDirFirst( bool );
+ void slotToggleAutoAlign( bool );
+ void slotToggleLockIcons( bool );
+ void slotToggleDesktopMenu();
+ void slotUnclutterWindows();
+ void slotCascadeWindows();
+ void slotWindowList();
+ void slotLock();
+ void slotLogout();
+ void slotSwitchUser();
+ void slotPopulateSessions();
+ void slotSessionActivated( int );
+ void slotNewSession();
+ void slotLockNNewSession();
+
+private:
+ KDesktop* m_pDesktop;
+
+ // The five root menus :
+ KWindowListMenu* windowListMenu;
+ QPopupMenu* desktopMenu;
+ // the appMenu is (will be) provided by kicker
+ QPopupMenu* customMenu1;
+ QPopupMenu* customMenu2;
+ KCMultiDialog* m_configDialog;
+
+ // Configuration for the root menus :
+ typedef enum { NOTHING = 0, WINDOWLISTMENU, DESKTOPMENU, APPMENU, CUSTOMMENU1, CUSTOMMENU2, BOOKMARKSMENU, SESSIONSMENU } menuChoice;
+ menuChoice leftButtonChoice;
+ menuChoice middleButtonChoice;
+ menuChoice rightButtonChoice;
+
+ KNewMenu* menuNew;
+ KActionMenu* bookmarks;
+ KBookmarkMenu* bookmarkMenu;
+ KActionCollection * m_actionCollection;
+ QPoint m_desktopMenuPosition;
+
+ void activateMenu( menuChoice choice, const QPoint& global );
+ void buildMenus();
+
+ bool m_bShowMenuBar;
+ bool m_bGlobalMenuBar;
+ bool m_bInit;
+ bool m_bDesktopEnabled;
+ KMenuBar *menuBar;
+
+ QPopupMenu *file;
+ QPopupMenu *desk;
+ KHelpMenu *help;
+
+ QPixmap defaultPixmap;
+
+ void doNewSession( bool lock );
+ QPopupMenu *sessionsMenu;
+
+ static KRootWm * s_rootWm;
+
+
+private slots:
+
+ void slotMenuItemActivated(int);
+ void slotFileNewAboutToShow();
+ void slotWindowListAboutToShow();
+ void slotConfigClosed();
+};
+
+#endif
diff --git a/kdesktop/kshadowengine.cpp b/kdesktop/kshadowengine.cpp
new file mode 100644
index 000000000..12d0319d3
--- /dev/null
+++ b/kdesktop/kshadowengine.cpp
@@ -0,0 +1,194 @@
+/* This file is proposed to be part of the KDE libraries.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow
+ * algorithm (currently used)
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kshadowengine.h"
+#include <qcolor.h>
+#include "kshadowsettings.h"
+
+KShadowEngine::KShadowEngine() :
+ m_shadowSettings( new KShadowSettings )
+{
+}
+
+KShadowEngine::~KShadowEngine()
+{
+ delete m_shadowSettings;
+}
+
+KShadowEngine::KShadowEngine(KShadowSettings *fx) :
+ m_shadowSettings(0L)
+{
+ setShadowSettings(fx);
+}
+
+
+void KShadowEngine::setShadowSettings(KShadowSettings *fx)
+{
+ delete m_shadowSettings;
+
+ m_shadowSettings = fx;
+}
+
+KShadowSettings *KShadowEngine::shadowSettings()
+{
+ return m_shadowSettings;
+}
+
+QImage KShadowEngine::makeShadow(const QPixmap& textPixmap, const QColor &bgColor)
+{
+ QImage result;
+
+ // create a new image for for the shaddow
+ int w = textPixmap.width();
+ int h = textPixmap.height();
+
+ // avoid calling these methods for every pixel
+ int bgRed = bgColor.red();
+ int bgGreen = bgColor.green();
+ int bgBlue = bgColor.blue();
+
+ int thick = m_shadowSettings->thickness() >> 1;
+
+ double alphaShadow;
+
+ /*
+ * This is the source pixmap
+ */
+ QImage img = textPixmap.convertToImage().convertDepth(32);
+
+ /*
+ * Resize the image if necessary
+ */
+ if ((result.width() != w) || (result.height() != h))
+ {
+ result.create(w, h, 32);
+ }
+
+ result.fill(0); // all black
+ result.setAlphaBuffer(true);
+
+ for (int i = thick; i < w - thick; i++)
+ {
+ for (int j = thick; j < h - thick; j++)
+ {
+ switch (m_shadowSettings->algorithm())
+ {
+ case KShadowSettings::DoubleLinearDecay:
+ alphaShadow = doubleLinearDecay(img, i, j);
+ break;
+ case KShadowSettings::RadialDecay:
+ alphaShadow = radialDecay(img, i, j);
+ break;
+ case KShadowSettings::NoDecay:
+ alphaShadow = noDecay(img, i, j);
+ break;
+ case KShadowSettings::DefaultDecay:
+ default:
+ alphaShadow = defaultDecay(img, i, j);
+ }
+
+ alphaShadow = (alphaShadow > m_shadowSettings->maxOpacity()) ? m_shadowSettings->maxOpacity() : alphaShadow;
+
+ // update the shadow's i,j pixel.
+ result.setPixel(i,j, qRgba(bgRed, bgGreen , bgBlue, (int) alphaShadow));
+ }
+ }
+ return result;
+}
+
+// Multiplication factor for pixels directly above, under, or next to the text
+#define AXIS_FACTOR 2.0
+// Multiplication factor for pixels diagonal to the text
+#define DIAGONAL_FACTOR 1.0
+
+double KShadowEngine::defaultDecay(QImage& source, int i, int j)
+{
+ if ((i < 1) || (j < 1) || (i > source.width() - 2) || (j > source.height() - 2))
+ return 0;
+
+ double alphaShadow;
+ alphaShadow =(qGray(source.pixel(i-1,j-1)) * DIAGONAL_FACTOR +
+ qGray(source.pixel(i-1,j )) * AXIS_FACTOR +
+ qGray(source.pixel(i-1,j+1)) * DIAGONAL_FACTOR +
+ qGray(source.pixel(i ,j-1)) * AXIS_FACTOR +
+ 0 +
+ qGray(source.pixel(i ,j+1)) * AXIS_FACTOR +
+ qGray(source.pixel(i+1,j-1)) * DIAGONAL_FACTOR +
+ qGray(source.pixel(i+1,j )) * AXIS_FACTOR +
+ qGray(source.pixel(i+1,j+1)) * DIAGONAL_FACTOR) / m_shadowSettings->multiplicationFactor();
+
+ return alphaShadow;
+}
+
+double KShadowEngine::doubleLinearDecay(QImage& source, int i, int j)
+{
+ //printf("img: %p, %d %d\n", (char *) &source, i, j);
+ return defaultDecay( source, i, j ); // for now
+}
+
+double KShadowEngine::radialDecay(QImage& source, int i, int j)
+{
+ //printf("img: %p, %d %d\n", (char *) &source, i, j);
+ return defaultDecay( source, i, j ); // for now
+}
+
+double KShadowEngine::noDecay(QImage& source, int i, int j)
+{
+ // create a new image for for the shaddow
+ int w = source.width();
+ int h = source.height();
+ int sx, sy;
+ //int thick = m_shadowSettings->thickness() >> 1;
+
+ double alphaShadow = 0;
+ double opacity = 0;
+ for (int k = 1; k <= m_shadowSettings->thickness(); k++) {
+ /* Generate a shadow THICKNESS pixels thicker
+ * on either side than the text image. Ensure
+ * that i +/- k and j +/- k are within the
+ * bounds of the text pixmap.
+ */
+ opacity = 0;
+ for (int l = -k; l <= k; l++) {
+ if (i < k)
+ sx = 0;
+ else if (i >= w - k)
+ sx = w - 1;
+ else
+ sx = i + l;
+
+ for (int m = -k; m <= k; m++) {
+ if (j < k)
+ sy = 0;
+ else if (j >= h - k)
+ sy = h - 1;
+ else
+ sy = j + m;
+
+ opacity += qGray(source.pixel(sx, sy));
+ }
+ }
+ alphaShadow += opacity / m_shadowSettings->multiplicationFactor();
+ }
+ return alphaShadow;
+}
diff --git a/kdesktop/kshadowengine.h b/kdesktop/kshadowengine.h
new file mode 100644
index 000000000..3649ea3f4
--- /dev/null
+++ b/kdesktop/kshadowengine.h
@@ -0,0 +1,113 @@
+/* This file is proposed to be part of the KDE libraries.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Bernardo Hung <deciare@gta.igs.net> for the enhanced shadow
+ * algorithm (currently used)
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FX_SHADOW
+#define __FX_SHADOW
+
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qcolor.h>
+
+class KShadowSettings;
+
+/**
+ * This class implements the shadow algorithm(s). It uses a FxData
+ * object for its parameters. Note that the shadow algorithm is using the
+ * luminosity of the original pixmap for the shadow one.
+ * @see KShadowSettings
+ * @author laur.ivan@corvil.com
+ * @since 3.2
+ */
+class KShadowEngine
+{
+ public:
+ /// Creates a new shadow engine.
+ KShadowEngine();
+
+ ~KShadowEngine();
+
+ /**
+ * Creates a new shadow engine.
+ * @param fx the shadow settings object with the configuration. The Shadow
+ * Engine will own this object and also delete it. Must
+ * be heap-allocated
+ */
+ KShadowEngine(KShadowSettings *fx);
+
+ /**
+ * Set the KShadowSettings object.
+ * @param fx the shadow settings object with the configuration. The Shadow
+ * Engine will own this object and also delete it. Must
+ * be heap-allocated.
+ */
+ void setShadowSettings(KShadowSettings *fx);
+
+ /**
+ * Get the current KShadowSettings.
+ * @param the current shadow settings
+ */
+ KShadowSettings *shadowSettings();
+
+ /**
+ * Make shadow!
+ *
+ * textPixmap is the original pixmap where a (white) text is drawn.
+ * bgColor is the color used for the shadow.
+ * @param textPixmap the pixmap of the text
+ * @param bgColor the background color
+ * @return the resulting image
+ */
+ QImage makeShadow(const QPixmap& textPixmap, const QColor &bgColor);
+
+ private:
+ // No static objects in libs, and no static deleters in kdefx...
+ //static KShadowSettings s_defaultShadowSettings;
+
+ KShadowSettings *m_shadowSettings;
+
+ /*
+ * a simple algorithm with 3 pixels thickness
+ */
+ double defaultDecay(QImage& source, int x, int y);
+
+ /*
+ * a slower algorithm where the influence of a pixel
+ * is qGray(px)/(abs(dx) + abs(dy) +1).
+ */
+ double doubleLinearDecay(QImage& source, int x, int y);
+
+ /*
+ * a very slow algorithm where the influence of a pixel
+ * is qGray(px)/(sqrt(sqr(dx) + sqr(dy)) +1).
+ */
+ double radialDecay(QImage& source, int x, int y);
+
+ /*
+ * a nice/fast algorithm proposed by Bernardo Hung
+ */
+ double noDecay(QImage& source, int x, int y);
+
+ void *d;
+};
+
+#endif
diff --git a/kdesktop/kshadowsettings.cpp b/kdesktop/kshadowsettings.cpp
new file mode 100644
index 000000000..9c935d30f
--- /dev/null
+++ b/kdesktop/kshadowsettings.cpp
@@ -0,0 +1,182 @@
+/* This file is proposed to be part of the KDE libraries.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include "kshadowsettings.h"
+
+KShadowSettings::KShadowSettings()
+{
+ // init the components with some default values
+ setDefaults();
+}
+
+// load/save methods
+void KShadowSettings::fromString(const QString &val)
+{
+ setOffsetX(val.section(',', OFFSET_X, OFFSET_X).toInt());
+ setOffsetY(val.section(',', OFFSET_Y, OFFSET_Y).toInt());
+ setMultiplicationFactor(val.section(',', MULTIPLICATION_FACTOR, MULTIPLICATION_FACTOR).toDouble());
+ setMaxOpacity(val.section(',', MAX_OPACITY, MAX_OPACITY).toDouble());
+ setThickness(val.section(',', THICKNESS, THICKNESS).toInt());
+ setAlgorithm((Algorithm) val.section(',', ALGORITHM, ALGORITHM).toInt());
+ setSelectionType((SelectionType)val.section(',', SELECTION_TYPE, SELECTION_TYPE).toInt());
+}
+
+QString KShadowSettings::toString() const
+{
+ QString result;
+ result.sprintf("%d,%d,%f,%f,%d,%d,%d",
+ offsetX(),
+ offsetY(),
+ multiplicationFactor(),
+ maxOpacity(),
+ thickness(),
+ (int)algorithm(),
+ (int)selectionType());
+ return result;
+}
+
+//***********************************
+// get methods
+//***********************************
+
+/**
+ * Returns the decay algorithm to be used (see the alg. enumeration in the .h)
+ */
+KShadowSettings::Algorithm KShadowSettings::algorithm() const
+{
+ return _algorithm;
+}
+
+/**
+ * Returns a multiplication facor used to average the resulted data
+ */
+double KShadowSettings::multiplicationFactor() const
+{
+ return _multiplicationFactor;
+}
+
+/**
+ * Returns the max opacity allowed (0 = transparent, 255 = opaque)
+ */
+double KShadowSettings::maxOpacity() const
+{
+ return _maxOpacity;
+}
+
+/**
+ * Returns the Y offset (0 is centered on text)
+ */
+int KShadowSettings::offsetX() const
+{
+ return _offsetX;
+}
+
+/**
+ * Returns the Y offset (0 is centered on text)
+ */
+int KShadowSettings::offsetY() const
+{
+ return _offsetY;
+}
+
+/**
+ * Returns the thickness. Used by the KShadow algorithm
+ */
+int KShadowSettings::thickness() const
+{
+ return _thickness;
+}
+
+/**
+ * Returns the selection type
+ */
+KShadowSettings::SelectionType KShadowSettings::selectionType() const
+{
+ return _selectionType;
+}
+
+// set methods
+/**
+ * set the default parameters
+ */
+void KShadowSettings::setDefaults()
+{
+ fromString(DEFAULT_SHADOW_CONFIGURATION);
+}
+
+
+/**
+ * Set the algorithm
+ */
+void KShadowSettings::setAlgorithm(Algorithm val)
+{
+ _algorithm = val;
+}
+
+/**
+ * Set the multiplication factor
+ */
+void KShadowSettings::setMultiplicationFactor(double val)
+{
+ _multiplicationFactor = val;
+}
+
+/**
+ * Set the max. opacity
+ */
+void KShadowSettings::setMaxOpacity(double val)
+{
+ _maxOpacity = val;
+}
+
+/**
+ * Set the X offset of the shadow
+ */
+void KShadowSettings::setOffsetX(int val)
+{
+ _offsetX = val;
+}
+
+/**
+ * Set the Y offset of the shadow
+ */
+void KShadowSettings::setOffsetY(int val)
+{
+ _offsetY = val;
+}
+
+/**
+ * Set the shadow thickness
+ */
+void KShadowSettings::setThickness(int val)
+{
+ _thickness = val;
+}
+
+/**
+ * Set the selection type
+ */
+void KShadowSettings::setSelectionType(SelectionType val)
+{
+ _selectionType = val;
+}
diff --git a/kdesktop/kshadowsettings.h b/kdesktop/kshadowsettings.h
new file mode 100644
index 000000000..9b707a853
--- /dev/null
+++ b/kdesktop/kshadowsettings.h
@@ -0,0 +1,234 @@
+/* This file is proposed to be part of the KDE libraries.
+ * Copyright (C) 2003 Laur Ivan <laurivan@eircom.net>
+ *
+ * Many thanks to:
+ * - Tim Jansen <tim@tjansen.de> for the API updates and fixes.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __FX_DATA
+#define __FX_DATA
+
+#define SHADOW_CONFIG_ENTRY QString("ShadowParameters")
+#define SHADOW_TEXT_COLOR QString("ShadowTextColor")
+#define SHADOW_TEXT_BACKGROUND QString("ShadowTextBackground")
+
+// fallback configuration string
+#define DEFAULT_SHADOW_CONFIGURATION QString("0,0,4.0,120.0,2,1,1,0,0,0")
+
+/**
+ * This class is the implementation of a structure for the
+ * various parameters required by the shadow class.
+ *
+ * One may afford this implementation since the shadow class is
+ * designed to be used as singleton for an application.
+ * @see KShadowEngine
+ * @author laur.ivan@corvil.com
+ * @since 3.2
+ */
+class KShadowSettings
+{
+ public:
+ /**
+ * Specifies the order of the options.
+ * @see fromString
+ */
+ enum ConfigurationOrder
+ {
+ OFFSET_X = 0,
+ OFFSET_Y = OFFSET_X + 1,
+ MULTIPLICATION_FACTOR = OFFSET_Y + 1,
+ MAX_OPACITY = MULTIPLICATION_FACTOR + 1,
+ THICKNESS = MAX_OPACITY + 1,
+ ALGORITHM = THICKNESS + 1,
+ SELECTION_TYPE = ALGORITHM + 1
+ };
+
+ public:
+ /**
+ * The algorithm used.
+ */
+ enum Algorithm
+ {
+ DefaultDecay = 1, ///< the default AXIS/DIAGONAL_FACTOR based alg
+ DoubleLinearDecay, ///< decay factor is 1/dx+dy
+ RadialDecay, ///< decay factor is 1/sqrt(dx*dx + dy*dy)
+ NoDecay ///< decay factor is 1 always
+ };
+
+ /**
+ * The selected method used.
+ */
+ enum SelectionType
+ {
+ InverseVideoOnSelection = 0, ///< when selected, the halo is on I/Video
+ SelectionColorsOnSelection ///< the halo is made w/ selected colors
+ };
+
+ /**
+ * The default constructor.
+ * Creates an object with default settings for all the variabless.
+ */
+ KShadowSettings();
+
+ // load/save methods
+ /**
+ * Loads the configuration from a string.
+ * @param the string to load from (comma-separated values)
+ * @see ConfigurationOrder
+ */
+ virtual void fromString(const QString &s);
+ /**
+ * Saves the configuration to a string.
+ * @return the configuration (comma-separated values)
+ * @see ConfigurationOrder
+ */
+ virtual QString toString() const;
+
+ // get methods
+ /**
+ * Returns the x offset of the shadow.
+ * @return the x offset
+ */
+ int offsetX() const;
+
+ /**
+ * Returns the y offset of the shadow.
+ * @return the y offset
+ */
+ int offsetY() const;
+
+ /**
+ * Returns the multiplication factor.
+ * @return the multiplication factor
+ */
+ double multiplicationFactor() const;
+
+ /**
+ * Returns the maximum opacity of the shadow.
+ * @return the maximum opacity
+ */
+ double maxOpacity() const;
+
+ /**
+ * Returns the thickness.
+ * @return the thickness
+ */
+ int thickness() const;
+
+ /**
+ * Returns the used algorithm.
+ * @return the algorithm used
+ */
+ Algorithm algorithm() const;
+
+ /**
+ * Returns the selection type used.
+ * @return the selection type
+ */
+ SelectionType selectionType() const;
+
+ // set methods
+ /**
+ * Sets default values.
+ */
+ virtual void setDefaults();
+
+ /**
+ * Sets the used algorithm.
+ * @param a the algorithm used
+ */
+ virtual void setAlgorithm(Algorithm a);
+
+ /**
+ * Sets the multiplication factor.
+ * @param mf the multiplication factor
+ */
+ virtual void setMultiplicationFactor(double mf);
+
+ /**
+ * Sets the maximum opacity of the shadow.
+ * @param mo the maximum opacity
+ */
+ virtual void setMaxOpacity(double mo);
+
+ /**
+ * Sets the x offset of the shadow.
+ * @param x the x offset
+ */
+ virtual void setOffsetX(int x);
+
+ /**
+ * Sets the y offset of the shadow.
+ * @param y the y offset
+ */
+ virtual void setOffsetY(int y);
+
+ /**
+ * Sets the thickness.
+ * @param t the thickness
+ */
+ virtual void setThickness(int t);
+
+ /**
+ * Sets the selection type used.
+ * @param s the selection type
+ */
+ virtual void setSelectionType(SelectionType s);
+
+ private:
+
+ /*
+ * The employed algorithm (see fxshadow.h)
+ */
+ Algorithm _algorithm;
+
+ /**
+ * This is the multiplication factor for the resulted shadow
+ */
+ double _multiplicationFactor;
+
+ /**
+ * The maximum permitted opacity for the shadow
+ */
+ double _maxOpacity;
+
+ /*
+ * offsetX and offsetY are the x/y offsets of the shadow with
+ * the mention that 0,0 is a centered shadow.
+ */
+ int _offsetX;
+ int _offsetY;
+
+ /*
+ * The shadow thickness:
+ * shadow is this many pixels thicker than the text.
+ */
+ int _thickness;
+
+ /*
+ * If the value is InverseVideoOnSelection, then the fg/bg
+ * colours are swapped when the element is selected.
+ * Otherwise, the selected fg/bg colors are used for text
+ * as well
+ */
+ SelectionType _selectionType;
+
+ void *d;
+};
+
+
+#endif
diff --git a/kdesktop/kwebdesktop/Makefile.am b/kdesktop/kwebdesktop/Makefile.am
new file mode 100644
index 000000000..def6fa938
--- /dev/null
+++ b/kdesktop/kwebdesktop/Makefile.am
@@ -0,0 +1,15 @@
+
+INCLUDES= $(all_includes)
+LDADD = $(LIB_KHTML)
+
+bin_PROGRAMS = kwebdesktop
+
+METASOURCES = AUTO
+
+kwebdesktop_SOURCES = kwebdesktop.cpp kwebdesktopsettings.kcfgc
+kwebdesktop_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+kdesktop_kwebdesktop_data_DATA = kwebdesktop.desktop
+kdesktop_kwebdesktop_datadir = $(kde_datadir)/kdesktop/programs
+
+kde_kcfg_DATA = kwebdesktop.kcfg
diff --git a/kdesktop/kwebdesktop/kwebdesktop.cpp b/kdesktop/kwebdesktop/kwebdesktop.cpp
new file mode 100644
index 000000000..e7010f06d
--- /dev/null
+++ b/kdesktop/kwebdesktop/kwebdesktop.cpp
@@ -0,0 +1,191 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Idea by Gael Duval
+// Implementation by David Faure
+
+#include <config.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kurifilter.h>
+#include <kio/job.h>
+
+#include <qscrollview.h>
+#include "kwebdesktop.h"
+#include <kmimetype.h>
+#include <kparts/componentfactory.h>
+#include "kwebdesktopsettings.h"
+
+#include "kwebdesktop.moc"
+
+static KCmdLineOptions options[] =
+{
+ { "+width", I18N_NOOP("Width of the image to create"), 0 },
+ { "+height", I18N_NOOP("Height of the image to create"), 0 },
+ { "+file", I18N_NOOP("File sname where to dump the output in png format"), 0 },
+ { "+[URL]", I18N_NOOP("URL to open (if not specified, it is read from kwebdesktoprc)"), 0 },
+ KCmdLineLastOption
+};
+
+KWebDesktopRun::KWebDesktopRun( KWebDesktop* webDesktop, const KURL & url )
+ : m_webDesktop(webDesktop), m_url(url)
+{
+ kdDebug() << "KWebDesktopRun::KWebDesktopRun starting get" << endl;
+ KIO::Job * job = KIO::get(m_url, false, false);
+ connect( job, SIGNAL( result( KIO::Job *)),
+ this, SLOT( slotFinished(KIO::Job *)));
+ connect( job, SIGNAL( mimetype( KIO::Job *, const QString &)),
+ this, SLOT( slotMimetype(KIO::Job *, const QString &)));
+}
+
+void KWebDesktopRun::slotMimetype( KIO::Job *job, const QString &_type )
+{
+ KIO::SimpleJob *sjob = static_cast<KIO::SimpleJob *>(job);
+ // Update our URL in case of a redirection
+ m_url = sjob->url();
+ QString type = _type; // necessary copy if we plan to use it
+ sjob->putOnHold();
+ kdDebug() << "slotMimetype : " << type << endl;
+
+ KParts::ReadOnlyPart* part = m_webDesktop->createPart( type );
+ // Now open the URL in the part
+ if ( part )
+ part->openURL( m_url );
+}
+
+void KWebDesktopRun::slotFinished( KIO::Job * job )
+{
+ // The whole point of all this is to abort silently on error
+ if (job->error())
+ {
+ kdDebug() << job->errorString() << endl;
+ kapp->exit(1);
+ }
+}
+
+
+int main( int argc, char **argv )
+{
+ KAboutData data( "kwebdesktop", I18N_NOOP("KDE Web Desktop"),
+ VERSION,
+ I18N_NOOP("Displays an HTML page as the background of the desktop"),
+ KAboutData::License_GPL,
+ "(c) 2000, David Faure <faure@kde.org>" );
+ data.addAuthor( "David Faure", I18N_NOOP("developer and maintainer"), "faure@kde.org" );
+
+ KCmdLineArgs::init( argc, argv, &data );
+
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KApplication app;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if ( args->count() != 3 && args->count() != 4 )
+ {
+ args->usage();
+ return 1;
+ }
+ const int width = QCString(args->arg(0)).toInt();
+ const int height = QCString(args->arg(1)).toInt();
+ QCString imageFile = args->arg(2);
+ QString url;
+ if (args->count() == 4)
+ url = QString::fromLocal8Bit(args->arg(3));
+
+ KWebDesktop *webDesktop = new KWebDesktop( 0, imageFile, width, height );
+
+ if (url.isEmpty())
+ url = KWebDesktopSettings::uRL();
+ // Apply uri filter
+ KURIFilterData uridata = url;
+ KURIFilter::self()->filterURI( uridata );
+ KURL u = uridata.uri();
+
+ // Now start getting, to ensure mimetype and possible connection
+ KWebDesktopRun * run = new KWebDesktopRun( webDesktop, u );
+
+ int ret = app.exec();
+
+ KIO::SimpleJob::removeOnHold(); // Kill any slave that was put on hold.
+ delete webDesktop;
+ delete run;
+ //khtml::Cache::clear();
+
+ return ret;
+}
+
+void KWebDesktop::slotCompleted()
+{
+ kdDebug() << "KWebDesktop::slotCompleted" << endl;
+ // Dump image to m_imageFile
+ QPixmap snapshot = QPixmap::grabWidget( m_part->widget() );
+ snapshot.save( m_imageFile, "PNG" );
+ // And terminate the app.
+ kapp->quit();
+}
+
+KParts::ReadOnlyPart* KWebDesktop::createPart( const QString& mimeType )
+{
+ delete m_part;
+ m_part = 0;
+
+ KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
+ if ( !mime || mime == KMimeType::defaultMimeTypePtr() )
+ return 0;
+ if ( mime->is( "text/html" ) || mime->is( "text/xml" ) || mime->is( "application/xhtml+xml" ) )
+ {
+ KHTMLPart* htmlPart = new KHTMLPart;
+ htmlPart->widget()->resize(m_width,m_height);
+
+ htmlPart->setMetaRefreshEnabled(false);
+ htmlPart->setJScriptEnabled(false);
+ htmlPart->setJavaEnabled(false);
+
+ ((QScrollView *)htmlPart->widget())->setHScrollBarMode( QScrollView::AlwaysOff );
+ ((QScrollView *)htmlPart->widget())->setVScrollBarMode( QScrollView::AlwaysOff );
+
+ connect( htmlPart, SIGNAL( completed() ), this, SLOT( slotCompleted() ) );
+ m_part = htmlPart;
+ } else {
+ // Try to find an appropriate viewer component
+ m_part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>
+ ( mimeType, QString::null, 0, 0, this, 0 );
+ if ( !m_part )
+ kdWarning() << "No handler found for " << mimeType << endl;
+ else {
+ kdDebug() << "Loaded " << m_part->className() << endl;
+ connect( m_part, SIGNAL( completed() ),
+ this, SLOT( slotCompleted() ) );
+ }
+ }
+ if ( m_part ) {
+ connect( m_part, SIGNAL( canceled(const QString &) ),
+ this, SLOT( slotCompleted() ) );
+ }
+ return m_part;
+}
+
+KWebDesktop::~KWebDesktop()
+{
+ delete m_part;
+}
diff --git a/kdesktop/kwebdesktop/kwebdesktop.desktop b/kdesktop/kwebdesktop/kwebdesktop.desktop
new file mode 100644
index 000000000..747140f15
--- /dev/null
+++ b/kdesktop/kwebdesktop/kwebdesktop.desktop
@@ -0,0 +1,80 @@
+[KDE Desktop Program]
+Comment=KDE Web Desktop
+Comment[af]=KDE Web Werkskerm
+Comment[ar]=سطح المكتب KDE للشبكة
+Comment[az]=KDE Veb Masa üstü
+Comment[be]=Працоўны стол Web
+Comment[bn]=কে.ডি.ই. ওয়েব ডেস্কটপ
+Comment[br]=Burev gwiad KDE
+Comment[bs]=KDE Web radna površina
+Comment[ca]=Escriptori Web KDE
+Comment[cs]=Aktivní plocha KDE
+Comment[csb]=Pùlt w sztélu sécë WWW
+Comment[cy]=Penbwrdd Gwe KDE
+Comment[da]=KDE-net-desktop
+Comment[de]=KDE-Web-Arbeitsfläche
+Comment[el]=Επιφάνεια εργασίας Ιστού του KDE
+Comment[eo]=KDEa TTT-tabulo
+Comment[es]=Escritorio Web para KDE
+Comment[et]=KDE veebitöölaud
+Comment[eu]=KDE web mahaigaina
+Comment[fa]=رومیزی وب KDE
+Comment[fi]=KDE:n web-työpöytä
+Comment[fr]=Bureau web de KDE
+Comment[fy]=KDE Web Buroblêd
+Comment[gl]=Escritório Web de KDE
+Comment[he]=שולחן העבודה האינטרנטי של KDE
+Comment[hi]=केडीई वेब डेस्कटॉप
+Comment[hr]=KDE web radna površina
+Comment[hu]=KDE internetes munkaasztal
+Comment[id]=Desktop Web KDE
+Comment[is]=KDE vefskjáborð
+Comment[it]=Desktop Web di KDE
+Comment[ja]=KDE ウェブデスクトップ
+Comment[ka]=KDE ვებ სამუშაო დაფა
+Comment[km]=ផ្ទៃតុ​បណ្ដាញ KDE
+Comment[lo]=ພື້ນທີ່ທຳງານບົນເວ໊ບ KDE
+Comment[lt]=KDE žiniatinklio darbastalis
+Comment[lv]=KDE Web Darbvirsma
+Comment[mk]=KDE веб-површина
+Comment[mn]=КДЭ-Вэб-Ажлын тавцан
+Comment[ms]=Desktop Web KDE
+Comment[mt]=Desktop Web KDE
+Comment[nb]=KDE nettskrivebord
+Comment[nds]=KDE-Nettschriefdisch
+Comment[ne]=KDE वेब डेस्कटप
+Comment[nl]=KDE Web Bureaublad
+Comment[nn]=KDE Vevskrivebord
+Comment[nso]=Desktop ya Web ya KDE
+Comment[oc]=BurèU Web KDE
+Comment[pa]=KDE ਵੈੱਬ ਵੇਹੜਾ
+Comment[pl]=Pulpit w stylu sieci WWW
+Comment[pt]=Ecrã Web do KDE
+Comment[pt_BR]=Área de Trabalho Web do KDE
+Comment[ro]=Ecran web pentru KDE
+Comment[rw]=KDE Ibiro Rubugamakuru
+Comment[se]=KDE Web-čállinbeavdi
+Comment[sk]=KDE Web pracovná plocha
+Comment[sl]=Spletno namizje KDE
+Comment[sr]=KDE веб радна површина
+Comment[sr@Latn]=KDE veb radna površina
+Comment[sv]=KDE-webbskrivbord
+Comment[ta]=KDE வலை மேல்மேசை
+Comment[te]=కెడిఈ వెబ్ రంగస్థలం
+Comment[tg]=Мизи кории KDE Вэб
+Comment[th]=พื้นที่ทำงาน KDE แบบเว็บ
+Comment[tr]=KDE Web Masaüstü
+Comment[tt]=KDE Web Östäl
+Comment[uk]=Стільниця "а ля Web" для KDE
+Comment[uz]=KDE veb-ish stoli
+Comment[uz@cyrillic]=KDE веб-иш столи
+Comment[ven]=Webe ya desikithopo ya KDE
+Comment[vi]=màn hình nền kiểu trang mạng của KDE
+Comment[wa]=Sicribanne waibe KDE
+Comment[zh_CN]=KDE Web 桌面
+Comment[zh_TW]=KDE 網頁桌面
+Comment[zu]=I-Desktop ye-Web ye-KDE
+Executable=kwebdesktop
+Command=kwebdesktop %x %y %f http://www.kde.org/
+PreviewCommand=kwebdesktop %x %y %f http://www.kde.org/
+Refresh=10
diff --git a/kdesktop/kwebdesktop/kwebdesktop.h b/kdesktop/kwebdesktop/kwebdesktop.h
new file mode 100644
index 000000000..d364f8022
--- /dev/null
+++ b/kdesktop/kwebdesktop/kwebdesktop.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KWEBDESKTOP_H
+#define KWEBDESKTOP_H
+
+#include <qobject.h>
+#include <qcstring.h>
+#include <kparts/browserextension.h>
+#include <khtml_part.h>
+
+namespace KIO { class Job; }
+
+class KWebDesktop : public QObject
+{
+ Q_OBJECT
+public:
+ KWebDesktop( QObject* parent, const QCString & imageFile, int width, int height )
+ : QObject( parent ),
+ m_part( 0 ),
+ m_imageFile( imageFile ),
+ m_width( width ),
+ m_height( height ) {}
+ ~KWebDesktop();
+
+ KParts::ReadOnlyPart* createPart( const QString& mimeType );
+
+private slots:
+ void slotCompleted();
+
+private:
+ KParts::ReadOnlyPart* m_part;
+ QCString m_imageFile;
+ int m_width;
+ int m_height;
+};
+
+
+class KWebDesktopRun : public QObject
+{
+ Q_OBJECT
+public:
+ KWebDesktopRun( KWebDesktop* webDesktop, const KURL & url );
+ ~KWebDesktopRun() {}
+
+protected slots:
+ void slotMimetype( KIO::Job *job, const QString &_type );
+ void slotFinished( KIO::Job * job );
+
+private:
+ KWebDesktop* m_webDesktop;
+ KURL m_url;
+};
+
+#endif
diff --git a/kdesktop/kwebdesktop/kwebdesktop.kcfg b/kdesktop/kwebdesktop/kwebdesktop.kcfg
new file mode 100644
index 000000000..fad395a19
--- /dev/null
+++ b/kdesktop/kwebdesktop/kwebdesktop.kcfg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kwebdesktoprc" />
+ <!-- generated by KConfig XTraKtor -->
+
+ <group name="Settings">
+ <entry key="URL" type="String">
+ <default>http://www.kde.org/</default>
+ <label></label>
+ <whatsthis></whatsthis>
+ <!-- kdiconview.cc:1103 -->
+ <!-- cfg.readEntry( "URL" ) == "trash:/" ) { -->
+ </entry>
+ </group>
+
+</kcfg>
diff --git a/kdesktop/kwebdesktop/kwebdesktopsettings.kcfgc b/kdesktop/kwebdesktop/kwebdesktopsettings.kcfgc
new file mode 100644
index 000000000..6989a0071
--- /dev/null
+++ b/kdesktop/kwebdesktop/kwebdesktopsettings.kcfgc
@@ -0,0 +1,4 @@
+File=kwebdesktop.kcfg
+ClassName=KWebDesktopSettings
+Singleton=true
+Mutators=true
diff --git a/kdesktop/lock/Makefile.am b/kdesktop/lock/Makefile.am
new file mode 100644
index 000000000..4af8d4fae
--- /dev/null
+++ b/kdesktop/lock/Makefile.am
@@ -0,0 +1,24 @@
+## Makefile.am of kdebase/kdesktop/lock
+
+INCLUDES = -I.. -I$(top_srcdir)/kcheckpass -I$(top_srcdir)/kdmlib $(GLINC) $(all_includes)
+kdesktop_lock_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kdesktop_lock_LDADD = ../libkdesktopsettings.la ../../kdmlib/libdmctl.la $(LIB_KIO) $(LIB_XF86MISC) $(GLLIB)
+
+####### Files
+
+bin_PROGRAMS = kdesktop_lock
+
+kdesktop_lock_SOURCES = lockprocess.cc lockdlg.cc autologout.cc main.cc
+
+noinst_HEADERS = lockprocess.h lockdlg.h autologout.h main.h
+
+METASOURCES = AUTO
+
+lockprocess.o: ../kdesktopsettings.h
+
+####### Build rules
+
+PAM = @KSCREENSAVER_PAM_SERVICE@
+
+install-data-local:
+ -@test -n "$(DESTDIR)" || test -z "$(PAM)" || $(top_srcdir)/mkpamserv $(PAM)
diff --git a/kdesktop/lock/autologout.cc b/kdesktop/lock/autologout.cc
new file mode 100644
index 000000000..f351fe2e7
--- /dev/null
+++ b/kdesktop/lock/autologout.cc
@@ -0,0 +1,115 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 2004 Chris Howells <howells@kde.org>
+
+#include "lockprocess.h"
+#include "autologout.h"
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <dcopref.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+
+#include <qlayout.h>
+#include <qmessagebox.h>
+#include <qlabel.h>
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qdialog.h>
+#include <qprogressbar.h>
+
+#define COUNTDOWN 30
+
+AutoLogout::AutoLogout(LockProcess *parent) : QDialog(parent, "password dialog", true, WX11BypassWM)
+{
+ frame = new QFrame(this);
+ frame->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ frame->setLineWidth(2);
+
+ QLabel *pixLabel = new QLabel( frame, "pixlabel" );
+ pixLabel->setPixmap(DesktopIcon("exit"));
+
+ QLabel *greetLabel = new QLabel(i18n("<nobr><qt><b>Automatic Log Out</b></qt><nobr>"), frame);
+ QLabel *infoLabel = new QLabel(i18n("<qt>To prevent being logged out, resume using this session by moving the mouse or pressing a key.</qt>"), frame);
+
+ mStatusLabel = new QLabel("<b> </b>", frame);
+ mStatusLabel->setAlignment(QLabel::AlignCenter);
+
+ QLabel *mProgressLabel = new QLabel("Time Remaining:", frame);
+ mProgressRemaining = new QProgressBar(frame);
+ mProgressRemaining->setPercentageVisible(false);
+
+ QVBoxLayout *unlockDialogLayout = new QVBoxLayout( this );
+ unlockDialogLayout->addWidget( frame );
+
+ frameLayout = new QGridLayout(frame, 1, 1, KDialog::marginHint(), KDialog::spacingHint());
+ frameLayout->addMultiCellWidget(pixLabel, 0, 2, 0, 0, Qt::AlignCenter | Qt::AlignTop);
+ frameLayout->addWidget(greetLabel, 0, 1);
+ frameLayout->addWidget(mStatusLabel, 1, 1);
+ frameLayout->addWidget(infoLabel, 2, 1);
+ frameLayout->addWidget(mProgressLabel, 3, 1);
+ frameLayout->addWidget(mProgressRemaining, 4, 1);
+
+ // get the time remaining in seconds for the status label
+ mRemaining = COUNTDOWN * 25;
+
+ mProgressRemaining->setTotalSteps(COUNTDOWN * 25);
+
+ updateInfo(mRemaining);
+
+ mCountdownTimerId = startTimer(1000/25);
+
+ connect(qApp, SIGNAL(activity()), SLOT(slotActivity()));
+}
+
+AutoLogout::~AutoLogout()
+{
+ hide();
+}
+
+void AutoLogout::updateInfo(int timeout)
+{
+ mStatusLabel->setText(i18n("<nobr><qt>You will be automatically logged out in 1 second</qt></nobr>",
+ "<nobr><qt>You will be automatically logged out in %n seconds</qt></nobr>",
+ timeout / 25) );
+ mProgressRemaining->setProgress(timeout);
+}
+
+void AutoLogout::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mCountdownTimerId)
+ {
+ updateInfo(mRemaining);
+ --mRemaining;
+ if (mRemaining < 0)
+ {
+ logout();
+ }
+ }
+}
+
+void AutoLogout::slotActivity()
+{
+ accept();
+}
+
+void AutoLogout::logout()
+{
+ killTimers();
+ DCOPRef("ksmserver","ksmserver").send("logout", 0, 0, 0);
+}
+
+void AutoLogout::show()
+{
+ QDialog::show();
+ QApplication::flushX();
+}
+
+#include "autologout.moc"
diff --git a/kdesktop/lock/autologout.h b/kdesktop/lock/autologout.h
new file mode 100644
index 000000000..e48716575
--- /dev/null
+++ b/kdesktop/lock/autologout.h
@@ -0,0 +1,51 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+// Coypright (c) 2004 Chris Howells <howells@kde.org>
+
+#ifndef __TIMEOUT_H__
+#define __TIMEOUT_H__
+
+#include <qstringlist.h>
+
+#include <qlayout.h>
+
+class LockProcess;
+class QFrame;
+class QGridLayout;
+class QLabel;
+class QDialog;
+class QProgressBar;
+
+class AutoLogout : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AutoLogout(LockProcess *parent);
+ ~AutoLogout();
+ virtual void show();
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+
+private slots:
+ void slotActivity();
+
+private:
+ void updateInfo(int);
+ QFrame *frame;
+ QGridLayout *frameLayout;
+ QLabel *mStatusLabel;
+ int mCountdownTimerId;
+ int mRemaining;
+ QTimer countDownTimer;
+ QProgressBar *mProgressRemaining;
+ void logout();
+};
+
+#endif
+
diff --git a/kdesktop/lock/configure.in.in b/kdesktop/lock/configure.in.in
new file mode 100644
index 000000000..d5d61a5f9
--- /dev/null
+++ b/kdesktop/lock/configure.in.in
@@ -0,0 +1,37 @@
+xss_save_ldflags="$LDFLAGS"
+LDFLAGS="$X_LDFLAGS"
+
+LIB_XF86MISC=
+
+KDE_CHECK_HEADER(X11/extensions/xf86misc.h,
+ [
+ AC_CHECK_LIB(Xxf86misc,XF86MiscQueryVersion,
+ [
+ AC_DEFINE(HAVE_XF86MISC, 1, [Define if you have the xf86misc extension])
+ LIB_XF86MISC="-lXxf86misc"
+ ],
+ [], [ $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS ])
+ ],[],
+ [
+ #include <X11/Xlib.h>
+ ])
+AC_SUBST(LIB_XF86MISC)
+
+if test -n "$LIB_XF86MISC"; then
+ AC_CHECK_LIB(Xxf86misc,XF86MiscSetGrabKeysState,
+ [
+ AC_DEFINE(HAVE_XF86MISCSETGRABKEYSSTATE, 1, [Define if you have XF86MiscSetGrabKeysState()])
+ ],
+ [], [ $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS ])
+fi
+
+LDFLAGS="$xss_save_ldflags"
+
+AC_HAVE_GL(
+ [
+ AC_CHECK_LIB(GL,glXChooseVisual,
+ [
+ AC_DEFINE(HAVE_GLXCHOOSEVISUAL, 1, [Define if you have glXChooseVisual()])
+ ])
+ ],[]
+ )
diff --git a/kdesktop/lock/lockdlg.cc b/kdesktop/lock/lockdlg.cc
new file mode 100644
index 000000000..8006cf29d
--- /dev/null
+++ b/kdesktop/lock/lockdlg.cc
@@ -0,0 +1,720 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2003 Chris Howells <howells@kde.org>
+// Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+
+#include <config.h>
+
+#include "lockprocess.h"
+#include "lockdlg.h"
+
+#include <kcheckpass.h>
+#include <dmctl.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kseparator.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kdesu/defaults.h>
+#include <kpassdlg.h>
+#include <kdebug.h>
+#include <kuser.h>
+#include <dcopref.h>
+#include <kmessagebox.h>
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qmessagebox.h>
+#include <qsimplerichtext.h>
+#include <qlabel.h>
+#include <qstringlist.h>
+#include <qfontmetrics.h>
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qlistview.h>
+#include <qheader.h>
+#include <qcheckbox.h>
+
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <fixx11h.h>
+
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif
+
+#define PASSDLG_HIDE_TIMEOUT 10000
+
+//===========================================================================
+//
+// Simple dialog for entering a password.
+//
+PasswordDlg::PasswordDlg(LockProcess *parent, GreeterPluginHandle *plugin)
+ : QDialog(parent, "password dialog", true, WX11BypassWM),
+ mPlugin( plugin ),
+ mCapsLocked(-1),
+ mUnlockingFailed(false)
+{
+ frame = new QFrame( this );
+ frame->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ frame->setLineWidth( 2 );
+
+ QLabel *pixLabel = new QLabel( frame, "pixlabel" );
+ pixLabel->setPixmap(DesktopIcon("lock"));
+
+ KUser user;
+ QLabel *greetLabel = new QLabel( user.fullName().isEmpty() ?
+ i18n("<nobr><b>The session is locked</b><br>") :
+ i18n("<nobr><b>The session was locked by %1</b><br>").arg( user.fullName() ), frame );
+
+ mStatusLabel = new QLabel( "<b> </b>", frame );
+ mStatusLabel->setAlignment( QLabel::AlignCenter );
+
+ mLayoutButton = new QPushButton( frame );
+ mLayoutButton->setFlat( true );
+
+ KSeparator *sep = new KSeparator( KSeparator::HLine, frame );
+
+ mNewSessButton = new KPushButton( KGuiItem(i18n("Sw&itch User..."), "fork"), frame );
+ ok = new KPushButton( i18n("Unl&ock"), frame );
+ cancel = new KPushButton( KStdGuiItem::cancel(), frame );
+
+ greet = plugin->info->create( this, 0, this, mLayoutButton, QString::null,
+ KGreeterPlugin::Authenticate, KGreeterPlugin::ExUnlock );
+
+
+ QVBoxLayout *unlockDialogLayout = new QVBoxLayout( this );
+ unlockDialogLayout->addWidget( frame );
+
+ QHBoxLayout *layStatus = new QHBoxLayout( 0, 0, KDialog::spacingHint());
+ layStatus->addWidget( mStatusLabel );
+ layStatus->addWidget( mLayoutButton );
+
+ QHBoxLayout *layButtons = new QHBoxLayout( 0, 0, KDialog::spacingHint());
+ layButtons->addWidget( mNewSessButton );
+ layButtons->addStretch();
+ layButtons->addWidget( ok );
+ layButtons->addWidget( cancel );
+
+ frameLayout = new QGridLayout( frame, 1, 1, KDialog::marginHint(), KDialog::spacingHint() );
+ frameLayout->addMultiCellWidget( pixLabel, 0, 2, 0, 0, AlignTop );
+ frameLayout->addWidget( greetLabel, 0, 1 );
+ frameLayout->addItem( greet->getLayoutItem(), 1, 1 );
+ frameLayout->addLayout( layStatus, 2, 1 );
+ frameLayout->addMultiCellWidget( sep, 3, 3, 0, 1 );
+ frameLayout->addMultiCellLayout( layButtons, 4, 4, 0, 1 );
+
+ setTabOrder( ok, cancel );
+ setTabOrder( cancel, mNewSessButton );
+ setTabOrder( mNewSessButton, mLayoutButton );
+
+ connect(mLayoutButton, SIGNAL(clicked()), this, SLOT(layoutClicked()));
+ connect(cancel, SIGNAL(clicked()), SLOT(reject()));
+ connect(ok, SIGNAL(clicked()), SLOT(slotOK()));
+ connect(mNewSessButton, SIGNAL(clicked()), SLOT(slotSwitchUser()));
+
+ if (!DM().isSwitchable() || !kapp->authorize("switch_user"))
+ mNewSessButton->hide();
+
+ installEventFilter(this);
+
+ mFailedTimerId = 0;
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+ connect(qApp, SIGNAL(activity()), SLOT(slotActivity()) );
+
+ greet->start();
+
+ DCOPRef kxkb("kxkb", "kxkb");
+ if( !kxkb.isNull() ) {
+ layoutsList = kxkb.call("getLayoutsList");
+ QString currentLayout = kxkb.call("getCurrentLayout");
+ if( !currentLayout.isEmpty() && layoutsList.count() > 1 ) {
+ currLayout = layoutsList.find(currentLayout);
+ if (currLayout == layoutsList.end())
+ setLayoutText("err");
+ else
+ setLayoutText(*currLayout);
+ } else
+ mLayoutButton->hide();
+ } else {
+ mLayoutButton->hide(); // no kxkb running
+ }
+ capsLocked();
+}
+
+PasswordDlg::~PasswordDlg()
+{
+ hide();
+ frameLayout->removeItem( greet->getLayoutItem() );
+ delete greet;
+}
+
+void PasswordDlg::layoutClicked()
+{
+
+ if( ++currLayout == layoutsList.end() )
+ currLayout = layoutsList.begin();
+
+ DCOPRef kxkb("kxkb", "kxkb");
+ setLayoutText( kxkb.call("setLayout", *currLayout) ? *currLayout : "err" );
+
+}
+
+void PasswordDlg::setLayoutText( const QString &txt )
+{
+ mLayoutButton->setText( txt );
+ QSize sz = mLayoutButton->fontMetrics().size( 0, txt );
+ int mrg = mLayoutButton->style().pixelMetric( QStyle::PM_ButtonMargin ) * 2;
+ mLayoutButton->setFixedSize( sz.width() + mrg, sz.height() + mrg );
+}
+
+void PasswordDlg::updateLabel()
+{
+ if (mUnlockingFailed)
+ {
+ mStatusLabel->setPaletteForegroundColor(Qt::black);
+ mStatusLabel->setText(i18n("<b>Unlocking failed</b>"));
+ }
+ else
+ if (mCapsLocked)
+ {
+ mStatusLabel->setPaletteForegroundColor(Qt::red);
+ mStatusLabel->setText(i18n("<b>Warning: Caps Lock on</b>"));
+ }
+ else
+ {
+ mStatusLabel->setText("<b> </b>");
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Handle timer events.
+//
+void PasswordDlg::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == mTimeoutTimerId)
+ {
+ reject();
+ }
+ else if (ev->timerId() == mFailedTimerId)
+ {
+ killTimer(mFailedTimerId);
+ mFailedTimerId = 0;
+ // Show the normal password prompt.
+ mUnlockingFailed = false;
+ updateLabel();
+ ok->setEnabled(true);
+ cancel->setEnabled(true);
+ mNewSessButton->setEnabled( true );
+ greet->revive();
+ greet->start();
+ }
+}
+
+bool PasswordDlg::eventFilter(QObject *, QEvent *ev)
+{
+ if (ev->type() == QEvent::KeyPress || ev->type() == QEvent::KeyRelease)
+ capsLocked();
+ return false;
+}
+
+void PasswordDlg::slotActivity()
+{
+ if (mTimeoutTimerId) {
+ killTimer(mTimeoutTimerId);
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+ }
+}
+
+////// kckeckpass interface code
+
+int PasswordDlg::Reader (void *buf, int count)
+{
+ int ret, rlen;
+
+ for (rlen = 0; rlen < count; ) {
+ dord:
+ ret = ::read (sFd, (void *)((char *)buf + rlen), count - rlen);
+ if (ret < 0) {
+ if (errno == EINTR)
+ goto dord;
+ if (errno == EAGAIN)
+ break;
+ return -1;
+ }
+ if (!ret)
+ break;
+ rlen += ret;
+ }
+ return rlen;
+}
+
+bool PasswordDlg::GRead (void *buf, int count)
+{
+ return Reader (buf, count) == count;
+}
+
+bool PasswordDlg::GWrite (const void *buf, int count)
+{
+ return ::write (sFd, buf, count) == count;
+}
+
+bool PasswordDlg::GSendInt (int val)
+{
+ return GWrite (&val, sizeof(val));
+}
+
+bool PasswordDlg::GSendStr (const char *buf)
+{
+ int len = buf ? ::strlen (buf) + 1 : 0;
+ return GWrite (&len, sizeof(len)) && GWrite (buf, len);
+}
+
+bool PasswordDlg::GSendArr (int len, const char *buf)
+{
+ return GWrite (&len, sizeof(len)) && GWrite (buf, len);
+}
+
+bool PasswordDlg::GRecvInt (int *val)
+{
+ return GRead (val, sizeof(*val));
+}
+
+bool PasswordDlg::GRecvArr (char **ret)
+{
+ int len;
+ char *buf;
+
+ if (!GRecvInt(&len))
+ return false;
+ if (!len) {
+ *ret = 0;
+ return true;
+ }
+ if (!(buf = (char *)::malloc (len)))
+ return false;
+ *ret = buf;
+ return GRead (buf, len);
+}
+
+void PasswordDlg::reapVerify()
+{
+ ::close( sFd );
+ int status;
+ ::waitpid( sPid, &status, 0 );
+ if (WIFEXITED(status))
+ switch (WEXITSTATUS(status)) {
+ case AuthOk:
+ greet->succeeded();
+ accept();
+ return;
+ case AuthBad:
+ greet->failed();
+ mUnlockingFailed = true;
+ updateLabel();
+ mFailedTimerId = startTimer(1500);
+ ok->setEnabled(false);
+ cancel->setEnabled(false);
+ mNewSessButton->setEnabled( false );
+ return;
+ case AuthAbort:
+ return;
+ }
+ cantCheck();
+}
+
+void PasswordDlg::handleVerify()
+{
+ int ret;
+ char *arr;
+
+ while (GRecvInt( &ret )) {
+ switch (ret) {
+ case ConvGetBinary:
+ if (!GRecvArr( &arr ))
+ break;
+ greet->binaryPrompt( arr, false );
+ if (arr)
+ ::free( arr );
+ return;
+ case ConvGetNormal:
+ if (!GRecvArr( &arr ))
+ break;
+ greet->textPrompt( arr, true, false );
+ if (arr)
+ ::free( arr );
+ return;
+ case ConvGetHidden:
+ if (!GRecvArr( &arr ))
+ break;
+ greet->textPrompt( arr, false, false );
+ if (arr)
+ ::free( arr );
+ return;
+ case ConvPutInfo:
+ if (!GRecvArr( &arr ))
+ break;
+ if (!greet->textMessage( arr, false ))
+ static_cast< LockProcess* >(parent())->msgBox( QMessageBox::Information, QString::fromLocal8Bit( arr ) );
+ ::free( arr );
+ continue;
+ case ConvPutError:
+ if (!GRecvArr( &arr ))
+ break;
+ if (!greet->textMessage( arr, true ))
+ static_cast< LockProcess* >(parent())->msgBox( QMessageBox::Warning, QString::fromLocal8Bit( arr ) );
+ ::free( arr );
+ continue;
+ }
+ break;
+ }
+ reapVerify();
+}
+
+////// greeter plugin callbacks
+
+void PasswordDlg::gplugReturnText( const char *text, int tag )
+{
+ GSendStr( text );
+ if (text)
+ GSendInt( tag );
+ handleVerify();
+}
+
+void PasswordDlg::gplugReturnBinary( const char *data )
+{
+ if (data) {
+ unsigned const char *up = (unsigned const char *)data;
+ int len = up[3] | (up[2] << 8) | (up[1] << 16) | (up[0] << 24);
+ if (!len)
+ GSendArr( 4, data );
+ else
+ GSendArr( len, data );
+ } else
+ GSendArr( 0, 0 );
+ handleVerify();
+}
+
+void PasswordDlg::gplugSetUser( const QString & )
+{
+ // ignore ...
+}
+
+void PasswordDlg::cantCheck()
+{
+ greet->failed();
+ static_cast< LockProcess* >(parent())->msgBox( QMessageBox::Critical,
+ i18n("Cannot unlock the session because the authentication system failed to work;\n"
+ "you must kill kdesktop_lock (pid %1) manually.").arg(getpid()) );
+ greet->revive();
+}
+
+//---------------------------------------------------------------------------
+//
+// Starts the kcheckpass process to check the user's password.
+//
+void PasswordDlg::gplugStart()
+{
+ int sfd[2];
+ char fdbuf[16];
+
+ if (::socketpair(AF_LOCAL, SOCK_STREAM, 0, sfd)) {
+ cantCheck();
+ return;
+ }
+ if ((sPid = ::fork()) < 0) {
+ ::close(sfd[0]);
+ ::close(sfd[1]);
+ cantCheck();
+ return;
+ }
+ if (!sPid) {
+ ::close(sfd[0]);
+ sprintf(fdbuf, "%d", sfd[1]);
+ execlp("kcheckpass", "kcheckpass",
+#ifdef HAVE_PAM
+ "-c", KSCREENSAVER_PAM_SERVICE,
+#endif
+ "-m", mPlugin->info->method,
+ "-S", fdbuf,
+ (char *)0);
+ exit(20);
+ }
+ ::close(sfd[1]);
+ sFd = sfd[0];
+ handleVerify();
+}
+
+void PasswordDlg::gplugActivity()
+{
+ slotActivity();
+}
+
+void PasswordDlg::gplugMsgBox( QMessageBox::Icon type, const QString &text )
+{
+ QDialog dialog( this, 0, true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( &dialog );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QVBoxLayout *vbox = new QVBoxLayout( &dialog );
+ vbox->addWidget( winFrame );
+
+ QLabel *label1 = new QLabel( winFrame );
+ label1->setPixmap( QMessageBox::standardIcon( type ) );
+ QLabel *label2 = new QLabel( text, winFrame );
+ KPushButton *button = new KPushButton( KStdGuiItem::ok(), winFrame );
+ button->setDefault( true );
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+ connect( button, SIGNAL( clicked() ), SLOT( accept() ) );
+
+ QGridLayout *grid = new QGridLayout( winFrame, 2, 2, 10 );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ grid->addMultiCellWidget( button, 1,1, 0,1, Qt::AlignCenter );
+
+ static_cast< LockProcess* >(parent())->execDialog( &dialog );
+}
+
+void PasswordDlg::slotOK()
+{
+ greet->next();
+}
+
+
+void PasswordDlg::show()
+{
+ QDialog::show();
+ QApplication::flushX();
+}
+
+void PasswordDlg::slotStartNewSession()
+{
+ if (!KMessageBox::shouldBeShownContinue( ":confirmNewSession" )) {
+ DM().startReserve();
+ return;
+ }
+
+ killTimer(mTimeoutTimerId);
+ mTimeoutTimerId = 0;
+
+ QDialog *dialog = new QDialog( this, "warnbox", true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( dialog );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QVBoxLayout *vbox = new QVBoxLayout( dialog );
+ vbox->addWidget( winFrame );
+
+ QLabel *label1 = new QLabel( winFrame );
+ label1->setPixmap( QMessageBox::standardIcon( QMessageBox::Warning ) );
+ QString qt_text =
+ i18n("You have chosen to open another desktop session "
+ "instead of resuming the current one.<br>"
+ "The current session will be hidden "
+ "and a new login screen will be displayed.<br>"
+ "An F-key is assigned to each session; "
+ "F%1 is usually assigned to the first session, "
+ "F%2 to the second session and so on. "
+ "You can switch between sessions by pressing "
+ "Ctrl, Alt and the appropriate F-key at the same time. "
+ "Additionally, the KDE Panel and Desktop menus have "
+ "actions for switching between sessions.")
+ .arg(7).arg(8);
+ QLabel *label2 = new QLabel( qt_text, winFrame );
+ KPushButton *okbutton = new KPushButton( KGuiItem(i18n("&Start New Session"), "fork"), winFrame );
+ okbutton->setDefault( true );
+ connect( okbutton, SIGNAL( clicked() ), dialog, SLOT( accept() ) );
+ KPushButton *cbutton = new KPushButton( KStdGuiItem::cancel(), winFrame );
+ connect( cbutton, SIGNAL( clicked() ), dialog, SLOT( reject() ) );
+
+ QBoxLayout *mbox = new QVBoxLayout( winFrame, KDialog::marginHint(), KDialog::spacingHint() );
+
+ QGridLayout *grid = new QGridLayout( mbox, 2, 2, 2 * KDialog::spacingHint() );
+ grid->setMargin( KDialog::marginHint() );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ QCheckBox *cb = new QCheckBox( i18n("&Do not ask again"), winFrame );
+ grid->addMultiCellWidget( cb, 1,1, 0,1 );
+
+ QBoxLayout *hbox = new QHBoxLayout( mbox, KDialog::spacingHint() );
+ hbox->addStretch( 1 );
+ hbox->addWidget( okbutton );
+ hbox->addStretch( 1 );
+ hbox->addWidget( cbutton );
+ hbox->addStretch( 1 );
+
+ // stolen from kmessagebox
+ int pref_width = 0;
+ int pref_height = 0;
+ // Calculate a proper size for the text.
+ {
+ QSimpleRichText rt(qt_text, dialog->font());
+ QRect rect = KGlobalSettings::desktopGeometry(dialog);
+
+ pref_width = rect.width() / 3;
+ rt.setWidth(pref_width);
+ int used_width = rt.widthUsed();
+ pref_height = rt.height();
+ if (used_width <= pref_width)
+ {
+ while(true)
+ {
+ int new_width = (used_width * 9) / 10;
+ rt.setWidth(new_width);
+ int new_height = rt.height();
+ if (new_height > pref_height)
+ break;
+ used_width = rt.widthUsed();
+ if (used_width > new_width)
+ break;
+ }
+ pref_width = used_width;
+ }
+ else
+ {
+ if (used_width > (pref_width *2))
+ pref_width = pref_width *2;
+ else
+ pref_width = used_width;
+ }
+ }
+ label2->setFixedSize(QSize(pref_width+10, pref_height));
+
+ int ret = static_cast< LockProcess* >( parent())->execDialog( dialog );
+
+ delete dialog;
+
+ if (ret == QDialog::Accepted) {
+ if (cb->isChecked())
+ KMessageBox::saveDontShowAgainContinue( ":confirmNewSession" );
+ DM().startReserve();
+ }
+
+ mTimeoutTimerId = startTimer(PASSDLG_HIDE_TIMEOUT);
+}
+
+class LockListViewItem : public QListViewItem {
+public:
+ LockListViewItem( QListView *parent,
+ const QString &sess, const QString &loc, int _vt )
+ : QListViewItem( parent )
+ , vt( _vt )
+ {
+ setText( 0, sess );
+ setText( 1, loc );
+ }
+
+ int vt;
+};
+
+void PasswordDlg::slotSwitchUser()
+{
+ int p = 0;
+ DM dm;
+
+ QDialog dialog( this, "sessbox", true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( &dialog );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QBoxLayout *vbox = new QVBoxLayout( &dialog );
+ vbox->addWidget( winFrame );
+
+ QBoxLayout *hbox = new QHBoxLayout( winFrame, KDialog::marginHint(), KDialog::spacingHint() );
+
+ QBoxLayout *vbox1 = new QVBoxLayout( hbox, KDialog::spacingHint() );
+ QBoxLayout *vbox2 = new QVBoxLayout( hbox, KDialog::spacingHint() );
+
+ KPushButton *btn;
+
+ SessList sess;
+ if (dm.localSessions( sess )) {
+
+ lv = new QListView( winFrame );
+ connect( lv, SIGNAL(doubleClicked(QListViewItem *, const QPoint&, int)), SLOT(slotSessionActivated()) );
+ connect( lv, SIGNAL(doubleClicked(QListViewItem *, const QPoint&, int)), &dialog, SLOT(reject()) );
+ lv->setAllColumnsShowFocus( true );
+ lv->addColumn( i18n("Session") );
+ lv->addColumn( i18n("Location") );
+ lv->setColumnWidthMode( 0, QListView::Maximum );
+ lv->setColumnWidthMode( 1, QListView::Maximum );
+ QListViewItem *itm = 0;
+ QString user, loc;
+ int ns = 0;
+ for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
+ DM::sess2Str2( *it, user, loc );
+ itm = new LockListViewItem( lv, user, loc, (*it).vt );
+ if (!(*it).vt)
+ itm->setEnabled( false );
+ if ((*it).self) {
+ lv->setCurrentItem( itm );
+ itm->setSelected( true );
+ }
+ ns++;
+ }
+ int fw = lv->frameWidth() * 2;
+ QSize hds( lv->header()->sizeHint() );
+ lv->setMinimumWidth( fw + hds.width() +
+ (ns > 10 ? style().pixelMetric(QStyle::PM_ScrollBarExtent) : 0 ) );
+ lv->setFixedHeight( fw + hds.height() +
+ itm->height() * (ns < 6 ? 6 : ns > 10 ? 10 : ns) );
+ lv->header()->adjustHeaderSize();
+ vbox1->addWidget( lv );
+
+ btn = new KPushButton( KGuiItem(i18n("session", "&Activate"), "fork"), winFrame );
+ connect( btn, SIGNAL(clicked()), SLOT(slotSessionActivated()) );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ vbox2->addWidget( btn );
+ vbox2->addStretch( 2 );
+ }
+
+ if (kapp->authorize("start_new_session") && (p = dm.numReserve()) >= 0)
+ {
+ btn = new KPushButton( KGuiItem(i18n("Start &New Session"), "fork"), winFrame );
+ connect( btn, SIGNAL(clicked()), SLOT(slotStartNewSession()) );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ if (!p)
+ btn->setEnabled( false );
+ vbox2->addWidget( btn );
+ vbox2->addStretch( 1 );
+ }
+
+ btn = new KPushButton( KStdGuiItem::cancel(), winFrame );
+ connect( btn, SIGNAL(clicked()), &dialog, SLOT(reject()) );
+ vbox2->addWidget( btn );
+
+ static_cast< LockProcess* >(parent())->execDialog( &dialog );
+}
+
+void PasswordDlg::slotSessionActivated()
+{
+ LockListViewItem *itm = (LockListViewItem *)lv->currentItem();
+ if (itm && itm->vt > 0)
+ DM().switchVT( itm->vt );
+}
+
+void PasswordDlg::capsLocked()
+{
+ unsigned int lmask;
+ Window dummy1, dummy2;
+ int dummy3, dummy4, dummy5, dummy6;
+ XQueryPointer(qt_xdisplay(), DefaultRootWindow( qt_xdisplay() ), &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, &dummy6, &lmask);
+ mCapsLocked = lmask & LockMask;
+ updateLabel();
+}
+
+#include "lockdlg.moc"
diff --git a/kdesktop/lock/lockdlg.h b/kdesktop/lock/lockdlg.h
new file mode 100644
index 000000000..4bb468c03
--- /dev/null
+++ b/kdesktop/lock/lockdlg.h
@@ -0,0 +1,92 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+//
+
+#ifndef __LOCKDLG_H__
+#define __LOCKDLG_H__
+
+#include <kgreeterplugin.h>
+
+#include <qdialog.h>
+#include <qstringlist.h>
+
+struct GreeterPluginHandle;
+class LockProcess;
+class QFrame;
+class QGridLayout;
+class QLabel;
+class KPushButton;
+class QListView;
+
+//===========================================================================
+//
+// Simple dialog for entering a password.
+// It does not handle password validation.
+//
+class PasswordDlg : public QDialog, public KGreeterPluginHandler
+{
+ Q_OBJECT
+
+public:
+ PasswordDlg(LockProcess *parent, GreeterPluginHandle *plugin);
+ ~PasswordDlg();
+ virtual void show();
+
+ // from KGreetPluginHandler
+ virtual void gplugReturnText( const char *text, int tag );
+ virtual void gplugReturnBinary( const char *data );
+ virtual void gplugSetUser( const QString & );
+ virtual void gplugStart();
+ virtual void gplugActivity();
+ virtual void gplugMsgBox( QMessageBox::Icon type, const QString &text );
+
+protected:
+ virtual void timerEvent(QTimerEvent *);
+ virtual bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void slotSwitchUser();
+ void slotSessionActivated();
+ void slotStartNewSession();
+ void slotOK();
+ void layoutClicked();
+ void slotActivity();
+
+private:
+ void setLayoutText( const QString &txt );
+ void capsLocked();
+ void updateLabel();
+ int Reader (void *buf, int count);
+ bool GRead (void *buf, int count);
+ bool GWrite (const void *buf, int count);
+ bool GSendInt (int val);
+ bool GSendStr (const char *buf);
+ bool GSendArr (int len, const char *buf);
+ bool GRecvInt (int *val);
+ bool GRecvArr (char **buf);
+ void handleVerify();
+ void reapVerify();
+ void cantCheck();
+ GreeterPluginHandle *mPlugin;
+ KGreeterPlugin *greet;
+ QFrame *frame;
+ QGridLayout *frameLayout;
+ QLabel *mStatusLabel;
+ KPushButton *mNewSessButton, *ok, *cancel;
+ QPushButton *mLayoutButton;
+ int mFailedTimerId;
+ int mTimeoutTimerId;
+ int mCapsLocked;
+ bool mUnlockingFailed;
+ QStringList layoutsList;
+ QStringList::iterator currLayout;
+ int sPid, sFd;
+ QListView *lv;
+};
+
+#endif
+
diff --git a/kdesktop/lock/lockprocess.cc b/kdesktop/lock/lockprocess.cc
new file mode 100644
index 000000000..a813b6899
--- /dev/null
+++ b/kdesktop/lock/lockprocess.cc
@@ -0,0 +1,1172 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+//
+
+//kdesktop keeps running and checks user inactivity
+//when it should show screensaver (and maybe lock the session),
+//it starts kdesktop_lock, who does all the locking and who
+//actually starts the screensaver
+
+//It's done this way to prevent screen unlocking when kdesktop
+//crashes (e.g. because it's set to multiple wallpapers and
+//some image will be corrupted).
+
+#include <config.h>
+
+#include "lockprocess.h"
+#include "lockdlg.h"
+#include "autologout.h"
+#include "kdesktopsettings.h"
+
+#include <dmctl.h>
+
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kservicegroup.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <klibloader.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kpixmapeffect.h>
+#include <kpixmap.h>
+
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qfile.h>
+#include <qsocketnotifier.h>
+#include <qvaluevector.h>
+#include <qtooltip.h>
+
+#include <qdatetime.h>
+
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#ifdef HAVE_SETPRIORITY
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+
+#ifdef HAVE_DPMS
+extern "C" {
+#include <X11/Xmd.h>
+#ifndef Bool
+#define Bool BOOL
+#endif
+#include <X11/extensions/dpms.h>
+
+#ifndef HAVE_DPMSINFO_PROTO
+Status DPMSInfo ( Display *, CARD16 *, BOOL * );
+#endif
+}
+#endif
+
+#ifdef HAVE_XF86MISC
+#include <X11/extensions/xf86misc.h>
+#endif
+
+#ifdef HAVE_GLXCHOOSEVISUAL
+#include <GL/glx.h>
+#endif
+
+#define LOCK_GRACE_DEFAULT 5000
+#define AUTOLOGOUT_DEFAULT 600
+
+static Window gVRoot = 0;
+static Window gVRootData = 0;
+static Atom gXA_VROOT;
+static Atom gXA_SCREENSAVER_VERSION;
+
+//===========================================================================
+//
+// Screen saver handling process. Handles screensaver window,
+// starting screensaver hacks, and password entry.f
+//
+LockProcess::LockProcess(bool child, bool useBlankOnly)
+ : QWidget(0L, "saver window", WX11BypassWM),
+ mOpenGLVisual(0),
+ child_saver(child),
+ mParent(0),
+ mUseBlankOnly(useBlankOnly),
+ mSuspended(false),
+ mVisibility(false),
+ mRestoreXF86Lock(false),
+ mForbidden(false),
+ mAutoLogout(false)
+{
+ setupSignals();
+
+ kapp->installX11EventFilter(this);
+
+ // Get root window size
+ XWindowAttributes rootAttr;
+ XGetWindowAttributes(qt_xdisplay(), RootWindow(qt_xdisplay(),
+ qt_xscreen()), &rootAttr);
+ mRootWidth = rootAttr.width;
+ mRootHeight = rootAttr.height;
+ { // trigger creation of QToolTipManager, it does XSelectInput() on the root window
+ QWidget w;
+ QToolTip::add( &w, "foo" );
+ }
+ XSelectInput( qt_xdisplay(), qt_xrootwin(),
+ SubstructureNotifyMask | rootAttr.your_event_mask );
+
+ // Add non-KDE path
+ KGlobal::dirs()->addResourceType("scrsav",
+ KGlobal::dirs()->kde_default("apps") +
+ "System/ScreenSavers/");
+
+ // Add KDE specific screensaver path
+ QString relPath="System/ScreenSavers/";
+ KServiceGroup::Ptr servGroup = KServiceGroup::baseGroup( "screensavers");
+ if (servGroup)
+ {
+ relPath=servGroup->relPath();
+ kdDebug(1204) << "relPath=" << relPath << endl;
+ }
+ KGlobal::dirs()->addResourceType("scrsav",
+ KGlobal::dirs()->kde_default("apps") +
+ relPath);
+
+ // virtual root property
+ gXA_VROOT = XInternAtom (qt_xdisplay(), "__SWM_VROOT", False);
+ gXA_SCREENSAVER_VERSION = XInternAtom (qt_xdisplay(), "_SCREENSAVER_VERSION", False);
+
+ connect(&mHackProc, SIGNAL(processExited(KProcess *)),
+ SLOT(hackExited(KProcess *)));
+
+ connect(&mSuspendTimer, SIGNAL(timeout()), SLOT(suspend()));
+
+ QStringList dmopt =
+ QStringList::split(QChar(','),
+ QString::fromLatin1( ::getenv( "XDM_MANAGED" )));
+ for (QStringList::ConstIterator it = dmopt.begin(); it != dmopt.end(); ++it)
+ if ((*it).startsWith("method="))
+ mMethod = (*it).mid(7);
+
+ configure();
+
+#ifdef HAVE_DPMS
+ if (mDPMSDepend) {
+ BOOL on;
+ CARD16 state;
+ DPMSInfo(qt_xdisplay(), &state, &on);
+ if (on)
+ {
+ connect(&mCheckDPMS, SIGNAL(timeout()), SLOT(checkDPMSActive()));
+ // we can save CPU if we stop it as quickly as possible
+ // but we waste CPU if we check too often -> so take 10s
+ mCheckDPMS.start(10000);
+ }
+ }
+#endif
+
+ greetPlugin.library = 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// Destructor - usual cleanups.
+//
+LockProcess::~LockProcess()
+{
+ if (greetPlugin.library) {
+ if (greetPlugin.info->done)
+ greetPlugin.info->done();
+ greetPlugin.library->unload();
+ }
+}
+
+static int signal_pipe[2];
+
+static void sigterm_handler(int)
+{
+ char tmp = 'T';
+ ::write( signal_pipe[1], &tmp, 1);
+}
+
+static void sighup_handler(int)
+{
+ char tmp = 'H';
+ ::write( signal_pipe[1], &tmp, 1);
+}
+
+void LockProcess::timerEvent(QTimerEvent *ev)
+{
+ if (mAutoLogout && ev->timerId() == mAutoLogoutTimerId)
+ {
+ killTimer(mAutoLogoutTimerId);
+ AutoLogout autologout(this);
+ execDialog(&autologout);
+ }
+}
+
+void LockProcess::setupSignals()
+{
+ struct sigaction act;
+ // ignore SIGINT
+ act.sa_handler=SIG_IGN;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGINT);
+ act.sa_flags = 0;
+ sigaction(SIGINT, &act, 0L);
+ // ignore SIGQUIT
+ act.sa_handler=SIG_IGN;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGQUIT);
+ act.sa_flags = 0;
+ sigaction(SIGQUIT, &act, 0L);
+ // exit cleanly on SIGTERM
+ act.sa_handler= sigterm_handler;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGTERM);
+ act.sa_flags = 0;
+ sigaction(SIGTERM, &act, 0L);
+ // SIGHUP forces lock
+ act.sa_handler= sighup_handler;
+ sigemptyset(&(act.sa_mask));
+ sigaddset(&(act.sa_mask), SIGHUP);
+ act.sa_flags = 0;
+ sigaction(SIGHUP, &act, 0L);
+
+ pipe(signal_pipe);
+ QSocketNotifier* notif = new QSocketNotifier(signal_pipe[0],
+ QSocketNotifier::Read, this );
+ connect( notif, SIGNAL(activated(int)), SLOT(signalPipeSignal()));
+}
+
+
+void LockProcess::signalPipeSignal()
+{
+ char tmp;
+ ::read( signal_pipe[0], &tmp, 1);
+ if( tmp == 'T' )
+ quitSaver();
+ else if( tmp == 'H' ) {
+ if( !mLocked )
+ startLock();
+ }
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::lock()
+{
+ if (startSaver()) {
+ // In case of a forced lock we don't react to events during
+ // the dead-time to give the screensaver some time to activate.
+ // That way we don't accidentally show the password dialog before
+ // the screensaver kicks in because the user moved the mouse after
+ // selecting "lock screen", that looks really untidy.
+ mBusy = true;
+ if (startLock())
+ {
+ QTimer::singleShot(1000, this, SLOT(slotDeadTimePassed()));
+ return true;
+ }
+ stopSaver();
+ mBusy = false;
+ }
+ return false;
+}
+//---------------------------------------------------------------------------
+void LockProcess::slotDeadTimePassed()
+{
+ mBusy = false;
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::defaultSave()
+{
+ mLocked = false;
+ if (startSaver()) {
+ if (mLockGrace >= 0)
+ QTimer::singleShot(mLockGrace, this, SLOT(startLock()));
+ return true;
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+bool LockProcess::dontLock()
+{
+ mLocked = false;
+ return startSaver();
+}
+
+//---------------------------------------------------------------------------
+void LockProcess::quitSaver()
+{
+ stopSaver();
+ kapp->quit();
+}
+
+//---------------------------------------------------------------------------
+//
+// Read and apply configuration.
+//
+void LockProcess::configure()
+{
+ // the configuration is stored in kdesktop's config file
+ if( KDesktopSettings::lock() )
+ {
+ mLockGrace = KDesktopSettings::lockGrace();
+ if (mLockGrace < 0)
+ mLockGrace = 0;
+ else if (mLockGrace > 300000)
+ mLockGrace = 300000; // 5 minutes, keep the value sane
+ }
+ else
+ mLockGrace = -1;
+
+ if ( KDesktopSettings::autoLogout() )
+ {
+ mAutoLogout = true;
+ mAutoLogoutTimeout = KDesktopSettings::autoLogoutTimeout();
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout * 1000); // in milliseconds
+ }
+
+#ifdef HAVE_DPMS
+ //if the user decided that the screensaver should run independent from
+ //dpms, we shouldn't check for it, aleXXX
+ mDPMSDepend = KDesktopSettings::dpmsDependent();
+#endif
+
+ mPriority = KDesktopSettings::priority();
+ if (mPriority < 0) mPriority = 0;
+ if (mPriority > 19) mPriority = 19;
+
+ mSaver = KDesktopSettings::saver();
+ if (mSaver.isEmpty() || mUseBlankOnly)
+ mSaver = "KBlankscreen.desktop";
+
+ readSaver();
+
+ mPlugins = KDesktopSettings::pluginsUnlock();
+ if (mPlugins.isEmpty())
+ mPlugins = QStringList("classic");
+ mPluginOptions = KDesktopSettings::pluginOptions();
+}
+
+//---------------------------------------------------------------------------
+//
+// Read the command line needed to run the screensaver given a .desktop file.
+//
+void LockProcess::readSaver()
+{
+ if (!mSaver.isEmpty())
+ {
+ QString file = locate("scrsav", mSaver);
+
+ bool opengl = kapp->authorize("opengl_screensavers");
+ bool manipulatescreen = kapp->authorize("manipulatescreen_screensavers");
+ KDesktopFile config(file, true);
+ if (config.readEntry("X-KDE-Type").utf8())
+ {
+ QString saverType = config.readEntry("X-KDE-Type").utf8();
+ QStringList saverTypes = QStringList::split(";", saverType);
+ for (uint i = 0; i < saverTypes.count(); i++)
+ {
+ if ((saverTypes[i] == "ManipulateScreen") && !manipulatescreen)
+ {
+ kdDebug(1204) << "Screensaver is type ManipulateScreen and ManipulateScreen is forbidden" << endl;
+ mForbidden = true;
+ }
+ if ((saverTypes[i] == "OpenGL") && !opengl)
+ {
+ kdDebug(1204) << "Screensaver is type OpenGL and OpenGL is forbidden" << endl;
+ mForbidden = true;
+ }
+ if (saverTypes[i] == "OpenGL")
+ {
+ mOpenGLVisual = true;
+ }
+ }
+ }
+
+ kdDebug(1204) << "mForbidden: " << (mForbidden ? "true" : "false") << endl;
+
+ if (config.hasActionGroup("Root"))
+ {
+ config.setActionGroup("Root");
+ mSaverExec = config.readPathEntry("Exec");
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// Create a window to draw our screen saver on.
+//
+void LockProcess::createSaverWindow()
+{
+ Visual* visual = CopyFromParent;
+ XSetWindowAttributes attrs;
+ int flags = CWOverrideRedirect;
+#ifdef HAVE_GLXCHOOSEVISUAL
+ if( mOpenGLVisual )
+ {
+ static int attribs[][ 15 ] =
+ {
+ #define R GLX_RED_SIZE
+ #define G GLX_GREEN_SIZE
+ #define B GLX_BLUE_SIZE
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, GLX_DOUBLEBUFFER, None },
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, R, 8, G, 8, B, 8, GLX_DEPTH_SIZE, 8, None },
+ { GLX_RGBA, R, 4, G, 4, B, 4, GLX_DEPTH_SIZE, 4, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, GLX_DOUBLEBUFFER, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, GLX_STENCIL_SIZE, 1, None },
+ { GLX_RGBA, GLX_DEPTH_SIZE, 8, None }
+ #undef R
+ #undef G
+ #undef B
+ };
+ for( unsigned int i = 0;
+ i < sizeof( attribs ) / sizeof( attribs[ 0 ] );
+ ++i )
+ {
+ if( XVisualInfo* info = glXChooseVisual( x11Display(), x11Screen(), attribs[ i ] ))
+ {
+ visual = info->visual;
+ static Colormap colormap = 0;
+ if( colormap != 0 )
+ XFreeColormap( x11Display(), colormap );
+ colormap = XCreateColormap( x11Display(), RootWindow( x11Display(), x11Screen()), visual, AllocNone );
+ attrs.colormap = colormap;
+ flags |= CWColormap;
+ XFree( info );
+ break;
+ }
+ }
+ }
+#endif
+
+ attrs.override_redirect = 1;
+ hide();
+ Window w = XCreateWindow( x11Display(), RootWindow( x11Display(), x11Screen()),
+ x(), y(), width(), height(), 0, x11Depth(), InputOutput, visual, flags, &attrs );
+ create( w );
+
+ // Some xscreensaver hacks check for this property
+ const char *version = "KDE 2.0";
+ XChangeProperty (qt_xdisplay(), winId(),
+ gXA_SCREENSAVER_VERSION, XA_STRING, 8, PropModeReplace,
+ (unsigned char *) version, strlen(version));
+
+ XSetWindowAttributes attr;
+ attr.event_mask = KeyPressMask | ButtonPressMask | PointerMotionMask |
+ VisibilityChangeMask | ExposureMask;
+ XChangeWindowAttributes(qt_xdisplay(), winId(),
+ CWEventMask, &attr);
+
+ // erase();
+
+ // set NoBackground so that the saver can capture the current
+ // screen state if necessary
+ setBackgroundMode(QWidget::NoBackground);
+
+ setCursor( blankCursor );
+ setGeometry(0, 0, mRootWidth, mRootHeight);
+
+ kdDebug(1204) << "Saver window Id: " << winId() << endl;
+}
+
+//---------------------------------------------------------------------------
+//
+// Hide the screensaver window
+//
+void LockProcess::hideSaverWindow()
+{
+ hide();
+ lower();
+ removeVRoot(winId());
+ XDeleteProperty(qt_xdisplay(), winId(), gXA_SCREENSAVER_VERSION);
+ if ( gVRoot ) {
+ unsigned long vroot_data[1] = { gVRootData };
+ XChangeProperty(qt_xdisplay(), gVRoot, gXA_VROOT, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+ gVRoot = 0;
+ }
+ XSync(qt_xdisplay(), False);
+}
+
+//---------------------------------------------------------------------------
+static int ignoreXError(Display *, XErrorEvent *)
+{
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// Save the current virtual root window
+//
+void LockProcess::saveVRoot()
+{
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ Window root = RootWindowOfScreen(ScreenOfDisplay(qt_xdisplay(), qt_xscreen()));
+
+ gVRoot = 0;
+ gVRootData = 0;
+
+ int (*oldHandler)(Display *, XErrorEvent *);
+ oldHandler = XSetErrorHandler(ignoreXError);
+
+ if (XQueryTree(qt_xdisplay(), root, &rootReturn, &parentReturn,
+ &children, &numChildren))
+ {
+ for (unsigned int i = 0; i < numChildren; i++)
+ {
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned char *newRoot = 0;
+
+ if ((XGetWindowProperty(qt_xdisplay(), children[i], gXA_VROOT, 0, 1,
+ False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
+ &newRoot) == Success) && newRoot)
+ {
+ gVRoot = children[i];
+ Window *dummy = (Window*)newRoot;
+ gVRootData = *dummy;
+ XFree ((char*) newRoot);
+ break;
+ }
+ }
+ if (children)
+ {
+ XFree((char *)children);
+ }
+ }
+
+ XSetErrorHandler(oldHandler);
+}
+
+//---------------------------------------------------------------------------
+//
+// Set the virtual root property
+//
+void LockProcess::setVRoot(Window win, Window vr)
+{
+ if (gVRoot)
+ removeVRoot(gVRoot);
+
+ unsigned long rw = RootWindowOfScreen(ScreenOfDisplay(qt_xdisplay(), qt_xscreen()));
+ unsigned long vroot_data[1] = { vr };
+
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+ Window top = win;
+ while (1) {
+ XQueryTree(qt_xdisplay(), top , &rootReturn, &parentReturn,
+ &children, &numChildren);
+ if (children)
+ XFree((char *)children);
+ if (parentReturn == rw) {
+ break;
+ } else
+ top = parentReturn;
+ }
+
+ XChangeProperty(qt_xdisplay(), top, gXA_VROOT, XA_WINDOW, 32,
+ PropModeReplace, (unsigned char *)vroot_data, 1);
+}
+
+//---------------------------------------------------------------------------
+//
+// Remove the virtual root property
+//
+void LockProcess::removeVRoot(Window win)
+{
+ XDeleteProperty (qt_xdisplay(), win, gXA_VROOT);
+}
+
+//---------------------------------------------------------------------------
+//
+// Grab the keyboard. Returns true on success
+//
+bool LockProcess::grabKeyboard()
+{
+ int rv = XGrabKeyboard( qt_xdisplay(), QApplication::desktop()->winId(),
+ True, GrabModeAsync, GrabModeAsync, CurrentTime );
+
+ return (rv == GrabSuccess);
+}
+
+#define GRABEVENTS ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \
+ EnterWindowMask | LeaveWindowMask
+
+//---------------------------------------------------------------------------
+//
+// Grab the mouse. Returns true on success
+//
+bool LockProcess::grabMouse()
+{
+ int rv = XGrabPointer( qt_xdisplay(), QApplication::desktop()->winId(),
+ True, GRABEVENTS, GrabModeAsync, GrabModeAsync, None,
+ blankCursor.handle(), CurrentTime );
+
+ return (rv == GrabSuccess);
+}
+
+//---------------------------------------------------------------------------
+//
+// Grab keyboard and mouse. Returns true on success.
+//
+bool LockProcess::grabInput()
+{
+ XSync(qt_xdisplay(), False);
+
+ if (!grabKeyboard())
+ {
+ sleep(1);
+ if (!grabKeyboard())
+ {
+ return false;
+ }
+ }
+
+ if (!grabMouse())
+ {
+ sleep(1);
+ if (!grabMouse())
+ {
+ XUngrabKeyboard(qt_xdisplay(), CurrentTime);
+ return false;
+ }
+ }
+
+ lockXF86();
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Release mouse an keyboard grab.
+//
+void LockProcess::ungrabInput()
+{
+ XUngrabKeyboard(qt_xdisplay(), CurrentTime);
+ XUngrabPointer(qt_xdisplay(), CurrentTime);
+ unlockXF86();
+}
+
+//---------------------------------------------------------------------------
+//
+// Start the screen saver.
+//
+bool LockProcess::startSaver()
+{
+ if (!child_saver && !grabInput())
+ {
+ kdWarning(1204) << "LockProcess::startSaver() grabInput() failed!!!!" << endl;
+ return false;
+ }
+ mBusy = false;
+
+ saveVRoot();
+
+ if (mParent) {
+ QSocketNotifier *notifier = new QSocketNotifier(mParent, QSocketNotifier::Read, this, "notifier");
+ connect(notifier, SIGNAL( activated (int)), SLOT( quitSaver()));
+ }
+ createSaverWindow();
+ move(0, 0);
+ show();
+ setCursor( blankCursor );
+
+ raise();
+ XSync(qt_xdisplay(), False);
+ setVRoot( winId(), winId() );
+ startHack();
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Stop the screen saver.
+//
+void LockProcess::stopSaver()
+{
+ kdDebug(1204) << "LockProcess: stopping saver" << endl;
+ resume( true );
+ stopHack();
+ hideSaverWindow();
+ mVisibility = false;
+ if (!child_saver) {
+ if (mLocked)
+ DM().setLock( false );
+ ungrabInput();
+ const char *out = "GOAWAY!";
+ for (QValueList<int>::ConstIterator it = child_sockets.begin(); it != child_sockets.end(); ++it)
+ write(*it, out, sizeof(out));
+ }
+}
+
+// private static
+QVariant LockProcess::getConf(void *ctx, const char *key, const QVariant &dflt)
+{
+ LockProcess *that = (LockProcess *)ctx;
+ QString fkey = QString::fromLatin1( key ) + '=';
+ for (QStringList::ConstIterator it = that->mPluginOptions.begin();
+ it != that->mPluginOptions.end(); ++it)
+ if ((*it).startsWith( fkey ))
+ return (*it).mid( fkey.length() );
+ return dflt;
+}
+
+void LockProcess::cantLock( const QString &txt)
+{
+ msgBox( QMessageBox::Critical, i18n("Will not lock the session, as unlocking would be impossible:\n") + txt );
+}
+
+#if 0 // placeholders for later
+i18n("Cannot start <i>kcheckpass</i>.");
+i18n("<i>kcheckpass</i> is unable to operate. Possibly it is not SetUID root.");
+#endif
+
+//---------------------------------------------------------------------------
+//
+// Make the screen saver password protected.
+//
+bool LockProcess::startLock()
+{
+ for (QStringList::ConstIterator it = mPlugins.begin(); it != mPlugins.end(); ++it) {
+ GreeterPluginHandle plugin;
+ QString path = KLibLoader::self()->findLibrary(
+ ((*it)[0] == '/' ? *it : "kgreet_" + *it ).latin1() );
+ if (path.isEmpty()) {
+ kdWarning(1204) << "GreeterPlugin " << *it << " does not exist" << endl;
+ continue;
+ }
+ if (!(plugin.library = KLibLoader::self()->library( path.latin1() ))) {
+ kdWarning(1204) << "Cannot load GreeterPlugin " << *it << " (" << path << ")" << endl;
+ continue;
+ }
+ if (!plugin.library->hasSymbol( "kgreeterplugin_info" )) {
+ kdWarning(1204) << "GreeterPlugin " << *it << " (" << path << ") is no valid greet widget plugin" << endl;
+ plugin.library->unload();
+ continue;
+ }
+ plugin.info = (kgreeterplugin_info*)plugin.library->symbol( "kgreeterplugin_info" );
+ if (plugin.info->method && !mMethod.isEmpty() && mMethod != plugin.info->method) {
+ kdDebug(1204) << "GreeterPlugin " << *it << " (" << path << ") serves " << plugin.info->method << ", not " << mMethod << endl;
+ plugin.library->unload();
+ continue;
+ }
+ if (!plugin.info->init( mMethod, getConf, this )) {
+ kdDebug(1204) << "GreeterPlugin " << *it << " (" << path << ") refuses to serve " << mMethod << endl;
+ plugin.library->unload();
+ continue;
+ }
+ kdDebug(1204) << "GreeterPlugin " << *it << " (" << plugin.info->method << ", " << plugin.info->name << ") loaded" << endl;
+ greetPlugin = plugin;
+ mLocked = true;
+ DM().setLock( true );
+ return true;
+ }
+ cantLock( i18n("No appropriate greeter plugin configured.") );
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+
+
+bool LockProcess::startHack()
+{
+ if (mSaverExec.isEmpty())
+ {
+ return false;
+ }
+
+ if (mHackProc.isRunning())
+ {
+ stopHack();
+ }
+
+ mHackProc.clearArguments();
+
+ QTextStream ts(&mSaverExec, IO_ReadOnly);
+ QString word;
+ ts >> word;
+ QString path = KStandardDirs::findExe(word);
+
+ if (!path.isEmpty())
+ {
+ mHackProc << path;
+
+ kdDebug(1204) << "Starting hack: " << path << endl;
+
+ while (!ts.atEnd())
+ {
+ ts >> word;
+ if (word == "%w")
+ {
+ word = word.setNum(winId());
+ }
+ mHackProc << word;
+ }
+
+ if (!mForbidden)
+ {
+
+ if (mHackProc.start() == true)
+ {
+#ifdef HAVE_SETPRIORITY
+ setpriority(PRIO_PROCESS, mHackProc.pid(), mPriority);
+#endif
+ //bitBlt(this, 0, 0, &mOriginal);
+ return true;
+ }
+ }
+ else
+ // we aren't allowed to start the specified screensaver either because it didn't run for some reason
+ // according to the kiosk restrictions forbid it
+ {
+ setBackgroundColor(black);
+ }
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------
+//
+void LockProcess::stopHack()
+{
+ if (mHackProc.isRunning())
+ {
+ mHackProc.kill();
+ if (!mHackProc.wait(10))
+ {
+ mHackProc.kill(SIGKILL);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+void LockProcess::hackExited(KProcess *)
+{
+ // Hack exited while we're supposed to be saving the screen.
+ // Make sure the saver window is black.
+ setBackgroundColor(black);
+}
+
+void LockProcess::suspend()
+{
+ if(!mSuspended)
+ {
+ mHackProc.kill(SIGSTOP);
+ QApplication::syncX();
+ mSavedScreen = QPixmap::grabWindow( winId());
+ }
+ mSuspended = true;
+}
+
+void LockProcess::resume( bool force )
+{
+ if( !force && (!mDialogs.isEmpty() || !mVisibility ))
+ return; // no resuming with dialog visible or when not visible
+ if(mSuspended)
+ {
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+ bitBlt( this, 0, 0, &mSavedScreen );
+ QApplication::syncX();
+ mHackProc.kill(SIGCONT);
+ }
+ mSuspended = false;
+}
+
+//---------------------------------------------------------------------------
+//
+// Show the password dialog
+// This is called only in the master process
+//
+bool LockProcess::checkPass()
+{
+ if (mAutoLogout)
+ killTimer(mAutoLogoutTimerId);
+
+ PasswordDlg passDlg( this, &greetPlugin);
+
+ int ret = execDialog( &passDlg );
+
+ XWindowAttributes rootAttr;
+ XGetWindowAttributes(qt_xdisplay(), RootWindow(qt_xdisplay(),
+ qt_xscreen()), &rootAttr);
+ if(( rootAttr.your_event_mask & SubstructureNotifyMask ) == 0 )
+ {
+ kdWarning() << "ERROR: Something removed SubstructureNotifyMask from the root window!!!" << endl;
+ XSelectInput( qt_xdisplay(), qt_xrootwin(),
+ SubstructureNotifyMask | rootAttr.your_event_mask );
+ }
+
+ return ret == QDialog::Accepted;
+}
+
+static void fakeFocusIn( WId window )
+{
+ // We have keyboard grab, so this application will
+ // get keyboard events even without having focus.
+ // Fake FocusIn to make Qt realize it has the active
+ // window, so that it will correctly show cursor in the dialog.
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xfocus.display = qt_xdisplay();
+ ev.xfocus.type = FocusIn;
+ ev.xfocus.window = window;
+ ev.xfocus.mode = NotifyNormal;
+ ev.xfocus.detail = NotifyAncestor;
+ XSendEvent( qt_xdisplay(), window, False, NoEventMask, &ev );
+}
+
+int LockProcess::execDialog( QDialog *dlg )
+{
+ dlg->adjustSize();
+
+ QRect rect = dlg->geometry();
+ rect.moveCenter(KGlobalSettings::desktopGeometry(QCursor::pos()).center());
+ dlg->move( rect.topLeft() );
+
+ if (mDialogs.isEmpty())
+ {
+ suspend();
+ XChangeActivePointerGrab( qt_xdisplay(), GRABEVENTS,
+ arrowCursor.handle(), CurrentTime);
+ }
+ mDialogs.prepend( dlg );
+ fakeFocusIn( dlg->winId());
+ int rt = dlg->exec();
+ mDialogs.remove( dlg );
+ if( mDialogs.isEmpty() ) {
+ XChangeActivePointerGrab( qt_xdisplay(), GRABEVENTS,
+ blankCursor.handle(), CurrentTime);
+ resume( false );
+ } else
+ fakeFocusIn( mDialogs.first()->winId());
+ return rt;
+}
+
+void LockProcess::preparePopup()
+{
+ QWidget *dlg = (QWidget *)sender();
+ mDialogs.prepend( dlg );
+ fakeFocusIn( dlg->winId() );
+}
+
+void LockProcess::cleanupPopup()
+{
+ QWidget *dlg = (QWidget *)sender();
+ mDialogs.remove( dlg );
+ fakeFocusIn( mDialogs.first()->winId() );
+}
+
+//---------------------------------------------------------------------------
+//
+// X11 Event.
+//
+bool LockProcess::x11Event(XEvent *event)
+{
+ switch (event->type)
+ {
+ case KeyPress:
+ case ButtonPress:
+ case MotionNotify:
+ if (mBusy || !mDialogs.isEmpty())
+ break;
+ mBusy = true;
+ if (!mLocked || checkPass())
+ {
+ stopSaver();
+ kapp->quit();
+ }
+ else if (mAutoLogout) // we need to restart the auto logout countdown
+ {
+ killTimer(mAutoLogoutTimerId);
+ mAutoLogoutTimerId = startTimer(mAutoLogoutTimeout);
+ }
+ mBusy = false;
+ return true;
+
+ case VisibilityNotify:
+ if( event->xvisibility.window == winId())
+ { // mVisibility == false means the screensaver is not visible at all
+ // e.g. when switched to text console
+ mVisibility = !(event->xvisibility.state == VisibilityFullyObscured);
+ if(!mVisibility)
+ mSuspendTimer.start(2000, true);
+ else
+ {
+ mSuspendTimer.stop();
+ resume( false );
+ }
+ if (event->xvisibility.state != VisibilityUnobscured)
+ stayOnTop();
+ }
+ break;
+
+ case ConfigureNotify: // from SubstructureNotifyMask on the root window
+ if(event->xconfigure.event == qt_xrootwin())
+ stayOnTop();
+ break;
+ case MapNotify: // from SubstructureNotifyMask on the root window
+ if( event->xmap.event == qt_xrootwin())
+ stayOnTop();
+ break;
+ }
+
+ // We have grab with the grab window being the root window.
+ // This results in key events being sent to the root window,
+ // but they should be sent to the dialog if it's visible.
+ // It could be solved by setFocus() call, but that would mess
+ // the focus after this process exits.
+ // Qt seems to be quite hard to persuade to redirect the event,
+ // so let's simply dupe it with correct destination window,
+ // and ignore the original one.
+ if(!mDialogs.isEmpty() && ( event->type == KeyPress || event->type == KeyRelease)
+ && event->xkey.window != mDialogs.first()->winId())
+ {
+ XEvent ev2 = *event;
+ ev2.xkey.window = ev2.xkey.subwindow = mDialogs.first()->winId();
+ qApp->x11ProcessEvent( &ev2 );
+ return true;
+ }
+
+ return false;
+}
+
+void LockProcess::stayOnTop()
+{
+ if(!mDialogs.isEmpty())
+ {
+ // this restacking is written in a way so that
+ // if the stacking positions actually don't change,
+ // all restacking operations will be no-op,
+ // and no ConfigureNotify will be generated,
+ // thus avoiding possible infinite loops
+ XRaiseWindow( qt_xdisplay(), mDialogs.first()->winId()); // raise topmost
+ // and stack others below it
+ Window* stack = new Window[ mDialogs.count() + 1 ];
+ int count = 0;
+ for( QValueList< QWidget* >::ConstIterator it = mDialogs.begin();
+ it != mDialogs.end();
+ ++it )
+ stack[ count++ ] = (*it)->winId();
+ stack[ count++ ] = winId();
+ XRestackWindows( x11Display(), stack, count );
+ delete[] stack;
+ }
+ else
+ XRaiseWindow(qt_xdisplay(), winId());
+}
+
+void LockProcess::checkDPMSActive()
+{
+#ifdef HAVE_DPMS
+ BOOL on;
+ CARD16 state;
+ DPMSInfo(qt_xdisplay(), &state, &on);
+ //kdDebug() << "checkDPMSActive " << on << " " << state << endl;
+ if (state == DPMSModeStandby || state == DPMSModeSuspend || state == DPMSModeOff)
+ {
+ suspend();
+ } else if ( mSuspended )
+ {
+ resume( true );
+ }
+#endif
+}
+
+#if defined(HAVE_XF86MISC) && defined(HAVE_XF86MISCSETGRABKEYSSTATE)
+// see http://cvsweb.xfree86.org/cvsweb/xc/programs/Xserver/hw/xfree86/common/xf86Events.c#rev3.113
+// This allows enabling the "Allow{Deactivate/Closedown}Grabs" options in XF86Config,
+// and kdesktop_lock will still lock the session.
+static enum { Unknown, Yes, No } can_do_xf86_lock = Unknown;
+void LockProcess::lockXF86()
+{
+ if( can_do_xf86_lock == Unknown )
+ {
+ int major, minor;
+ if( XF86MiscQueryVersion( qt_xdisplay(), &major, &minor )
+ && major >= 0 && minor >= 5 )
+ can_do_xf86_lock = Yes;
+ else
+ can_do_xf86_lock = No;
+ }
+ if( can_do_xf86_lock != Yes )
+ return;
+ if( mRestoreXF86Lock )
+ return;
+ if( XF86MiscSetGrabKeysState( qt_xdisplay(), False ) != MiscExtGrabStateSuccess )
+ return;
+ // success
+ mRestoreXF86Lock = true;
+}
+
+void LockProcess::unlockXF86()
+{
+ if( can_do_xf86_lock != Yes )
+ return;
+ if( !mRestoreXF86Lock )
+ return;
+ XF86MiscSetGrabKeysState( qt_xdisplay(), True );
+ mRestoreXF86Lock = false;
+}
+#else
+void LockProcess::lockXF86()
+{
+}
+
+void LockProcess::unlockXF86()
+{
+}
+#endif
+
+void LockProcess::msgBox( QMessageBox::Icon type, const QString &txt )
+{
+ QDialog box( 0, "messagebox", true, WX11BypassWM );
+ QFrame *winFrame = new QFrame( &box );
+ winFrame->setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+ winFrame->setLineWidth( 2 );
+ QLabel *label1 = new QLabel( winFrame );
+ label1->setPixmap( QMessageBox::standardIcon( type ) );
+ QLabel *label2 = new QLabel( txt, winFrame );
+ KPushButton *button = new KPushButton( KStdGuiItem::ok(), winFrame );
+ button->setDefault( true );
+ button->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+ connect( button, SIGNAL( clicked() ), &box, SLOT( accept() ) );
+
+ QVBoxLayout *vbox = new QVBoxLayout( &box );
+ vbox->addWidget( winFrame );
+ QGridLayout *grid = new QGridLayout( winFrame, 2, 2, 10 );
+ grid->addWidget( label1, 0, 0, Qt::AlignCenter );
+ grid->addWidget( label2, 0, 1, Qt::AlignCenter );
+ grid->addMultiCellWidget( button, 1,1, 0,1, Qt::AlignCenter );
+
+ execDialog( &box );
+}
+
+#include "lockprocess.moc"
diff --git a/kdesktop/lock/lockprocess.h b/kdesktop/lock/lockprocess.h
new file mode 100644
index 000000000..d7043e64d
--- /dev/null
+++ b/kdesktop/lock/lockprocess.h
@@ -0,0 +1,131 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+//
+
+#ifndef __LOCKENG_H__
+#define __LOCKENG_H__
+
+#include <kgreeterplugin.h>
+
+#include <kprocess.h>
+#include <kpixmap.h>
+
+#include <qwidget.h>
+#include <qtimer.h>
+#include <qvaluestack.h>
+#include <qmessagebox.h>
+#include <qpixmap.h>
+
+#include <X11/Xlib.h>
+
+class KLibrary;
+
+struct GreeterPluginHandle {
+ KLibrary *library;
+ kgreeterplugin_info *info;
+};
+
+//===========================================================================
+//
+// Screen saver handling process. Handles screensaver window,
+// starting screensaver hacks, and password entry.
+//
+class LockProcess
+ : public QWidget
+{
+ Q_OBJECT
+public:
+ LockProcess(bool child_saver = false, bool useBlankOnly = false);
+ ~LockProcess();
+
+ bool lock();
+
+ bool defaultSave();
+
+ bool dontLock();
+
+ void setChildren(QValueList<int> children) { child_sockets = children; }
+ void setParent(int fd) { mParent = fd; }
+
+ void msgBox( QMessageBox::Icon type, const QString &txt );
+ int execDialog( QDialog* dlg );
+
+public slots:
+ void quitSaver();
+ void preparePopup();
+ void cleanupPopup();
+
+protected:
+ virtual bool x11Event(XEvent *);
+ virtual void timerEvent(QTimerEvent *);
+
+private slots:
+ void hackExited(KProcess *);
+ void signalPipeSignal();
+ bool startLock();
+ void suspend();
+ void checkDPMSActive();
+ void slotDeadTimePassed();
+
+private:
+ void configure();
+ void readSaver();
+ void createSaverWindow();
+ void hideSaverWindow();
+ void saveVRoot();
+ void setVRoot(Window win, Window rw);
+ void removeVRoot(Window win);
+ bool grabKeyboard();
+ bool grabMouse();
+ bool grabInput();
+ void ungrabInput();
+ void cantLock(const QString &reason);
+ bool startSaver();
+ void stopSaver();
+ bool startHack();
+ void stopHack();
+ void setupSignals();
+ bool checkPass();
+ void stayOnTop();
+ void lockXF86();
+ void unlockXF86();
+ void resume( bool force );
+ static QVariant getConf(void *ctx, const char *key, const QVariant &dflt);
+
+ bool mLocked;
+ int mLockGrace;
+ int mPriority;
+ bool mBusy;
+ KProcess mHackProc;
+ int mRootWidth;
+ int mRootHeight;
+ QString mSaverExec;
+ QString mSaver;
+ bool mOpenGLVisual;
+ bool child_saver;
+ QValueList<int> child_sockets;
+ int mParent;
+ bool mUseBlankOnly;
+ bool mSuspended;
+ QTimer mSuspendTimer;
+ bool mVisibility;
+ bool mDPMSDepend;
+ QTimer mCheckDPMS;
+ QValueStack< QWidget* > mDialogs;
+ bool mRestoreXF86Lock;
+ bool mForbidden;
+ QStringList mPlugins, mPluginOptions;
+ QString mMethod;
+ GreeterPluginHandle greetPlugin;
+ QPixmap mSavedScreen;
+ int mAutoLogoutTimerId;
+ int mAutoLogoutTimeout;
+ bool mAutoLogout;
+};
+
+#endif
+
diff --git a/kdesktop/lock/main.cc b/kdesktop/lock/main.cc
new file mode 100644
index 000000000..b55e67ea6
--- /dev/null
+++ b/kdesktop/lock/main.cc
@@ -0,0 +1,174 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure
+ Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "lockprocess.h"
+#include "main.h"
+#include "kdesktopsettings.h"
+
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <dcopref.h>
+
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+
+bool MyApp::x11EventFilter( XEvent *ev )
+{
+ if (ev->type == XKeyPress || ev->type == ButtonPress)
+ emit activity();
+ else if (ev->type == MotionNotify) {
+ time_t tick = time( 0 );
+ if (tick != lastTick) {
+ lastTick = tick;
+ emit activity();
+ }
+ }
+ return KApplication::x11EventFilter( ev );
+}
+
+
+static KCmdLineOptions options[] =
+{
+ { "forcelock", I18N_NOOP("Force session locking"), 0 },
+ { "dontlock", I18N_NOOP("Only start screensaver"), 0 },
+ { "blank", I18N_NOOP("Only use the blank screensaver"), 0 },
+ KCmdLineLastOption
+};
+
+// -----------------------------------------------------------------------------
+
+int main( int argc, char **argv )
+{
+ KLocale::setMainCatalogue("kdesktop");
+
+ KCmdLineArgs::init( argc, argv, "kdesktop_lock", I18N_NOOP("KDesktop Locker"), I18N_NOOP("Session Locker for KDesktop"), "2.0" );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ putenv(strdup("SESSION_MANAGER="));
+
+ KApplication::disableAutoDcopRegistration(); // not needed
+
+ int kdesktop_screen_number = 0;
+ int starting_screen = 0;
+
+ bool child = false;
+ int parent_connection = 0; // socket to the parent saver
+ QValueList<int> child_sockets;
+
+ if (KGlobalSettings::isMultiHead())
+ {
+ Display *dpy = XOpenDisplay(NULL);
+ if (! dpy) {
+ fprintf(stderr,
+ "%s: FATAL ERROR: couldn't open display '%s'\n",
+ argv[0], XDisplayName(NULL));
+ exit(1);
+ }
+
+ int number_of_screens = ScreenCount(dpy);
+ starting_screen = kdesktop_screen_number = DefaultScreen(dpy);
+ int pos;
+ QCString display_name = XDisplayString(dpy);
+ XCloseDisplay(dpy);
+ kdDebug() << "screen " << number_of_screens << " " << kdesktop_screen_number << " " << display_name << " " << starting_screen << endl;
+ dpy = 0;
+
+ if ((pos = display_name.findRev('.')) != -1)
+ display_name.remove(pos, 10);
+
+ QCString env;
+ if (number_of_screens != 1) {
+ for (int i = 0; i < number_of_screens; i++) {
+ if (i != starting_screen) {
+ int fd[2];
+ if (pipe(fd)) {
+ perror("pipe");
+ break;
+ }
+ if (fork() == 0) {
+ child = true;
+ kdesktop_screen_number = i;
+ parent_connection = fd[0];
+ // break here because we are the child process, we don't
+ // want to fork() anymore
+ break;
+ } else {
+ child_sockets.append(fd[1]);
+ }
+ }
+ }
+
+ env.sprintf("DISPLAY=%s.%d", display_name.data(),
+ kdesktop_screen_number);
+ kdDebug() << "env " << env << endl;
+
+ if (putenv(strdup(env.data()))) {
+ fprintf(stderr,
+ "%s: WARNING: unable to set DISPLAY environment variable\n",
+ argv[0]);
+ perror("putenv()");
+ }
+ }
+ }
+
+ MyApp app;
+ kdDebug() << "app " << kdesktop_screen_number << " " << starting_screen << " " << child << " " << child_sockets.count() << " " << parent_connection << endl;
+ app.disableSessionManagement();
+ KGlobal::locale()->insertCatalogue("libdmctl");
+
+ // we need to read from the right rc file - possibly taking screen number in account
+ KDesktopSettings::instance("kdesktoprc");
+
+ LockProcess process(child, args->isSet( "blank" ));
+ if (!child)
+ process.setChildren(child_sockets);
+ else
+ process.setParent(parent_connection);
+
+ bool rt;
+ bool sig = false;
+ if( !child && args->isSet( "forcelock" ))
+ {
+ rt = process.lock();
+ sig = true;
+ }
+ else if( child || args->isSet( "dontlock" ))
+ rt = process.dontLock();
+ else
+ rt = process.defaultSave();
+ if (!rt)
+ return 1;
+
+ if( sig )
+ {
+ DCOPRef ref( "kdesktop", "KScreensaverIface");
+ ref.send( "saverLockReady" );
+ }
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/kdesktop/lock/main.h b/kdesktop/lock/main.h
new file mode 100644
index 000000000..c8e0e05a4
--- /dev/null
+++ b/kdesktop/lock/main.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ Copyright (c) 2003 Oswald Buddenhagen <ossi@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _MAIN_H
+#define _MAIN_H
+
+#include <kapplication.h>
+
+#include <time.h>
+
+class MyApp : public KApplication {
+ Q_OBJECT
+public:
+ MyApp() : KApplication(), lastTick( 0 ) {}
+protected:
+ bool x11EventFilter( XEvent * );
+signals:
+ void activity();
+private:
+ time_t lastTick;
+};
+
+#endif
diff --git a/kdesktop/lockeng.cc b/kdesktop/lockeng.cc
new file mode 100644
index 000000000..a8b9ddeea
--- /dev/null
+++ b/kdesktop/lockeng.cc
@@ -0,0 +1,371 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+//
+
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kservicegroup.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qfile.h>
+#include <dcopclient.h>
+#include <assert.h>
+
+#include "lockeng.h"
+#include "lockeng.moc"
+#include "kdesktopsettings.h"
+
+#include "xautolock_c.h"
+extern xautolock_corner_t xautolock_corners[ 4 ];
+
+
+//===========================================================================
+//
+// Screen saver engine. Doesn't handle the actual screensaver window,
+// starting screensaver hacks, or password entry. That's done by
+// a newly started process.
+//
+SaverEngine::SaverEngine()
+ : DCOPObject("KScreensaverIface"),
+ QWidget(),
+ mBlankOnly(false)
+{
+ // Save X screensaver parameters
+ XGetScreenSaver(qt_xdisplay(), &mXTimeout, &mXInterval,
+ &mXBlanking, &mXExposures);
+
+ mState = Waiting;
+ mXAutoLock = 0;
+ mEnabled = false;
+
+ connect(&mLockProcess, SIGNAL(processExited(KProcess *)),
+ SLOT(lockProcessExited()));
+
+ configure();
+}
+
+//---------------------------------------------------------------------------
+//
+// Destructor - usual cleanups.
+//
+SaverEngine::~SaverEngine()
+{
+ mLockProcess.detach(); // don't kill it if we crash
+ delete mXAutoLock;
+
+ // Restore X screensaver parameters
+ XSetScreenSaver(qt_xdisplay(), mXTimeout, mXInterval, mXBlanking,
+ mXExposures);
+}
+
+//---------------------------------------------------------------------------
+
+// This should be called only using DCOP.
+void SaverEngine::lock()
+{
+ bool ok = true;
+ if (mState == Waiting)
+ {
+ ok = startLockProcess( ForceLock );
+// It takes a while for kdesktop_lock to start and lock the screen.
+// Therefore delay the DCOP call until it tells kdesktop that the locking is in effect.
+// This is done only for --forcelock .
+ if( ok && mState != Saving )
+ {
+ DCOPClientTransaction* trans = kapp->dcopClient()->beginTransaction();
+ mLockTransactions.append( trans );
+ }
+ }
+ else
+ {
+ mLockProcess.kill( SIGHUP );
+ }
+}
+
+void SaverEngine::processLockTransactions()
+{
+ for( QValueVector< DCOPClientTransaction* >::ConstIterator it = mLockTransactions.begin();
+ it != mLockTransactions.end();
+ ++it )
+ {
+ QCString replyType = "void";
+ QByteArray arr;
+ kapp->dcopClient()->endTransaction( *it, replyType, arr );
+ }
+ mLockTransactions.clear();
+}
+
+void SaverEngine::saverLockReady()
+{
+ if( mState != Preparing )
+ {
+ kdDebug( 1204 ) << "Got unexpected saverReady()" << endl;
+ }
+ kdDebug( 1204 ) << "Saver Lock Ready" << endl;
+ processLockTransactions();
+}
+
+//---------------------------------------------------------------------------
+void SaverEngine::save()
+{
+ if (mState == Waiting)
+ {
+ startLockProcess( DefaultLock );
+ }
+}
+
+//---------------------------------------------------------------------------
+void SaverEngine::quit()
+{
+ if (mState == Saving || mState == Preparing)
+ {
+ stopLockProcess();
+ }
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::isEnabled()
+{
+ return mEnabled;
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::enable( bool e )
+{
+ if ( e == mEnabled )
+ return true;
+
+ // If we aren't in a suitable state, we will not reconfigure.
+ if (mState != Waiting)
+ return false;
+
+ mEnabled = e;
+
+ if (mEnabled)
+ {
+ if ( !mXAutoLock ) {
+ mXAutoLock = new XAutoLock();
+ connect(mXAutoLock, SIGNAL(timeout()), SLOT(idleTimeout()));
+ }
+ mXAutoLock->setTimeout(mTimeout);
+ mXAutoLock->setDPMS(true);
+ //mXAutoLock->changeCornerLockStatus( mLockCornerTopLeft, mLockCornerTopRight, mLockCornerBottomLeft, mLockCornerBottomRight);
+
+ // We'll handle blanking
+ XSetScreenSaver(qt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
+ kdDebug() << "XSetScreenSaver " << mTimeout + 10 << endl;
+
+ mXAutoLock->start();
+
+ kdDebug(1204) << "Saver Engine started, timeout: " << mTimeout << endl;
+ }
+ else
+ {
+ if (mXAutoLock)
+ {
+ delete mXAutoLock;
+ mXAutoLock = 0;
+ }
+
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+ XSetScreenSaver(qt_xdisplay(), 0, mXInterval, PreferBlanking, DontAllowExposures);
+ kdDebug(1204) << "Saver Engine disabled" << endl;
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+bool SaverEngine::isBlanked()
+{
+ return (mState != Waiting);
+}
+
+//---------------------------------------------------------------------------
+//
+// Read and apply configuration.
+//
+void SaverEngine::configure()
+{
+ // If we aren't in a suitable state, we will not reconfigure.
+ if (mState != Waiting)
+ return;
+
+ // create a new config obj to ensure we read the latest options
+ KDesktopSettings::self()->readConfig();
+
+ bool e = KDesktopSettings::screenSaverEnabled();
+ mTimeout = KDesktopSettings::timeout();
+
+ mEnabled = !e; // force the enable()
+
+ int action;
+ action = KDesktopSettings::actionTopLeft();
+ xautolock_corners[0] = applyManualSettings(action);
+ action = KDesktopSettings::actionTopRight();
+ xautolock_corners[1] = applyManualSettings(action);
+ action = KDesktopSettings::actionBottomLeft();
+ xautolock_corners[2] = applyManualSettings(action);
+ action = KDesktopSettings::actionBottomRight();
+ xautolock_corners[3] = applyManualSettings(action);
+
+ enable( e );
+}
+
+//---------------------------------------------------------------------------
+//
+// Set a variable to indicate only using the blanker and not the saver.
+//
+void SaverEngine::setBlankOnly( bool blankOnly )
+{
+ mBlankOnly = blankOnly;
+ // FIXME: if running, stop and restart? What about security
+ // implications of this?
+}
+
+//---------------------------------------------------------------------------
+//
+// Start the screen saver.
+//
+bool SaverEngine::startLockProcess( LockType lock_type )
+{
+ if (mState != Waiting)
+ return true;
+
+ kdDebug(1204) << "SaverEngine: starting saver" << endl;
+ emitDCOPSignal("KDE_start_screensaver()", QByteArray());
+
+ if (mLockProcess.isRunning())
+ {
+ stopLockProcess();
+ }
+ mLockProcess.clearArguments();
+ QString path = KStandardDirs::findExe( "kdesktop_lock" );
+ if( path.isEmpty())
+ {
+ kdDebug( 1204 ) << "Can't find kdesktop_lock!" << endl;
+ return false;
+ }
+ mLockProcess << path;
+ switch( lock_type )
+ {
+ case ForceLock:
+ mLockProcess << QString( "--forcelock" );
+ break;
+ case DontLock:
+ mLockProcess << QString( "--dontlock" );
+ break;
+ default:
+ break;
+ }
+ if (mBlankOnly)
+ mLockProcess << QString( "--blank" );
+
+ if (mLockProcess.start() == false )
+ {
+ kdDebug( 1204 ) << "Failed to start kdesktop_lock!" << endl;
+ return false;
+ }
+ XSetScreenSaver(qt_xdisplay(), 0, mXInterval, PreferBlanking, mXExposures);
+
+ mState = Preparing;
+ if (mXAutoLock)
+ {
+ mXAutoLock->stop();
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Stop the screen saver.
+//
+void SaverEngine::stopLockProcess()
+{
+ if (mState == Waiting)
+ {
+ kdWarning(1204) << "SaverEngine::stopSaver() saver not active" << endl;
+ return;
+ }
+ kdDebug(1204) << "SaverEngine: stopping lock" << endl;
+ emitDCOPSignal("KDE_stop_screensaver()", QByteArray());
+
+ mLockProcess.kill();
+
+ if (mEnabled)
+ {
+ if (mXAutoLock)
+ {
+ mXAutoLock->start();
+ }
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+ XSetScreenSaver(qt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
+ }
+ processLockTransactions();
+ mState = Waiting;
+}
+
+void SaverEngine::lockProcessExited()
+{
+ kdDebug(1204) << "SaverEngine: lock exited" << endl;
+ if( mState == Waiting )
+ return;
+ emitDCOPSignal("KDE_stop_screensaver()", QByteArray());
+ if (mEnabled)
+ {
+ if (mXAutoLock)
+ {
+ mXAutoLock->start();
+ }
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+ XSetScreenSaver(qt_xdisplay(), mTimeout + 10, mXInterval, PreferBlanking, mXExposures);
+ }
+ processLockTransactions();
+ mState = Waiting;
+}
+
+//---------------------------------------------------------------------------
+//
+// XAutoLock has detected the required idle time.
+//
+void SaverEngine::idleTimeout()
+{
+ // disable X screensaver
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+ XSetScreenSaver(qt_xdisplay(), 0, mXInterval, PreferBlanking, DontAllowExposures);
+ startLockProcess( DefaultLock );
+}
+
+xautolock_corner_t SaverEngine::applyManualSettings(int action)
+{
+ if (action == 0)
+ {
+ kdDebug() << "no lock" << endl;
+ return ca_nothing;
+ }
+ else
+ if (action == 1)
+ {
+ kdDebug() << "lock screen" << endl;
+ return ca_forceLock;
+ }
+ else
+ if (action == 2)
+ {
+ kdDebug() << "prevent lock" << endl;
+ return ca_dontLock;
+ }
+ else
+ {
+ kdDebug() << "no lock nothing" << endl;
+ return ca_nothing;
+ }
+}
diff --git a/kdesktop/lockeng.h b/kdesktop/lockeng.h
new file mode 100644
index 000000000..0eb67f9d6
--- /dev/null
+++ b/kdesktop/lockeng.h
@@ -0,0 +1,113 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+//
+
+#ifndef __LOCKENG_H__
+#define __LOCKENG_H__
+
+#include <qwidget.h>
+#include <kprocess.h>
+#include <qvaluevector.h>
+#include "KScreensaverIface.h"
+#include "xautolock.h"
+#include "xautolock_c.h"
+
+class DCOPClientTransaction;
+
+//===========================================================================
+/**
+ * Screen saver engine. Handles screensaver window, starting screensaver
+ * hacks, and password entry.
+ */
+class SaverEngine
+ : public QWidget,
+ virtual public KScreensaverIface
+{
+ Q_OBJECT
+public:
+ SaverEngine();
+ ~SaverEngine();
+
+ /**
+ * Lock the screen
+ */
+ virtual void lock();
+
+ /**
+ * Save the screen
+ */
+ virtual void save();
+
+ /**
+ * Quit the screensaver if running
+ */
+ virtual void quit();
+
+ /**
+ * return true if the screensaver is enabled
+ */
+ virtual bool isEnabled();
+
+ /**
+ * enable/disable the screensaver
+ */
+ virtual bool enable( bool e );
+
+ /**
+ * return true if the screen is currently blanked
+ */
+ virtual bool isBlanked();
+
+ /**
+ * Read and apply configuration.
+ */
+ virtual void configure();
+
+ /**
+ * Enable or disable "blank only" mode. This is useful for
+ * laptops where one might not want a cpu thirsty screensaver
+ * draining the battery.
+ */
+ virtual void setBlankOnly( bool blankOnly );
+
+ /**
+ * Called by kdesktop_lock when locking is in effect.
+ */
+ virtual void saverLockReady();
+
+protected slots:
+ void idleTimeout();
+ void lockProcessExited();
+
+protected:
+ enum LockType { DontLock, DefaultLock, ForceLock };
+ bool startLockProcess( LockType lock_type );
+ void stopLockProcess();
+ bool handleKeyPress(XKeyEvent *xke);
+ void processLockTransactions();
+ xautolock_corner_t applyManualSettings(int);
+
+protected:
+ enum State { Waiting, Preparing, Saving };
+ bool mEnabled;
+
+ State mState;
+ XAutoLock *mXAutoLock;
+ KProcess mLockProcess;
+ int mTimeout;
+
+ // the original X screensaver parameters
+ int mXTimeout;
+ int mXInterval;
+ int mXBlanking;
+ int mXExposures;
+
+ bool mBlankOnly; // only use the blanker, not the defined saver
+ QValueVector< DCOPClientTransaction* > mLockTransactions;
+};
+
+#endif
+
diff --git a/kdesktop/main.cc b/kdesktop/main.cc
new file mode 100644
index 000000000..dd058c498
--- /dev/null
+++ b/kdesktop/main.cc
@@ -0,0 +1,215 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure (maintainer)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+#include <kuniqueapplication.h>
+#include <klocale.h>
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kopenwith.h>
+#include <kcrash.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kmanagerselection.h>
+
+#include "desktop.h"
+#include "lockeng.h"
+#include "init.h"
+#include "krootwm.h"
+#include "kdesktopsettings.h"
+
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+static const char description[] =
+ I18N_NOOP("The KDE desktop");
+
+static const char version[] = VERSION;
+
+static KCmdLineOptions options[] =
+{
+ { "x-root", I18N_NOOP("Use this if the desktop window appears as a real window"), 0 },
+ { "noautostart", I18N_NOOP("Obsolete"), 0 },
+ { "waitforkded", I18N_NOOP("Wait for kded to finish building database"), 0 },
+ KCmdLineLastOption
+};
+
+// -----------------------------------------------------------------------------
+
+int kdesktop_screen_number = 0;
+QCString kdesktop_name, kicker_name, kwin_name;
+
+static void crashHandler(int sigId)
+{
+ DCOPClient::emergencyClose(); // unregister DCOP
+ sleep( 1 );
+ system("kdesktop &"); // try to restart
+ fprintf(stderr, "*** kdesktop (%ld) got signal %d\n", (long) getpid(), sigId);
+ ::exit(1);
+}
+
+static void signalHandler(int sigId)
+{
+ fprintf(stderr, "*** kdesktop got signal %d (Exiting)\n", sigId);
+ KCrash::setEmergencySaveFunction(0); // No restarts any more
+ // try to cleanup all windows
+ signal(SIGTERM, SIG_DFL); // next one kills
+ signal(SIGHUP, SIG_DFL); // next one kills
+ if (kapp)
+ kapp->quit(); // turn catchable signals into clean shutdown
+}
+
+void KDesktop::slotUpAndRunning()
+{
+ // Activate crash recovery
+ if (getenv("KDE_DEBUG") == NULL)
+ KCrash::setEmergencySaveFunction(crashHandler); // Try to restart on crash
+}
+
+extern "C" KDE_EXPORT int kdemain( int argc, char **argv )
+{
+ //setup signal handling
+ signal(SIGTERM, signalHandler);
+ signal(SIGHUP, signalHandler);
+
+ {
+ if (KGlobalSettings::isMultiHead())
+ {
+ Display *dpy = XOpenDisplay(NULL);
+ if (! dpy) {
+ fprintf(stderr,
+ "%s: FATAL ERROR: couldn't open display '%s'\n",
+ argv[0], XDisplayName(NULL));
+ exit(1);
+ }
+
+ int number_of_screens = ScreenCount(dpy);
+ kdesktop_screen_number = DefaultScreen(dpy);
+ int pos;
+ QCString display_name = XDisplayString(dpy);
+ XCloseDisplay(dpy);
+ dpy = 0;
+
+ if ((pos = display_name.findRev('.')) != -1)
+ display_name.remove(pos, 10);
+
+ QCString env;
+ if (number_of_screens != 1) {
+ for (int i = 0; i < number_of_screens; i++) {
+ if (i != kdesktop_screen_number && fork() == 0) {
+ kdesktop_screen_number = i;
+ // break here because we are the child process, we don't
+ // want to fork() anymore
+ break;
+ }
+ }
+
+ env.sprintf("DISPLAY=%s.%d", display_name.data(),
+ kdesktop_screen_number);
+
+ if (putenv(strdup(env.data()))) {
+ fprintf(stderr,
+ "%s: WARNING: unable to set DISPLAY environment variable\n",
+ argv[0]);
+ perror("putenv()");
+ }
+ }
+ }
+ }
+
+ KGlobal::locale()->setMainCatalogue("kdesktop");
+
+ if (kdesktop_screen_number == 0) {
+ kdesktop_name = "kdesktop";
+ kicker_name = "kicker";
+ kwin_name = "kwin";
+ } else {
+ kdesktop_name.sprintf("kdesktop-screen-%d", kdesktop_screen_number);
+ kicker_name.sprintf("kicker-screen-%d", kdesktop_screen_number);
+ kwin_name.sprintf("kwin-screen-%d", kdesktop_screen_number);
+ }
+
+ KAboutData aboutData( kdesktop_name, I18N_NOOP("KDesktop"),
+ version, description, KAboutData::License_GPL,
+ "(c) 1998-2000, The KDesktop Authors");
+ aboutData.addAuthor("David Faure", 0, "faure@kde.org");
+ aboutData.addAuthor("Martin Koller", 0, "m.koller@surfeu.at");
+ aboutData.addAuthor("Waldo Bastian", 0, "bastian@kde.org");
+ aboutData.addAuthor("Luboš Luňák", 0, "l.lunak@kde.org");
+ aboutData.addAuthor("Joseph Wenninger", 0, "kde@jowenn.at");
+ aboutData.addAuthor("Tim Jansen", 0, "tim@tjansen.de");
+ aboutData.addAuthor("Benoit Walter", 0, "b.walter@free.fr");
+ aboutData.addAuthor("Torben Weis", 0, "weis@kde.org");
+ aboutData.addAuthor("Matthias Ettrich", 0, "ettrich@kde.org");
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ if (!KUniqueApplication::start()) {
+ fprintf(stderr, "kdesktop is already running!\n");
+ exit(0);
+ }
+ DCOPClient* cl = new DCOPClient;
+ cl->attach();
+ DCOPRef r( "ksmserver", "ksmserver" );
+ r.setDCOPClient( cl );
+ r.send( "suspendStartup", QCString( "kdesktop" ));
+ delete cl;
+ KUniqueApplication app;
+ app.disableSessionManagement(); // Do SM, but don't restart.
+
+ KDesktopSettings::instance(kdesktop_name + "rc");
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ bool x_root_hack = args->isSet("x-root");
+ bool wait_for_kded = args->isSet("waitforkded");
+
+ // This MUST be created before any widgets are created
+ SaverEngine saver;
+
+ // Do this before forking so that if a dialog box appears it won't
+ // be covered by other apps.
+ // And before creating KDesktop too, of course.
+ testLocalInstallation();
+
+ // Mark kdeskop as immutable if all of its config modules have been disabled
+ if (!app.config()->isImmutable() &&
+ kapp->authorizeControlModules(KRootWm::configModules()).isEmpty())
+ {
+ app.config()->setReadOnly(true);
+ app.config()->reparseConfiguration();
+ }
+
+ // for the KDE-already-running check in startkde
+ KSelectionOwner kde_running( "_KDE_RUNNING", 0 );
+ kde_running.claim( false );
+
+ KDesktop desktop( x_root_hack, wait_for_kded );
+
+ args->clear();
+
+ app.dcopClient()->setDefaultObject( "KDesktopIface" );
+
+ return app.exec();
+}
diff --git a/kdesktop/minicli.cpp b/kdesktop/minicli.cpp
new file mode 100644
index 000000000..096b293d0
--- /dev/null
+++ b/kdesktop/minicli.cpp
@@ -0,0 +1,886 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 1999-2002,2003 Dawit Alemayehu <adawit@kde.org>
+ Copyright (C) 2000 Malte Starostik <starosti@zedat.fu-berlin.de>
+ Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
+
+ Kdesu integration:
+ Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+
+ Original authors:
+ Copyright (C) 1997 Matthias Ettrich <ettrich@kde.org>
+ Copyright (C) 1997 Torben Weis [ Added command completion ]
+ Copyright (C) 1999 Preston Brown <pbrown@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <pwd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <qvbox.h>
+#include <qlabel.h>
+#include <qbitmap.h>
+#include <qfile.h>
+#include <qslider.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qregexp.h>
+#include <qwhatsthis.h>
+#include <qstylesheet.h>
+
+#include <dcopclient.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kpassdlg.h>
+#include <krun.h>
+#include <kwin.h>
+#include <kdesu/su.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+#include <kguiitem.h>
+#include <kstdguiitem.h>
+#include <kmimetype.h>
+#include <kurifilter.h>
+#include <kcompletionbox.h>
+
+#include "minicli.moc"
+#include "minicli_ui.h"
+#include "kdesktopsettings.h"
+
+#define KDESU_ERR strerror(errno)
+
+Minicli::Minicli( QWidget *parent, const char *name)
+ :KDialog( parent, name, false, WType_TopLevel ),
+ m_autoCheckedRunInTerm(false)
+{
+ setPlainCaption( i18n("Run Command") );
+ KWin::setIcons( winId(), DesktopIcon("run"), SmallIcon("run") );
+
+ QVBoxLayout* mainLayout = new QVBoxLayout( this, 0, KDialog::spacingHint() );
+ m_dlg = new MinicliDlgUI (this);
+ mainLayout->addWidget(m_dlg);
+
+ m_dlg->lbRunIcon->setPixmap(DesktopIcon("kmenu"));
+ m_dlg->lbComment->setAlignment( Qt::WordBreak );
+
+ m_dlg->cbCommand->setDuplicatesEnabled( false );
+ m_dlg->cbCommand->setTrapReturnKey( true );
+
+ // Options button...
+ m_dlg->pbOptions->setGuiItem (KGuiItem( i18n("&Options >>"), "configure" ));
+
+ // Run button...
+ m_dlg->pbRun->setGuiItem (KGuiItem( i18n("&Run"), "run" ));
+
+ // Cancel button...
+ m_dlg->pbCancel->setGuiItem ( KStdGuiItem::cancel() );
+
+ if (!kapp->authorize("shell_access"))
+ m_dlg->pbOptions->hide();
+
+ m_dlg->pbRun->setEnabled(!m_dlg->cbCommand->currentText().isEmpty());
+ m_dlg->pbRun->setDefault( true );
+
+ // Do not show the advanced group box on startup...
+ m_dlg->gbAdvanced->hide();
+
+ // URI Filter meta object...
+ m_filterData = new KURIFilterData();
+
+ // Create a timer object...
+ m_parseTimer = new QTimer(this);
+
+ m_FocusWidget = 0;
+
+ m_prevCached = false;
+ m_iPriority = 50;
+ m_iScheduler = StubProcess::SchedNormal;
+
+ m_dlg->leUsername->setText("root");
+
+ // Main widget buttons...
+ connect( m_dlg->pbRun, SIGNAL(clicked()), this, SLOT(accept()) );
+ connect( m_dlg->pbCancel, SIGNAL(clicked()), this, SLOT(reject()) );
+ connect( m_dlg->pbOptions, SIGNAL(clicked()), SLOT(slotAdvanced()) );
+ connect( m_parseTimer, SIGNAL(timeout()), SLOT(slotParseTimer()) );
+
+ connect( m_dlg->cbCommand, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotCmdChanged(const QString&) ) );
+
+ connect( m_dlg->cbCommand, SIGNAL( returnPressed() ),
+ m_dlg->pbRun, SLOT( animateClick() ) );
+
+ // Advanced group box...
+ connect(m_dlg->cbPriority, SIGNAL(toggled(bool)), SLOT(slotChangeScheduler(bool)));
+ connect(m_dlg->slPriority, SIGNAL(valueChanged(int)), SLOT(slotPriority(int)));
+ connect(m_dlg->cbRealtime, SIGNAL(toggled(bool)), SLOT(slotRealtime(bool)));
+ connect(m_dlg->cbRunAsOther, SIGNAL(toggled(bool)), SLOT(slotChangeUid(bool)));
+ connect(m_dlg->leUsername, SIGNAL(lostFocus()), SLOT(updateAuthLabel()));
+ connect(m_dlg->cbRunInTerminal, SIGNAL(toggled(bool)), SLOT(slotTerminal(bool)));
+
+ m_dlg->slPriority->setValue(50);
+
+ loadConfig();
+}
+
+Minicli::~Minicli()
+{
+ delete m_filterData;
+}
+
+void Minicli::setCommand(const QString& command)
+{
+ m_dlg->cbCommand->lineEdit()->setText(command);
+ m_dlg->cbCommand->lineEdit()->deselect();
+ int firstSpace = command.find(' ');
+ if (firstSpace > 0) {
+ m_dlg->cbCommand->lineEdit()->setSelection(firstSpace+1, command.length());
+ }
+}
+
+QSize Minicli::sizeHint() const
+{
+ int maxWidth = qApp->desktop()->screenGeometry((QWidget*)this).width();
+ if (maxWidth < 603)
+ {
+ // a sensible max for smaller screens
+ maxWidth = (maxWidth > 240) ? 240 : maxWidth;
+ }
+ else
+ {
+ maxWidth = maxWidth * 2 / 5;
+ }
+
+ return QSize(maxWidth, -1);
+}
+
+void Minicli::show()
+{
+ KWin::setState( winId(), NET::StaysOnTop );
+ KDialog::show();
+}
+
+void Minicli::loadConfig()
+{
+ QStringList histList = KDesktopSettings::history();
+ int maxHistory = KDesktopSettings::historyLength();
+ m_terminalAppList = KDesktopSettings::terminalApps();
+
+ if (m_terminalAppList.isEmpty())
+ m_terminalAppList << "ls"; // Default
+
+ bool block = m_dlg->cbCommand->signalsBlocked();
+ m_dlg->cbCommand->blockSignals( true );
+ m_dlg->cbCommand->setMaxCount( maxHistory );
+ m_dlg->cbCommand->setHistoryItems( histList );
+ m_dlg->cbCommand->blockSignals( block );
+
+ QStringList compList = KDesktopSettings::completionItems();
+ if( compList.isEmpty() )
+ m_dlg->cbCommand->completionObject()->setItems( histList );
+ else
+ m_dlg->cbCommand->completionObject()->setItems( compList );
+
+ int mode = KDesktopSettings::completionMode();
+ m_dlg->cbCommand->setCompletionMode( (KGlobalSettings::Completion) mode );
+
+ KCompletionBox* box = m_dlg->cbCommand->completionBox();
+ if (box)
+ box->setActivateOnSelect( false );
+
+ m_finalFilters = KURIFilter::self()->pluginNames();
+ m_finalFilters.remove("kuriikwsfilter");
+
+ m_middleFilters = m_finalFilters;
+ m_middleFilters.remove("localdomainurifilter");
+
+ // Provide username completions. Use saner and configurable maximum values.
+ int maxEntries = KDesktopSettings::maxUsernameCompletions();
+ QStringList users;
+
+ struct passwd *pw;
+ setpwent();
+ for (int count=0; ((pw = getpwent()) != 0L) && (count < maxEntries); count++)
+ users << QString::fromLocal8Bit(pw->pw_name);
+ endpwent();
+
+ KCompletion *completion = new KCompletion;
+ completion->setOrder(KCompletion::Sorted);
+ completion->insertItems (users);
+
+ m_dlg->leUsername->setCompletionObject(completion, true);
+ m_dlg->leUsername->setCompletionMode(KGlobalSettings::completionMode());
+ m_dlg->leUsername->setAutoDeleteCompletionObject( true );
+
+}
+
+void Minicli::saveConfig()
+{
+ KDesktopSettings::setHistory( m_dlg->cbCommand->historyItems() );
+ KDesktopSettings::setTerminalApps( m_terminalAppList );
+ KDesktopSettings::setCompletionItems( m_dlg->cbCommand->completionObject()->items() );
+ KDesktopSettings::setCompletionMode( m_dlg->cbCommand->completionMode() );
+ KDesktopSettings::writeConfig();
+}
+
+void Minicli::clearHistory()
+{
+ m_dlg->cbCommand->clearHistory();
+ saveConfig();
+}
+
+void Minicli::accept()
+{
+ QString cmd = m_dlg->cbCommand->currentText().stripWhiteSpace();
+ if (!cmd.isEmpty() && (cmd[0].isNumber() || (cmd[0] == '(')) &&
+ (QRegExp("[a-zA-Z\\]\\[]").search(cmd) == -1))
+ {
+ QString result = calculate(cmd);
+ if (!result.isEmpty())
+ m_dlg->cbCommand->setCurrentText(result);
+ return;
+ }
+
+ bool logout = (cmd == "logout");
+ if( !logout && runCommand() == 1 )
+ return;
+
+ m_dlg->cbCommand->addToHistory( m_dlg->cbCommand->currentText().stripWhiteSpace() );
+ reset();
+ saveConfig();
+ QDialog::accept();
+
+ if ( logout )
+ {
+ kapp->propagateSessionManager();
+ kapp->requestShutDown();
+ }
+}
+
+void Minicli::reject()
+{
+ reset();
+ QDialog::reject();
+}
+
+void Minicli::reset()
+{
+ if( m_dlg->gbAdvanced->isShown() )
+ slotAdvanced();
+
+ bool block = m_dlg->cbCommand->signalsBlocked();
+ m_dlg->cbCommand->blockSignals( true );
+ m_dlg->cbCommand->clearEdit();
+ m_dlg->cbCommand->setFocus();
+ m_dlg->cbCommand->reset();
+ m_dlg->cbCommand->blockSignals( block );
+ m_dlg->pbRun->setEnabled( false );
+
+ m_iPriority = 50;
+ m_iScheduler = StubProcess::SchedNormal;
+
+ m_dlg->cbRunInTerminal->setChecked(false);
+ m_dlg->cbRunAsOther->setChecked(false);
+
+ m_dlg->leUsername->setText("root");
+
+ m_dlg->cbPriority->setChecked(false);
+
+ m_dlg->slPriority->setValue(m_iPriority);
+
+ m_dlg->cbRealtime->setChecked( m_iScheduler == StubProcess::SchedRealtime );
+ m_dlg->lePassword->erase();
+
+ m_FocusWidget = 0;
+ m_iconName = QString::null;
+ m_prevIconName = QString::null;
+
+ m_prevCached = false;
+ updateAuthLabel();
+ setIcon();
+}
+
+void Minicli::keyPressEvent( QKeyEvent* e )
+{
+ if ( e->key() == Qt::Key_Escape )
+ {
+ e->accept();
+ m_dlg->pbCancel->animateClick();
+ return;
+ }
+
+ QDialog::keyPressEvent( e );
+}
+
+QString Minicli::terminalCommand (const QString& cmd, const QString& args)
+{
+ QString terminal = KDesktopSettings::terminalApplication().stripWhiteSpace();
+ if (terminal.endsWith("konsole"))
+ terminal += " --noclose";
+
+ if( args.isEmpty() )
+ terminal += QString(" -e /bin/sh -c \"%1\"").arg(cmd);
+ else
+ terminal += QString(" -e /bin/sh -c \"%1 %2\"").arg(cmd).arg(args);
+
+ if (!m_terminalAppList.contains(cmd))
+ m_terminalAppList << cmd;
+
+ return terminal;
+}
+
+int Minicli::runCommand()
+{
+ m_parseTimer->stop();
+
+ // Make sure we have an updated data
+ parseLine( true );
+
+ // Ignore empty commands...
+ if ( m_dlg->cbCommand->currentText().isEmpty() )
+ return 1;
+
+ QString cmd;
+ KURL uri = m_filterData->uri();
+ if ( uri.isLocalFile() && !uri.hasRef() && uri.query().isEmpty() )
+ cmd = uri.path();
+ else
+ cmd = uri.url();
+
+ // Determine whether the application should be run through
+ // the command line (terminal) interface...
+ bool useTerminal = m_dlg->cbRunInTerminal->isChecked();
+
+ kdDebug (1207) << "Use terminal ? " << useTerminal << endl;
+
+ if (!kapp->authorize("shell_access"))
+ useTerminal = false;
+
+ if( needsKDEsu() )
+ {
+ QCString user;
+ struct passwd *pw;
+
+ if (m_dlg->cbRunAsOther)
+ {
+ pw = getpwnam(m_dlg->leUsername->text().local8Bit());
+ if (pw == 0L)
+ {
+ KMessageBox::sorry( this, i18n("<qt>The user <b>%1</b> "
+ "does not exist on this system.</qt>").arg(m_dlg->leUsername->text()));
+ return 1;
+ }
+ }
+ else
+ {
+ pw = getpwuid(getuid());
+ if (pw == 0L)
+ {
+ KMessageBox::error( this, i18n("You do not exist.\n"));
+ return 1;
+ }
+ }
+
+ user = pw->pw_name;
+
+ {
+ // Scoped. we want this object to go away before the fork
+ // (maybe not necessary, but can't hurt) according to the cvs log,
+ // creating the SuProcess object in the parent and using it in the
+ // child creates crashes, but we need to check password before the
+ // fork in order to not get in trouble with X for the messagebox
+
+ SuProcess proc_checkpwd;
+ proc_checkpwd.setUser( user );
+
+ if (m_dlg->cbPriority->isChecked())
+ {
+ proc_checkpwd.setPriority(m_iPriority);
+ proc_checkpwd.setScheduler(m_iScheduler);
+ }
+
+ if (proc_checkpwd.checkInstall(m_dlg->lePassword->password()) != 0)
+ {
+ KMessageBox::sorry(this, i18n("Incorrect password; please try again."));
+ return 1;
+ }
+ }
+
+ QApplication::flushX();
+
+ int pid = fork();
+
+ if (pid < 0)
+ {
+ kdError(1207) << "fork(): " << KDESU_ERR << "\n";
+ return -1;
+ }
+
+ if (pid > 0)
+ return 0;
+
+ // From here on, this is child...
+
+ SuProcess proc;
+ proc.setUser(user);
+
+ if (m_dlg->cbPriority->isChecked())
+ {
+ proc.setPriority(m_iPriority);
+ proc.setScheduler(m_iScheduler);
+ }
+
+ QCString command;
+
+ if (useTerminal)
+ command = terminalCommand( cmd, m_filterData->argsAndOptions() ).local8Bit();
+ else
+ {
+ command = cmd.local8Bit();
+ if( m_filterData->hasArgsAndOptions() )
+ command += m_filterData->argsAndOptions().local8Bit();
+ }
+
+ proc.setCommand(command);
+
+ // Block SIGCHLD because SuProcess::exec() uses waitpid()
+ sigset_t sset;
+ sigemptyset(&sset);
+ sigaddset(&sset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sset, 0L);
+ proc.setTerminal(true);
+ proc.setErase(true);
+ _exit(proc.exec(m_dlg->lePassword->password()));
+ return 0;
+ }
+ else
+ {
+ QString exec;
+
+ // yes, this is a hack, but there is no way of doing it
+ // through SuProcess without providing the user password
+ if (m_iPriority < 50)
+ {
+ // from kdesu_stub.c
+ int val = 20 - (int) (((double) m_iPriority) * 40 / 100 + 0.5);
+ cmd = "nice -n " + QString::number( val ) + " " + cmd;
+ }
+
+ if (useTerminal)
+ {
+ cmd = terminalCommand( cmd, m_filterData->argsAndOptions() );
+ kdDebug(1207) << "Terminal command: " << cmd << endl;
+ }
+ else
+ {
+ switch( m_filterData->uriType() )
+ {
+ case KURIFilterData::LOCAL_FILE:
+ case KURIFilterData::LOCAL_DIR:
+ case KURIFilterData::NET_PROTOCOL:
+ case KURIFilterData::HELP:
+ {
+ // No need for kfmclient, KRun does it all (David)
+ (void) new KRun( m_filterData->uri(), parentWidget());
+ return 0;
+ }
+ case KURIFilterData::EXECUTABLE:
+ {
+ if( !m_filterData->hasArgsAndOptions() )
+ {
+ // Look for desktop file
+ KService::Ptr service = KService::serviceByDesktopName(cmd);
+ if (service && service->isValid() && service->type() == "Application")
+ {
+ notifyServiceStarted(service);
+ KRun::run(*service, KURL::List());
+ return 0;
+ }
+ }
+ }
+ // fall-through to shell case
+ case KURIFilterData::SHELL:
+ {
+ if (kapp->authorize("shell_access"))
+ {
+ exec = cmd;
+
+ if( m_filterData->hasArgsAndOptions() )
+ cmd += m_filterData->argsAndOptions();
+
+ break;
+ }
+ else
+ {
+ KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n"
+ "You do not have permission to execute "
+ "this command.")
+ .arg( QStyleSheet::convertFromPlainText(cmd) ));
+ return 1;
+ }
+ }
+ case KURIFilterData::UNKNOWN:
+ case KURIFilterData::ERROR:
+ default:
+ {
+ // Look for desktop file
+ KService::Ptr service = KService::serviceByDesktopName(cmd);
+ if (service && service->isValid() && service->type() == "Application")
+ {
+ notifyServiceStarted(service);
+ KRun::run(*service, KURL::List(), this);
+ return 0;
+ }
+
+ service = KService::serviceByName(cmd);
+ if (service && service->isValid() && service->type() == "Application")
+ {
+ notifyServiceStarted(service);
+ KRun::run(*service, KURL::List(), this);
+ return 0;
+ }
+
+ KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n"
+ "Could not run the specified command.")
+ .arg( QStyleSheet::convertFromPlainText(cmd) ));
+ return 1;
+ }
+ }
+ }
+
+ if ( KRun::runCommand( cmd, exec, m_iconName ) )
+ return 0;
+ else
+ {
+ KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n"
+ "The specified command does not exist.").arg(cmd) );
+ return 1; // Let the user try again...
+ }
+ }
+}
+
+void Minicli::notifyServiceStarted(KService::Ptr service)
+{
+ // Inform other applications (like the quickstarter applet)
+ // that an application was started
+ QByteArray params;
+ QDataStream stream(params, IO_WriteOnly);
+ stream << "minicli" << service->storageId();
+ kdDebug() << "minicli appLauncher dcop signal: " << service->storageId() << endl;
+ KApplication::kApplication()->dcopClient()->emitDCOPSignal("appLauncher",
+ "serviceStartedByStorageId(QString,QString)", params);
+}
+
+void Minicli::slotCmdChanged(const QString& text)
+{
+ bool isEmpty = text.isEmpty();
+ m_dlg->pbRun->setEnabled( !isEmpty );
+
+ if( isEmpty )
+ {
+ // Reset values to default
+ m_filterData->setData(KURL());
+
+ // Empty String is certainly no terminal application
+ slotTerminal(false);
+
+ // Reset the icon if needed...
+ const QPixmap pixmap = DesktopIcon("kmenu");
+
+ if ( pixmap.serialNumber() != m_dlg->lbRunIcon->pixmap()->serialNumber())
+ m_dlg->lbRunIcon->setPixmap(pixmap);
+
+ return;
+ }
+
+ m_parseTimer->start(250, true);
+}
+
+void Minicli::slotAdvanced()
+{
+ if (m_dlg->gbAdvanced->isHidden())
+ {
+ m_dlg->gbAdvanced->show();
+ m_dlg->pbOptions->setText(i18n("&Options <<"));
+
+ // Set the focus back to the widget that had it to begin with, i.e.
+ // do not put the focus on the "Options" button.
+ m_FocusWidget = focusWidget();
+
+ if( m_FocusWidget )
+ m_FocusWidget->setFocus();
+ }
+ else
+ {
+ m_dlg->gbAdvanced->hide();
+ m_dlg->pbOptions->setText(i18n("&Options >>"));
+
+ if( m_FocusWidget && m_FocusWidget->parent() != m_dlg->gbAdvanced )
+ m_FocusWidget->setFocus();
+ }
+ adjustSize();
+}
+
+void Minicli::slotParseTimer()
+{
+ //kdDebug (1207) << "Minicli::slotParseTimer: Timed out..." << endl;
+ parseLine( false );
+}
+
+void Minicli::parseLine( bool final )
+{
+ QString cmd = m_dlg->cbCommand->currentText().stripWhiteSpace();
+ m_filterData->setData( cmd );
+
+ if( final )
+ KURIFilter::self()->filterURI( *(m_filterData), m_finalFilters );
+ else
+ KURIFilter::self()->filterURI( *(m_filterData), m_middleFilters );
+
+ bool isTerminalApp = ((m_filterData->uriType() == KURIFilterData::EXECUTABLE) &&
+ m_terminalAppList.contains(m_filterData->uri().url()));
+
+ if( !isTerminalApp )
+ {
+ m_iconName = m_filterData->iconName();
+ setIcon();
+ }
+
+ if ( isTerminalApp && final && !m_dlg->cbRunInTerminal->isChecked() )
+ {
+ m_terminalAppList.remove( m_filterData->uri().url() );
+ isTerminalApp = false;
+ }
+ else
+ {
+ bool wasAutoChecked = m_autoCheckedRunInTerm;
+ bool willBeAutoChecked = isTerminalApp && !m_dlg->cbRunInTerminal->isChecked();
+ slotTerminal(isTerminalApp || (m_dlg->cbRunInTerminal->isChecked() && !m_autoCheckedRunInTerm));
+ if (!wasAutoChecked && willBeAutoChecked)
+ m_autoCheckedRunInTerm = true;
+ }
+
+ kdDebug (1207) << "Command: " << m_filterData->uri().url() << endl;
+ kdDebug (1207) << "Arguments: " << m_filterData->argsAndOptions() << endl;
+}
+
+void Minicli::setIcon ()
+{
+ if( m_iconName.isEmpty() || m_iconName == "unknown" || m_iconName == "kde" )
+ m_iconName = QString::fromLatin1("kmenu");
+
+ QPixmap icon = DesktopIcon( m_iconName );
+
+ if ( m_iconName == "www" )
+ {
+ // Not using KIconEffect::overlay as that requires the same size
+ // for the icon and the overlay, also the overlay definately doesn't
+ // have a more that one-bit alpha channel here
+ QPixmap overlay( locate ( "icon", KMimeType::favIconForURL( m_filterData->uri() ) + ".png" ) );
+ if ( !overlay.isNull() )
+ {
+ int x = icon.width() - overlay.width();
+ int y = icon.height() - overlay.height();
+ if ( icon.mask() )
+ {
+ QBitmap mask = *icon.mask();
+ bitBlt( &mask, x, y,
+ overlay.mask() ? const_cast<QBitmap *>(overlay.mask()) : &overlay,
+ 0, 0, overlay.width(), overlay.height(),
+ overlay.mask() ? OrROP : SetROP );
+ icon.setMask(mask);
+ }
+ bitBlt( &icon, x, y, &overlay );
+ }
+ }
+
+ m_dlg->lbRunIcon->setPixmap( icon );
+}
+
+void Minicli::updateAuthLabel()
+{
+ if (m_dlg->cbPriority->isChecked() && (m_iPriority > 50) ||
+ (m_iScheduler != StubProcess::SchedNormal))
+ {
+ if (!m_prevCached && !m_dlg->leUsername->text().isEmpty())
+ {
+ //kdDebug(1207) << k_funcinfo << "Caching: user=" << m_dlg->leUsername->text() <<
+ // ", checked=" << m_dlg->cbRunAsOther->isChecked() << endl;
+
+ m_prevUser = m_dlg->leUsername->text();
+ m_prevPass = m_dlg->lePassword->text();
+ m_prevChecked = m_dlg->cbRunAsOther->isChecked();
+ m_prevCached = true;
+ }
+ if (m_dlg->leUsername->text() != QString::fromLatin1("root"))
+ m_dlg->lePassword->setText(QString::null);
+ m_dlg->leUsername->setText(QString::fromLatin1("root"));
+ m_dlg->cbRunAsOther->setChecked(true);
+ m_dlg->cbRunAsOther->setEnabled(false);
+ m_dlg->leUsername->setEnabled(false);
+ m_dlg->lbUsername->setEnabled(true);
+ m_dlg->lePassword->setEnabled(true);
+ m_dlg->lbPassword->setEnabled(true);
+ }
+ else if (m_dlg->cbRunAsOther->isEnabled() &&
+ m_dlg->cbRunAsOther->isChecked() && !m_dlg->leUsername->text().isEmpty())
+ {
+ m_dlg->lePassword->setEnabled(true);
+ m_dlg->lbPassword->setEnabled(true);
+ }
+ else
+ {
+ if (m_prevCached)
+ {
+ m_dlg->leUsername->setText(m_prevUser);
+ m_dlg->lePassword->setText(m_prevPass);
+ m_dlg->cbRunAsOther->setChecked(m_prevChecked);
+ m_dlg->leUsername->setEnabled(m_prevChecked);
+ m_dlg->lbUsername->setEnabled(m_prevChecked);
+ }
+ else
+ {
+ m_dlg->cbRunAsOther->setChecked(false);
+ m_dlg->leUsername->setEnabled(false);
+ m_dlg->lbUsername->setEnabled(false);
+ }
+ m_dlg->cbRunAsOther->setEnabled(true);
+ m_dlg->lePassword->setEnabled(false);
+ m_dlg->lbPassword->setEnabled(false);
+ m_prevCached = false;
+ }
+}
+
+void Minicli::slotTerminal(bool enable)
+{
+ m_dlg->cbRunInTerminal->setChecked(enable);
+ m_autoCheckedRunInTerm = false;
+
+ if (enable)
+ {
+ m_prevIconName = m_iconName;
+ m_iconName = QString::fromLatin1( "konsole" );
+ setIcon();
+ }
+ else if (!m_prevIconName.isEmpty())
+ {
+ m_iconName = m_prevIconName;
+ setIcon();
+ }
+}
+
+void Minicli::slotChangeUid(bool enable)
+{
+ m_dlg->leUsername->setEnabled(enable);
+ m_dlg->lbUsername->setEnabled(enable);
+
+ if(enable)
+ {
+ m_dlg->leUsername->selectAll();
+ m_dlg->leUsername->setFocus();
+ }
+
+ updateAuthLabel();
+}
+
+void Minicli::slotChangeScheduler(bool enable)
+{
+ m_dlg->slPriority->setEnabled(enable);
+ m_dlg->lbLowPriority->setEnabled(enable);
+ m_dlg->lbHighPriority->setEnabled(enable);
+
+ updateAuthLabel();
+}
+
+bool Minicli::needsKDEsu()
+{
+ return ((m_dlg->cbPriority->isChecked() && ((m_iPriority > 50) ||
+ (m_iScheduler != StubProcess::SchedNormal))) ||
+ (m_dlg->cbRunAsOther->isChecked() && !m_dlg->leUsername->text().isEmpty()));
+}
+
+void Minicli::slotRealtime(bool enabled)
+{
+ m_iScheduler = enabled ? StubProcess::SchedRealtime : StubProcess::SchedNormal;
+
+ if (enabled)
+ {
+ if (KMessageBox::warningContinueCancel(this,
+ i18n("Running a realtime application can be very dangerous. "
+ "If the application misbehaves, the system might hang "
+ "unrecoverably.\nAre you sure you want to continue?"),
+ i18n("Warning - Run Command"), KGuiItem(i18n("&Run Realtime")),QString::null,KMessageBox::Notify|KMessageBox::PlainCaption)
+ != KMessageBox::Continue )
+ {
+ m_iScheduler = StubProcess::SchedNormal;
+ m_dlg->cbRealtime->setChecked(false);
+ }
+ }
+
+ updateAuthLabel();
+}
+
+void Minicli::slotPriority(int priority)
+{
+ // Provide a way to easily return to the default priority
+ if ((priority > 40) && (priority < 60))
+ {
+ priority = 50;
+ m_dlg->slPriority->setValue(50);
+ }
+
+ m_iPriority = priority;
+
+ updateAuthLabel();
+}
+
+QString Minicli::calculate(const QString &exp)
+{
+ QString result, cmd;
+ const QString bc = KStandardDirs::findExe("bc");
+ if ( !bc.isEmpty() )
+ cmd = QString("echo %1 | %2").arg(KProcess::quote(QString("scale=8; ")+exp), KProcess::quote(bc));
+ else
+ cmd = QString("echo $((%1))").arg(exp);
+ FILE *fs = popen(QFile::encodeName(cmd).data(), "r");
+ if (fs)
+ {
+ { // scope for QTextStream
+ QTextStream ts(fs, IO_ReadOnly);
+ result = ts.read().stripWhiteSpace();
+ }
+ pclose(fs);
+ }
+ return result;
+}
+
+void Minicli::fontChange( const QFont & )
+{
+ adjustSize();
+}
+
+// vim: set et ts=2 sts=2 sw=2:
+
diff --git a/kdesktop/minicli.h b/kdesktop/minicli.h
new file mode 100644
index 000000000..8f98fe3ea
--- /dev/null
+++ b/kdesktop/minicli.h
@@ -0,0 +1,112 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 1999-2002,2003 Dawit Alemayehu <adawit@kde.org>
+ Copyright (C) 2000 Malte Starostik <starosti@zedat.fu-berlin.de>
+ Copyright (C) 2003 Sven Leiber <s.leiber@web.de>
+
+ Kdesu integration:
+ Copyright (C) 2000 Geert Jansen <jansen@kde.org>
+
+ Original authors:
+ Copyright (C) 1997 Matthias Ettrich <ettrich@kde.org>
+ Copyright (C) 1997 Torben Weis [ Added command completion ]
+ Copyright (C) 1999 Preston Brown <pbrown@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MINICLI_H
+#define MINICLI_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <kdialog.h>
+#include <kservice.h>
+
+class QTimer;
+class QWidget;
+class MinicliDlgUI;
+class KURIFilterData;
+
+class Minicli : public KDialog
+{
+ Q_OBJECT
+
+public:
+ Minicli( QWidget *parent=0, const char *name=0 );
+ virtual ~Minicli();
+
+ void setCommand(const QString& command);
+ void reset();
+ void saveConfig();
+ void clearHistory();
+
+ virtual void show();
+ virtual QSize sizeHint() const;
+
+protected slots:
+ virtual void accept();
+ virtual void reject();
+ void updateAuthLabel();
+
+protected:
+ void loadConfig();
+ bool needsKDEsu();
+ virtual void keyPressEvent( QKeyEvent* );
+ virtual void fontChange( const QFont & );
+
+private slots:
+ void slotAdvanced();
+ void slotParseTimer();
+ void slotPriority(int);
+ void slotRealtime(bool);
+ void slotTerminal(bool);
+ void slotChangeUid(bool);
+ void slotChangeScheduler(bool);
+ void slotCmdChanged(const QString&);
+
+private:
+ void setIcon();
+ int runCommand();
+ void parseLine( bool final );
+ QString terminalCommand (const QString&, const QString&);
+ QString calculate(const QString &exp);
+ void notifyServiceStarted(KService::Ptr service);
+
+
+ int m_iPriority;
+ int m_iScheduler;
+
+ QString m_iconName;
+ QString m_prevIconName;
+ QStringList m_terminalAppList;
+ QStringList m_middleFilters;
+ QStringList m_finalFilters;
+
+ QTimer* m_parseTimer;
+ QWidget* m_FocusWidget;
+ MinicliDlgUI* m_dlg;
+ KURIFilterData* m_filterData;
+
+ // Cached values
+ QString m_prevUser;
+ QString m_prevPass;
+ bool m_prevChecked;
+ bool m_prevCached;
+ bool m_autoCheckedRunInTerm;
+};
+#endif
diff --git a/kdesktop/minicli_ui.ui b/kdesktop/minicli_ui.ui
new file mode 100644
index 000000000..32416b8f3
--- /dev/null
+++ b/kdesktop/minicli_ui.ui
@@ -0,0 +1,624 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>MinicliDlgUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MinicliDlgUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>325</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="resizeMode">
+ <enum>FreeResize</enum>
+ </property>
+ <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>pbOptions</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>pbRun</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>pbCancel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>57</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>gbAdvanced</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <spacer row="6" column="0">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="7" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>cbRealtime</cstring>
+ </property>
+ <property name="text">
+ <string>Run with realtime &amp;scheduling</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Select whether realtime scheduling should be enabled for the application. The scheduler governs which process will run and which will have to wait. Two schedulers are available:
+&lt;ul&gt;
+&lt;li&gt;&lt;em&gt;Normal:&lt;/em&gt; This is the standard, timesharing scheduler. It will divide fairly the available processing time between all processes.&lt;/li&gt;
+&lt;li&gt;&lt;em&gt;Realtime:&lt;/em&gt;This scheduler will run your application uninterrupted until it gives up the processor. This can be dangerous. An application that does not give up the processor might hang the system. You need root's password to use the scheduler.&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>lbUsername</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>User&amp;name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>leUsername</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the user you want to run the application as here.</string>
+ </property>
+ </widget>
+ <widget class="KPasswordEdit" row="4" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>lePassword</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>5</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the password here for the user you specified above.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>lbPassword</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Pass&amp;word:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>lePassword</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the password here for the user you specified above.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>cbRunInTerminal</cstring>
+ </property>
+ <property name="text">
+ <string>Run in &amp;terminal window</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if the application you want to run is a text mode application. The application will then be run in a terminal emulator window.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="6" column="1">
+ <property name="name">
+ <cstring>layout30</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Priority:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>slPriority</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The priority that the command will be run with can be set here. From left to right, it goes from low to high. The center position is the default value. For priorities higher than the default, you will need to provide the root password.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer33</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>9</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>cbPriority</cstring>
+ </property>
+ <property name="text">
+ <string>Run with a &amp;different priority</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to run the application with a different priority. A higher priority tells the operating system to give more processing time to your application.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>leUsername</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>5</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the user you want to run the application as here.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="6" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout29</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lbLowPriority</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Low</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The priority that the command will be run with can be set here. From left to right, it goes from low to high. The center position is the default value. For priorities higher than the default, you will need to provide the root password.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>lbHighPriority</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>High</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The priority that the command will be run with can be set here. From left to right, it goes from low to high. The center position is the default value. For priorities higher than the default, you will need to provide the root password.</string>
+ </property>
+ </widget>
+ <widget class="QSlider" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>slPriority</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="lineStep">
+ <number>5</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The priority that the command will be run with can be set here. From left to right, it goes from low to high. The center position is the default value. For priorities higher than the default, you will need to provide the root password.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>cbRunAsOther</cstring>
+ </property>
+ <property name="text">
+ <string>Run as a different &amp;user</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this option if you want to run the application with a different user id. Every process has a user id associated with it. This id code determines file access and other permissions. The password of the user is required to do this.</string>
+ </property>
+ </widget>
+ <spacer row="3" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>separator</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lbCommand</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Com&amp;mand:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>cbCommand</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the command you wish to execute or the address of the resource you want to open. This can be a remote URL like "www.kde.org" or a local one like "~/.kderc".</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lbRunIcon</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="KHistoryCombo" row="1" column="1">
+ <property name="name">
+ <cstring>cbCommand</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>388</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Enter the command you wish to execute or the address of the resource you want to open. This can be a remote URL like "www.kde.org" or a local one like "~/.kderc".</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>lbComment</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Enter the name of the application you want to run or the URL you want to view</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>cbPriority</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lbLowPriority</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbPriority</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>slPriority</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbPriority</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lbHighPriority</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbRunAsOther</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lbUsername</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbRunAsOther</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>leUsername</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbRunAsOther</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lbPassword</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbRunAsOther</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>lePassword</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>cbPriority</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel1</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>cbCommand</tabstop>
+ <tabstop>cbRunInTerminal</tabstop>
+ <tabstop>cbRunAsOther</tabstop>
+ <tabstop>leUsername</tabstop>
+ <tabstop>lePassword</tabstop>
+ <tabstop>cbPriority</tabstop>
+ <tabstop>slPriority</tabstop>
+ <tabstop>pbOptions</tabstop>
+ <tabstop>pbRun</tabstop>
+ <tabstop>pbCancel</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">fixx11h.h</include>
+ <include location="local" impldecl="in implementation">kdialog.h</include>
+ <include location="local" impldecl="in implementation">kiconloader.h</include>
+ <include location="local" impldecl="in implementation">kpassdlg.h</include>
+ <include location="local" impldecl="in implementation">kcombobox.h</include>
+ <include location="local" impldecl="in implementation">klineedit.h</include>
+ <include location="local" impldecl="in implementation">kpushbutton.h</include>
+</includes>
+<pixmapfunction>BarIcon</pixmapfunction>
+<layoutdefaults spacing="3" margin="6"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpassdlg.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/kdesktop/patterns/Makefile.am b/kdesktop/patterns/Makefile.am
new file mode 100644
index 000000000..edf7ba024
--- /dev/null
+++ b/kdesktop/patterns/Makefile.am
@@ -0,0 +1,5 @@
+patdir=$(kde_datadir)/kdesktop/patterns
+pat_DATA = night-rock.desktop night-rock.jpg stonewall2.png \
+ stonewall2.desktop fish.desktop fish.png flowers.desktop \
+ flowers.png pavement.desktop pavement.png rattan.desktop rattan.png \
+ triangles.desktop triangles.png
diff --git a/kdesktop/patterns/fish.desktop b/kdesktop/patterns/fish.desktop
new file mode 100644
index 000000000..7644bb0c8
--- /dev/null
+++ b/kdesktop/patterns/fish.desktop
@@ -0,0 +1,74 @@
+[KDE Desktop Pattern]
+Comment=Fish Net
+Comment[af]=Visnet
+Comment[az]=Balıq Şəbəkəsi
+Comment[be]=Сетка Fish
+Comment[bn]=মাছ ধরার জাল
+Comment[br]=Roued pesk
+Comment[ca]=Xarxa de pesca
+Comment[cs]=Rybářská síť
+Comment[csb]=Rëbackô séc
+Comment[cy]=Rhwyd Pysgod
+Comment[da]=Fiskenet
+Comment[de]=Fischnetz
+Comment[el]=Δίχτυ ψαρέματος
+Comment[eo]=Fiŝreto
+Comment[es]=Red de pesca
+Comment[et]=Kalavõrk
+Comment[eu]=Arrainetarako sarea
+Comment[fa]=تور ماهی
+Comment[fi]=Kalaverkko
+Comment[fr]=Filet
+Comment[fy]=Fisknet
+Comment[gl]=Rede de Pesca
+Comment[he]=רשת דייגים
+Comment[hi]=मछली जाली
+Comment[hr]=Ribarska mreža
+Comment[hu]=Halászháló
+Comment[is]=Net
+Comment[it]=Rete da pesca
+Comment[ja]=漁網
+Comment[ka]=მეთევზის ბადე
+Comment[kk]=Балықшы ауы
+Comment[km]=សំណាញ់
+Comment[lo]=ປາ
+Comment[lt]=Žuvų tinklas
+Comment[lv]=Zivju Tīkls
+Comment[mk]=Рибарска мрежа
+Comment[mn]=Загас сүлжээ
+Comment[ms]=Jala Ikan
+Comment[mt]=Xibka
+Comment[nb]=Fiskegarn
+Comment[nds]=Fischernett
+Comment[ne]=फिस नेट
+Comment[nl]=Visnet
+Comment[nn]=Fiskegarn
+Comment[nso]=Sefo ya Dihlapi
+Comment[oc]=resèu de pesca
+Comment[pa]=ਮੱਛੀ ਨੈੱਟ
+Comment[pl]=Sieć rybacka
+Comment[pt]=Rede de Pesca
+Comment[ro]=Plasă de pescuit
+Comment[ru]=Рыбацкая сеть
+Comment[se]=Sáibma
+Comment[sk]=Ryby a sieť
+Comment[sl]=Ribiška mreža
+Comment[sr]=Рибарска мрежа
+Comment[sr@Latn]=Ribarska mreža
+Comment[sv]=Fisknät
+Comment[ta]=மீன் வலை
+Comment[te]=చేపల వల
+Comment[tg]=Таври моҳигирӣ
+Comment[th]=แห
+Comment[tr]=Balık Ağı
+Comment[tt]=Balıqçı Yätmäse
+Comment[uk]=Тенета
+Comment[uz]=Toʻr
+Comment[uz@cyrillic]=Тўр
+Comment[ven]=Mulavhu wa khovhe
+Comment[vi]=Lưới đánh cá
+Comment[wa]=Filet d' pexhe
+Comment[zh_CN]=渔网
+Comment[zh_TW]=漁網
+Comment[zu]=I-nethi yofishi
+File=fish.png
diff --git a/kdesktop/patterns/fish.png b/kdesktop/patterns/fish.png
new file mode 100644
index 000000000..33de9be7c
--- /dev/null
+++ b/kdesktop/patterns/fish.png
Binary files differ
diff --git a/kdesktop/patterns/flowers.desktop b/kdesktop/patterns/flowers.desktop
new file mode 100644
index 000000000..7e57db75c
--- /dev/null
+++ b/kdesktop/patterns/flowers.desktop
@@ -0,0 +1,79 @@
+[KDE Desktop Pattern]
+Comment=Flowers
+Comment[af]=Blomme
+Comment[az]=Çiçəklər
+Comment[be]=Кветкі
+Comment[bn]=ফুল
+Comment[br]=Bleunioù
+Comment[ca]=Flors
+Comment[cs]=Květiny
+Comment[csb]=Kwiôtczi
+Comment[cy]=Blodau
+Comment[da]=Blomster
+Comment[de]=Blumen
+Comment[el]=Λουλούδια
+Comment[eo]=Floroj
+Comment[es]=Flores
+Comment[et]=Lilled
+Comment[eu]=Loreak
+Comment[fa]=گلها
+Comment[fi]=Kukat
+Comment[fr]=Fleurs
+Comment[fy]=Blommen
+Comment[ga]=Bláthanna
+Comment[gl]=Flores
+Comment[he]=פרחים
+Comment[hi]=पुष्प
+Comment[hr]=Cvijeće
+Comment[hu]=Virágok
+Comment[id]=Bunga
+Comment[is]=Blóm
+Comment[it]=Fiori
+Comment[ja]=花
+Comment[ka]=ყვავილები
+Comment[kk]=Гүлдер
+Comment[km]=ផ្កា
+Comment[lo]=ດອກໄມ້
+Comment[lt]=Gėlės
+Comment[lv]=Puķes
+Comment[mk]=Цвеќиња
+Comment[mn]=Цэцэг
+Comment[ms]=Bunga
+Comment[mt]=Fjuri
+Comment[nb]=Blomster
+Comment[nds]=Blomen
+Comment[ne]=फूल
+Comment[nl]=Bloemen
+Comment[nn]=Blomar
+Comment[nso]=Mapolomo
+Comment[oc]=Flors
+Comment[pa]=ਫੁੱਲ
+Comment[pl]=Kwiaty
+Comment[pt]=Flores
+Comment[pt_BR]=Flores
+Comment[ro]=Flori
+Comment[ru]=Цветы
+Comment[rw]=Indabo
+Comment[se]=Lieđit
+Comment[sk]=Kvety
+Comment[sl]=Rože
+Comment[sr]=Цвеће
+Comment[sr@Latn]=Cveće
+Comment[sv]=Blommor
+Comment[ta]=பூக்கள்
+Comment[te]=పువ్వులు
+Comment[tg]=Гулҳо
+Comment[th]=ดอกไม้
+Comment[tr]=Çiçekler
+Comment[tt]=Çäçäklär
+Comment[uk]=Квіти
+Comment[uz]=Gullar
+Comment[uz@cyrillic]=Гуллар
+Comment[ven]=Maluvha
+Comment[vi]=Bông hoa
+Comment[wa]=Fleurs
+Comment[xh]=Iintyatyambo
+Comment[zh_CN]=花
+Comment[zh_TW]=花朵
+Comment[zu]=Izimbali
+File=flowers.png
diff --git a/kdesktop/patterns/flowers.png b/kdesktop/patterns/flowers.png
new file mode 100644
index 000000000..cab6af8eb
--- /dev/null
+++ b/kdesktop/patterns/flowers.png
Binary files differ
diff --git a/kdesktop/patterns/night-rock.desktop b/kdesktop/patterns/night-rock.desktop
new file mode 100644
index 000000000..4a324e47a
--- /dev/null
+++ b/kdesktop/patterns/night-rock.desktop
@@ -0,0 +1,75 @@
+[KDE Desktop Pattern]
+Comment=Night Rock by Tigert
+Comment[af]=Nag Klip deur Tigert
+Comment[ar]=Night Rock من Tigert
+Comment[az]=Tigert'dan Gecə Qayası
+Comment[be]=Начная Гара ад Tigert
+Comment[bn]=Tigert-এর নাইট রক
+Comment[br]=Karreg da noz gant Tigert
+Comment[bs]=Night Rock - Tigert
+Comment[ca]=Rock nocturn per Tigert
+Comment[cs]=Night Rock vytvořil Tigert
+Comment[csb]=Nocny Rock (ùs. Tigert)
+Comment[cy]=Carreg Nos gan Tigert
+Comment[da]=Night Rock af Tigert
+Comment[de]=Night Rock
+Comment[el]=Night Rock από τον Tigert
+Comment[eo]=Nokta roko
+Comment[es]=Roca de noche de Tigert
+Comment[et]=Night Rock (Tigert)
+Comment[eu]=Gaueko Haitza, Tigert-ek egina
+Comment[fa]=Night Rock توسط تیگرت
+Comment[fi]=Night Rock, tehnyt Tigert
+Comment[fr]=Night Rock par Tigert
+Comment[fy]=Rots by Nacht, door Tigert
+Comment[gl]=Night Rock por Tigert
+Comment[he]=סלעים
+Comment[hi]=टिगर्ट द्वारा नाइट रॉक
+Comment[hr]=Night Rock (izr. Tigert)
+Comment[hu]=Tigert éjjeli sziklája
+Comment[id]=Batu Malam oleh Tigert
+Comment[is]=Night Rock eftir Tigert
+Comment[it]=Rock notturno (di Tigert)
+Comment[ja]=Tigert による Night Rock
+Comment[ka]=კლდე ღამით (Tigert)
+Comment[kk]=Түнгі жартас (Tigert)
+Comment[km]=សិលា​រាត្រី ដោយ Tigert
+Comment[lo]=ຄຳ່ມັນຯ ໂດຍ Tigert
+Comment[lv]=Nakts Roks no Tigerta
+Comment[mk]=Ноќен рок од Tigert
+Comment[mn]=Шөнийн рок
+Comment[ms]=Batuan Malan oleh Tigert
+Comment[mt]=Night Rock minn Tigert
+Comment[nb]=Nattrock av Tigert
+Comment[nds]=Night Rock vun Tigert
+Comment[ne]=टिग्रेटद्वारा रातीको रक
+Comment[nl]=Rots bij Nacht, door Tigert
+Comment[nn]=Nattrock av Tigert
+Comment[nso]=Leswika la Bosego ka Tigert
+Comment[oc]=Rock nocturn per Tigert
+Comment[pa]=ਰਾਤ ਪਹਾੜੀ ਟੀਰਿਰਟ
+Comment[pl]=Nocny Rock (wyk. Tigert)
+Comment[pt]=Night Rock de Tigert
+Comment[pt_BR]=Night Rock por Tigert
+Comment[ro]=Piatră întunecată de Tigert
+Comment[ru]=Ночная скала (Tigert)
+Comment[rw]=Night Rock na Tigert
+Comment[se]=Tigert:a idjarocka
+Comment[sk]=Nočný kameň od Tigerta
+Comment[sl]=Nočni rock Tigerta
+Comment[sv]=Nattsten av Tigert
+Comment[ta]=டைக்ரட்இன் நைட்ராக்
+Comment[tg]=Сахраҳои дар шаб аз Tigert
+Comment[th]=ค่ำคืนมัน ๆ โดย Tigert
+Comment[tr]=Tigert'dan Gece Kayası
+Comment[tt]=Tönge Taw (Tigert tarafınnan)
+Comment[uk]=Нічний політ Тайгерта
+Comment[uz]=Oqshom qoyasi (Tigert tomonidan)
+Comment[uz@cyrillic]=Оқшом қояси (Тигерт томонидан)
+Comment[ven]=Vhusiku ha Rock nga Tigert
+Comment[vi]=Rock Buổi đêm bởi Tigert
+Comment[wa]=Rotche di nute pa Tigert
+Comment[zh_CN]=Tigert 的夜色中的岩石
+Comment[zh_TW]=午夜搖滾 (Tigert 繪製)
+Comment[zu]=Night Rock ngu-Tigert
+File=night-rock.jpg
diff --git a/kdesktop/patterns/night-rock.jpg b/kdesktop/patterns/night-rock.jpg
new file mode 100644
index 000000000..8a3297be8
--- /dev/null
+++ b/kdesktop/patterns/night-rock.jpg
Binary files differ
diff --git a/kdesktop/patterns/pavement.desktop b/kdesktop/patterns/pavement.desktop
new file mode 100644
index 000000000..3ecabd35d
--- /dev/null
+++ b/kdesktop/patterns/pavement.desktop
@@ -0,0 +1,75 @@
+[KDE Desktop Pattern]
+Comment=Pavement
+Comment[af]=Sypaadjie
+Comment[az]=Səki
+Comment[be]=Брушчатка
+Comment[bn]=ফুটপাথ
+Comment[br]=Pavezadur
+Comment[ca]=Paviment
+Comment[cs]=Dlažba
+Comment[csb]=Trotuar
+Comment[cy]=Palmant
+Comment[da]=Brolægning
+Comment[de]=Gehsteig
+Comment[el]=Πεζοδρόμιο
+Comment[eo]=Pavimo
+Comment[es]=Pavimento
+Comment[eu]=Zorua
+Comment[fa]=سنگ‌فرش
+Comment[fi]=Katukivetys
+Comment[fr]=Pavés
+Comment[fy]=Estrikken
+Comment[ga]=Pábháil
+Comment[gl]=Pavemento
+Comment[he]=ריצוף
+Comment[hi]=फर्श
+Comment[hr]=Pločnik
+Comment[hu]=Járda
+Comment[is]=Gangstétt
+Comment[it]=Marciapiede
+Comment[ja]=歩道
+Comment[ka]=ქვაფენილი
+Comment[kk]=Тас алаң
+Comment[km]=កម្រាល​ថ្ម
+Comment[lo]=ທາງເດີນ
+Comment[lt]=Grindinys
+Comment[lv]=Ielas segums
+Comment[mk]=Калдрма
+Comment[mn]=Явган зам
+Comment[ms]=Turapan
+Comment[mt]=Bankina
+Comment[nb]=Brolegning
+Comment[nds]=Börgerstieg
+Comment[ne]=शीलास्तर
+Comment[nl]=Plavuizen
+Comment[oc]=Paviment
+Comment[pa]=ਪਾਵੀਮੈਂਟ
+Comment[pl]=Chodnik
+Comment[pt]=Chão
+Comment[pt_BR]=Pavimento
+Comment[ro]=Pavaj
+Comment[ru]=Мостовая
+Comment[rw]=Umuteguro
+Comment[se]=Ravdaváccahat
+Comment[sk]=Chodník
+Comment[sl]=Pločnik
+Comment[sr]=Плочник
+Comment[sr@Latn]=Pločnik
+Comment[sv]=Trottoar
+Comment[ta]=நடைபாதை
+Comment[te]=తలవరుస
+Comment[tg]=Пиёдарав
+Comment[th]=ทางเท้า
+Comment[tr]=Kaldırım
+Comment[tt]=Uram
+Comment[uk]=Дорога
+Comment[uz]=Yoʻlak
+Comment[uz@cyrillic]=Йўлак
+Comment[ven]=Ludila
+Comment[vi]=Lát gạch hoa
+Comment[wa]=Trotwer
+Comment[xh]=Umgangatho osecaleni kwendlela
+Comment[zh_CN]=人行道
+Comment[zh_TW]=人行道
+Comment[zu]=Unqenqema eceleni komgwaqo
+File=pavement.png
diff --git a/kdesktop/patterns/pavement.png b/kdesktop/patterns/pavement.png
new file mode 100644
index 000000000..7ba9bcf14
--- /dev/null
+++ b/kdesktop/patterns/pavement.png
Binary files differ
diff --git a/kdesktop/patterns/rattan.desktop b/kdesktop/patterns/rattan.desktop
new file mode 100644
index 000000000..73c133c08
--- /dev/null
+++ b/kdesktop/patterns/rattan.desktop
@@ -0,0 +1,40 @@
+[KDE Desktop Pattern]
+Comment=Rattan
+Comment[bn]=রাটান
+Comment[br]=Lien skosat
+Comment[cs]=Rákos
+Comment[eo]=Plektaĵo
+Comment[es]=Rota (planta)
+Comment[fa]=چوب‌دستی
+Comment[fi]=Rottinki
+Comment[fr]=Rotin
+Comment[fy]=Rotan
+Comment[ga]=Ratán
+Comment[he]=דקלים
+Comment[hi]=बेंत
+Comment[hu]=Nádfonat
+Comment[id]=Rotan
+Comment[ja]=籐 (とう)
+Comment[ka]=რატანი
+Comment[km]=ផ្ដៅ
+Comment[lo]=ຫວາຍ
+Comment[lv]=Rotangpalma
+Comment[mk]=Трска
+Comment[ms]=Rotan
+Comment[ne]=रेटन
+Comment[nl]=Rotan
+Comment[pa]=ਰਾਟਾਨ
+Comment[pt]=Rota
+Comment[ro]=Sac de iută
+Comment[rw]=Umukindo
+Comment[sk]=Trsť
+Comment[sv]=Rotting
+Comment[ta]=ரட்டன்
+Comment[te]=రట్టాన్
+Comment[th]=หวาย
+Comment[uz]=Palma
+Comment[uz@cyrillic]=Пальма
+Comment[vi]=Cây song mây
+Comment[zh_CN]=藤条
+Comment[zh_TW]=藤條
+File=rattan.png
diff --git a/kdesktop/patterns/rattan.png b/kdesktop/patterns/rattan.png
new file mode 100644
index 000000000..28f600541
--- /dev/null
+++ b/kdesktop/patterns/rattan.png
Binary files differ
diff --git a/kdesktop/patterns/stonewall2.desktop b/kdesktop/patterns/stonewall2.desktop
new file mode 100644
index 000000000..c9c49dde9
--- /dev/null
+++ b/kdesktop/patterns/stonewall2.desktop
@@ -0,0 +1,76 @@
+[KDE Desktop Pattern]
+Comment=Stonewall 2 by Tigert
+Comment[af]=Klipmuur 2 deur Tigert
+Comment[ar]=Stonewall 2 من Tigert
+Comment[az]=Tigert'dan Daş Divar 2
+Comment[be]=Каменная сцяна 2 ад Tigert
+Comment[bn]=Tigert-এর স্টোনওয়াল ২
+Comment[br]=Moger mein 2 gant Tigert
+Comment[ca]=Mur de pedra 2 per Tigert
+Comment[cs]=Stonewall 2 vytvořil Tigert
+Comment[csb]=Kamny mùr 2 (ùs. Tigert)
+Comment[cy]=Stonewall 2 gan Tigert
+Comment[da]=Stenmur 2 af Tigert
+Comment[de]=Stonewall 2
+Comment[el]=Stonewall 2 από τον Tigert
+Comment[eo]=Ŝtonmuro 2
+Comment[es]=Pared de piedra 2 de Tigert
+Comment[et]=Stonewall 2 (Tigert)
+Comment[eu]=Stonewall 2, Tigertek egina
+Comment[fa]=Stonewall ۲ توسط تیگرت
+Comment[fi]=Kiviseinä 2, tehnyt Tigert
+Comment[fr]=Stonewall 2 par Tigert
+Comment[fy]=Stienen muorre 2, troch Tigert
+Comment[gl]=Stonewall 2 por Tigert
+Comment[he]=חומת אבנים
+Comment[hi]=टिगर्ट द्वारा स्टोनवाल 2
+Comment[hr]=Stonewall 2 (izr. Tigert)
+Comment[hu]=Tigert 2. kőfala
+Comment[id]=Tembok batu 2 oleh Tigert
+Comment[is]=Steinveggur 2 eftir Tigert
+Comment[it]=Mattoni 2 (di Tigert)
+Comment[ja]=Tigert による Stonewall
+Comment[ka]=ქვის კედელი 2 (Tigert)
+Comment[kk]=Тас дуал 2 (Tigert)
+Comment[km]=ជញ្ជាំង​ថ្ម ២ ដោយ Tigert
+Comment[lo]=ກຳແພງຫີນ 2 ໂດຍ Tigert
+Comment[lt]=Tigert'o akmens siena 2
+Comment[lv]=Akmens siena 2 no Tigerta
+Comment[mk]=Камен ѕид 2 од Tigert
+Comment[mn]=Чулуун хана 2
+Comment[ms]=Tembok Batu 2 oleh Tigert
+Comment[mt]=Stonewall 2 minn Tigert
+Comment[nb]=Steinvegg 2 av Tigert
+Comment[nds]=Stonewall 2 vun Tigert
+Comment[ne]=टिग्रेटद्वारा स्टोनवाल २
+Comment[nl]=Stenen muur 2, door Tigert
+Comment[nn]=Steinvegg 2 av Tigert
+Comment[nso]=Stonewall 2 ka Tigert
+Comment[oc]=Mur de peira 2 per Tigert
+Comment[pa]=ਪੱਥਰੀ ਕੰਧ ਟੀਗਿਰਟ
+Comment[pl]=Kamienny mur 2 (wyk. Tigert)
+Comment[pt]=Stonewall 2 de Tigert
+Comment[pt_BR]=Stonewall 2 por Tigert
+Comment[ro]=Zid de piatră 2 de Tigert
+Comment[ru]=Каменная стена 2 (Tigert)
+Comment[rw]=Stonewall 2 na Tigert
+Comment[se]=Tigert:a geađgeseaidni 2
+Comment[sk]=Stonewall 2 od Tigerta
+Comment[sl]=Stonewall 2, Tigert
+Comment[sv]=Stenmur 2 av Tigert
+Comment[ta]=டைக்ரெட்டின் ஸ்டோன்வால் 2
+Comment[tg]=Девори сангии 2 аз Tigert
+Comment[th]=กำแพงหิน 2 โดย Tigert
+Comment[tr]=Tigert'dan Taşduvar 2
+Comment[tt]=Taşdíwar 2 (Tigert tarafınnan)
+Comment[uk]=Кам'яна стіна Тайгерта 2
+Comment[uz]=Tosh devol 2 (Tigert tomonidan)
+Comment[uz@cyrillic]=Тош девол 2 (Тигерт томонидан)
+Comment[ven]=Luvhondo lwa tombo lwa vhuvhili nga Tigert
+Comment[vi]=Tường đá 2 bởi Tigert
+Comment[wa]=Meur di pires 2 pa Tigert
+Comment[xh]=Stonewall 2 ngu Tigert
+Comment[zh_CN]=Tigert 的石墙 2
+Comment[zh_TW]=石牆 2 (Tigert 繪製)
+Comment[zu]=Stonewall 2 ngu-Tigert
+File=stonewall2.png
diff --git a/kdesktop/patterns/stonewall2.png b/kdesktop/patterns/stonewall2.png
new file mode 100644
index 000000000..cb9f10f40
--- /dev/null
+++ b/kdesktop/patterns/stonewall2.png
Binary files differ
diff --git a/kdesktop/patterns/triangles.desktop b/kdesktop/patterns/triangles.desktop
new file mode 100644
index 000000000..846e698ce
--- /dev/null
+++ b/kdesktop/patterns/triangles.desktop
@@ -0,0 +1,76 @@
+[KDE Desktop Pattern]
+Comment=Triangles
+Comment[af]=Driehoeke
+Comment[ar]=مثلثات
+Comment[az]=Üç Bucaqlar
+Comment[be]=Трохкутнікі
+Comment[bn]=ত্রিভুজ
+Comment[br]=Tric'hornioù
+Comment[cs]=Trojúhelníky
+Comment[csb]=Trzënórtë
+Comment[cy]=Trionglau
+Comment[da]=Trekanter
+Comment[de]=Dreiecke
+Comment[el]=Τρίγωνα
+Comment[eo]=Trianguloj
+Comment[es]=Triángulos
+Comment[eu]=Triangeluak
+Comment[fa]=مثلثها
+Comment[fi]=Kolmiot
+Comment[fy]=Trijehoeken
+Comment[ga]=Triantáin
+Comment[gl]=Triángulos
+Comment[he]=משולשים
+Comment[hi]=त्रिभुज
+Comment[hr]=Trokuti
+Comment[hu]=Háromszögek
+Comment[id]=Segi Tiga
+Comment[is]=Þríhyrningar
+Comment[it]=Triangoli
+Comment[ja]=三角
+Comment[ka]=სამკუთხედები
+Comment[kk]=Үшбұрыштар
+Comment[km]=ត្រីកោណ
+Comment[lo]=ສາມລ່ງມ
+Comment[lt]=Trikampiai
+Comment[lv]=Trīsstūri
+Comment[mk]=Триаголници
+Comment[mn]=Гурвалжин
+Comment[ms]=Segi Tiga
+Comment[mt]=Triangoli
+Comment[nb]=Trekanter
+Comment[nds]=Dre'ecks
+Comment[ne]=त्रिभुज
+Comment[nl]=Driehoeken
+Comment[nn]=Trekantar
+Comment[nso]=Dikhutlotharo
+Comment[pa]=ਤਿਕੋਣਾਂ
+Comment[pl]=Trójkąty
+Comment[pt]=Triângulos
+Comment[pt_BR]=Triângulos
+Comment[ro]=Triunghiuri
+Comment[ru]=Треугольники
+Comment[rw]=Mpandeshatu
+Comment[se]=Golmmehat
+Comment[sk]=Trojuholníky
+Comment[sl]=Trikotniki
+Comment[sr]=Троуглови
+Comment[sr@Latn]=Trouglovi
+Comment[sv]=Trianglar
+Comment[ta]=முக்கோணங்கள்
+Comment[te]=త్రికొణాలు
+Comment[tg]=Секунҷаҳо
+Comment[th]=สามเหลี่ยม
+Comment[tr]=Üçgenler
+Comment[tt]=Öçpoçmaq
+Comment[uk]=Трикутники
+Comment[uz]=Uchburchaklar
+Comment[uz@cyrillic]=Учбурчаклар
+Comment[ven]=Thiriengele
+Comment[vi]=Tam giác
+Comment[wa]=Triyangues
+Comment[xh]=Oonxantathu
+Comment[zh_CN]=三角形
+Comment[zh_TW]=三角形
+Comment[zu]=Onxantathu
+File=triangles.png
diff --git a/kdesktop/patterns/triangles.png b/kdesktop/patterns/triangles.png
new file mode 100644
index 000000000..cde9068eb
--- /dev/null
+++ b/kdesktop/patterns/triangles.png
Binary files differ
diff --git a/kdesktop/pics/Makefile.am b/kdesktop/pics/Makefile.am
new file mode 100644
index 000000000..79bb5381a
--- /dev/null
+++ b/kdesktop/pics/Makefile.am
@@ -0,0 +1,9 @@
+# Makefile.am of kdebase/kdesktop/pics
+
+pics_DATA = ksslogo.png splash.png splash2.png kde2.xbm
+
+picsdir = $(kde_datadir)/kdesktop/pics
+
+EXTRA_DIST = $(pics_DATA)
+
+KDE_ICON = error
diff --git a/kdesktop/pics/cr32-app-error.png b/kdesktop/pics/cr32-app-error.png
new file mode 100644
index 000000000..1de7a6fda
--- /dev/null
+++ b/kdesktop/pics/cr32-app-error.png
Binary files differ
diff --git a/kdesktop/pics/kde2.xbm b/kdesktop/pics/kde2.xbm
new file mode 100644
index 000000000..0eced4666
--- /dev/null
+++ b/kdesktop/pics/kde2.xbm
@@ -0,0 +1,38 @@
+#define kde2_width 64
+#define kde2_height 64
+static char kde2_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x0f,0x80,0x01,0x00,0x00,0x00,0x00,0xf8,0x0f,0x80,0x1f,0x00,0x00,0x00,0x00,
+ 0xf8,0x0f,0xc0,0xff,0x01,0x00,0x00,0x00,0xf8,0x0f,0xe0,0xff,0x00,0x00,0x00,
+ 0x00,0xf8,0x0f,0xf0,0xff,0x00,0x00,0x00,0x00,0xf8,0x0f,0xf0,0x7f,0x00,0x00,
+ 0x00,0x00,0xf8,0x0f,0xf8,0x3f,0x00,0x00,0x00,0x03,0xf8,0x0f,0xfc,0x1f,0x00,
+ 0x00,0x80,0x07,0xf8,0x0f,0xfe,0x1f,0x00,0x00,0xc0,0x1f,0xf9,0x0f,0xff,0x0f,
+ 0x00,0x00,0xe0,0xbf,0xf9,0x0f,0xff,0x07,0x00,0x00,0xc0,0xff,0xf9,0x8f,0xff,
+ 0x03,0x00,0x00,0x80,0xff,0xf9,0xcf,0xff,0x01,0x00,0x00,0x80,0xff,0xf8,0xef,
+ 0xff,0x01,0x00,0x00,0x00,0x7f,0xf8,0xef,0xff,0x00,0x00,0x00,0x00,0x3e,0xf8,
+ 0xff,0x7f,0x00,0x00,0x00,0x00,0x1e,0xf8,0xff,0x3f,0x00,0x00,0x00,0x00,0x0f,
+ 0xf8,0xff,0x1f,0x00,0x00,0x00,0x00,0x07,0xf8,0xff,0x3f,0x00,0x00,0x00,0x80,
+ 0x07,0xf8,0xff,0x3f,0x00,0x00,0x00,0x80,0x07,0xf8,0xff,0x7f,0x00,0x00,0x00,
+ 0xc0,0x03,0xf8,0xef,0xff,0x00,0x00,0x00,0xff,0x03,0xf8,0xef,0xff,0xfc,0x00,
+ 0x00,0xff,0x03,0xf8,0xcf,0xff,0xf9,0x00,0x00,0xff,0x03,0xf8,0x8f,0xff,0xf3,
+ 0x00,0x00,0xff,0x03,0xf8,0x0f,0xff,0xf7,0x00,0x80,0xff,0x03,0xf8,0x0f,0xff,
+ 0xe7,0x00,0x80,0xff,0x03,0xf8,0x0f,0xfe,0xcf,0x00,0x00,0xf0,0x03,0xf8,0x0f,
+ 0xfc,0x1f,0x00,0x00,0x80,0x03,0xf8,0x0f,0xfc,0x1f,0x00,0x00,0x80,0x07,0xf8,
+ 0x0f,0xf8,0x3f,0x00,0x00,0x80,0x07,0xf8,0x0f,0xf0,0x7f,0x00,0x00,0x00,0x0f,
+ 0xf8,0x0f,0xf0,0xff,0x00,0x00,0x00,0x0f,0xf8,0x0f,0xe4,0xff,0x00,0x00,0x00,
+ 0x1e,0xf8,0x0f,0xcc,0xff,0x01,0x00,0x00,0x3f,0xf8,0x0f,0x9e,0x1f,0x00,0x00,
+ 0x80,0x7f,0x08,0x80,0x9f,0x03,0x00,0x00,0x80,0xff,0x01,0xc0,0x3f,0x00,0x00,
+ 0x00,0xc0,0xff,0x07,0xf8,0x7f,0x00,0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x03,
+ 0x00,0x00,0xe0,0xbf,0xff,0xff,0xfe,0x07,0x00,0x00,0xe0,0x0f,0xfc,0x3f,0xf8,
+ 0x03,0x00,0x00,0xc0,0x07,0xf0,0x0f,0xf0,0x01,0x00,0x00,0x80,0x01,0xf0,0x0f,
+ 0xc0,0x00,0x00,0x00,0x00,0x00,0xf0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xe0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xe0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/kdesktop/pics/ksslogo.png b/kdesktop/pics/ksslogo.png
new file mode 100644
index 000000000..88874ebc3
--- /dev/null
+++ b/kdesktop/pics/ksslogo.png
Binary files differ
diff --git a/kdesktop/pics/splash.png b/kdesktop/pics/splash.png
new file mode 100644
index 000000000..00faf07e7
--- /dev/null
+++ b/kdesktop/pics/splash.png
Binary files differ
diff --git a/kdesktop/pics/splash2.png b/kdesktop/pics/splash2.png
new file mode 100644
index 000000000..88785147c
--- /dev/null
+++ b/kdesktop/pics/splash2.png
Binary files differ
diff --git a/kdesktop/pixmapserver.cc b/kdesktop/pixmapserver.cc
new file mode 100644
index 000000000..ba66ef966
--- /dev/null
+++ b/kdesktop/pixmapserver.cc
@@ -0,0 +1,254 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdesktop.
+ * Copyright (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
+ *
+ * You can Freely distribute this program under the GNU General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ *
+ *
+ * Shared pixmap server for KDE.
+ *
+ * 5 Dec 99: Geert Jansen:
+ *
+ * Initial implementation using the X11 selection mechanism.
+ */
+
+#include <assert.h>
+
+
+#include <kapplication.h>
+#include <kdebug.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include "pixmapserver.h"
+
+#ifndef None
+#define None 0L
+#endif
+
+#ifdef __GNUC__
+#define ID __PRETTY_FUNCTION__ << ": "
+#else
+#define ID "KPixmapServer: "
+#endif
+
+
+KPixmapServer::KPixmapServer()
+ : QWidget(0L, "shpixmap comm window")
+{
+ kapp->installX11EventFilter(this);
+ pixmap = XInternAtom(qt_xdisplay(), "PIXMAP", false);
+}
+
+
+KPixmapServer::~KPixmapServer()
+{
+ SelectionIterator it;
+ for (it=m_Selections.begin(); it!=m_Selections.end(); it++)
+ XSetSelectionOwner(qt_xdisplay(), it.key(), None, CurrentTime);
+
+ DataIterator it2;
+ for (it2=m_Data.begin(); it2!=m_Data.end(); it2++)
+ delete it2.data().pixmap;
+}
+
+
+void KPixmapServer::add(QString name, QPixmap *pm, bool overwrite)
+{
+ if (m_Names.contains(name))
+ {
+ if (overwrite)
+ remove(name);
+ else return;
+ }
+
+ QString str = QString("KDESHPIXMAP:%1").arg(name);
+ Atom sel = XInternAtom(qt_xdisplay(), str.latin1(), false);
+ KPixmapInode pi;
+ pi.handle = pm->handle();
+ pi.selection = sel;
+ m_Names[name] = pi;
+
+ KSelectionInode si;
+ si.name = name;
+ si.handle = pm->handle();
+ m_Selections[sel] = si;
+
+ DataIterator it = m_Data.find(pm->handle());
+ if (it == m_Data.end())
+ {
+ KPixmapData data;
+ data.pixmap = pm;
+ data.usecount = 0;
+ data.refcount = 1;
+ m_Data[pm->handle()] = data;
+ } else
+ it.data().refcount++;
+
+ XSetSelectionOwner(qt_xdisplay(), sel, winId(), CurrentTime);
+}
+
+
+void KPixmapServer::remove(QString name)
+{
+ // Remove the name
+ NameIterator it = m_Names.find(name);
+ if (it == m_Names.end())
+ return;
+ KPixmapInode pi = it.data();
+ m_Names.remove(it);
+
+ // Remove and disown the selection
+ SelectionIterator it2 = m_Selections.find(pi.selection);
+ assert(it2 != m_Selections.end());
+ m_Selections.remove(it2);
+ XSetSelectionOwner(qt_xdisplay(), pi.selection, None, CurrentTime);
+
+ // Decrease refcount on data
+ DataIterator it3 = m_Data.find(pi.handle);
+ assert(it3 != m_Data.end());
+ it3.data().refcount--;
+ if (!it3.data().refcount && !it3.data().usecount)
+ {
+ delete it3.data().pixmap;
+ m_Data.remove(it3);
+ }
+}
+
+
+QStringList KPixmapServer::list()
+{
+ QStringList lst;
+ NameIterator it;
+ for (it=m_Names.begin(); it!=m_Names.end(); it++)
+ lst += it.key();
+ return lst;
+}
+
+
+void KPixmapServer::setOwner(QString name)
+{
+ NameIterator it = m_Names.find(name);
+ if (it == m_Names.end())
+ return;
+
+ XSetSelectionOwner(qt_xdisplay(), it.data().selection, winId(), CurrentTime);
+}
+
+
+bool KPixmapServer::x11Event(XEvent *event)
+{
+ // Handle SelectionRequest events by which a X client can request a
+ // shared pixmap.
+
+ if (event->type == SelectionRequest)
+ {
+ XSelectionRequestEvent *ev = &event->xselectionrequest;
+
+ // Build negative reply
+ XEvent reply;
+ reply.type = SelectionNotify;
+ reply.xselection.display = qt_xdisplay();
+ reply.xselection.requestor = ev->requestor;
+ reply.xselection.selection = ev->selection;
+ reply.xselection.target = pixmap;
+ reply.xselection.property = None;
+ reply.xselection.time = ev->time;
+
+ // Check if we know about this selection
+ Atom sel = ev->selection;
+ SelectionIterator it = m_Selections.find(sel);
+ if (it == m_Selections.end())
+ return false;
+ KSelectionInode si = it.data();
+
+ // Only convert to pixmap
+ if (ev->target != pixmap)
+ {
+ kdDebug(1204) << ID << "illegal target\n";
+ XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
+ return true;
+ }
+
+ // Check if there is no transaction in progress to the same property
+ if (m_Active.contains(ev->property))
+ {
+ kdDebug(1204) << ID << "selection is busy.\n";
+ XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
+ return true;
+ }
+
+ // Check if the selection was not deleted
+ DataIterator it2 = m_Data.find(si.handle);
+ if (it2 == m_Data.end())
+ {
+ kdDebug(1204) << ID << "selection has been deleted.\n";
+ XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
+ return true;
+ }
+
+ kdDebug(1204) << ID << "request for " << si.name << "\n";
+
+ // All OK: pass the pixmap handle.
+ XChangeProperty(qt_xdisplay(), ev->requestor, ev->property, pixmap,
+ 32, PropModeReplace, (unsigned char *) &si.handle, 1);
+ it2.data().usecount++;
+ m_Active[ev->property] = si.handle;
+
+ // Request PropertyNotify events for the target window
+ // XXX: The target window better not be handled by us!
+ XSelectInput(qt_xdisplay(), ev->requestor, PropertyChangeMask);
+
+ // Acknowledge to the client and return
+ reply.xselection.property = ev->property;
+ XSendEvent(qt_xdisplay(), ev->requestor, false, 0, &reply);
+ return true;
+ }
+
+ // ICCCM says that the target property is to be deleted by the
+ // requestor. We are notified of this by a PropertyNotify. Only then, we
+ // can actually delete the pixmap if it was removed.
+
+ if (event->type == PropertyNotify)
+ {
+ XPropertyEvent *ev = &event->xproperty;
+
+ AtomIterator it = m_Active.find(ev->atom);
+ if (it == m_Active.end())
+ return false;
+ HANDLE handle = it.data();
+ m_Active.remove(it);
+
+ DataIterator it2 = m_Data.find(handle);
+ assert(it2 != m_Data.end());
+ it2.data().usecount--;
+ if (!it2.data().usecount && !it2.data().refcount)
+ {
+ delete it2.data().pixmap;
+ m_Data.remove(it2);
+ }
+ return true;
+ }
+
+ // Handle SelectionClear events.
+
+ if (event->type == SelectionClear)
+ {
+ XSelectionClearEvent *ev = &event->xselectionclear;
+
+ SelectionIterator it = m_Selections.find(ev->selection);
+ if (it == m_Selections.end())
+ return false;
+
+ emit selectionCleared(it.data().name);
+ return true;
+ }
+
+ // Process further
+ return false;
+}
+
+#include "pixmapserver.moc"
diff --git a/kdesktop/pixmapserver.h b/kdesktop/pixmapserver.h
new file mode 100644
index 000000000..e0f871988
--- /dev/null
+++ b/kdesktop/pixmapserver.h
@@ -0,0 +1,124 @@
+/* vi: ts=8 sts=4 sw=4
+ *
+ * This file is part of the KDE project, module kdesktop.
+ * Copyright (C) 1999 Geert Jansen <g.t.jansen@stud.tue.nl>
+ *
+ * You can Freely distribute this program under the GNU General Public
+ * License. See the file "COPYING" for the exact licensing terms.
+ */
+
+#ifndef __PixmapServer_h_Included__
+#define __PixmapServer_h_Included__
+
+#include <qwindowdefs.h>
+
+#include <qwidget.h>
+#include <qmap.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+/**
+ * Used internally by KPixmapServer.
+ */
+
+struct KPixmapInode
+{
+ Qt::HANDLE handle;
+ Atom selection;
+};
+
+struct KPixmapData
+{
+ QPixmap *pixmap;
+ int usecount;
+ int refcount;
+};
+
+struct KSelectionInode
+{
+ Qt::HANDLE handle;
+ QString name;
+};
+
+/**
+ * KPixmapServer: Share pixmaps between X clients with deletion and
+ * multi-server capabilities.
+ * The sharing is implemented using X11 Selections.
+ *
+ * @author Geert Jansen <g.t.jansen@stud.tue.nl>
+ */
+class KPixmapServer: public QWidget
+{
+ Q_OBJECT
+
+public:
+ KPixmapServer();
+ ~KPixmapServer();
+
+ /**
+ * Adds a pixmap to this server. This will make it available to all
+ * other X clients on the current display.
+ *
+ * You must never delete a pixmap that you add()'ed. The pixmap is
+ * deleted when you call remove() and after all clients have stopped
+ * using it.
+ *
+ * You can add the same pixmap under multiple names.
+ *
+ * @param name An X11-wide unique identifier for the pixmap.
+ * @param pm A pointer to the pixmap.
+ * @param overwrite Should an pixmap with the same name be overwritten?
+ */
+ void add(QString name, QPixmap *pm, bool overwrite=true);
+
+ /**
+ * Remove a pixmap from the server. This will delete the pixmap after
+ * all clients have stopped using it.
+ *
+ * @param name The name of the shared pixmap.
+ */
+ void remove(QString name);
+
+ /**
+ * List all pixmaps currently served by this server.
+ *
+ * @return A QStringList containing all the shared pixmaps.
+ */
+ QStringList list();
+
+ /**
+ * Re-set ownership of the selection providing the shared pixmap.
+ *
+ * @param name The name of the shared pixmap.
+ */
+ void setOwner(QString name);
+
+signals:
+ /**
+ * This signal is emitted when the selection providing the named pixmap
+ * is disowned. This means that said pixmap won't be served anymore by
+ * this server, though it can be served by another. You can re-aqcuire
+ * the selection by calling setOwner().
+ */
+ void selectionCleared(QString name);
+
+protected:
+ bool x11Event(XEvent *);
+
+private:
+ Atom pixmap;
+
+ QMap<QString,KPixmapInode> m_Names;
+ QMap<Atom,KSelectionInode> m_Selections;
+ QMap<HANDLE,KPixmapData> m_Data;
+ QMap<Atom,HANDLE> m_Active;
+
+ typedef QMap<QString,KPixmapInode>::Iterator NameIterator;
+ typedef QMap<Atom,KSelectionInode>::Iterator SelectionIterator;
+ typedef QMap<HANDLE,KPixmapData>::Iterator DataIterator;
+ typedef QMap<Atom,HANDLE>::Iterator AtomIterator;
+};
+
+
+#endif // __PixmapServer_h_Included__
diff --git a/kdesktop/programs/Makefile.am b/kdesktop/programs/Makefile.am
new file mode 100644
index 000000000..abf5c0b31
--- /dev/null
+++ b/kdesktop/programs/Makefile.am
@@ -0,0 +1,2 @@
+progdir=$(kde_datadir)/kdesktop/programs
+prog_DATA = xearth.desktop xglobe.desktop xplanet.desktop
diff --git a/kdesktop/programs/xearth.desktop b/kdesktop/programs/xearth.desktop
new file mode 100644
index 000000000..5bb26f550
--- /dev/null
+++ b/kdesktop/programs/xearth.desktop
@@ -0,0 +1,81 @@
+[KDE Desktop Program]
+Comment=XEarth by Kirk Johnson
+Comment[af]=XEarth deur Kirk Johnson
+Comment[ar]=XEarth من تأليف Kirk Johnson
+Comment[az]=Kirk Johnson'dan XEarth
+Comment[be]=Зямля (Kirk Johnson)
+Comment[bn]=কার্ক জনসন-এর এক্স-আর্থ
+Comment[br]=XEarth gant Kirk Johnson
+Comment[ca]=XEarth per Kirk Johnson
+Comment[cs]=XEarth vytvořil Kirk Johnson
+Comment[csb]=XEarth (ùs. Kirk Johnson)
+Comment[cy]=XEarth gan Kirk Johnson
+Comment[da]=XEarth af Kirk Johnson
+Comment[de]=XEarth
+Comment[el]=XEarth από τον Kirk Johnson
+Comment[eo]=XTero
+Comment[es]=XEarth de Kirk Johnson
+Comment[et]=XEarth (Kirk Johnson)
+Comment[eu]=XEarth, Kirk Johnsonek egina
+Comment[fa]=XEarth توسط کیرک جانسون
+Comment[fi]=XEarth, tehnyt Kirk Johnson
+Comment[fr]=XEarth par Kirk Johnson
+Comment[fy]=XEarth, troch Kirk Johnson
+Comment[ga]=XEarth le Kirk Johnson
+Comment[gl]=XEarth por Kirk Johnson
+Comment[he]=XEarth מאת Kirk Johnson
+Comment[hi]=किर्क जॉनसन द्वारा एक्स-अर्थ
+Comment[hr]=XEarth (izr. Kirka Johnsona)
+Comment[hu]=Kirk Johnson földgömbje
+Comment[id]=XEarth oleh Kirk Johnson
+Comment[is]=XJörð eftir Kirk Johnson
+Comment[it]=XEarth (di Kirk Johnson)
+Comment[ja]=Kirk Johnson による XEarth
+Comment[ka]=Xდედამიწა (Kirk Johnson)
+Comment[kk]=XEarth (Kirk Johnson)
+Comment[km]=XEarth ដោយ Kirk Johnson
+Comment[lo]=ເເຜນທີ່ໂລກ ໂດຍ Kirk Johnson
+Comment[lt]=Kirk Johnson'o XEarth
+Comment[lv]=XEarth no Kirk Johnson
+Comment[mk]=X-Земја од Kirk Johnson
+Comment[mn]=XEarth
+Comment[ms]=XEarth oleh Kirk Johnson
+Comment[mt]=XEarth minn Kirk Johnson
+Comment[nb]=XEarth av Kirk Johnson
+Comment[nds]=XEarth vun Kirk Johnson
+Comment[ne]=किर्क जोहान्सनद्वारा X अर्थ
+Comment[nl]=XEarth, door Kirk Johnson
+Comment[nn]=XEarth av Kirk Johnson
+Comment[nso]=XLefase ka Kirk Johnson
+Comment[oc]=XEarth per Kirk Johnson
+Comment[pa]=ਕਿਰਕ ਜਾਨਸਨ ਵਲੋਂ XEarth
+Comment[pl]=XEarth autorstwa Kirka Johnsona
+Comment[pt]=XEarth de Kirk Johnson
+Comment[pt_BR]=XEarth por Kirk Johnson
+Comment[ro]=XEarth de Kirk Johnson
+Comment[ru]=XEarth (Kirk Johnson)
+Comment[rw]=XEarth na Kirk Johnson
+Comment[se]=Kirk Johnson:a XEarth
+Comment[sk]=XEarth od Kirka Johnsona
+Comment[sl]=XEarth avtorja Kirka Johnsona
+Comment[ss]=XEarth ngu Kirk Johnson
+Comment[sv]=Xearth av Kirk Johnson
+Comment[ta]=கிர்க் ஜான்சனின் Xஎர்த்
+Comment[tg]=XEarth аз Kirk Johnson
+Comment[th]=แผนที่โลก โดยเคิร์ก จอห์นสัน
+Comment[tr]=Kirk Johnson'dan XEarth
+Comment[tt]=XEarth, Kirk Johnson tarafınnan
+Comment[uk]=XEarth Кірка Джонсона
+Comment[uz]=XEarth (Kirik Jonson tomonidan)
+Comment[uz@cyrillic]=XEarth (Кирик Жонсон томонидан)
+Comment[ven]=Shango la X nga Kirk Johnson
+Comment[vi]=Trái Đất X bởi Kirk Johnson
+Comment[wa]=XDaegn pa Kirk Johnson
+Comment[xh]=XEarth ngu Kirk Johnson
+Comment[zh_CN]=Kirk Johnson 的 XEarth
+Comment[zh_TW]=XEarth (Kirk Johnson 繪製)
+Comment[zu]=XEarth ngu-Kirk Johnson
+Executable=xearth
+Command=xearth -size %x,%y -ppm > %f
+PreviewCommand=xearth -size %x,%y -nomarkers -ppm > %f
+Refresh=10
diff --git a/kdesktop/programs/xglobe.desktop b/kdesktop/programs/xglobe.desktop
new file mode 100644
index 000000000..b177b406d
--- /dev/null
+++ b/kdesktop/programs/xglobe.desktop
@@ -0,0 +1,81 @@
+[KDE Desktop Program]
+Comment=XGlobe by Thorsten Scheuermann
+Comment[af]=XGlobe deur Thorsten Scheuermann
+Comment[ar]=XGlobe من تأليف Thorsten Scheuermann
+Comment[az]=Thorsten Scheuermann'dan XGlobe
+Comment[be]=Глобус (Thorsten Scheuermann)
+Comment[bn]=থর্সটেন শিউয়ারমান-এর এক্স-গ্লোব
+Comment[br]=XGlobe gant Thorsten Scheuermann
+Comment[ca]=XGlobe per en Thorsten Scheuermann
+Comment[cs]=XGlobe vytvořil Thorsten Scheuermann
+Comment[csb]=XGlobe (ùs. Thorsten Scheuermann)
+Comment[cy]=XGlobe gan Thorsten Scheuermann
+Comment[da]=XGlobe af Thorsten Scheuermann
+Comment[de]=XGlobe
+Comment[el]=XGlobe από τον Thorsten Scheuermann
+Comment[eo]=XGlobo
+Comment[es]=XGlobe por Thorsten Scheuermann
+Comment[et]=XGlobe (Thorsten Scheuermann)
+Comment[eu]=XGlobe, Thorsten Scheuermannek egina
+Comment[fa]=XGlobe توسط تورستن شرمن
+Comment[fi]=XGlobe, tehnyt Thorsten Scheuermann
+Comment[fr]=XGlobe par Thorsten Scheuermann
+Comment[fy]=XGlobe, troch Thorsten Scheuermann
+Comment[ga]=XGlobe le Thorsten Scheuermann
+Comment[gl]=XGlobe por Thorsten Scheuermann
+Comment[he]=XGlobe מאת Thorsten Scheuermann
+Comment[hi]=थार्स्टन शर्मन द्वारा एक्स-ग्लोब
+Comment[hr]=XGlobe (izr. Thorsten Scheuermann)
+Comment[hu]=Thorsten Scheuermann földgömbje
+Comment[id]=XGlobe oleh Thorsten Scheuermann
+Comment[is]=XHnöttur eftir Thorsten Scheuermann
+Comment[it]=XGlobe (di Thorsten Scheuermann)
+Comment[ja]=Thorsten Scheuermann による XGlobe
+Comment[ka]=Xგლობუსი (Thorsten Scheuermann)
+Comment[kk]=XGlobe (Thorsten Scheuermann)
+Comment[km]=XGlobe ដោយ Thorsten Scheuermann
+Comment[lo]=ລູກໂລກ ໂດຍ Thorsten Scheuermann
+Comment[lt]=Thorsten Scheuermann'o XGlobe
+Comment[lv]=XGlobe no Thorsten Scheuermann
+Comment[mk]=X-Глобус од Thorsten Scheuermann
+Comment[mn]=XGlobe
+Comment[ms]=XGlobe oleh Thorsten Scheuermann
+Comment[mt]=XGlobe minn Thorsten Scheuermann
+Comment[nb]=XGlobe av Thorsten Scheuermann
+Comment[nds]=XGlobe vun Thorsten Scheuermann
+Comment[ne]=थर्स्टर सेचरम्यानद्वारा X ग्लोब
+Comment[nl]=XGlobe, door Thorsten Scheuermann
+Comment[nn]=XGlobe av Thorsten Scheuermann
+Comment[nso]=XGlobe ka Thorsten Scheuermann
+Comment[oc]=XGlobe per Thorsten Scheuermann
+Comment[pa]=ਥੋਰਸਟੀਨ ਸਚੀਉਰਮਨ ਵਲੋਂ XGlobe
+Comment[pl]=XGlobe autorstwa Thorstena Scheuermanna
+Comment[pt]=XGlobe de Thorsten Scheuermann
+Comment[pt_BR]=XGlobe por Thorsten Scheuermann
+Comment[ro]=XGlobe de Thorsten Scheuermann
+Comment[ru]=XGlobe (Thorsten Scheuermann)
+Comment[rw]=XGlobe na Thorsten Scheuermann
+Comment[se]=Thorsten Scheuermann:a XGlobe
+Comment[sk]=XGlobe od Thorstena Scheuermanna
+Comment[sl]=XGlobe avtorja Thorstena Scheuermanna
+Comment[ss]=XGlobe ngu Thorsten Scheuermann
+Comment[sv]=Xglobe av Thorsten Scheuermann
+Comment[ta]=த்ராஸ்டன் ஸ்யூர்மானின் எக்ஸ் க்ளோப்
+Comment[tg]=XGlobe аз Thorsten Scheuermann
+Comment[th]=ลูกโลก โดย Thorsten Scheuermann
+Comment[tr]=Thorsten Scheuermann'dan XGlobe
+Comment[tt]=XGlobe, Thorsten Scheuermann tarafınnan
+Comment[uk]=XGlobe Торстена Шоєрмана
+Comment[uz]=XGlobe (Torsten Shoyerman tomonidan)
+Comment[uz@cyrillic]=XGlobe (Торстен Шойерман томонидан)
+Comment[ven]=Lifhasi la X nga Thorsten Scheuermann
+Comment[vi]=Qủa cầu X bởi Thorsten Scheuermann
+Comment[wa]=XGlobe pa Thorsten Scheuermann
+Comment[xh]=XGlobe ngu Thorsten Scheuermann
+Comment[zh_CN]=Thorsten Scheuermann 的 XGlobe
+Comment[zh_TW]=XGlobe (Thorsten Scheuermann 繪製)
+Comment[zu]=XGlobe ngu-Thorsten Scheuermann
+Executable=xglobe
+Command=xglobe -dump -once -size %x,%y -nomarkers && mv xglobe-dump.bmp %f
+PreviewCommand=xglobe -nomarkers -nolabel -dump -once -size %x,%y && mv xglobe-dump.bmp %f
+Refresh=10
diff --git a/kdesktop/programs/xplanet.desktop b/kdesktop/programs/xplanet.desktop
new file mode 100644
index 000000000..5590a53e0
--- /dev/null
+++ b/kdesktop/programs/xplanet.desktop
@@ -0,0 +1,80 @@
+[KDE Desktop Program]
+Command=xplanet --geometry %xx%y --num_times 1 --output %f.jpg && mv %f.jpg %f
+Comment=XPlanet by Hari Nair
+Comment[af]=XPlaneet deur Hari Nair
+Comment[ar]=XPlanet من تليف Hari Nair
+Comment[az]=Hari Nair'dan XPlanet
+Comment[be]=Планета (Hari Nair)
+Comment[bn]=হরি নায়ার-এর এক্স-প্ল্যানেট
+Comment[br]=XPlanet gant Hari Nair
+Comment[ca]=XPlanet per en Hari Nair
+Comment[cs]=XPlanet od Hariho Naira
+Comment[csb]=XPlanet (ùs.Hari Neir)
+Comment[cy]=XPlanet gan Hari Nair
+Comment[da]=XPlanet af Hari Nair
+Comment[de]=XPlanet
+Comment[el]=XPlanet του Hari Nair
+Comment[eo]=XPlanedo de Hari Nair
+Comment[es]=XPlanet de Hari Nair
+Comment[et]=XPlanet (Hari Nair)
+Comment[eu]=XPlanet Hari Nair-ek egina
+Comment[fa]=XPlanet توسط هاری نیر
+Comment[fi]=XPlanet, tehnyt Hari Nair
+Comment[fr]=XPlanet par Hari Nair
+Comment[fy]=XPlanet, troch Hari Nair
+Comment[ga]=XPlanet le Hari Nair
+Comment[gl]=XPlanet por Hari Nair
+Comment[he]=XPlanet מאת הארי נייר
+Comment[hi]=हरी नायर द्वारा एक्स-प्लेनेट
+Comment[hr]=XPlanet (izr. Hari Nair)
+Comment[hu]=Hari Nair XPlanetje
+Comment[id]=,XPlanet by Hari Nair
+Comment[is]=XPlánetur eftir Hari Nair
+Comment[it]=XPlanet (di Hari Nair)
+Comment[ja]=Hari Nair による XPlanet
+Comment[ka]=Xპლანეტა (Hari Nair)
+Comment[kk]=XPlanet (Hari Nair)
+Comment[km]=XPlanet ដោយ Hari Nair
+Comment[lo]=ອາວະກາດ ໂດຍ Hari Nair
+Comment[lt]=Hari Nair'o XPlanet
+Comment[lv]=XPlanet no Hari Nair
+Comment[mk]=XПланета од Hari Nair
+Comment[mn]=XPlanet
+Comment[ms]=XPlanet oleh Hari Nair
+Comment[mt]=XPlanet minn Hari Nair
+Comment[nb]=XPlanet av Hari Nair
+Comment[nds]=XPlanet vun Hari Nair
+Comment[ne]=हरि नैरद्वारा X प्लानेट
+Comment[nl]=XPlanet, door Hari Nair
+Comment[nn]=XPlanet av Hari Nair
+Comment[nso]=XPlanet ka Hari Nair
+Comment[pa]=ਹੇਰੀ ਨਾਇਰ ਵਲੋਂ XPlanet
+Comment[pl]=XPlanet autorstwa Hari Neir
+Comment[pt]=XPlanet de Hari Nair
+Comment[pt_BR]=XPlanet por Hari Nair
+Comment[ro]=XPlanet de Hari Nair
+Comment[ru]=XPlanet (Hari Nair)
+Comment[rw]=XPlanet na Hari Nair
+Comment[se]=Hari Naira XPlanet
+Comment[sk]=XPlanet od Hari Nair
+Comment[sl]=XPlanet Harija Naira
+Comment[ss]=XPlanet ngu Hari Nair
+Comment[sv]=Xplanet av Hari Nair
+Comment[ta]=ஹரி நாயரின் Xப்ளானட்
+Comment[tg]=XPlanet аз Hari Nair
+Comment[th]=ดาวเคราะห์ โดย Hari Nair
+Comment[tr]=Hari Nair'dan XPlanet
+Comment[tt]=XPlanet, Hari Nair tarafınnan
+Comment[uk]=XPlanet від Hari Nair
+Comment[uz]=XPlanet (Xari Neyr tomonidan)
+Comment[uz@cyrillic]=XPlanet (Хари Нейр томонидан)
+Comment[ven]=Pulanete ya X nga Hari Nair
+Comment[vi]=Hành tinh X bởi Hari Nair
+Comment[wa]=XPlanete pa Hari Nair
+Comment[xh]=XPlanet ngu Hari Nair
+Comment[zh_CN]=Hari Nair 的 XPlanet
+Comment[zh_TW]=XPlanet (Hari Nair 繪製)
+Comment[zu]=XPlanet ngu-Hari Nair
+Executable=xplanet
+PreviewCommand=xplanet --geometry %xx%y --num_times 1 --output %f.jpg && mv %f.jpg %f
+Refresh=10
diff --git a/kdesktop/startupid.cpp b/kdesktop/startupid.cpp
new file mode 100644
index 000000000..7f0549ff4
--- /dev/null
+++ b/kdesktop/startupid.cpp
@@ -0,0 +1,301 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Lubos Lunak <l.lunak@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include "startupid.h"
+#include "klaunchsettings.h"
+
+#include <kiconloader.h>
+#include <qcursor.h>
+#include <kapplication.h>
+#include <qimage.h>
+#include <qbitmap.h>
+#include <kconfig.h>
+#include <X11/Xlib.h>
+
+#define KDE_STARTUP_ICON "kmenu"
+
+#ifdef HAVE_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
+
+enum kde_startup_status_enum { StartupPre, StartupIn, StartupDone };
+static kde_startup_status_enum kde_startup_status = StartupPre;
+static Atom kde_splash_progress;
+
+StartupId::StartupId( QWidget* parent, const char* name )
+ : QWidget( parent, name ),
+ startup_info( KStartupInfo::CleanOnCantDetect ),
+ startup_widget( NULL ),
+ blinking( true ),
+ bouncing( false )
+ {
+ hide(); // is QWidget only because of x11Event()
+ if( kde_startup_status == StartupPre )
+ {
+ kde_splash_progress = XInternAtom( qt_xdisplay(), "_KDE_SPLASH_PROGRESS", False );
+ XWindowAttributes attrs;
+ XGetWindowAttributes( qt_xdisplay(), qt_xrootwin(), &attrs);
+ XSelectInput( qt_xdisplay(), qt_xrootwin(), attrs.your_event_mask | SubstructureNotifyMask);
+ kapp->installX11EventFilter( this );
+ }
+ connect( &update_timer, SIGNAL( timeout()), SLOT( update_startupid()));
+ connect( &startup_info,
+ SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )),
+ SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )));
+ connect( &startup_info,
+ SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )),
+ SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )));
+ connect( &startup_info,
+ SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )),
+ SLOT( gotRemoveStartup( const KStartupInfoId& )));
+ }
+
+StartupId::~StartupId()
+ {
+ stop_startupid();
+ }
+
+void StartupId::configure()
+ {
+ startup_info.setTimeout( KLaunchSettings::timeout());
+ blinking = KLaunchSettings::blinking();
+ bouncing = KLaunchSettings::bouncing();
+ }
+
+void StartupId::gotNewStartup( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
+ {
+ QString icon = data_P.findIcon();
+ current_startup = id_P;
+ startups[ id_P ] = icon;
+ start_startupid( icon );
+ }
+
+void StartupId::gotStartupChange( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
+ {
+ if( current_startup == id_P )
+ {
+ QString icon = data_P.findIcon();
+ if( !icon.isEmpty() && icon != startups[ current_startup ] )
+ {
+ startups[ id_P ] = icon;
+ start_startupid( icon );
+ }
+ }
+ }
+
+void StartupId::gotRemoveStartup( const KStartupInfoId& id_P )
+ {
+ startups.remove( id_P );
+ if( startups.count() == 0 )
+ {
+ current_startup = KStartupInfoId(); // null
+ if( kde_startup_status == StartupIn )
+ start_startupid( KDE_STARTUP_ICON );
+ else
+ stop_startupid();
+ return;
+ }
+ current_startup = startups.begin().key();
+ start_startupid( startups[ current_startup ] );
+ }
+
+bool StartupId::x11Event( XEvent* e )
+ {
+ if( e->type == ClientMessage && e->xclient.window == qt_xrootwin()
+ && e->xclient.message_type == kde_splash_progress )
+ {
+ const char* s = e->xclient.data.b;
+ if( strcmp( s, "kicker" ) == 0 && kde_startup_status == StartupPre )
+ {
+ kde_startup_status = StartupIn;
+ if( startups.count() == 0 )
+ start_startupid( KDE_STARTUP_ICON );
+ // 60(?) sec timeout - shouldn't be hopefully needed anyway, ksmserver should have it too
+ QTimer::singleShot( 60000, this, SLOT( finishKDEStartup()));
+ }
+ else if( strcmp( s, "session ready" ) == 0 && kde_startup_status < StartupDone )
+ QTimer::singleShot( 2000, this, SLOT( finishKDEStartup()));
+ }
+ return false;
+ }
+
+void StartupId::finishKDEStartup()
+ {
+ kde_startup_status = StartupDone;
+ kapp->removeX11EventFilter( this );
+ if( startups.count() == 0 )
+ stop_startupid();
+ }
+
+void StartupId::stop_startupid()
+ {
+ delete startup_widget;
+ startup_widget = NULL;
+ if( blinking )
+ for( int i = 0;
+ i < NUM_BLINKING_PIXMAPS;
+ ++i )
+ pixmaps[ i ] = QPixmap(); // null
+ update_timer.stop();
+ }
+
+static QPixmap scalePixmap( const QPixmap& pm, int w, int h )
+{
+#if QT_VERSION >= 0x030200
+ QPixmap result( 20, 20, pm.depth() );
+ result.setMask( QBitmap( 20, 20, true ) );
+ QPixmap scaled( pm.convertToImage().smoothScale( w, h ) );
+ copyBlt( &result, (20 - w) / 2, (20 - h) / 2, &scaled, 0, 0, w, h );
+ return result;
+#else
+ Q_UNUSED(w);
+ Q_UNUSED(h);
+ return pm;
+#endif
+}
+
+void StartupId::start_startupid( const QString& icon_P )
+ {
+
+ const QColor startup_colors[ StartupId::NUM_BLINKING_PIXMAPS ]
+ = { Qt::black, Qt::darkGray, Qt::lightGray, Qt::white, Qt::white };
+
+
+ QPixmap icon_pixmap = KGlobal::iconLoader()->loadIcon( icon_P, KIcon::Small, 0,
+ KIcon::DefaultState, 0, true ); // return null pixmap if not found
+ if( icon_pixmap.isNull())
+ icon_pixmap = SmallIcon( "exec" );
+ if( startup_widget == NULL )
+ {
+ startup_widget = new QWidget( NULL, NULL, WX11BypassWM );
+ XSetWindowAttributes attr;
+ attr.save_under = True; // useful saveunder if possible to avoid redrawing
+ XChangeWindowAttributes( qt_xdisplay(), startup_widget->winId(), CWSaveUnder, &attr );
+ }
+ startup_widget->resize( icon_pixmap.width(), icon_pixmap.height());
+ if( blinking )
+ {
+ startup_widget->clearMask();
+ int window_w = icon_pixmap.width();
+ int window_h = icon_pixmap.height();
+ for( int i = 0;
+ i < NUM_BLINKING_PIXMAPS;
+ ++i )
+ {
+ pixmaps[ i ] = QPixmap( window_w, window_h );
+ pixmaps[ i ].fill( startup_colors[ i ] );
+ bitBlt( &pixmaps[ i ], 0, 0, &icon_pixmap );
+ }
+ color_index = 0;
+ }
+ else if( bouncing )
+ {
+ startup_widget->resize( 20, 20 );
+ pixmaps[ 0 ] = scalePixmap( icon_pixmap, 16, 16 );
+ pixmaps[ 1 ] = scalePixmap( icon_pixmap, 14, 18 );
+ pixmaps[ 2 ] = scalePixmap( icon_pixmap, 12, 20 );
+ pixmaps[ 3 ] = scalePixmap( icon_pixmap, 18, 14 );
+ pixmaps[ 4 ] = scalePixmap( icon_pixmap, 20, 12 );
+ frame = 0;
+ }
+ else
+ {
+ if( icon_pixmap.mask() != NULL )
+ startup_widget->setMask( *icon_pixmap.mask());
+ else
+ startup_widget->clearMask();
+ startup_widget->setBackgroundPixmap( icon_pixmap );
+ startup_widget->erase();
+ }
+ update_startupid();
+ }
+
+namespace
+{
+const int X_DIFF = 15;
+const int Y_DIFF = 15;
+const int color_to_pixmap[] = { 0, 1, 2, 3, 2, 1 };
+const int frame_to_yoffset[] =
+ {
+ -5, -1, 2, 5, 8, 10, 12, 13, 15, 15, 15, 15, 14, 12, 10, 8, 5, 2, -1, -5
+ };
+const int frame_to_pixmap[] =
+ {
+ 0, 0, 0, 1, 2, 2, 1, 0, 3, 4, 4, 3, 0, 1, 2, 2, 1, 0, 0, 0
+ };
+}
+
+void StartupId::update_startupid()
+ {
+ int yoffset = 0;
+ if( blinking )
+ {
+ startup_widget->setBackgroundPixmap( pixmaps[ color_to_pixmap[ color_index ]] );
+ if( ++color_index >= ( sizeof( color_to_pixmap ) / sizeof( color_to_pixmap[ 0 ] )))
+ color_index = 0;
+ }
+ else if( bouncing )
+ {
+ yoffset = frame_to_yoffset[ frame ];
+ QPixmap pm = pixmaps[ frame_to_pixmap[ frame ] ];
+ startup_widget->setBackgroundPixmap( pm );
+ if ( pm.mask() != NULL )
+ startup_widget->setMask( *pm.mask() );
+ else
+ startup_widget->clearMask();
+ if ( ++frame >= ( sizeof( frame_to_yoffset ) / sizeof( frame_to_yoffset[ 0 ] ) ) )
+ frame = 0;
+ }
+ Window dummy1, dummy2;
+ int x, y;
+ int dummy3, dummy4;
+ unsigned int dummy5;
+ if( !XQueryPointer( qt_xdisplay(), qt_xrootwin(), &dummy1, &dummy2, &x, &y, &dummy3, &dummy4, &dummy5 ))
+ {
+ startup_widget->hide();
+ update_timer.start( 100, true );
+ return;
+ }
+ QPoint c_pos( x, y );
+ int cursor_size = 0;
+#ifdef HAVE_XCURSOR
+ cursor_size = XcursorGetDefaultSize( qt_xdisplay());
+#endif
+ int X_DIFF;
+ if( cursor_size <= 16 )
+ X_DIFF = 8 + 7;
+ else if( cursor_size <= 32 )
+ X_DIFF = 16 + 7;
+ else if( cursor_size <= 48 )
+ X_DIFF = 24 + 7;
+ else
+ X_DIFF = 32 + 7;
+ int Y_DIFF = X_DIFF;
+ if( startup_widget->x() != c_pos.x() + X_DIFF
+ || startup_widget->y() != c_pos.y() + Y_DIFF + yoffset )
+ startup_widget->move( c_pos.x() + X_DIFF, c_pos.y() + Y_DIFF + yoffset );
+ startup_widget->show();
+ XRaiseWindow( qt_xdisplay(), startup_widget->winId());
+ update_timer.start( bouncing ? 30 : 100, true );
+ QApplication::flushX();
+ }
+
+#include "startupid.moc"
diff --git a/kdesktop/startupid.h b/kdesktop/startupid.h
new file mode 100644
index 000000000..986c45c3f
--- /dev/null
+++ b/kdesktop/startupid.h
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Lubos Lunak <l.lunak@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __startup_h__
+#define __startup_h__
+
+#include <sys/types.h>
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qtimer.h>
+#include <qmap.h>
+#include <kstartupinfo.h>
+
+class QStyle;
+
+class StartupId
+ : public QWidget
+ {
+ Q_OBJECT
+ public:
+ StartupId( QWidget* parent = 0, const char* name = 0 );
+ virtual ~StartupId();
+ void configure();
+ protected:
+ virtual bool x11Event( XEvent* e );
+ void start_startupid( const QString& icon );
+ void stop_startupid();
+ protected slots:
+ void update_startupid();
+ void gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data );
+ void gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data );
+ void gotRemoveStartup( const KStartupInfoId& id );
+ void finishKDEStartup();
+ protected:
+ KStartupInfo startup_info;
+ QWidget* startup_widget;
+ QTimer update_timer;
+ QMap< KStartupInfoId, QString > startups; // QString == pixmap
+ KStartupInfoId current_startup;
+ bool blinking;
+ bool bouncing;
+ unsigned int color_index;
+ unsigned int frame;
+ enum { NUM_BLINKING_PIXMAPS = 5 };
+ QPixmap pixmaps[ NUM_BLINKING_PIXMAPS ];
+ };
+
+#endif
diff --git a/kdesktop/xautolock.cc b/kdesktop/xautolock.cc
new file mode 100644
index 000000000..d8f4bbfbe
--- /dev/null
+++ b/kdesktop/xautolock.cc
@@ -0,0 +1,289 @@
+//----------------------------------------------------------------------------
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+// Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
+//
+// KDE screensaver engine
+//
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xautolock.h"
+#include "xautolock.moc"
+
+#include <kapplication.h>
+#include <kdebug.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <ctime>
+#include "xautolock_c.h"
+
+#ifdef HAVE_DPMS
+extern "C" {
+#include <X11/Xmd.h>
+#ifndef Bool
+#define Bool BOOL
+#endif
+#include <X11/extensions/dpms.h>
+
+#ifndef HAVE_DPMSINFO_PROTO
+Status DPMSInfo ( Display *, CARD16 *, BOOL * );
+#endif
+}
+#endif
+
+int xautolock_useXidle = 0;
+int xautolock_useMit = 0;
+xautolock_corner_t xautolock_corners[ 4 ];
+
+static XAutoLock* self = NULL;
+
+extern "C" {
+static int catchFalseAlarms(Display *, XErrorEvent *)
+{
+ return 0;
+}
+}
+
+//===========================================================================
+//
+// Detect user inactivity.
+// Named XAutoLock after the program that it is based on.
+//
+XAutoLock::XAutoLock()
+{
+ self = this;
+ xautolock_useXidle = 0;
+ xautolock_useMit = 0;
+#ifdef HAVE_XIDLE
+ int dummy1;
+ xautolock_useXidle = XidleQueryExtension( qt_xdisplay(), &dummy1, &dummy1 );
+#endif
+#ifdef HAVE_XSCREENSAVER
+ int dummy2;
+ if( !xautolock_useXidle )
+ xautolock_useMit = XScreenSaverQueryExtension( qt_xdisplay(), &dummy2, &dummy2 );
+#endif
+ if( !xautolock_useXidle && !xautolock_useMit )
+ {
+ kapp->installX11EventFilter( this );
+ int (*oldHandler)(Display *, XErrorEvent *);
+ oldHandler = XSetErrorHandler(catchFalseAlarms);
+ XSync(qt_xdisplay(), False );
+ xautolock_initDiy( qt_xdisplay());
+ XSync(qt_xdisplay(), False );
+ XSetErrorHandler(oldHandler);
+ }
+
+ mTimeout = DEFAULT_TIMEOUT;
+ mDPMS = true;
+ resetTrigger();
+
+ time(&mLastTimeout);
+ mActive = false;
+
+ mTimerId = startTimer( CHECK_INTERVAL );
+
+}
+
+//---------------------------------------------------------------------------
+//
+// Destructor.
+//
+XAutoLock::~XAutoLock()
+{
+ self = NULL;
+}
+
+//---------------------------------------------------------------------------
+//
+// The time in seconds of continuous inactivity.
+//
+void XAutoLock::setTimeout(int t)
+{
+ mTimeout = t;
+ resetTrigger();
+}
+
+void XAutoLock::setDPMS(bool s)
+{
+#ifdef HAVE_DPMS
+ BOOL on;
+ CARD16 state;
+ DPMSInfo( qt_xdisplay(), &state, &on );
+ if (!on)
+ s = false;
+#endif
+ mDPMS = s;
+}
+
+//---------------------------------------------------------------------------
+//
+// Start watching Activity
+//
+void XAutoLock::start()
+{
+ resetTrigger();
+ time(&mLastTimeout);
+ mActive = true;
+}
+
+//---------------------------------------------------------------------------
+//
+// Stop watching Activity
+//
+void XAutoLock::stop()
+{
+ mActive = false;
+}
+
+//---------------------------------------------------------------------------
+//
+// Reset the trigger time.
+//
+void XAutoLock::resetTrigger()
+{
+ mTrigger = time(0) + mTimeout;
+}
+
+//---------------------------------------------------------------------------
+//
+// Move the trigger time in order to postpone (repeat) emitting of timeout().
+//
+void XAutoLock::postpone()
+{
+ mTrigger = time(0) + 60; // delay by 60sec
+}
+
+//---------------------------------------------------------------------------
+//
+// Set the remaining time to 't', if it's shorter than already set.
+//
+void XAutoLock::setTrigger( time_t t )
+{
+ if( t < mTrigger )
+ mTrigger = t;
+}
+
+//---------------------------------------------------------------------------
+//
+// Process new windows and check the mouse.
+//
+void XAutoLock::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() != mTimerId)
+ {
+ return;
+ }
+
+ int (*oldHandler)(Display *, XErrorEvent *) = NULL;
+ if( !xautolock_useXidle && !xautolock_useMit )
+ { // only the diy way needs special X handler
+ XSync( qt_xdisplay(), False );
+ oldHandler = XSetErrorHandler(catchFalseAlarms);
+ }
+
+ xautolock_processQueue();
+
+ time_t now = time(0);
+ if ((now > mLastTimeout && now - mLastTimeout > TIME_CHANGE_LIMIT) ||
+ (mLastTimeout > now && mLastTimeout - now > TIME_CHANGE_LIMIT+1))
+ {
+ /* the time has changed in one large jump. This could be because
+ the date was changed, or the machine was suspended. We'll just
+ reset the triger. */
+ resetTrigger();
+ }
+
+ mLastTimeout = now;
+
+ xautolock_queryIdleTime( qt_xdisplay());
+ xautolock_queryPointer( qt_xdisplay());
+
+ if( !xautolock_useXidle && !xautolock_useMit )
+ XSetErrorHandler(oldHandler);
+
+ bool activate = false;
+
+ //kdDebug() << now << " " << mTrigger << endl;
+ if (now >= mTrigger)
+ {
+ resetTrigger();
+ activate = true;
+ }
+
+#ifdef HAVE_DPMS
+ BOOL on;
+ CARD16 state;
+ DPMSInfo( qt_xdisplay(), &state, &on );
+
+ //kdDebug() << "DPMSInfo " << state << " " << on << endl;
+ // If DPMS is active, it makes XScreenSaverQueryInfo() report idle time
+ // that is always smaller than DPMS timeout (X bug I guess). So if DPMS
+ // saving is active, simply always activate our saving too, otherwise
+ // this could prevent locking from working.
+ if(state == DPMSModeStandby || state == DPMSModeSuspend || state == DPMSModeOff)
+ activate = true;
+ if(!on && mDPMS) {
+ activate = false;
+#ifdef HAVE_XSCREENSAVER
+ XForceScreenSaver(qt_xdisplay(), ScreenSaverReset );
+#endif
+ resetTrigger();
+ }
+#endif
+
+#ifdef HAVE_XSCREENSAVER
+ static XScreenSaverInfo* mitInfo = 0;
+ if (!mitInfo) mitInfo = XScreenSaverAllocInfo ();
+ if (XScreenSaverQueryInfo (qt_xdisplay(), DefaultRootWindow (qt_xdisplay()), mitInfo)) {
+ //kdDebug() << "XScreenSaverQueryInfo " << mitInfo->state << " " << ScreenSaverDisabled << endl;
+ if (mitInfo->state == ScreenSaverDisabled)
+ activate = false;
+ }
+#endif
+
+ if(mActive && activate)
+ emit timeout();
+}
+
+bool XAutoLock::x11Event( XEvent* ev )
+{
+ xautolock_processEvent( ev );
+// don't futher process key events that were received only because XAutoLock wants them
+ if( ev->type == KeyPress && !ev->xkey.send_event
+ && !xautolock_useXidle && !xautolock_useMit
+ && !QWidget::find( ev->xkey.window ))
+ return true;
+ return false;
+}
+
+bool XAutoLock::ignoreWindow( WId w )
+{
+ if( w != qt_xrootwin() && QWidget::find( w ))
+ return true;
+ return false;
+}
+
+extern "C"
+void xautolock_resetTriggers()
+{
+ self->resetTrigger();
+}
+
+extern "C"
+void xautolock_setTrigger( time_t t )
+{
+ self->setTrigger( t );
+}
+
+extern "C"
+int xautolock_ignoreWindow( Window w )
+{
+ return self->ignoreWindow( w );
+}
diff --git a/kdesktop/xautolock.h b/kdesktop/xautolock.h
new file mode 100644
index 000000000..aa618f252
--- /dev/null
+++ b/kdesktop/xautolock.h
@@ -0,0 +1,77 @@
+//===========================================================================
+//
+// This file is part of the KDE project
+//
+// Copyright (c) 1999 Martin R. Jones <mjones@kde.org>
+//
+
+#ifndef __XAUTOLOCK_H__
+#define __XAUTOLOCK_H__
+
+#include <qwidget.h>
+
+#include <X11/Xlib.h>
+
+//===========================================================================
+//
+// Detect user inactivity.
+// Named XAutoLock after the program that it is based on.
+//
+class XAutoLock : public QWidget
+{
+ Q_OBJECT
+public:
+ XAutoLock();
+ ~XAutoLock();
+
+ //-----------------------------------------------------------------------
+ //
+ // The time in seconds of continuous inactivity.
+ //
+ void setTimeout(int t);
+
+ void setDPMS(bool s);
+
+ //-----------------------------------------------------------------------
+ //
+ // Start watching Activity
+ //
+ void start();
+
+ //-----------------------------------------------------------------------
+ //
+ // Stop watching Activity
+ //
+ void stop();
+
+ //-----------------------------------------------------------------------
+ //
+ // Should be called only from a slot connected to the timeout() signal. Will
+ // result in the timeout() signal being emitted again with a delay (i.e. postponed).
+ //
+ void postpone();
+
+ // internal
+ void resetTrigger();
+ // internal
+ void setTrigger( time_t );
+ // internal
+ bool ignoreWindow( WId );
+
+signals:
+ void timeout();
+
+protected:
+ virtual void timerEvent(QTimerEvent *ev);
+ virtual bool x11Event( XEvent* );
+
+protected:
+ int mTimerId;
+ int mTimeout;
+ time_t mTrigger;
+ bool mActive;
+ time_t mLastTimeout;
+ bool mDPMS;
+};
+
+#endif
diff --git a/kdesktop/xautolock_c.h b/kdesktop/xautolock_c.h
new file mode 100644
index 000000000..a53ad9377
--- /dev/null
+++ b/kdesktop/xautolock_c.h
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ *
+ * Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
+ *
+ * Content: This file is part of version 2.x of xautolock. It takes care
+ * of most OS dependencies, and defines the program's default
+ * settings.
+ *
+ * Please send bug reports etc. to eyckmans@imec.be.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
+ *
+ * Versions 2.0 and above of xautolock are available under version 2 of the
+ * GNU GPL. Earlier versions are available under other conditions. For more
+ * information, see the License file.
+ *
+ *****************************************************************************/
+
+#ifndef __xautolock_c_h
+#define __xautolock_c_h
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_XSCREENSAVER
+#define HasScreenSaver
+#include <X11/extensions/scrnsaver.h>
+#endif
+
+/* I'd first need to get my hands on this */
+#undef HAVE_XIDLE
+#undef HasXidle
+
+#define DEFAULT_TIMEOUT 600
+
+#define CHECK_INTERVAL 5000 /* ms */
+
+#define CREATION_DELAY 30 /* should be > 10 and
+ < min (45,(MIN_MINUTES*30)) */
+#define TIME_CHANGE_LIMIT 120 /* if the time changes by more
+ than x secs then we will
+ assume someone has changed
+ date or machine has suspended */
+
+#define cornerSize 5
+
+#define cornerDelay 5
+
+#define cornerRedelay 5
+
+typedef enum { ca_nothing, ca_dontLock, ca_forceLock } xautolock_corner_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+void xautolock_processEvent( XEvent* ev );
+void xautolock_queryIdleTime( Display* d);
+void xautolock_processQueue( void );
+void xautolock_queryPointer (Display* d);
+void xautolock_initDiy (Display* d);
+void xautolock_resetTriggers( void );
+void xautolock_setTrigger( time_t );
+int xautolock_ignoreWindow( Window );
+extern int xautolock_useXidle;
+extern int xautolock_useMit;
+extern xautolock_corner_t xautolock_corners[ 4 ];
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/kdesktop/xautolock_diy.c b/kdesktop/xautolock_diy.c
new file mode 100644
index 000000000..b9df2f895
--- /dev/null
+++ b/kdesktop/xautolock_diy.c
@@ -0,0 +1,289 @@
+/*****************************************************************************
+ *
+ * Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
+ *
+ * Content: This file is part of version 2.x of xautolock. It implements
+ * the stuff used when the program is not using a screen saver
+ * extension and thus has to use the good old "do it yourself"
+ * approach for detecting user activity.
+ *
+ * The basic idea is that we initially traverse the window tree,
+ * selecting SubstructureNotify on all windows and adding each
+ * window to a temporary list. About +- 30 seconds later, we
+ * scan this list, now asking for KeyPress events. The delay
+ * is needed in order to interfere as little as possible with
+ * the event propagation mechanism. Whenever a new window is
+ * created by an application, a similar process takes place.
+ *
+ * Please send bug reports etc. to eyckmans@imec.be.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
+ *
+ * Versions 2.0 and above of xautolock are available under version 2 of the
+ * GNU GPL. Earlier versions are available under other conditions. For more
+ * information, see the License file.
+ *
+ *****************************************************************************/
+
+#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "xautolock_c.h"
+
+static void selectEvents (Window window, Bool substructureOnly);
+
+/*
+ * Window queue management.
+ */
+typedef struct item
+{
+ Window window;
+ time_t creationtime;
+ struct item* next;
+} xautolock_anItem, *xautolock_item;
+
+static struct
+{
+ Display* display;
+ struct item* head;
+ struct item* tail;
+} queue;
+
+static void
+addToQueue (Window window)
+{
+ xautolock_item newItem = malloc(sizeof(xautolock_anItem));
+
+ newItem->window = window;
+ newItem->creationtime = time (0);
+ newItem->next = 0;
+
+ if (!queue.head) queue.head = newItem;
+ if ( queue.tail) queue.tail->next = newItem;
+
+ queue.tail = newItem;
+}
+
+static void
+processQueue (time_t age)
+{
+ if (queue.head)
+ {
+ time_t now = time (0);
+ xautolock_item current = queue.head;
+
+ while (current && current->creationtime + age < now)
+ {
+ selectEvents (current->window, False);
+ queue.head = current->next;
+ free (current);
+ current = queue.head;
+ }
+
+ if (!queue.head) queue.tail = 0;
+ }
+}
+
+/*
+ * Function for selecting all interesting events on a given
+ * (tree of) window(s).
+ */
+static void
+selectEvents (Window window, Bool substructureOnly)
+{
+ Window root; /* root window of the window */
+ Window parent; /* parent of the window */
+ Window* children; /* children of the window */
+ unsigned nofChildren = 0; /* number of children */
+ unsigned i; /* loop counter */
+ XWindowAttributes attribs; /* attributes of the window */
+
+ if( xautolock_ignoreWindow( window ))
+ return;
+ /*
+ * Start by querying the server about the root and parent windows.
+ */
+ if (!XQueryTree (queue.display, window, &root, &parent,
+ &children, &nofChildren))
+ {
+ return;
+ }
+
+ if (nofChildren) (void) XFree ((char*) children);
+
+ /*
+ * Build the appropriate event mask. The basic idea is that we don't
+ * want to interfere with the normal event propagation mechanism if
+ * we don't have to.
+ *
+ * On the root window, we need to ask for both substructureNotify
+ * and KeyPress events. On all other windows, we always need
+ * substructureNotify, but only need Keypress if some other client
+ * also asked for them, or if they are not being propagated up the
+ * window tree.
+ */
+#if 0
+ if (substructureOnly)
+ {
+ (void) XSelectInput (queue.display, window, SubstructureNotifyMask);
+ }
+ else
+ {
+ if (parent == None) /* the *real* rootwindow */
+ {
+ attribs.all_event_masks =
+ attribs.do_not_propagate_mask = KeyPressMask;
+ }
+ else if (!XGetWindowAttributes (queue.display, window, &attribs))
+#else
+ {
+ if (!XGetWindowAttributes (queue.display, window, &attribs))
+#endif
+ {
+ return;
+ }
+
+#if 0
+ (void) XSelectInput (queue.display, window,
+ SubstructureNotifyMask
+ | ( ( attribs.all_event_masks
+ | attribs.do_not_propagate_mask)
+ & KeyPressMask));
+#else
+ {
+ int mask = SubstructureNotifyMask | attribs.your_event_mask;
+ if( !substructureOnly )
+ {
+ mask |= ( ( attribs.all_event_masks
+ | attribs.do_not_propagate_mask)
+ & KeyPressMask );
+ }
+ (void) XSelectInput (queue.display, window, mask );
+ }
+#endif
+
+ }
+
+ /*
+ * Now ask for the list of children again, since it might have changed
+ * in between the last time and us selecting SubstructureNotifyMask.
+ *
+ * There is a (very small) chance that we might process a subtree twice:
+ * child windows that have been created after our XSelectinput() has
+ * been processed but before we get to the XQueryTree() bit will be
+ * in this situation. This is harmless. It could be avoided by using
+ * XGrabServer(), but that'd be an impolite thing to do, and since it
+ * isn't required...
+ */
+ if (!XQueryTree (queue.display, window, &root, &parent,
+ &children, &nofChildren))
+ {
+ return;
+ }
+
+ /*
+ * Now do the same thing for all children.
+ */
+ for (i = 0; i < nofChildren; ++i)
+ {
+ selectEvents (children[i], substructureOnly);
+ }
+
+ if (nofChildren) (void) XFree ((char*) children);
+}
+
+#if 0
+/*
+ * Function for processing any events that have come in since
+ * last time. It is crucial that this function does not block
+ * in case nothing interesting happened.
+ */
+void
+processEvents (void)
+{
+ while (XPending (queue.display))
+ {
+ XEvent event;
+
+ if (XCheckMaskEvent (queue.display, SubstructureNotifyMask, &event))
+ {
+ if (event.type == CreateNotify)
+ {
+ addToQueue (event.xcreatewindow.window);
+ }
+ }
+ else
+ {
+ (void) XNextEvent (queue.display, &event);
+ }
+
+ /*
+ * Reset the triggers if and only if the event is a
+ * KeyPress event *and* was not generated by XSendEvent().
+ */
+ if ( event.type == KeyPress
+ && !event.xany.send_event)
+ {
+ resetTriggers ();
+ }
+ }
+
+ /*
+ * Check the window queue for entries that are older than
+ * CREATION_DELAY seconds.
+ */
+ processQueue ((time_t) CREATION_DELAY);
+}
+#else
+void xautolock_processEvent( XEvent* event )
+{
+ if (event->type == CreateNotify)
+ {
+ addToQueue (event->xcreatewindow.window);
+ }
+ /*
+ * Reset the triggers if and only if the event is a
+ * KeyPress event *and* was not generated by XSendEvent().
+ */
+ if ( event->type == KeyPress
+ && !event->xany.send_event)
+ {
+ xautolock_resetTriggers ();
+ }
+}
+
+void xautolock_processQueue()
+{
+ /*
+ * Check the window queue for entries that are older than
+ * CREATION_DELAY seconds.
+ */
+ processQueue ((time_t) CREATION_DELAY);
+}
+#endif
+
+
+/*
+ * Function for initialising the whole shebang.
+ */
+void
+xautolock_initDiy (Display* d)
+{
+ int s;
+
+ queue.display = d;
+ queue.tail = 0;
+ queue.head = 0;
+
+ for (s = -1; ++s < ScreenCount (d); )
+ {
+ Window root = RootWindowOfScreen (ScreenOfDisplay (d, s));
+ addToQueue (root);
+#if 0
+ selectEvents (root, True);
+#endif
+ }
+}
diff --git a/kdesktop/xautolock_engine.c b/kdesktop/xautolock_engine.c
new file mode 100644
index 000000000..1825b7fe2
--- /dev/null
+++ b/kdesktop/xautolock_engine.c
@@ -0,0 +1,419 @@
+/*****************************************************************************
+ *
+ * Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
+ *
+ * Content: This file is part of version 2.x of xautolock. It implements
+ * the program's core functions.
+ *
+ * Please send bug reports etc. to eyckmans@imec.be.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
+ *
+ * Versions 2.0 and above of xautolock are available under version 2 of the
+ * GNU GPL. Earlier versions are available under other conditions. For more
+ * information, see the License file.
+ *
+ *****************************************************************************/
+
+#include <X11/Xlib.h>
+#include <time.h>
+
+#include "xautolock_c.h"
+
+/*
+ * Function for querying the idle time from the server.
+ * Only used if either the Xidle or the Xscreensaver
+ * extension is present.
+ */
+void
+xautolock_queryIdleTime (Display* d)
+{
+ Time idleTime = 0; /* millisecs since last input event */
+
+#ifdef HasXidle
+ if (xautolock_useXidle)
+ {
+ XGetIdleTime (d, &idleTime);
+ }
+ else
+#endif /* HasXIdle */
+ {
+#ifdef HasScreenSaver
+ if( xautolock_useMit )
+ {
+ static XScreenSaverInfo* mitInfo = 0;
+ if (!mitInfo) mitInfo = XScreenSaverAllocInfo ();
+ XScreenSaverQueryInfo (d, DefaultRootWindow (d), mitInfo);
+ idleTime = mitInfo->idle;
+ }
+ else
+#endif /* HasScreenSaver */
+ {
+ d = d; /* shut up */
+ return; /* DIY */
+ }
+ }
+
+ if (idleTime < CHECK_INTERVAL )
+ {
+ xautolock_resetTriggers ();
+ }
+}
+
+/*
+ * Function for monitoring pointer movements. This implements the
+ * `corners' feature and as a side effect also tracks pointer
+ * related user activity. The latter actually is only needed when
+ * we're using the DIY mode of operations, but it's much simpler
+ * to do it unconditionally.
+ */
+void
+xautolock_queryPointer (Display* d)
+{
+ Window dummyWin; /* as it says */
+ int dummyInt; /* as it says */
+ unsigned mask; /* modifier mask */
+ int rootX; /* as it says */
+ int rootY; /* as it says */
+ int corner; /* corner index */
+ time_t now; /* as it says */
+ time_t newTrigger; /* temporary storage */
+ int i; /* loop counter */
+ static Window root; /* root window the pointer is on */
+ static Screen* screen; /* screen the pointer is on */
+ static unsigned prevMask = 0; /* as it says */
+ static int prevRootX = -1; /* as it says */
+ static int prevRootY = -1; /* as it says */
+ static Bool firstCall = True; /* as it says */
+
+ /*
+ * Have a guess...
+ */
+ if (firstCall)
+ {
+ firstCall = False;
+ root = DefaultRootWindow (d);
+ screen = ScreenOfDisplay (d, DefaultScreen (d));
+ }
+
+ /*
+ * Find out whether the pointer has moved. Using XQueryPointer for this
+ * is gross, but it also is the only way never to mess up propagation
+ * of pointer events.
+ */
+ if (!XQueryPointer (d, root, &root, &dummyWin, &rootX, &rootY,
+ &dummyInt, &dummyInt, &mask))
+ {
+ /*
+ * Pointer has moved to another screen, so let's find out which one.
+ */
+ for (i = -1; ++i < ScreenCount (d); )
+ {
+ if (root == RootWindow (d, i))
+ {
+ screen = ScreenOfDisplay (d, i);
+ break;
+ }
+ }
+ }
+
+ if ( rootX == prevRootX
+ && rootY == prevRootY
+ && mask == prevMask)
+ {
+ xautolock_corner_t* corners = xautolock_corners;
+ /*
+ * If the pointer has not moved since the previous call and
+ * is inside one of the 4 corners, we act according to the
+ * contents of the "corners" array.
+ *
+ * If rootX and rootY are less than zero, don't lock even if
+ * ca_forceLock is set in the upper-left corner. Why? 'cause
+ * on initial server startup, if (and only if) the pointer is
+ * never moved, XQueryPointer() can return values less than
+ * zero (only some servers, Openwindows 2.0 and 3.0 in
+ * particular).
+ */
+ if ( (corner = 0,
+ rootX <= cornerSize && rootX >= 0
+ && rootY <= cornerSize && rootY >= 0)
+ || (corner++,
+ rootX >= WidthOfScreen (screen) - cornerSize - 1
+ && rootY <= cornerSize)
+ || (corner++,
+ rootX <= cornerSize
+ && rootY >= HeightOfScreen (screen) - cornerSize - 1)
+ || (corner++,
+ rootX >= WidthOfScreen (screen) - cornerSize - 1
+ && rootY >= HeightOfScreen (screen) - cornerSize - 1))
+ {
+ now = time (0);
+
+ switch (corners[corner])
+ {
+ case ca_forceLock:
+#if 0
+ newTrigger = now + (useRedelay ? cornerRedelay : cornerDelay) - 1;
+#else
+ newTrigger = now;
+#endif
+
+#if 0
+ if (newTrigger < lockTrigger)
+ {
+ setLockTrigger (newTrigger - now);
+ }
+#else
+ xautolock_setTrigger( newTrigger );
+#endif
+ break;
+
+ case ca_dontLock:
+ xautolock_resetTriggers ();
+
+#ifdef __GNUC__
+ default: ; /* Makes gcc -Wall shut up. */
+#endif /* __GNUC__ */
+ }
+ }
+ }
+ else
+ {
+#if 0
+ useRedelay = False;
+#endif
+ prevRootX = rootX;
+ prevRootY = rootY;
+ prevMask = mask;
+
+ xautolock_resetTriggers ();
+ }
+}
+
+#if 0
+/*
+ * Support for deciding whether to lock or kill.
+ */
+void
+evaluateTriggers (Display* d)
+{
+ static time_t prevNotification = 0;
+ time_t now = 0;
+
+ /*
+ * Obvious things first.
+ *
+ * The triggers are being moved all the time while in disabled
+ * mode in order to make absolutely sure we cannot run into
+ * trouble by an enable message coming in at an odd moment.
+ * Otherwise we possibly might lock or kill too soon.
+ */
+ if (disabled)
+ {
+ resetTriggers ();
+ }
+
+ /*
+ * Next, wait for (or kill, if we were so told) the previous
+ * locker (if any). Note that this must also be done while in
+ * disabled mode. Not only to avoid a potential zombie proces
+ * hanging around until we are re-enabled, but also to prevent
+ * us from incorrectly setting a kill trigger at the moment
+ * when we are finally re-enabled.
+ */
+#ifdef VMS
+ if (vmsStatus == 0)
+ {
+#else /* VMS */
+ if (lockerPid)
+ {
+#if !defined (UTEKV) && !defined (SYSV) && !defined (SVR4)
+ union wait status; /* childs process status */
+#else /* !UTEKV && !SYSV && !SVR4 */
+ int status = 0; /* childs process status */
+#endif /* !UTEKV && !SYSV && !SVR4 */
+
+ if (unlockNow && !disabled)
+ {
+ (void) kill (lockerPid, SIGTERM);
+ }
+
+#if !defined (UTEKV) && !defined (SYSV) && !defined (SVR4)
+ if (wait3 (&status, WNOHANG, 0))
+#else /* !UTEKV && !SYSV && !SVR4 */
+ if (waitpid (-1, &status, WNOHANG))
+#endif /* !UTEKV && !SYSV && !SVR4 */
+ {
+ /*
+ * If the locker exited normally, we disable any pending kill
+ * trigger. Otherwise, we assume that it either has crashed or
+ * was not able to lock the display because of an existing
+ * locker (which may have been started manually). In both of
+ * the later cases, disabling the kill trigger would open a
+ * loop hole.
+ */
+ if ( WIFEXITED (status)
+ && WEXITSTATUS (status) == EXIT_SUCCESS)
+ {
+ disableKillTrigger ();
+ }
+
+ useRedelay = True;
+ lockerPid = 0;
+ }
+#endif /* VMS */
+
+ setLockTrigger (lockTime);
+
+ /*
+ * No return here! The pointer may be sitting in a corner, while
+ * parameter settings may be such that we need to start another
+ * locker without further delay. If you think this cannot happen,
+ * consider the case in which the locker simply crashed.
+ */
+ }
+
+ unlockNow = False;
+
+ /*
+ * Note that the above lot needs to be done even when we're in
+ * disabled mode, since we may have entered said mode with an
+ * active locker around.
+ */
+ if (disabled) return;
+
+ /*
+ * Is it time to run the killer command?
+ */
+ now = time (0);
+
+ if (killTrigger && now >= killTrigger)
+ {
+ /*
+ * There is a dirty trick here. On the one hand, we don't want
+ * to block until the killer returns, but on the other one
+ * we don't want to have it interfere with the wait() stuff we
+ * do to keep track of the locker. To obtain both, the killer
+ * command has already been patched by KillerChecker() so that
+ * it gets backgrounded by the shell started by system().
+ *
+ * For the time being, VMS users are out of luck: their xautolock
+ * will indeed block until the killer returns.
+ */
+ (void) system (killer);
+ setKillTrigger (killTime);
+ }
+
+ /*
+ * Now trigger the notifier if required.
+ */
+ if ( notifyLock
+ && now + notifyMargin >= lockTrigger
+ && prevNotification < now - notifyMargin - 1)
+ {
+ if (notifierSpecified)
+ {
+ /*
+ * Here we use the same dirty trick as for the killer command.
+ */
+ (void) system (notifier);
+ }
+ else
+ {
+ (void) XBell (d, bellPercent);
+ (void) XSync (d, 0);
+ }
+
+ prevNotification = now;
+ }
+
+ /*
+ * Finally fire up the locker if time has somehow come.
+ */
+ if ( lockNow
+ || now >= lockTrigger)
+ {
+#ifdef VMS
+ if (vmsStatus != 0)
+#else /* VMS */
+ if (!lockerPid)
+#endif /* VMS */
+ {
+ switch (lockerPid = vfork ())
+ {
+ case -1:
+ lockerPid = 0;
+ break;
+
+ case 0:
+ (void) close (ConnectionNumber (d));
+#ifdef VMS
+ vmsStatus = 0;
+ lockerPid = lib$spawn ((lockNow ? &nowLockerDescr : &lockerDescr),
+ 0, 0, &1, 0, 0, &vmsStatus);
+
+ if (!(lockerPid & 1)) exit (lockerPid);
+
+#ifdef SLOW_VMS
+ (void) sleep (SLOW_VMS_DELAY);
+#endif /* SLOW_VMS */
+#else /* VMS */
+ (void) execl ("/bin/sh", "/bin/sh", "-c",
+ (lockNow ? nowLocker : locker), 0);
+#endif /* VMS */
+ _exit (EXIT_FAILURE);
+
+ default:
+ /*
+ * In general xautolock should keep its fingers off the real
+ * screensaver because no universally acceptable policy can
+ * be defined. In no case should it decide to disable or enable
+ * it all by itself. Setting the screensaver policy is something
+ * the locker should take care of. After all, xautolock is not
+ * supposed to know what the "locker" does and doesn't do.
+ * People might be using xautolock for totally different
+ * purposes (which, by the way, is why it will accept a
+ * different set of X resources after being renamed).
+ *
+ * Nevertheless, simply resetting the screensaver is a
+ * convenience action that aids many xlock users, and doesn't
+ * harm anyone (*). The problem with older versions of xlock
+ * is that they can be told to replace (= disable) the real
+ * screensaver, but forget to reset that same screensaver if
+ * it was already active at the time xlock starts. I guess
+ * xlock initially wasn't designed to be run without a user
+ * actually typing the comand ;-).
+ *
+ * (*) Well, at least it used not to harm anyone, but with the
+ * advent of DPMS monitors, it now can mess up the power
+ * saving setup. Hence we better make it optional.
+ *
+ * Also, some xlock versions also unconditionally call
+ * XResetScreenSaver, yielding the same kind of problems
+ * with DPMS that xautolock did. The latest and greatest
+ * xlocks also have a -resetsaver option for this very
+ * reason. You may want to upgrade.
+ */
+ if (resetSaver) (void) XResetScreenSaver(d);
+
+ setLockTrigger (lockTime);
+ (void) XSync (d,0);
+ }
+
+ /*
+ * Once the locker is running, all that needs to be done is to
+ * set the killTrigger if needed. Notice that this must be done
+ * even if we actually failed to start the locker. Otherwise
+ * the error would "propagate" from one feature to another.
+ */
+ if (killerSpecified) setKillTrigger (killTime);
+
+ useRedelay = False;
+ }
+
+ lockNow = False;
+ }
+}
+#endif