summaryrefslogtreecommitdiffstats
path: root/ksmserver
diff options
context:
space:
mode:
Diffstat (limited to 'ksmserver')
-rw-r--r--ksmserver/CMakeLists.txt54
-rw-r--r--ksmserver/ConfigureChecks.cmake12
-rw-r--r--ksmserver/KSMServerInterface.h29
-rw-r--r--ksmserver/LICENSE16
-rw-r--r--ksmserver/Makefile.am50
-rw-r--r--ksmserver/README177
-rw-r--r--ksmserver/client.cpp190
-rw-r--r--ksmserver/client.h63
-rw-r--r--ksmserver/configure.in.in4
-rw-r--r--ksmserver/global.h17
-rw-r--r--ksmserver/ksmserver.upd6
-rw-r--r--ksmserver/legacy.cpp400
-rw-r--r--ksmserver/main.cpp249
-rwxr-xr-xksmserver/move_session_config.sh32
-rw-r--r--ksmserver/server.cpp992
-rw-r--r--ksmserver/server.h264
-rw-r--r--ksmserver/server2.h16
-rw-r--r--ksmserver/shutdown.cpp1062
-rw-r--r--ksmserver/shutdown.pngbin0 -> 16266 bytes
-rw-r--r--ksmserver/shutdowndlg.cpp1525
-rw-r--r--ksmserver/shutdowndlg.h270
-rw-r--r--ksmserver/shutdownkonq.pngbin0 -> 62692 bytes
-rw-r--r--ksmserver/startup.cpp489
-rw-r--r--ksmserver/startupdlg.cpp86
-rw-r--r--ksmserver/startupdlg.h49
-rw-r--r--ksmserver/test.cpp32
-rw-r--r--ksmserver/timed.ui352
27 files changed, 6436 insertions, 0 deletions
diff --git a/ksmserver/CMakeLists.txt b/ksmserver/CMakeLists.txt
new file mode 100644
index 000000000..8578b01c1
--- /dev/null
+++ b/ksmserver/CMakeLists.txt
@@ -0,0 +1,54 @@
+#################################################
+#
+# (C) 2010-2011 Serghei Amelian
+# serghei (DOT) amelian (AT) gmail.com
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+include( ConfigureChecks.cmake )
+
+if( NOT DBUS_SYSTEM_BUS )
+ set( DBUS_SYSTEM_BUS "unix:path=/var/run/dbus/system_bus_socket" CACHE INTERNAL "" FORCE )
+endif()
+
+if( WITH_UPOWER )
+ add_definitions( -DWITH_UPOWER )
+endif( )
+
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/tdmlib
+ ${TDE_INCLUDE_DIR}
+ ${TQT_INCLUDE_DIRS}
+ ${DBUS_TQT_INCLUDE_DIRS}
+ ${HAL_INCLUDE_DIRS}
+)
+
+link_directories(
+ ${TQT_LIBRARY_DIRS}
+ ${DBUS_TQT_LIBRARY_DIRS}
+)
+
+
+##### other data ################################
+
+install( FILES shutdown.png DESTINATION ${DATA_INSTALL_DIR}/ksmserver/pics )
+install( FILES shutdownkonq.png DESTINATION ${DATA_INSTALL_DIR}/ksmserver/pics )
+install( FILES ksmserver.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR} )
+install( FILES move_session_config.sh DESTINATION ${KCONF_UPDATE_INSTALL_DIR} )
+
+
+##### ksmserver (tdeinit) #######################
+
+tde_add_tdeinit_executable( ksmserver AUTOMOC
+ SOURCES
+ main.cpp server.cpp shutdowndlg.cpp startupdlg.cpp
+ legacy.cpp startup.cpp shutdown.cpp client.cpp
+ KSMServerInterface.skel server.skel timed.ui
+ LINK dmctl-static tdeui-shared tdersync-shared ${HAL_LIBRARIES} ${DBUS_TQT_LIBRARIES}
+)
diff --git a/ksmserver/ConfigureChecks.cmake b/ksmserver/ConfigureChecks.cmake
new file mode 100644
index 000000000..4f8cf7978
--- /dev/null
+++ b/ksmserver/ConfigureChecks.cmake
@@ -0,0 +1,12 @@
+#################################################
+#
+# (C) 2014 Timothy Pearson
+# kb9vqf (AT) pearsoncomputing (DOT) net
+#
+# Improvements and feedback are welcome
+#
+# This file is released under GPL >= 2
+#
+#################################################
+
+check_library_exists( ICE _IceTransNoListen "" HAVE__ICETRANSNOLISTEN ) \ No newline at end of file
diff --git a/ksmserver/KSMServerInterface.h b/ksmserver/KSMServerInterface.h
new file mode 100644
index 000000000..a628b92ba
--- /dev/null
+++ b/ksmserver/KSMServerInterface.h
@@ -0,0 +1,29 @@
+#ifndef KSMSERVER_INTERFACE_H
+#define KSMSERVER_INTERFACE_H
+
+#include <dcopobject.h>
+#include <tqstringlist.h>
+
+class KSMServerInterface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+ virtual void logout(int, int, int ) = 0;
+ virtual void restoreSessionInternal() = 0;
+ virtual void restoreSessionDoneInternal() = 0;
+ virtual TQStringList sessionList() = 0;
+
+ virtual TQString currentSession() = 0;
+ virtual void saveCurrentSession() = 0;
+ virtual void saveCurrentSessionAs( TQString ) = 0;
+
+ virtual void autoStart2() = 0;
+
+ virtual void suspendStartup( TQCString ) = 0;
+ virtual void resumeStartup( TQCString ) = 0;
+
+ virtual void logoutTimed( int, int, TQString ) = 0;
+};
+
+#endif
diff --git a/ksmserver/LICENSE b/ksmserver/LICENSE
new file mode 100644
index 000000000..d28a48f92
--- /dev/null
+++ b/ksmserver/LICENSE
@@ -0,0 +1,16 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/ksmserver/Makefile.am b/ksmserver/Makefile.am
new file mode 100644
index 000000000..e18adec94
--- /dev/null
+++ b/ksmserver/Makefile.am
@@ -0,0 +1,50 @@
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+SUBDIRS = .
+
+INCLUDES= -I$(top_srcdir)/tdmlib $(all_includes) $(HAL_INCS) $(DBUS_INCS)
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+tdeinit_LTLIBRARIES = ksmserver.la
+noinst_HEADERS = global.h server.h
+
+ksmserver_la_METASOURCES = AUTO
+# Order is important for --enable-final!
+ksmserver_la_SOURCES = main.cpp server.cpp shutdowndlg.cpp \
+ legacy.cpp startup.cpp shutdown.cpp client.cpp \
+ KSMServerInterface.skel server.skel timed.ui
+
+ksmserver_la_LDFLAGS = $(all_libraries) -avoid-version -module
+ksmserver_la_LIBADD = ../tdmlib/libdmctl.la $(LIB_TDEUI) $(HAL_LIBS) $(DBUS_LIBS)
+
+picsdir = $(kde_datadir)/ksmserver/pics
+pics_DATA = shutdownkonq.png
+
+update_DATA = ksmserver.upd
+update_SCRIPTS = move_session_config.sh
+updatedir = $(kde_datadir)/tdeconf_update
+
+
+EXTRA_PROGRAMS = testsh
+testsh_SOURCES = test.cpp timed.ui
+testsh_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+testsh_LDADD = $(LIB_TDEUI) shutdowndlg.lo ../tdmlib/libdmctl.la $(HAL_LIBS) $(DBUS_LIBS)
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/ksmserver.pot
diff --git a/ksmserver/README b/ksmserver/README
new file mode 100644
index 000000000..b2c26273b
--- /dev/null
+++ b/ksmserver/README
@@ -0,0 +1,177 @@
+TDE session manager (ksmserver)
+--------------------------------
+
+Matthias Ettrich <[email protected]>
+Lubos Lunak <[email protected]>
+
+ksmserver is TDE's new session management server. It talks the
+standard X11R6 session management protocol (XSMP). Thus, in theory,
+it should be compatible with all session managment compliant X11R6
+applications. Unfortunately, there aren't that many of them. To be
+precise, I have never seen a single commercial application that
+supports it and even within the official X11R6 distribution, 'xclock'
+is the only exception. Nevertheless we've chosen to support XSMP
+despites the complexity of the protocol in order to provide TDE users
+more interoperability with applications that were not explicitely
+written with TDE in mind. XSMP, as an official X standard, promised to
+be more likely to be supported by third parties than even a superior
+TDE-specific protocol. Let's see whether we were right and more
+applications will actually talk XSMP. At least all TDE applications do
+now.
+
+Here's a short overview on how session management works.
+
+Starting the server
+-------------------
+
+The server is usually started from the 'starttde' script. It supports the following options:
+
+ -r, --restore Restores the previous session if available
+ -w, --windowmanager <wm> Starts 'wm' in case no other window manager is
+ participating in the session. Default is 'twin'
+
+The default 'starttde' launches 'ksmserver --restore'. The
+'windowmanager' option is useful for users that prefer a window
+manager other than twin. Since the window manager has to participate
+in the session (it has to remember window positions and states), it is
+usually restarted when the session is restored. To be *really* sure
+that this happens, even if the wm might have crashed during the
+previous session, ksmserver ensures that. The option specifies, which
+windowmanager shall be launched for sure. But again: if the stored
+session contains a window manager, the restored one will be used, not
+the specified one. As a special feature, ksmserver always starts the
+specified window manager first, which results in a much nicer startup
+sequence (less flashy).
+
+TDE startup sequence
+--------------------
+
+Ksmserver controls the second part of the TDE startup sequence,
+after it gets control from the starttde script, which controls
+the first part of the startup sequence. All code related to startup
+should be in startup.cpp and going down in that source file should
+follow the startup order (but note that this is just a documentation
+which may get outdated, so in case of doubts the source wins ;) ).
+
+The starttde scripts already launches tdeinit, which in turns launches
+TDE daemons like dcopserver, tdelauncher and kded. Kded loads autoloaded
+kded modules, i.e. those that have X-TDE-Kded-autoload=true in .desktop
+files. The exact way autoloading works is controlled by X-TDE-Kded-phase=,
+which may be 0, 1 or 2 (the default). Kded phase 0 means the module is
+always loaded by kded, even outside of TDE session. It should used only
+by kded modules which must be always running. Kded phase 1 modules are
+loaded right after kded startup, but only during TDE startup, i.e. it is
+for modules that are always needed by the TDE session. Phase 2 modules
+will be loaded later.
+
+Startkde also launches kcminit, which performs initialization done by kcontrol
+modules. There are three kcminit phases, 0, 1 and 2, controlled
+by X-TDE-Init-Phase= in the .desktop file, which defaults to 1. Phase 0 kcminit
+modules should be only those that really need to be run early in the startup
+process (and those should probably actually use tdestartupconfig in starttde
+to be done even before tdeinit and daemons). After executing phase 0
+modules kcminit returns and waits.
+
+When ksmserver is launched, the first thing it does is launching
+the window manager, as the WM is necessary before any windows are possibly
+shown. When the WM is ready, ksmserver tells tdelauncher to perform autostart
+phase 0 ($TDEHOME/share/autostart). There are 3 autostart phases, 0, 1 and 2,
+defined by X-TDE-autostart-phase, defaulting to 2. Phase 0 is reserved only
+for the actual visible base components of TDE, i.e. KDesktop and Kicker,
+in order to make the startup appear visually faster. Both KDesktop and Kicker
+use DCOP calls suspendStartup() and resumeStartup() to make ksmserver stay
+waiting for autostart phase 0 until both KDesktop and Kicker are ready.
+
+Next step is telling the waiting kcminit to perform phase 1 - all kcminit
+modules that should be executed before TDE startup is considered done.
+After that ksmserver tells tdelauncher to perform autostart phase 1,
+i.e. launching normal components of TDE that should be available right
+after TDE startup, and after this session restore is performed,
+i.e. launching all applications that were running during last session
+saving (usually logout).
+
+By this time TDE session is considered to be more or less ready and
+ksmserver does the knotify starttde event (i.e. plays the login sound).
+It also tells tdelauncher to perform autostart phase 2, kded to load all
+remaining autoload (i.e. kded phase 2) modules, kcminit to execute
+kcminit phase 2 (kcontrol modules that do initialization that can wait,
+like launching daemons) and kdesktop to execute the user Autostart folder.
+
+Technical note: There's a reason why kded modules and items in autostart
+default to the latest phase. Before you explicitly use a different phase,
+read and understand what's above. You should also consider whether something
+really needs to be launched during TDE startup and can't be loaded on-demand
+when really needed. Abusing the phases will result in public spanking
+for making TDE startup slower.
+
+
+Establishing the connection
+---------------------------
+
+As required by the XSMP specification, the session management server
+propagates its network address in the SESSION_MANAGER environment
+variable. Probably not the best way to do it, but it's the way it
+is. All TDE (and plain Qt) applications simply read this variable and
+try to establish a connection to an XSMP server at this address. If
+the variable is undefined, nothing happens.
+
+This means, if you want to start a program that should not participate
+in the session, simply undefine SESSION_MANAGER in your terminal
+window and launch the application. If you want to see an application
+desparately trying to connect to something, try setting it to some
+bogus value.
+
+In addition, ksmserver propagates both its network address and its
+process id in ~/.trinity/socket-$HOSTNAME/KSMserver-$DISPLAY. A
+utility function TDEApplication::propagateSessionManager() reads this
+setting and sets SESSION_MANAGER accordingly, so that child processes
+can pick it up. The function is called by clients that are started
+outside the session ( i.e. before ksmserver is started), but want to
+launch other processes that should participate in the session.
+Examples are kdesktop or kicker, see below.
+
+Authorization
+-------------
+
+XSMP is, just like DCOP, built on top of the Inter Client Exchange
+(ICE) protocol, which comes standard as a part of X11R6 and later.
+Authorization is done using 'iceauth', with MIT-MAGIC-COOKIE as used
+by X. In order to be able to access the session management server, you
+need to be able to read ~/.ICEauthority. For security reasons, we do
+not provide any host-based authorization (neither does DCOP, btw.).
+
+
+Requesting a shutdown
+---------------------
+
+If an application wants to request a shutdown (i.e. a logout), it does
+this via an SmcRequestSaveYourself message to the server. In TDE, a
+utility function TDEApplication::requestShutDown() does exactly
+this. It's for example called by TDE's panel or by the context menu of
+the desktop.
+
+
+User Interface
+--------------
+
+ksmserver has a very straight-forward user interface. It mainly asks
+the question "Shutdown TDE Session?" and provides two obvious command
+buttons "Yes" and "Cancel". The interesting bit is the additonal
+checkbox that says "Restore session when logging in next time". The
+checkbox remembers state within session, so simply use whatever you
+prefer. For those who remember, this was one of the main questions
+with TDE-1.x ("How to get rid of session managment?"). With TDE-2.x,
+most users will probably prepare a session once, store it with the
+checkbox enabled and keep the checkbox disabled in the future. This
+way you get a proper and clean 'homesession' each time.
+
+
+Troubleshooting
+---------------
+
+If you experience trouble like 'logout does not work anymore' or 'I
+cannot start new applications', as a result of a previous crash,
+ensure that ksmserver is indeed not running anymore and remove the
+file ~/.trinity/socket-$HOSTNAME/KSMserver-$DISPLAY. Shouldn't be necessry,
+but one never knows.
+
diff --git a/ksmserver/client.cpp b/ksmserver/client.cpp
new file mode 100644
index 000000000..c47877543
--- /dev/null
+++ b/ksmserver/client.cpp
@@ -0,0 +1,190 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+Copyright (C) 2005 Lubos Lunak <[email protected]>
+
+relatively small extensions by Oswald Buddenhagen <[email protected]>
+
+some code taken from the dcopserver (part of the KDE libraries), which is
+Copyright (c) 1999 Matthias Ettrich <[email protected]>
+Copyright (c) 1999 Preston Brown <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "client.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+#include <kstaticdeleter.h>
+
+#include "server.h"
+
+KSMClient::KSMClient( SmsConn conn)
+{
+ smsConn = conn;
+ id = 0;
+ resetState();
+}
+
+KSMClient::~KSMClient()
+{
+ for ( SmProp* prop = properties.first(); prop; prop = properties.next() )
+ SmFreeProperty( prop );
+ if (id) free((void*)id);
+}
+
+SmProp* KSMClient::property( const char* name ) const
+{
+ for ( TQPtrListIterator<SmProp> it( properties ); it.current(); ++it ) {
+ if ( !qstrcmp( it.current()->name, name ) )
+ return it.current();
+ }
+ return 0;
+}
+
+void KSMClient::resetState()
+{
+ saveYourselfDone = false;
+ pendingInteraction = false;
+ waitForPhase2 = false;
+ wasPhase2 = false;
+}
+
+/*
+ * This fakes SmsGenerateClientID() in case we can't read our own hostname.
+ * In this case SmsGenerateClientID() returns NULL, but we really want a
+ * client ID, so we fake one.
+ */
+static KStaticDeleter<TQString> smy_addr;
+static char * safeSmsGenerateClientID( SmsConn /*c*/ )
+{
+// Causes delays with misconfigured network :-/.
+// char *ret = SmsGenerateClientID(c);
+ char* ret = NULL;
+ if (!ret) {
+ static TQString *my_addr = 0;
+ if (!my_addr) {
+// tqWarning("Can't get own host name. Your system is severely misconfigured\n");
+ smy_addr.setObject(my_addr,new TQString);
+
+ /* Faking our IP address, the 0 below is "unknown" address format
+ (1 would be IP, 2 would be DEC-NET format) */
+ char hostname[ 256 ];
+ if( gethostname( hostname, 255 ) != 0 )
+ my_addr->sprintf("0%.8x", TDEApplication::random());
+ else {
+ // create some kind of hash for the hostname
+ int addr[ 4 ] = { 0, 0, 0, 0 };
+ int pos = 0;
+ for( unsigned int i = 0;
+ i < strlen( hostname );
+ ++i, ++pos )
+ addr[ pos % 4 ] += hostname[ i ];
+ *my_addr = "0";
+ for( int i = 0;
+ i < 4;
+ ++i )
+ *my_addr += TQString::number( addr[ i ], 16 );
+ }
+ }
+ /* Needs to be malloc(), to look the same as libSM */
+ ret = (char *)malloc(1+my_addr->length()+13+10+4+1 + /*safeness*/ 10);
+ static int sequence = 0;
+
+ if (ret == NULL)
+ return NULL;
+
+ sprintf(ret, "1%s%.13ld%.10d%.4d", my_addr->latin1(), (long)time(NULL),
+ getpid(), sequence);
+ sequence = (sequence + 1) % 10000;
+ }
+ return ret;
+}
+
+void KSMClient::registerClient( const char* previousId )
+{
+ id = previousId;
+ if ( !id )
+ id = safeSmsGenerateClientID( smsConn );
+ SmsRegisterClientReply( smsConn, (char*) id );
+ SmsSaveYourself( smsConn, SmSaveLocal, false, SmInteractStyleNone, false );
+ SmsSaveComplete( smsConn );
+ KSMServer::self()->clientRegistered( previousId );
+}
+
+
+TQString KSMClient::program() const
+{
+ SmProp* p = property( SmProgram );
+ if ( !p || qstrcmp( p->type, SmARRAY8) || p->num_vals < 1)
+ return TQString::null;
+ return TQString::fromLatin1( (const char*) p->vals[0].value );
+}
+
+TQStringList KSMClient::restartCommand() const
+{
+ TQStringList result;
+ SmProp* p = property( SmRestartCommand );
+ if ( !p || qstrcmp( p->type, SmLISTofARRAY8) || p->num_vals < 1)
+ return result;
+ for ( int i = 0; i < p->num_vals; i++ )
+ result +=TQString::fromLatin1( (const char*) p->vals[i].value );
+ return result;
+}
+
+TQStringList KSMClient::discardCommand() const
+{
+ TQStringList result;
+ SmProp* p = property( SmDiscardCommand );
+ if ( !p || qstrcmp( p->type, SmLISTofARRAY8) || p->num_vals < 1)
+ return result;
+ for ( int i = 0; i < p->num_vals; i++ )
+ result +=TQString::fromLatin1( (const char*) p->vals[i].value );
+ return result;
+}
+
+int KSMClient::restartStyleHint() const
+{
+ SmProp* p = property( SmRestartStyleHint );
+ if ( !p || qstrcmp( p->type, SmCARD8) || p->num_vals < 1)
+ return SmRestartIfRunning;
+ return *((int*)p->vals[0].value);
+}
+
+TQString KSMClient::userId() const
+{
+ SmProp* p = property( SmUserID );
+ if ( !p || qstrcmp( p->type, SmARRAY8) || p->num_vals < 1)
+ return TQString::null;
+ return TQString::fromLatin1( (const char*) p->vals[0].value );
+}
+
+
diff --git a/ksmserver/client.h b/ksmserver/client.h
new file mode 100644
index 000000000..e478cfc31
--- /dev/null
+++ b/ksmserver/client.h
@@ -0,0 +1,63 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+// needed to avoid clash with INT8 defined in X11/Xmd.h on solaris
+#define QT_CLEAN_NAMESPACE 1
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqsocketnotifier.h>
+#include <tqptrlist.h>
+#include <tqvaluelist.h>
+#include <tqcstring.h>
+#include <tqdict.h>
+#include <tqptrqueue.h>
+#include <tqptrdict.h>
+#include <tdeapplication.h>
+#include <tqtimer.h>
+#include <tqdatetime.h>
+#include <dcopobject.h>
+
+#include "server2.h"
+
+class KSMListener;
+class KSMConnection;
+class KSMClient
+{
+public:
+ KSMClient( SmsConn );
+ ~KSMClient();
+
+ void registerClient( const char* previousId = 0 );
+ SmsConn connection() const { return smsConn; }
+
+ void resetState();
+ uint saveYourselfDone : 1;
+ uint pendingInteraction : 1;
+ uint waitForPhase2 : 1;
+ uint wasPhase2 : 1;
+
+ TQPtrList<SmProp> properties;
+ SmProp* property( const char* name ) const;
+
+ TQString program() const;
+ TQStringList restartCommand() const;
+ TQStringList discardCommand() const;
+ int restartStyleHint() const;
+ TQString userId() const;
+ const char* clientId() { return id ? id : ""; }
+
+ TQDateTime terminationRequestTimeStamp;
+
+private:
+ const char* id;
+ SmsConn smsConn;
+};
+
+#endif
diff --git a/ksmserver/configure.in.in b/ksmserver/configure.in.in
new file mode 100644
index 000000000..aef963e2f
--- /dev/null
+++ b/ksmserver/configure.in.in
@@ -0,0 +1,4 @@
+ac_save_LIBS="$LIBS"
+LIBS="$LIBS $X_LDFLAGS -lICE"
+AC_CHECK_FUNCS(_IceTransNoListen)
+LIBS="$ac_save_LIBS"
diff --git a/ksmserver/global.h b/ksmserver/global.h
new file mode 100644
index 000000000..b76a8b363
--- /dev/null
+++ b/ksmserver/global.h
@@ -0,0 +1,17 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#define KSMVendorString "KDE"
+#define KSMReleaseString "1.0"
+
+#ifdef USE_QT4
+#define NO_QT3_DBUS_SUPPORT
+#endif
+
+#endif
diff --git a/ksmserver/ksmserver.upd b/ksmserver/ksmserver.upd
new file mode 100644
index 000000000..3416ed856
--- /dev/null
+++ b/ksmserver/ksmserver.upd
@@ -0,0 +1,6 @@
+# Move session config files from $TDEHOME/share/config to $TDEHOME/share/config/session
+Id=trinity
+File=ksmserverrc
+Group=Session
+Options=overwrite
+Script=move_session_config.sh,sh
diff --git a/ksmserver/legacy.cpp b/ksmserver/legacy.cpp
new file mode 100644
index 000000000..80f4e0984
--- /dev/null
+++ b/ksmserver/legacy.cpp
@@ -0,0 +1,400 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+Copyright (C) 2005 Lubos Lunak <[email protected]>
+
+relatively small extensions by Oswald Buddenhagen <[email protected]>
+
+some code taken from the dcopserver (part of the KDE libraries), which is
+Copyright (c) 1999 Matthias Ettrich <[email protected]>
+Copyright (c) 1999 Preston Brown <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include "server.h"
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <unistd.h>
+
+#include <tqtimer.h>
+
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <twinmodule.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+
+/*
+ * Legacy session management
+ */
+const int WM_SAVE_YOURSELF_TIMEOUT = 4000;
+
+static WindowMap* windowMapPtr = 0;
+
+static Atom wm_save_yourself = None;
+static Atom wm_protocols = None;
+static Atom wm_client_leader = None;
+
+static int winsErrorHandler(Display *, XErrorEvent *ev)
+{
+ if (windowMapPtr) {
+ WindowMap::Iterator it = windowMapPtr->find(ev->resourceid);
+ if (it != windowMapPtr->end())
+ (*it).type = SM_ERROR;
+ }
+ return 0;
+}
+
+void KSMServer::performLegacySessionSave()
+{
+ kdDebug( 1218 ) << "Saving legacy session apps" << endl;
+ // Setup error handler
+ legacyWindows.clear();
+ windowMapPtr = &legacyWindows;
+ XErrorHandler oldHandler = XSetErrorHandler(winsErrorHandler);
+ // Compute set of leader windows that need legacy session management
+ // and determine which style (WM_COMMAND or WM_SAVE_YOURSELF)
+ KWinModule module;
+ if( wm_save_yourself == (Atom)None ) {
+ Atom atoms[ 3 ];
+ const char* const names[]
+ = { "WM_SAVE_YOURSELF", "WM_PROTOCOLS", "WM_CLIENT_LEADER" };
+ XInternAtoms( tqt_xdisplay(), const_cast< char** >( names ), 3,
+ False, atoms );
+ wm_save_yourself = atoms[ 0 ];
+ wm_protocols = atoms[ 1 ];
+ wm_client_leader = atoms[ 2 ];
+ }
+ for ( TQValueList<WId>::ConstIterator it = module.windows().begin();
+ it != module.windows().end(); ++it) {
+ WId leader = windowWmClientLeader( *it );
+ if (!legacyWindows.contains(leader) && windowSessionId( *it, leader ).isEmpty()) {
+ SMType wtype = SM_WMCOMMAND;
+ int nprotocols = 0;
+ Atom *protocols = 0;
+ if( XGetWMProtocols(tqt_xdisplay(), leader, &protocols, &nprotocols)) {
+ for (int i=0; i<nprotocols; i++)
+ if (protocols[i] == wm_save_yourself) {
+ wtype = SM_WMSAVEYOURSELF;
+ break;
+ }
+ XFree((void*) protocols);
+ }
+ SMData data;
+ data.type = wtype;
+ XClassHint classHint;
+ if( XGetClassHint( tqt_xdisplay(), leader, &classHint ) ) {
+ data.wmclass1 = classHint.res_name;
+ data.wmclass2 = classHint.res_class;
+ XFree( classHint.res_name );
+ XFree( classHint.res_class );
+ }
+ legacyWindows.insert(leader, data);
+ }
+ }
+ // Open fresh display for sending WM_SAVE_YOURSELF
+ XSync(tqt_xdisplay(), False);
+ Display *newdisplay = XOpenDisplay(DisplayString(tqt_xdisplay()));
+ if (!newdisplay) {
+ windowMapPtr = NULL;
+ XSetErrorHandler(oldHandler);
+ return;
+ }
+ WId root = DefaultRootWindow(newdisplay);
+ XGrabKeyboard(newdisplay, root, False,
+ GrabModeAsync, GrabModeAsync, CurrentTime);
+ XGrabPointer(newdisplay, root, False, Button1Mask|Button2Mask|Button3Mask,
+ GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+ // Send WM_SAVE_YOURSELF messages
+ XEvent ev;
+ int awaiting_replies = 0;
+ for (WindowMap::Iterator it = legacyWindows.begin(); it != legacyWindows.end(); ++it) {
+ if ( (*it).type == SM_WMSAVEYOURSELF ) {
+ WId w = it.key();
+ awaiting_replies += 1;
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = w;
+ ev.xclient.message_type = wm_protocols;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = wm_save_yourself;
+ ev.xclient.data.l[1] = GET_QT_X_TIME();
+ XSelectInput(newdisplay, w, PropertyChangeMask|StructureNotifyMask);
+ XSendEvent(newdisplay, w, False, 0, &ev);
+ }
+ }
+ // Wait for change in WM_COMMAND with timeout
+ XFlush(newdisplay);
+ TQTime start = TQTime::currentTime();
+ while (awaiting_replies > 0) {
+ if (XPending(newdisplay)) {
+ /* Process pending event */
+ XNextEvent(newdisplay, &ev);
+ if ( ( ev.xany.type == UnmapNotify ) ||
+ ( ev.xany.type == PropertyNotify && ev.xproperty.atom == XA_WM_COMMAND ) ) {
+ WindowMap::Iterator it = legacyWindows.find( ev.xany.window );
+ if ( it != legacyWindows.end() && (*it).type != SM_WMCOMMAND ) {
+ awaiting_replies -= 1;
+ if ( (*it).type != SM_ERROR )
+ (*it).type = SM_WMCOMMAND;
+ }
+ }
+ } else {
+ /* Check timeout */
+ int msecs = start.elapsed();
+ if (msecs >= WM_SAVE_YOURSELF_TIMEOUT)
+ break;
+ /* Wait for more events */
+ fd_set fds;
+ FD_ZERO(&fds);
+ int fd = ConnectionNumber(newdisplay);
+ FD_SET(fd, &fds);
+ struct timeval tmwait;
+ tmwait.tv_sec = (WM_SAVE_YOURSELF_TIMEOUT - msecs) / 1000;
+ tmwait.tv_usec = ((WM_SAVE_YOURSELF_TIMEOUT - msecs) % 1000) * 1000;
+ ::select(fd+1, &fds, NULL, &fds, &tmwait);
+ }
+ }
+ // Terminate work in new display
+ XAllowEvents(newdisplay, ReplayPointer, CurrentTime);
+ XAllowEvents(newdisplay, ReplayKeyboard, CurrentTime);
+ XSync(newdisplay, False);
+ XCloseDisplay(newdisplay);
+ // Restore old error handler
+ XSync(tqt_xdisplay(), False);
+ XSetErrorHandler(oldHandler);
+ for (WindowMap::Iterator it = legacyWindows.begin(); it != legacyWindows.end(); ++it) {
+ if ( (*it).type != SM_ERROR) {
+ WId w = it.key();
+ (*it).wmCommand = windowWmCommand(w);
+ (*it).wmClientMachine = windowWmClientMachine(w);
+ }
+ }
+ kdDebug( 1218 ) << "Done saving " << legacyWindows.count() << " legacy session apps" << endl;
+}
+
+/*!
+ Stores legacy session management data
+*/
+void KSMServer::storeLegacySession( TDEConfig* config )
+{
+ // Write LegacySession data
+ config->deleteGroup( "Legacy" + sessionGroup );
+ TDEConfigGroupSaver saver( config, "Legacy" + sessionGroup );
+ int count = 0;
+ for (WindowMap::ConstIterator it = legacyWindows.begin(); it != legacyWindows.end(); ++it) {
+ if ( (*it).type != SM_ERROR) {
+ if( excludeApps.contains( (*it).wmclass1.lower())
+ || excludeApps.contains( (*it).wmclass2.lower()) || (*it).wmCommand[0] == "compiz" || (*it).wmCommand[0] == "beryl" || (*it).wmCommand[0] == "aquamarine" || (*it).wmCommand[0] == "beryl-manager" || (*it).wmCommand[0] == "beryl-settings" || (*it).wmCommand[0] == "kde-window-decorator" || (*it).wmCommand[0] == "emerald")
+ continue;
+ if ( !(*it).wmCommand.isEmpty() && !(*it).wmClientMachine.isEmpty() ) {
+ count++;
+ TQString n = TQString::number(count);
+ config->writeEntry( TQString("command")+n, (*it).wmCommand );
+ config->writeEntry( TQString("clientMachine")+n, (*it).wmClientMachine );
+ }
+ }
+ }
+ config->writeEntry( "count", count );
+}
+
+/*!
+ Restores legacy session management data (i.e. restart applications)
+*/
+void KSMServer::restoreLegacySession( TDEConfig* config )
+{
+ if( config->hasGroup( "Legacy" + sessionGroup )) {
+ TDEConfigGroupSaver saver( config, "Legacy" + sessionGroup );
+ restoreLegacySessionInternal( config );
+ } else if( wm == "twin" ) { // backwards comp. - get it from twinrc
+ TDEConfigGroupSaver saver( config, sessionGroup );
+ int count = config->readNumEntry( "count", 0 );
+ for ( int i = 1; i <= count; i++ ) {
+ TQString n = TQString::number(i);
+ if ( config->readEntry( TQString("program")+n ) != wm )
+ continue;
+ TQStringList restartCommand =
+ config->readListEntry( TQString("restartCommand")+n );
+ for( TQStringList::ConstIterator it = restartCommand.begin();
+ it != restartCommand.end();
+ ++it ) {
+ if( (*it) == "-session" ) {
+ ++it;
+ if( it != restartCommand.end()) {
+ TDEConfig cfg( "session/" + wm + "_" + (*it), true );
+ cfg.setGroup( "LegacySession" );
+ restoreLegacySessionInternal( &cfg, ' ' );
+ }
+ }
+ }
+ }
+ }
+}
+
+void KSMServer::restoreLegacySessionInternal( TDEConfig* config, char sep )
+{
+ int count = config->readNumEntry( "count" );
+ for ( int i = 1; i <= count; i++ ) {
+ TQString n = TQString::number(i);
+ TQStringList wmCommand = config->readListEntry( TQString("command")+n, sep );
+ if( wmCommand.isEmpty())
+ continue;
+ if( isWM( wmCommand.first()))
+ continue;
+ startApplication( wmCommand,
+ config->readEntry( TQString("clientMachine")+n ),
+ config->readEntry( TQString("userId")+n ));
+ }
+}
+
+static TQCString getQCStringProperty(WId w, Atom prop)
+{
+ Atom type;
+ int format, status;
+ unsigned long nitems = 0;
+ unsigned long extra = 0;
+ unsigned char *data = 0;
+ TQCString result = "";
+ status = XGetWindowProperty( tqt_xdisplay(), w, prop, 0, 10000,
+ FALSE, XA_STRING, &type, &format,
+ &nitems, &extra, &data );
+ if ( status == Success) {
+ if( data )
+ result = (char*)data;
+ XFree(data);
+ }
+ return result;
+}
+
+static TQStringList getQStringListProperty(WId w, Atom prop)
+{
+ Atom type;
+ int format, status;
+ unsigned long nitems = 0;
+ unsigned long extra = 0;
+ unsigned char *data = 0;
+ TQStringList result;
+
+ status = XGetWindowProperty( tqt_xdisplay(), w, prop, 0, 10000,
+ FALSE, XA_STRING, &type, &format,
+ &nitems, &extra, &data );
+ if ( status == Success) {
+ if (!data)
+ return result;
+ for (int i=0; i<(int)nitems; i++) {
+ result << TQString::fromLatin1( (const char*)data + i );
+ while(data[i]) i++;
+ }
+ XFree(data);
+ }
+ return result;
+}
+
+TQStringList KSMServer::windowWmCommand(WId w)
+{
+ TQStringList ret = getQStringListProperty(w, XA_WM_COMMAND);
+ // hacks here
+ if( ret.count() == 1 ) {
+ TQString command = ret.first();
+ // Mozilla is launched using wrapper scripts, so it's launched using "mozilla",
+ // but the actual binary is "mozilla-bin" or "<path>/mozilla-bin", and that's what
+ // will be also in WM_COMMAND - using this "mozilla-bin" doesn't work at all though
+ if( command.endsWith( "mozilla-bin" ))
+ return TQStringList() << "mozilla";
+ if( command.endsWith( "firefox-bin" ))
+ return TQStringList() << "firefox";
+ if( command.endsWith( "thunderbird-bin" ))
+ return TQStringList() << "thunderbird";
+ if( command.endsWith( "sunbird-bin" ))
+ return TQStringList() << "sunbird";
+ }
+ return ret;
+}
+
+TQString KSMServer::windowWmClientMachine(WId w)
+{
+ TQCString result = getQCStringProperty(w, XA_WM_CLIENT_MACHINE);
+ if (result.isEmpty()) {
+ result = "localhost";
+ } else {
+ // special name for the local machine (localhost)
+ char hostnamebuf[80];
+ if (gethostname (hostnamebuf, sizeof hostnamebuf) >= 0) {
+ hostnamebuf[sizeof(hostnamebuf)-1] = 0;
+ if (result == hostnamebuf)
+ result = "localhost";
+ if(char *dot = strchr(hostnamebuf, '.')) {
+ *dot = '\0';
+ if(result == hostnamebuf)
+ result = "localhost";
+ }
+ }
+ }
+ return TQString::fromLatin1(result);
+}
+
+WId KSMServer::windowWmClientLeader(WId w)
+{
+ Atom type;
+ int format, status;
+ unsigned long nitems = 0;
+ unsigned long extra = 0;
+ unsigned char *data = 0;
+ Window result = w;
+ status = XGetWindowProperty( tqt_xdisplay(), w, wm_client_leader, 0, 10000,
+ FALSE, XA_WINDOW, &type, &format,
+ &nitems, &extra, &data );
+ if (status == Success ) {
+ if (data && nitems > 0)
+ result = *((Window*) data);
+ XFree(data);
+ }
+ return result;
+}
+
+
+/*
+ Returns sessionId for this client,
+ taken either from its window or from the leader window.
+ */
+extern Atom tqt_sm_client_id;
+TQCString KSMServer::windowSessionId(WId w, WId leader)
+{
+ TQCString result = getQCStringProperty(w, tqt_sm_client_id);
+ if (result.isEmpty() && leader != (WId)None && leader != w)
+ result = getQCStringProperty(leader, tqt_sm_client_id);
+ return result;
+}
diff --git a/ksmserver/main.cpp b/ksmserver/main.cpp
new file mode 100644
index 000000000..1004c4394
--- /dev/null
+++ b/ksmserver/main.cpp
@@ -0,0 +1,249 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#include <config.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <dcopclient.h>
+#include <tqmessagebox.h>
+#include <tqdir.h>
+
+#include <tdeapplication.h>
+#include <tdecmdlineargs.h>
+#include <tdeaboutdata.h>
+#include <kdebug.h>
+#include <tdelocale.h>
+#include <tdeglobal.h>
+#include <tdeconfig.h>
+#include "server.h"
+
+
+static const char version[] = "0.4";
+static const char description[] = I18N_NOOP( "The reliable TDE session manager that talks the standard X11R6 \nsession management protocol (XSMP)." );
+
+static const TDECmdLineOptions options[] =
+{
+ { "r", 0, 0 },
+ { "restore", I18N_NOOP("Restores the saved user session if available"), 0},
+ { "w", 0, 0 },
+ { "windowmanager <wm>", I18N_NOOP("Starts 'wm' in case no other window manager is \nparticipating in the session. Default is 'twin'"), 0},
+ { "windowmanageraddargs <wm>", I18N_NOOP("Pass additional arguments to the window manager. Default is ''"), 0},
+ { "nolocal", I18N_NOOP("Also allow remote connections"), 0},
+ TDECmdLineLastOption
+};
+
+extern KSMServer* the_server;
+
+void IoErrorHandler ( IceConn iceConn)
+{
+ the_server->ioError( iceConn );
+}
+
+bool writeTest(TQCString path)
+{
+ path += "/XXXXXX";
+ int fd = mkstemp(path.data());
+ if (fd == -1)
+ return false;
+ if (write(fd, "Hello World\n", 12) == -1)
+ {
+ int save_errno = errno;
+ close(fd);
+ unlink(path.data());
+ errno = save_errno;
+ return false;
+ }
+ close(fd);
+ unlink(path.data());
+ return true;
+}
+
+void sanity_check( int argc, char* argv[] )
+{
+ TQCString msg;
+ TQCString path = getenv("HOME");
+ TQCString readOnly = getenv("TDE_HOME_READONLY");
+ if (path.isEmpty())
+ {
+ msg = "$HOME not set!";
+ }
+ if (msg.isEmpty() && access(path.data(), W_OK))
+ {
+ if (errno == ENOENT)
+ msg = "$HOME directory (%s) does not exist.";
+ else if (readOnly.isEmpty())
+ msg = "No write access to $HOME directory (%s).";
+ }
+ if (msg.isEmpty() && access(path.data(), R_OK))
+ {
+ if (errno == ENOENT)
+ msg = "$HOME directory (%s) does not exist.";
+ else
+ msg = "No read access to $HOME directory (%s).";
+ }
+ if (msg.isEmpty() && readOnly.isEmpty() && !writeTest(path))
+ {
+ if (errno == ENOSPC)
+ msg = "$HOME directory (%s) is out of disk space.";
+ else
+ msg = "Writing to the $HOME directory (%s) failed with\n "
+ "the error '"+TQCString(strerror(errno))+"'";
+ }
+ if (msg.isEmpty())
+ {
+ path = getenv("ICEAUTHORITY");
+ if (path.isEmpty())
+ {
+ path = getenv("HOME");
+ path += "/.ICEauthority";
+ }
+
+ if (access(path.data(), W_OK) && (errno != ENOENT))
+ msg = "No write access to '%s'.";
+ else if (access(path.data(), R_OK) && (errno != ENOENT))
+ msg = "No read access to '%s'.";
+ }
+ if (msg.isEmpty())
+ {
+ path = DCOPClient::dcopServerFile();
+ if (access(path.data(), R_OK) && (errno == ENOENT))
+ {
+ // Check iceauth
+ if (DCOPClient::iceauthPath().isEmpty())
+ msg = "Could not find 'iceauth' in path.";
+ }
+ }
+ if (msg.isEmpty())
+ {
+ path = getenv("TDETMP");
+ if (path.isEmpty())
+ path = "/tmp";
+ if (!writeTest(path))
+ {
+ if (errno == ENOSPC)
+ msg = "Temp directory (%s) is out of disk space.";
+ else
+ msg = "Writing to the temp directory (%s) failed with\n "
+ "the error '"+TQCString(strerror(errno))+"'";
+ }
+ }
+ if (msg.isEmpty() && (path != "/tmp"))
+ {
+ path = "/tmp";
+ if (!writeTest(path))
+ {
+ if (errno == ENOSPC)
+ msg = "Temp directory (%s) is out of disk space.";
+ else
+ msg = "Writing to the temp directory (%s) failed with\n "
+ "the error '"+TQCString(strerror(errno))+"'";
+ }
+ }
+ if (msg.isEmpty())
+ {
+ path += ".ICE-unix";
+ if (access(path.data(), W_OK) && (errno != ENOENT))
+ msg = "No write access to '%s'.";
+ else if (access(path.data(), R_OK) && (errno != ENOENT))
+ msg = "No read access to '%s'.";
+ }
+ if (!msg.isEmpty())
+ {
+ const char *msg_pre =
+ "The following installation problem was detected\n"
+ "while trying to start TDE:"
+ "\n\n ";
+ const char *msg_post = "\n\nTDE is unable to start.\n";
+ fputs(msg_pre, stderr);
+ fprintf(stderr, msg.data(), path.data());
+ fputs(msg_post, stderr);
+
+ TQApplication a(argc, argv);
+ TQCString qmsg(256+path.length());
+ qmsg.sprintf(msg.data(), path.data());
+ qmsg = msg_pre+qmsg+msg_post;
+ TQMessageBox::critical(0, "TDE Installation Problem!",
+ TQString::fromLatin1(qmsg.data()));
+ exit(255);
+ }
+}
+
+extern "C" KDE_EXPORT int kdemain( int argc, char* argv[] )
+{
+ sanity_check(argc, argv);
+
+ TDEAboutData aboutData( "ksmserver", I18N_NOOP("The TDE Session Manager"),
+ version, description, TDEAboutData::License_BSD,
+ "(C) 2000, The KDE Developers");
+ aboutData.addAuthor("Matthias Ettrich",0, "[email protected]");
+ aboutData.addAuthor("LuboÅ¡ Luňák", I18N_NOOP( "Maintainer" ), "[email protected]" );
+
+ TDECmdLineArgs::init(argc, argv, &aboutData);
+ TDECmdLineArgs::addCmdLineOptions( options );
+
+ putenv((char*)"SESSION_MANAGER=");
+ TDEApplication a(TDEApplication::openX11RGBADisplay(), false); // Disable styles until we need them.
+ fcntl(ConnectionNumber(tqt_xdisplay()), F_SETFD, 1);
+
+
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
+
+ kapp->dcopClient()->registerAs("ksmserver", false);
+ if (!kapp->dcopClient()->isRegistered())
+ {
+ tqWarning("[KSMServer] Could not register with DCOPServer. Aborting.");
+ return 1;
+ }
+
+ TQCString wm = args->getOption("windowmanager");
+ TQCString wmaddargs = args->getOption("windowmanageraddargs");
+ if ( wm.isEmpty() )
+ wm = "twin";
+
+ bool only_local = args->isSet("local");
+#ifndef HAVE__ICETRANSNOLISTEN
+ /* this seems strange, but the default is only_local, so if !only_local
+ * the option --nolocal was given, and we warn (the option --nolocal
+ * does nothing on this platform, as here the default is reversed)
+ */
+ if (!only_local) {
+ tqWarning("[KSMServer] --[no]local is not supported on your platform. Sorry.");
+ }
+ only_local = false;
+#endif
+
+ KSMServer *server = new KSMServer( TQString::fromLatin1(wm), TQString::fromLatin1(wmaddargs), only_local);
+ kapp->dcopClient()->setDefaultObject( server->objId() );
+
+ IceSetIOErrorHandler( IoErrorHandler );
+
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup( "General" );
+
+ int realScreenCount = ScreenCount( tqt_xdisplay() );
+ bool screenCountChanged =
+ ( config->readNumEntry( "screenCount", realScreenCount ) != realScreenCount );
+
+ TQString loginMode = config->readEntry( "loginMode", "restorePreviousLogout" );
+
+ if ( args->isSet("restore") && ! screenCountChanged )
+ server->restoreSession( SESSION_BY_USER );
+ else if ( loginMode == "default" || screenCountChanged )
+ server->startDefaultSession();
+ else if ( loginMode == "restorePreviousLogout" )
+ server->restoreSession( SESSION_PREVIOUS_LOGOUT );
+ else if ( loginMode == "restoreSavedSession" )
+ server->restoreSession( SESSION_BY_USER );
+ else
+ server->startDefaultSession();
+ return a.exec();
+}
+
diff --git a/ksmserver/move_session_config.sh b/ksmserver/move_session_config.sh
new file mode 100755
index 000000000..631dbcd74
--- /dev/null
+++ b/ksmserver/move_session_config.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+prefix=`tde-config --localprefix`
+source="${prefix}/share/config"
+dest="${prefix}/share/config/session"
+
+# move session config files
+
+if [ -n "$prefix" -a -d "$source" ]; then
+ while [ ! -d "$dest" ]; do
+ dir="$dest"
+ while [ ! -d `dirname "$dir"` ]; do
+ dir=`dirname "$dir"`
+ done
+ mkdir "$dir" || exit 1
+ done
+
+ files=`eval ls -1 "$source/*:[0-9a-f]*" 2> /dev/null`
+ if [ -n "$files" ]; then
+ for i in $files; do
+ origfile=`basename "$i"`
+ newfile=`echo "$origfile" | sed -e 's^:^_^'`
+ if [ -n "$newfile" -a ! -e "$dest/$newfile" ]; then
+ mv "$source/$origfile" "$dest/$newfile"
+ fi
+ done
+ fi
+fi
+
+# update references in ksmserverrc
+
+sed -e 's^share/config/\([^/:]*\):^share/config/session/\1_^'
diff --git a/ksmserver/server.cpp b/ksmserver/server.cpp
new file mode 100644
index 000000000..c9a037397
--- /dev/null
+++ b/ksmserver/server.cpp
@@ -0,0 +1,992 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+Copyright (C) 2005 Lubos Lunak <[email protected]>
+
+relatively small extensions by Oswald Buddenhagen <[email protected]>
+
+some code taken from the dcopserver (part of the KDE libraries), which is
+Copyright (c) 1999 Matthias Ettrich <[email protected]>
+Copyright (c) 1999 Preston Brown <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <tqfile.h>
+#include <tqtextstream.h>
+#include <tqdatastream.h>
+#include <tqptrstack.h>
+#include <tqpushbutton.h>
+#include <tqmessagebox.h>
+#include <tqguardedptr.h>
+#include <tqtimer.h>
+#include <tqregexp.h>
+
+#include <tdelocale.h>
+#include <tdeglobal.h>
+#include <tdeconfig.h>
+#include <kstandarddirs.h>
+#include <unistd.h>
+#include <tdeapplication.h>
+#include <kstaticdeleter.h>
+#include <tdetempfile.h>
+#include <kprocess.h>
+#include <dcopclient.h>
+#include <dcopref.h>
+
+#include "server.h"
+#include "global.h"
+#include "client.h"
+
+#include "server.moc"
+
+#include <kdebug.h>
+
+#include <dmctl.h>
+
+KSMServer* the_server = 0;
+
+KSMServer* KSMServer::self()
+{
+ return the_server;
+}
+
+/*! Utility function to execute a command on the local machine. Used
+ * to restart applications.
+ */
+void KSMServer::startApplication( TQStringList command, const TQString& clientMachine,
+ const TQString& userId )
+{
+ if ( command.isEmpty() )
+ return;
+ if ( !userId.isEmpty()) {
+ struct passwd* pw = getpwuid( getuid());
+ if( pw != NULL && userId != TQString::fromLocal8Bit( pw->pw_name )) {
+ command.prepend( "--" );
+ command.prepend( userId );
+ command.prepend( "-u" );
+ command.prepend( "tdesu" );
+ }
+ }
+ if ( !clientMachine.isEmpty() && clientMachine != "localhost" ) {
+ command.prepend( clientMachine );
+ command.prepend( xonCommand ); // "xon" by default
+ }
+ int n = command.count();
+ TQCString app = command[0].latin1();
+ TQValueList<TQCString> argList;
+ for ( int i=1; i < n; i++)
+ argList.append( TQCString(command[i].latin1()));
+ DCOPRef( launcher ).send( "exec_blind", app, DCOPArg( argList, "TQValueList<TQCString>" ) );
+}
+
+/*! Utility function to execute a command on the local machine. Used
+ * to discard session data
+ */
+void KSMServer::executeCommand( const TQStringList& command )
+{
+ if ( command.isEmpty() )
+ return;
+ TDEProcess proc;
+ for ( TQStringList::ConstIterator it = command.begin();
+ it != command.end(); ++it )
+ proc << (*it).latin1();
+ proc.start( TDEProcess::Block );
+}
+
+IceAuthDataEntry *authDataEntries = 0;
+static KTempFile *remAuthFile = 0;
+
+static IceListenObj *listenObjs = 0;
+int numTransports = 0;
+static bool only_local = 0;
+
+static Bool HostBasedAuthProc ( char* /*hostname*/)
+{
+ if (only_local)
+ return true;
+ else
+ return false;
+}
+
+
+Status KSMRegisterClientProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData,
+ char * previousId
+)
+{
+ KSMClient* client = (KSMClient*) managerData;
+ client->registerClient( previousId );
+ return 1;
+}
+
+void KSMInteractRequestProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData,
+ int dialogType
+)
+{
+ the_server->interactRequest( (KSMClient*) managerData, dialogType );
+}
+
+void KSMInteractDoneProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData,
+ Bool cancelShutdown
+)
+{
+ the_server->interactDone( (KSMClient*) managerData, cancelShutdown );
+}
+
+void KSMSaveYourselfRequestProc (
+ SmsConn smsConn ,
+ SmPointer /* managerData */,
+ int saveType,
+ Bool shutdown,
+ int interactStyle,
+ Bool fast,
+ Bool global
+)
+{
+ if ( shutdown ) {
+ the_server->shutdown( fast ?
+ TDEApplication::ShutdownConfirmNo :
+ TDEApplication::ShutdownConfirmDefault,
+ TDEApplication::ShutdownTypeDefault,
+ TDEApplication::ShutdownModeDefault );
+ } else if ( !global ) {
+ SmsSaveYourself( smsConn, saveType, false, interactStyle, fast );
+ SmsSaveComplete( smsConn );
+ }
+ // else checkpoint only, ksmserver does not yet support this
+ // mode. Will come for KDE 3.1
+}
+
+void KSMSaveYourselfPhase2RequestProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData
+)
+{
+ the_server->phase2Request( (KSMClient*) managerData );
+}
+
+void KSMSaveYourselfDoneProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData,
+ Bool success
+)
+{
+ the_server->saveYourselfDone( (KSMClient*) managerData, success );
+}
+
+void KSMCloseConnectionProc (
+ SmsConn smsConn,
+ SmPointer managerData,
+ int count,
+ char ** reasonMsgs
+)
+{
+ the_server->deleteClient( ( KSMClient* ) managerData );
+ if ( count )
+ SmFreeReasons( count, reasonMsgs );
+ IceConn iceConn = SmsGetIceConnection( smsConn );
+ SmsCleanUp( smsConn );
+ IceSetShutdownNegotiation (iceConn, False);
+ IceCloseConnection( iceConn );
+}
+
+void KSMSetPropertiesProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData,
+ int numProps,
+ SmProp ** props
+)
+{
+ KSMClient* client = ( KSMClient* ) managerData;
+ for ( int i = 0; i < numProps; i++ ) {
+ SmProp *p = client->property( props[i]->name );
+ if ( p ) {
+ client->properties.removeRef( p );
+ SmFreeProperty( p );
+ }
+ client->properties.append( props[i] );
+ if ( !qstrcmp( props[i]->name, SmProgram ) )
+ the_server->clientSetProgram( client );
+ }
+
+ if ( numProps )
+ free( props );
+
+}
+
+void KSMDeletePropertiesProc (
+ SmsConn /* smsConn */,
+ SmPointer managerData,
+ int numProps,
+ char ** propNames
+)
+{
+ KSMClient* client = ( KSMClient* ) managerData;
+ for ( int i = 0; i < numProps; i++ ) {
+ SmProp *p = client->property( propNames[i] );
+ if ( p ) {
+ client->properties.removeRef( p );
+ SmFreeProperty( p );
+ }
+ }
+}
+
+void KSMGetPropertiesProc (
+ SmsConn smsConn,
+ SmPointer managerData
+)
+{
+ KSMClient* client = ( KSMClient* ) managerData;
+ SmProp** props = new SmProp*[client->properties.count()];
+ int i = 0;
+ for ( SmProp* prop = client->properties.first(); prop; prop = client->properties.next() )
+ props[i++] = prop;
+
+ SmsReturnProperties( smsConn, i, props );
+ delete [] props;
+}
+
+
+class KSMListener : public TQSocketNotifier
+{
+public:
+ KSMListener( IceListenObj obj )
+ : TQSocketNotifier( IceGetListenConnectionNumber( obj ),
+ TQSocketNotifier::Read, 0, 0)
+{
+ listenObj = obj;
+}
+
+ IceListenObj listenObj;
+};
+
+class KSMConnection : public TQSocketNotifier
+{
+ public:
+ KSMConnection( IceConn conn )
+ : TQSocketNotifier( IceConnectionNumber( conn ),
+ TQSocketNotifier::Read, 0, 0 )
+ {
+ iceConn = conn;
+ }
+
+ IceConn iceConn;
+};
+
+
+/* for printing hex digits */
+static void fprintfhex (FILE *fp, unsigned int len, char *cp)
+{
+ static const char hexchars[] = "0123456789abcdef";
+
+ for (; len > 0; len--, cp++) {
+ unsigned char s = *cp;
+ putc(hexchars[s >> 4], fp);
+ putc(hexchars[s & 0x0f], fp);
+ }
+}
+
+/*
+ * We use temporary files which contain commands to add/remove entries from
+ * the .ICEauthority file.
+ */
+static void write_iceauth (FILE *addfp, FILE *removefp, IceAuthDataEntry *entry)
+{
+ fprintf (addfp,
+ "add %s \"\" %s %s ",
+ entry->protocol_name,
+ entry->network_id,
+ entry->auth_name);
+ fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
+ fprintf (addfp, "\n");
+
+ fprintf (removefp,
+ "remove protoname=%s protodata=\"\" netid=%s authname=%s\n",
+ entry->protocol_name,
+ entry->network_id,
+ entry->auth_name);
+}
+
+
+#define MAGIC_COOKIE_LEN 16
+
+Status SetAuthentication_local (int count, IceListenObj *listenObjs)
+{
+ int i;
+ for (i = 0; i < count; i ++) {
+ char *prot = IceGetListenConnectionString(listenObjs[i]);
+ if (!prot) continue;
+ char *host = strchr(prot, '/');
+ char *sock = 0;
+ if (host) {
+ *host=0;
+ host++;
+ sock = strchr(host, ':');
+ if (sock) {
+ *sock = 0;
+ sock++;
+ }
+ }
+ kdDebug( 1218 ) << "KSMServer: SetAProc_loc: conn " << (unsigned)i << ", prot=" << prot << ", file=" << sock << endl;
+ if (sock && !strcmp(prot, "local")) {
+ chmod(sock, 0700);
+ }
+ IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc);
+ free(prot);
+ }
+ return 1;
+}
+
+Status SetAuthentication (int count, IceListenObj *listenObjs,
+ IceAuthDataEntry **authDataEntries)
+{
+ KTempFile addAuthFile;
+ addAuthFile.setAutoDelete(true);
+
+ remAuthFile = new KTempFile;
+ remAuthFile->setAutoDelete(true);
+
+ if ((addAuthFile.status() != 0) || (remAuthFile->status() != 0))
+ return 0;
+
+ if ((*authDataEntries = (IceAuthDataEntry *) malloc (
+ count * 2 * sizeof (IceAuthDataEntry))) == NULL)
+ return 0;
+
+ for (int i = 0; i < numTransports * 2; i += 2) {
+ (*authDataEntries)[i].network_id =
+ IceGetListenConnectionString (listenObjs[i/2]);
+ (*authDataEntries)[i].protocol_name = (char *) "ICE";
+ (*authDataEntries)[i].auth_name = (char *) "MIT-MAGIC-COOKIE-1";
+
+ (*authDataEntries)[i].auth_data =
+ IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
+ (*authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
+
+ (*authDataEntries)[i+1].network_id =
+ IceGetListenConnectionString (listenObjs[i/2]);
+ (*authDataEntries)[i+1].protocol_name = (char *) "XSMP";
+ (*authDataEntries)[i+1].auth_name = (char *) "MIT-MAGIC-COOKIE-1";
+
+ (*authDataEntries)[i+1].auth_data =
+ IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
+ (*authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
+
+ write_iceauth (addAuthFile.fstream(), remAuthFile->fstream(), &(*authDataEntries)[i]);
+ write_iceauth (addAuthFile.fstream(), remAuthFile->fstream(), &(*authDataEntries)[i+1]);
+
+ IceSetPaAuthData (2, &(*authDataEntries)[i]);
+
+ IceSetHostBasedAuthProc (listenObjs[i/2], HostBasedAuthProc);
+ }
+ addAuthFile.close();
+ remAuthFile->close();
+
+ TQString iceAuth = TDEGlobal::dirs()->findExe("iceauth");
+ if (iceAuth.isEmpty())
+ {
+ tqWarning("[KSMServer] could not find iceauth");
+ return 0;
+ }
+
+ TDEProcess p;
+ p << iceAuth << "source" << addAuthFile.name();
+ p.start(TDEProcess::Block);
+
+ return (1);
+}
+
+/*
+ * Free up authentication data.
+ */
+void FreeAuthenticationData(int count, IceAuthDataEntry *authDataEntries)
+{
+ /* Each transport has entries for ICE and XSMP */
+ if (only_local)
+ return;
+
+ for (int i = 0; i < count * 2; i++) {
+ free (authDataEntries[i].network_id);
+ free (authDataEntries[i].auth_data);
+ }
+
+ free (authDataEntries);
+
+ TQString iceAuth = TDEGlobal::dirs()->findExe("iceauth");
+ if (iceAuth.isEmpty())
+ {
+ tqWarning("[KSMServer] could not find iceauth");
+ return;
+ }
+
+ TDEProcess p;
+ p << iceAuth << "source" << remAuthFile->name();
+ p.start(TDEProcess::Block);
+
+ delete remAuthFile;
+ remAuthFile = 0;
+}
+
+static int Xio_ErrorHandler( Display * )
+{
+ tqWarning("[KSMServer] Fatal IO error: client killed");
+
+ // Don't do anything that might require the X connection
+ if (the_server)
+ {
+ KSMServer *server = the_server;
+ the_server = 0;
+ server->cleanUp();
+ // Don't delete server!!
+ }
+
+ exit(0); // Don't report error, it's not our fault.
+}
+
+
+void KSMServer::setupXIOErrorHandler()
+{
+ XSetIOErrorHandler(Xio_ErrorHandler);
+}
+
+static void sighandler(int sig)
+{
+ if (sig == SIGHUP) {
+ signal(SIGHUP, sighandler);
+ return;
+ }
+
+ if (the_server)
+ {
+ KSMServer *server = the_server;
+ the_server = 0;
+ server->cleanUp();
+ delete server;
+ }
+
+ if (kapp) {
+ kapp->quit();
+ }
+ //::exit(0);
+}
+
+
+void KSMWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
+{
+ KSMServer* ds = ( KSMServer*) client_data;
+
+ if (opening) {
+ *watch_data = (IcePointer) ds->watchConnection( iceConn );
+ }
+ else {
+ ds->removeConnection( (KSMConnection*) *watch_data );
+ }
+}
+
+static Status KSMNewClientProc ( SmsConn conn, SmPointer manager_data,
+ unsigned long* mask_ret, SmsCallbacks* cb, char** failure_reason_ret)
+{
+ *failure_reason_ret = 0;
+
+ void* client = ((KSMServer*) manager_data )->newClient( conn );
+
+ cb->register_client.callback = KSMRegisterClientProc;
+ cb->register_client.manager_data = client;
+ cb->interact_request.callback = KSMInteractRequestProc;
+ cb->interact_request.manager_data = client;
+ cb->interact_done.callback = KSMInteractDoneProc;
+ cb->interact_done.manager_data = client;
+ cb->save_yourself_request.callback = KSMSaveYourselfRequestProc;
+ cb->save_yourself_request.manager_data = client;
+ cb->save_yourself_phase2_request.callback = KSMSaveYourselfPhase2RequestProc;
+ cb->save_yourself_phase2_request.manager_data = client;
+ cb->save_yourself_done.callback = KSMSaveYourselfDoneProc;
+ cb->save_yourself_done.manager_data = client;
+ cb->close_connection.callback = KSMCloseConnectionProc;
+ cb->close_connection.manager_data = client;
+ cb->set_properties.callback = KSMSetPropertiesProc;
+ cb->set_properties.manager_data = client;
+ cb->delete_properties.callback = KSMDeletePropertiesProc;
+ cb->delete_properties.manager_data = client;
+ cb->get_properties.callback = KSMGetPropertiesProc;
+ cb->get_properties.manager_data = client;
+
+ *mask_ret = SmsRegisterClientProcMask |
+ SmsInteractRequestProcMask |
+ SmsInteractDoneProcMask |
+ SmsSaveYourselfRequestProcMask |
+ SmsSaveYourselfP2RequestProcMask |
+ SmsSaveYourselfDoneProcMask |
+ SmsCloseConnectionProcMask |
+ SmsSetPropertiesProcMask |
+ SmsDeletePropertiesProcMask |
+ SmsGetPropertiesProcMask;
+ return 1;
+}
+
+
+#ifdef HAVE__ICETRANSNOLISTEN
+extern "C" int _IceTransNoListen(const char * protocol);
+#endif
+
+KSMServer::KSMServer( const TQString& windowManager, const TQString& windowManagerAddArgs, bool _only_local )
+ : DCOPObject("ksmserver"), startupNotifierIPDlg(0), shutdownNotifierIPDlg(0), sessionGroup( "" ), protectionTimerCounter(0)
+{
+ the_server = this;
+ clean = false;
+ wm = windowManager;
+ wmAddArgs = windowManagerAddArgs;
+
+ shutdownType = TDEApplication::ShutdownTypeNone;
+
+ state = Idle;
+ dialogActive = false;
+ saveSession = false;
+ wmPhase1WaitingCount = 0;
+ TDEConfig* config = TDEGlobal::config();
+ config->setGroup("General" );
+ clientInteracting = 0;
+ xonCommand = config->readEntry( "xonCommand", "xon" );
+
+#ifdef __TDE_HAVE_TDEHWLIB
+ hwDevices = TDEGlobal::hardwareDevices();
+#endif
+
+ connect( &knotifyTimeoutTimer, TQT_SIGNAL( timeout()), TQT_SLOT( knotifyTimeout()));
+ connect( &startupSuspendTimeoutTimer, TQT_SIGNAL( timeout()), TQT_SLOT( startupSuspendTimeout()));
+ connect( &pendingShutdown, TQT_SIGNAL( timeout()), TQT_SLOT( pendingShutdownTimeout()));
+
+ only_local = _only_local;
+#ifdef HAVE__ICETRANSNOLISTEN
+ if (only_local)
+ _IceTransNoListen("tcp");
+#else
+ only_local = false;
+#endif
+
+ launcher = TDEApplication::launcher();
+
+ char errormsg[256];
+ if (!SmsInitialize ( (char*) KSMVendorString, (char*) KSMReleaseString,
+ KSMNewClientProc,
+ (SmPointer) this,
+ HostBasedAuthProc, 256, errormsg ) ) {
+
+ tqWarning("[KSMServer] could not register XSM protocol");
+ }
+
+ if (!IceListenForConnections (&numTransports, &listenObjs,
+ 256, errormsg))
+ {
+ tqWarning("[KSMServer] Error listening for connections: %s", errormsg);
+ tqWarning("[KSMServer] Aborting.");
+ exit(1);
+ }
+
+ {
+ // publish available transports.
+ TQCString fName = TQFile::encodeName(locateLocal("socket", "KSMserver"));
+ TQCString display = ::getenv("DISPLAY");
+ // strip the screen number from the display
+ display.replace(TQRegExp("\\.[0-9]+$"), "");
+ int i;
+ while( (i = display.find(':')) >= 0)
+ display[i] = '_';
+
+ fName += "_"+display;
+ FILE *f;
+ f = ::fopen(fName.data(), "w+");
+ if (!f)
+ {
+ tqWarning("[KSMServer] can't open %s: %s", fName.data(), strerror(errno));
+ tqWarning("[KSMServer] Aborting.");
+ exit(1);
+ }
+ char* session_manager = IceComposeNetworkIdList(numTransports, listenObjs);
+ fprintf(f, "%s\n%i\n", session_manager, getpid());
+ fclose(f);
+ setenv( "SESSION_MANAGER", session_manager, true );
+ // Pass env. var to tdeinit.
+ DCOPRef( launcher ).send( "setLaunchEnv", "SESSION_MANAGER", (const char*) session_manager );
+ }
+
+ if (only_local) {
+ if (!SetAuthentication_local(numTransports, listenObjs))
+ tqFatal("[KSMServer] authentication setup failed.");
+ } else {
+ if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
+ tqFatal("[KSMServer] authentication setup failed.");
+ }
+
+ IceAddConnectionWatch (KSMWatchProc, (IcePointer) this);
+
+ listener.setAutoDelete( true );
+ KSMListener* con;
+ for ( int i = 0; i < numTransports; i++) {
+ con = new KSMListener( listenObjs[i] );
+ listener.append( con );
+ connect( con, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( newConnection(int) ) );
+ }
+
+ signal(SIGHUP, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGINT, sighandler);
+ signal(SIGPIPE, SIG_IGN);
+
+ connect( &notificationTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( notificationTimeout() ) );
+ connect( &protectionTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( protectionTimerTick() ) );
+ connect( &restoreTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( tryRestoreNext() ) );
+ connect( &shutdownTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( timeoutQuit() ) );
+ connect( kapp, TQT_SIGNAL( shutDown() ), this, TQT_SLOT( cleanUp() ) );
+}
+
+KSMServer::~KSMServer()
+{
+ the_server = 0;
+ cleanUp();
+}
+
+void KSMServer::cleanUp()
+{
+ if (clean) return;
+ clean = true;
+ IceFreeListenObjs (numTransports, listenObjs);
+
+ TQCString fName = TQFile::encodeName(locateLocal("socket", "KSMserver"));
+ TQCString display = ::getenv("DISPLAY");
+ // strip the screen number from the display
+ display.replace(TQRegExp("\\.[0-9]+$"), "");
+ int i;
+ while( (i = display.find(':')) >= 0) {
+ display[i] = '_';
+ }
+
+ fName += "_"+display;
+ ::unlink(fName.data());
+
+ FreeAuthenticationData(numTransports, authDataEntries);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ if (DM().canShutdown()) {
+ DM().shutdown( shutdownType, shutdownMode, bootOption );
+ }
+ else {
+#ifdef __TDE_HAVE_TDEHWLIB
+ TDERootSystemDevice* rootDevice = hwDevices->rootSystemDevice();
+ if (rootDevice) {
+ if (shutdownType == TDEApplication::ShutdownTypeHalt) {
+ rootDevice->setPowerState(TDESystemPowerState::PowerOff);
+ }
+ if (shutdownType == TDEApplication::ShutdownTypeReboot) {
+ rootDevice->setPowerState(TDESystemPowerState::Reboot);
+ }
+ }
+#endif
+ }
+}
+
+
+
+void* KSMServer::watchConnection( IceConn iceConn )
+{
+ KSMConnection* conn = new KSMConnection( iceConn );
+ connect( conn, TQT_SIGNAL( activated(int) ), this, TQT_SLOT( processData(int) ) );
+ return (void*) conn;
+}
+
+void KSMServer::removeConnection( KSMConnection* conn )
+{
+ delete conn;
+}
+
+
+/*!
+ Called from our IceIoErrorHandler
+ */
+void KSMServer::ioError( IceConn /*iceConn*/ )
+{
+}
+
+void KSMServer::processData( int /*socket*/ )
+{
+ IceConn iceConn = ((KSMConnection*)sender())->iceConn;
+ IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 );
+ if ( status == IceProcessMessagesIOError ) {
+ IceSetShutdownNegotiation( iceConn, False );
+ TQPtrListIterator<KSMClient> it ( clients );
+ while ( it.current() &&SmsGetIceConnection( it.current()->connection() ) != iceConn )
+ ++it;
+ if ( it.current() ) {
+ SmsConn smsConn = it.current()->connection();
+ deleteClient( it.current() );
+ SmsCleanUp( smsConn );
+ }
+ (void) IceCloseConnection( iceConn );
+ }
+}
+
+KSMClient* KSMServer::newClient( SmsConn conn )
+{
+ KSMClient* client = new KSMClient( conn );
+ clients.append( client );
+ return client;
+}
+
+void KSMServer::deleteClient( KSMClient* client )
+{
+ if ( clients.findRef( client ) == -1 ) // paranoia
+ return;
+ clients.removeRef( client );
+ if ( client == clientInteracting ) {
+ clientInteracting = 0;
+ handlePendingInteractions();
+ }
+ delete client;
+ if ( state == Shutdown || state == Checkpoint )
+ completeShutdownOrCheckpoint();
+ if ( state == Killing )
+ completeKilling();
+ if ( state == KillingWM )
+ completeKillingWM();
+}
+
+void KSMServer::newConnection( int /*socket*/ )
+{
+ IceAcceptStatus status;
+ IceConn iceConn = IceAcceptConnection( ((KSMListener*)sender())->listenObj, &status);
+ if (iceConn == NULL) {
+ return;
+ }
+ IceSetShutdownNegotiation( iceConn, False );
+ IceConnectStatus cstatus;
+ while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
+ (void) IceProcessMessages( iceConn, 0, 0 );
+ }
+
+ if (cstatus != IceConnectAccepted) {
+ if (cstatus == IceConnectIOError)
+ kdDebug( 1218 ) << "IO error opening ICE Connection!" << endl;
+ else
+ kdDebug( 1218 ) << "ICE Connection rejected!" << endl;
+ (void )IceCloseConnection (iceConn);
+ return;
+ }
+}
+
+
+TQString KSMServer::currentSession()
+{
+ if ( sessionGroup.startsWith( "Session: " ) )
+ return sessionGroup.mid( 9 );
+ return ""; // empty, not null, since used for TDEConfig::setGroup
+}
+
+void KSMServer::discardSession()
+{
+ TDEConfig* config = TDEGlobal::config();
+ config->setGroup( sessionGroup );
+ int count = config->readNumEntry( "count", 0 );
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ TQStringList discardCommand = c->discardCommand();
+ if ( discardCommand.isEmpty())
+ continue;
+ // check that non of the old clients used the exactly same
+ // discardCommand before we execute it. This used to be the
+ // case up to KDE and Qt < 3.1
+ int i = 1;
+ while ( i <= count &&
+ config->readPathListEntry( TQString("discardCommand") + TQString::number(i) ) != discardCommand )
+ i++;
+ if ( i <= count )
+ executeCommand( discardCommand );
+ }
+}
+
+void KSMServer::storeSession()
+{
+ TDEConfig* config = TDEGlobal::config();
+ config->reparseConfiguration(); // config may have changed in the KControl module
+ config->setGroup("General" );
+ excludeApps = TQStringList::split( TQRegExp( "[,:]" ), config->readEntry( "excludeApps" ).lower());
+ config->setGroup( sessionGroup );
+ int count = config->readNumEntry( "count" );
+ for ( int i = 1; i <= count; i++ ) {
+ TQStringList discardCommand = config->readPathListEntry( TQString("discardCommand") + TQString::number(i) );
+ if ( discardCommand.isEmpty())
+ continue;
+ // check that non of the new clients uses the exactly same
+ // discardCommand before we execute it. This used to be the
+ // case up to KDE and Qt < 3.1
+ KSMClient* c = clients.first();
+ while ( c && discardCommand != c->discardCommand() )
+ c = clients.next();
+ if ( c )
+ continue;
+ executeCommand( discardCommand );
+ }
+ config->deleteGroup( sessionGroup ); //### does not work with global config object...
+ config->setGroup( sessionGroup );
+ count = 0;
+
+ if ( !wm.isEmpty() ) {
+ // put the wm first
+ for ( KSMClient* c = clients.first(); c; c = clients.next() )
+ if ( c->program() == wm ) {
+ clients.prepend( clients.take() );
+ break;
+ }
+ }
+
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ int restartHint = c->restartStyleHint();
+ if (restartHint == SmRestartNever)
+ continue;
+ TQString program = c->program();
+ TQStringList restartCommand = c->restartCommand();
+ if (program.isEmpty() && restartCommand.isEmpty())
+ continue;
+ if (excludeApps.contains( program.lower()))
+ continue;
+
+ count++;
+ TQString n = TQString::number(count);
+ config->writeEntry( TQString("program")+n, program );
+ config->writeEntry( TQString("clientId")+n, c->clientId() );
+ config->writeEntry( TQString("restartCommand")+n, restartCommand );
+ config->writePathEntry( TQString("discardCommand")+n, c->discardCommand() );
+ config->writeEntry( TQString("restartStyleHint")+n, restartHint );
+ config->writeEntry( TQString("userId")+n, c->userId() );
+ config->writeEntry( TQString("wasWm")+n, isWM( c ));
+ }
+ config->writeEntry( "count", count );
+
+ config->setGroup("General");
+ config->writeEntry( "screenCount", ScreenCount(tqt_xdisplay()));
+
+ storeLegacySession( config );
+ config->sync();
+}
+
+
+TQStringList KSMServer::sessionList()
+{
+ TQStringList sessions = "default";
+ TDEConfig* config = TDEGlobal::config();
+ TQStringList groups = config->groupList();
+ for ( TQStringList::ConstIterator it = groups.begin(); it != groups.end(); it++ )
+ if ( (*it).startsWith( "Session: " ) )
+ sessions << (*it).mid( 9 );
+ return sessions;
+}
+
+bool KSMServer::isWM( const KSMClient* client ) const
+{
+ return isWM( client->program());
+}
+
+bool KSMServer::isWM( const TQString& program ) const
+{
+ // KWin relies on ksmserver's special treatment in phase1,
+ // therefore make sure it's recognized even if ksmserver
+ // was initially started with different WM, and twin replaced
+ // it later
+ return ((program == wm) || (program == "twin"));
+}
+
+bool KSMServer::isCM( const KSMClient* client ) const
+{
+ return isCM( client->program());
+}
+
+bool KSMServer::isCM( const TQString& program ) const
+{
+ // Returns true if the program in question is a composition manager
+ return (program == TDE_COMPOSITOR_BINARY);
+}
+
+bool KSMServer::isDesktop( const KSMClient* client ) const
+{
+ return isDesktop( client->program());
+}
+
+bool KSMServer::isDesktop( const TQString& program ) const
+{
+ // Returns true if the program in question is a desktop
+ return (program == "kdesktop");
+}
+
+bool KSMServer::isNotifier( const KSMClient* client ) const
+{
+ return isNotifier( client->program());
+}
+
+bool KSMServer::isNotifier( const TQString& program ) const
+{
+ return (program == "knotify");
+}
+
+bool KSMServer::isCrashHandler( const KSMClient* client ) const
+{
+ return isNotifier( client->program());
+}
+
+bool KSMServer::isCrashHandler( const TQString& program ) const
+{
+ return (program == "drkonqi");
+}
+
+bool KSMServer::defaultSession() const
+{
+ return sessionGroup.isEmpty();
+}
diff --git a/ksmserver/server.h b/ksmserver/server.h
new file mode 100644
index 000000000..bc677752c
--- /dev/null
+++ b/ksmserver/server.h
@@ -0,0 +1,264 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#ifndef SERVER_H
+#define SERVER_H
+
+// needed to avoid clash with INT8 defined in X11/Xmd.h on solaris
+#define QT_CLEAN_NAMESPACE 1
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqsocketnotifier.h>
+#include <tqptrlist.h>
+#include <tqvaluelist.h>
+#include <tqcstring.h>
+#include <tqdict.h>
+#include <tqptrqueue.h>
+#include <tqptrdict.h>
+#include <tdeapplication.h>
+#include <tqtimer.h>
+#include <dcopobject.h>
+
+#ifdef __TDE_HAVE_TDEHWLIB
+#include <tdehardwaredevices.h>
+#endif
+
+#include "server2.h"
+
+#include "KSMServerInterface.h"
+
+#define SESSION_PREVIOUS_LOGOUT "saved at previous logout"
+#define SESSION_BY_USER "saved by user"
+
+typedef TQValueList<TQCString> QCStringList;
+class KSMListener;
+class KSMConnection;
+class KSMClient;
+
+enum SMType { SM_ERROR, SM_WMCOMMAND, SM_WMSAVEYOURSELF };
+struct SMData
+ {
+ SMType type;
+ TQStringList wmCommand;
+ TQString wmClientMachine;
+ TQString wmclass1, wmclass2;
+ };
+typedef TQMap<WId,SMData> WindowMap;
+
+class KSMServer : public TQObject, public KSMServerInterface
+{
+Q_OBJECT
+K_DCOP
+k_dcop:
+ void notifySlot(TQString,TQString,TQString,TQString,TQString,int,int,int,int);
+ void logoutSoundFinished(int,int);
+ void autoStart0Done();
+ void autoStart1Done();
+ void autoStart2Done();
+ void kcmPhase1Done();
+ void kcmPhase2Done();
+public:
+ KSMServer( const TQString& windowManager, const TQString& windowManagerAddArgs, bool only_local );
+ ~KSMServer();
+
+ static KSMServer* self();
+
+ void* watchConnection( IceConn iceConn );
+ void removeConnection( KSMConnection* conn );
+
+ KSMClient* newClient( SmsConn );
+ void deleteClient( KSMClient* client );
+
+ // callbacks
+ void saveYourselfDone( KSMClient* client, bool success );
+ void interactRequest( KSMClient* client, int dialogType );
+ void interactDone( KSMClient* client, bool cancelShutdown );
+ void phase2Request( KSMClient* client );
+
+ // error handling
+ void ioError( IceConn iceConn );
+
+ // notification
+ void clientSetProgram( KSMClient* client );
+ void clientRegistered( const char* previousId );
+
+ // public API
+ void restoreSession( TQString sessionName );
+ void startDefaultSession();
+
+ void shutdown( TDEApplication::ShutdownConfirm confirm,
+ TDEApplication::ShutdownType sdtype,
+ TDEApplication::ShutdownMode sdmode );
+
+ virtual void suspendStartup( TQCString app );
+ virtual void resumeStartup( TQCString app );
+
+ bool checkStatus( bool &logoutConfirmed, bool &maysd, bool &mayrb,
+ TDEApplication::ShutdownConfirm confirm,
+ TDEApplication::ShutdownType sdtype,
+ TDEApplication::ShutdownMode sdmode );
+
+public slots:
+ void cleanUp();
+
+private slots:
+ void newConnection( int socket );
+ void processData( int socket );
+ void restoreSessionInternal();
+ void restoreSessionDoneInternal();
+
+ void notificationTimeout();
+ void protectionTimerTick();
+ void protectionTimeout();
+ void timeoutQuit();
+ void timeoutWMQuit();
+ void knotifyTimeout();
+ void kcmPhase1Timeout();
+ void kcmPhase2Timeout();
+ void pendingShutdownTimeout();
+
+ void autoStart0();
+ void autoStart1();
+ void autoStart2();
+ void tryRestoreNext();
+ void startupSuspendTimeout();
+
+ void cancelShutdown();
+ void forceSkipSaveYourself();
+
+private:
+ void handlePendingInteractions();
+ void completeShutdownOrCheckpoint();
+ void startKilling();
+ void performStandardKilling();
+ void completeKilling();
+ void killWM();
+ void completeKillingWM();
+ void cancelShutdown( TQString cancellationText );
+ void cancelShutdown( KSMClient* c );
+ void killingCompleted();
+
+ void discardSession();
+ void storeSession();
+
+ void startProtection();
+ void endProtection();
+ void handleProtectionTimeout();
+ void updateLogoutStatusDialog();
+
+ void startApplication( TQStringList command,
+ const TQString& clientMachine = TQString::null,
+ const TQString& userId = TQString::null );
+ void executeCommand( const TQStringList& command );
+
+ bool isWM( const KSMClient* client ) const;
+ bool isWM( const TQString& program ) const;
+ bool isCM( const KSMClient* client ) const;
+ bool isCM( const TQString& program ) const;
+ bool isDesktop( const KSMClient* client ) const;
+ bool isDesktop( const TQString& program ) const;
+ bool isNotifier( const KSMClient* client ) const;
+ bool isNotifier( const TQString& program ) const;
+ bool isCrashHandler( const KSMClient* client ) const;
+ bool isCrashHandler( const TQString& program ) const;
+ bool defaultSession() const; // empty session
+ void setupXIOErrorHandler();
+
+ void shutdownInternal( TDEApplication::ShutdownConfirm confirm,
+ TDEApplication::ShutdownType sdtype,
+ TDEApplication::ShutdownMode sdmode,
+ TQString bootOption = TQString::null );
+
+ void performLegacySessionSave();
+ void storeLegacySession( TDEConfig* config );
+ void restoreLegacySession( TDEConfig* config );
+ void restoreLegacySessionInternal( TDEConfig* config, char sep = ',' );
+ TQStringList windowWmCommand(WId w);
+ TQString windowWmClientMachine(WId w);
+ WId windowWmClientLeader(WId w);
+ TQCString windowSessionId(WId w, WId leader);
+
+ bool checkStartupSuspend();
+ void finishStartup();
+ void resumeStartupInternal();
+
+ // public dcop interface
+ void logout( int, int, int );
+ virtual void logoutTimed( int, int, TQString );
+ TQStringList sessionList();
+ TQString currentSession();
+ void saveCurrentSession();
+ void saveCurrentSessionAs( TQString );
+
+ TQWidget* startupNotifierIPDlg;
+ TQWidget* shutdownNotifierIPDlg;
+
+ private:
+ TQPtrList<KSMListener> listener;
+ TQPtrList<KSMClient> clients;
+
+ enum State
+ {
+ Idle,
+ LaunchingWM, AutoStart0, KcmInitPhase1, AutoStart1, Restoring, FinishingStartup, // startup
+ Shutdown, Checkpoint, Killing, KillingWM, WaitingForKNotify // shutdown
+ };
+ State state;
+ bool dialogActive;
+ bool saveSession;
+ int wmPhase1WaitingCount;
+ int saveType;
+ TQMap< TQCString, int > startupSuspendCount;
+
+ TDEApplication::ShutdownType shutdownType;
+ TDEApplication::ShutdownMode shutdownMode;
+ TQString bootOption;
+
+ bool clean;
+ KSMClient* clientInteracting;
+ TQString wm;
+ TQString wmAddArgs;
+ TQString sessionGroup;
+ TQString sessionName;
+ TQCString launcher;
+ TQTimer protectionTimer;
+ TQTimer notificationTimer;
+ TQTimer restoreTimer;
+ TQTimer shutdownTimer;
+ TQString xonCommand;
+ int logoutSoundEvent;
+ TQTimer knotifyTimeoutTimer;
+ TQTimer startupSuspendTimeoutTimer;
+ bool waitAutoStart2;
+ bool waitKcmInit2;
+ TQTimer pendingShutdown;
+ TDEApplication::ShutdownConfirm pendingShutdown_confirm;
+ TDEApplication::ShutdownType pendingShutdown_sdtype;
+ TDEApplication::ShutdownMode pendingShutdown_sdmode;
+
+ // ksplash interface
+ void upAndRunning( const TQString& msg );
+ void publishProgress( int progress, bool max = false );
+
+ // sequential startup
+ int appsToStart;
+ int lastAppStarted;
+ TQString lastIdStarted;
+
+ TQStringList excludeApps;
+
+ WindowMap legacyWindows;
+
+#ifdef __TDE_HAVE_TDEHWLIB
+ TDEHardwareDevices* hwDevices;
+#endif
+ int initialClientCount;
+ int phase2ClientCount;
+ int protectionTimerCounter;
+};
+
+#endif
diff --git a/ksmserver/server2.h b/ksmserver/server2.h
new file mode 100644
index 000000000..e16c9575c
--- /dev/null
+++ b/ksmserver/server2.h
@@ -0,0 +1,16 @@
+// This is in a separate file only because dcopidl doesn't handle
+// the extern "C" { ... } construct.
+
+#define INT32 QINT32
+#include <X11/Xlib.h>
+#include <X11/Xmd.h>
+#include <X11/ICE/ICElib.h>
+extern "C" {
+#include <X11/ICE/ICEutil.h>
+#include <X11/ICE/ICEmsg.h>
+#include <X11/ICE/ICEproto.h>
+#include <X11/SM/SM.h>
+#include <X11/SM/SMlib.h>
+}
+
+#include <fixx11h.h>
diff --git a/ksmserver/shutdown.cpp b/ksmserver/shutdown.cpp
new file mode 100644
index 000000000..a40bffc3b
--- /dev/null
+++ b/ksmserver/shutdown.cpp
@@ -0,0 +1,1062 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+Copyright (C) 2005 Lubos Lunak <[email protected]>
+
+relatively small extensions by Oswald Buddenhagen <[email protected]>
+
+some code taken from the dcopserver (part of the KDE libraries), which is
+Copyright (c) 1999 Matthias Ettrich <[email protected]>
+Copyright (c) 1999 Preston Brown <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <tqfile.h>
+#include <tqtextstream.h>
+#include <tqdatastream.h>
+#include <tqptrstack.h>
+#include <tqpushbutton.h>
+#include <tqmessagebox.h>
+#include <tqguardedptr.h>
+#include <tqtimer.h>
+#include <tqregexp.h>
+
+#include <tdelocale.h>
+#include <tdeglobal.h>
+#include <tdeconfig.h>
+#include <kstandarddirs.h>
+#include <unistd.h>
+#include <tdeapplication.h>
+#include <kstaticdeleter.h>
+#include <tdetempfile.h>
+#include <kprocess.h>
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <dmctl.h>
+#include <kdebug.h>
+#include <knotifyclient.h>
+
+#include <libtdersync/tdersync.h>
+
+#include "server.h"
+#include "global.h"
+#include "shutdowndlg.h"
+#include "client.h"
+
+#ifdef BUILD_PROFILE_SHUTDOWN
+#define PROFILE_SHUTDOWN 1
+#endif
+
+#ifdef PROFILE_SHUTDOWN
+ #define SHUTDOWN_MARKER(x) printf("[ksmserver] '%s' [%s]\n", x, TQTime::currentTime().toString("hh:mm:ss:zzz").ascii()); fflush(stdout);
+#else // PROFILE_SHUTDOWN
+ #define SHUTDOWN_MARKER(x)
+#endif // PROFILE_SHUTDOWN
+
+// Time to wait after close request for graceful application termination
+// If set too high running applications may be ungracefully terminated on slow machines or when many X11 applications are running
+#define KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT 20000
+
+// Time to wait before showing manual termination options
+// If set too low the user may be confused by buttons briefly flashing up on the screen during an otherwise normal logout process
+#define KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT 3000
+
+void KSMServer::logout( int confirm, int sdtype, int sdmode )
+{
+ shutdown( (TDEApplication::ShutdownConfirm)confirm,
+ (TDEApplication::ShutdownType)sdtype,
+ (TDEApplication::ShutdownMode)sdmode );
+}
+
+bool KSMServer::checkStatus( bool &logoutConfirmed, bool &maysd, bool &mayrb,
+ TDEApplication::ShutdownConfirm confirm,
+ TDEApplication::ShutdownType sdtype,
+ TDEApplication::ShutdownMode sdmode )
+{
+ pendingShutdown.stop();
+ if( dialogActive ) {
+ return false;
+ }
+ if( state >= Shutdown ) { // already performing shutdown
+ return false;
+ }
+ if( state != Idle ) { // performing startup
+ // perform shutdown as soon as startup is finished, in order to avoid saving partial session
+ if( !pendingShutdown.isActive()) {
+ pendingShutdown.start( 1000 );
+ pendingShutdown_confirm = confirm;
+ pendingShutdown_sdtype = sdtype;
+ pendingShutdown_sdmode = sdmode;
+ }
+ return false;
+ }
+
+ TDEConfig *config = TDEGlobal::config();
+ config->reparseConfiguration(); // config may have changed in the KControl module
+
+ config->setGroup("General" );
+ logoutConfirmed =
+ (confirm == TDEApplication::ShutdownConfirmYes) ? false :
+ (confirm == TDEApplication::ShutdownConfirmNo) ? true :
+ !config->readBoolEntry( "confirmLogout", true );
+ maysd = false;
+ mayrb = false;
+ if (config->readBoolEntry( "offerShutdown", true )) {
+ if (DM().canShutdown()) {
+ maysd = true;
+ mayrb = true;
+ }
+ else {
+#ifdef __TDE_HAVE_TDEHWLIB
+ TDERootSystemDevice* rootDevice = hwDevices->rootSystemDevice();
+ if (rootDevice) {
+ if (rootDevice->canPowerOff()) {
+ maysd = true;
+ }
+ if (rootDevice->canReboot()) {
+ mayrb = true;
+ }
+ }
+#endif
+ }
+ }
+ if (!maysd) {
+ if (sdtype != TDEApplication::ShutdownTypeNone &&
+ sdtype != TDEApplication::ShutdownTypeDefault &&
+ sdtype != TDEApplication::ShutdownTypeReboot &&
+ logoutConfirmed)
+ return false; /* unsupported fast shutdown */
+ }
+ if (!mayrb) {
+ if (sdtype != TDEApplication::ShutdownTypeNone &&
+ sdtype != TDEApplication::ShutdownTypeDefault &&
+ sdtype != TDEApplication::ShutdownTypeHalt &&
+ logoutConfirmed)
+ return false; /* unsupported fast shutdown */
+ }
+
+ return true;
+}
+
+void KSMServer::shutdownInternal( TDEApplication::ShutdownConfirm confirm,
+ TDEApplication::ShutdownType sdtype,
+ TDEApplication::ShutdownMode sdmode,
+ TQString bopt )
+{
+ bool maysd = false;
+ bool mayrb = false;
+ bool logoutConfirmed = false;
+ if ( !checkStatus( logoutConfirmed, maysd, mayrb, confirm, sdtype, sdmode ) ) {
+ return;
+ }
+
+ TDEConfig *config = TDEGlobal::config();
+
+ config->setGroup("General" );
+ if ((!maysd) && (sdtype != TDEApplication::ShutdownTypeReboot)) {
+ sdtype = TDEApplication::ShutdownTypeNone;
+ }
+ if ((!mayrb) && (sdtype != TDEApplication::ShutdownTypeHalt)) {
+ sdtype = TDEApplication::ShutdownTypeNone;
+ }
+ if (sdtype == TDEApplication::ShutdownTypeDefault) {
+ sdtype = (TDEApplication::ShutdownType) config->readNumEntry( "shutdownType", (int)TDEApplication::ShutdownTypeNone );
+ }
+ if (sdmode == TDEApplication::ShutdownModeDefault) {
+ sdmode = TDEApplication::ShutdownModeInteractive;
+ }
+
+ // shall we show a logout status dialog box?
+ bool showLogoutStatusDlg = TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("showLogoutStatusDlg", true);
+
+ if (showLogoutStatusDlg) {
+ KSMShutdownIPFeedback::start();
+ }
+
+ dialogActive = true;
+ if ( !logoutConfirmed ) {
+ int selection;
+ KSMShutdownFeedback::start(); // make the screen gray
+ logoutConfirmed =
+ KSMShutdownDlg::confirmShutdown( maysd, mayrb, sdtype, bopt, &selection );
+ // ###### We can't make the screen remain gray while talking to the apps,
+ // because this prevents interaction ("do you want to save", etc.)
+ // TODO: turn the feedback widget into a list of apps to be closed,
+ // with an indicator of the current status for each.
+ KSMShutdownFeedback::stop(); // make the screen become normal again
+ if (selection != 0) {
+ // respect lock on resume & disable suspend/hibernate settings
+ // from power-manager
+ TDEConfig config("power-managerrc");
+ bool lockOnResume = config.readBoolEntry("lockOnResume", true);
+ if (lockOnResume) {
+ TQCString replyType;
+ TQByteArray replyData;
+ // Block here until lock is complete
+ // If this is not done the desktop of the locked session will be shown after suspend/hibernate until the lock fully engages!
+ kapp->dcopClient()->call("kdesktop", "KScreensaverIface", "lock()", TQCString(""), replyType, replyData);
+ }
+#ifdef __TDE_HAVE_TDEHWLIB
+ TDERootSystemDevice* rootDevice = hwDevices->rootSystemDevice();
+ if (rootDevice) {
+ if (selection == 1) { // Suspend
+ rootDevice->setPowerState(TDESystemPowerState::Suspend);
+ }
+ if (selection == 2) { // Hibernate
+ rootDevice->setPowerState(TDESystemPowerState::Hibernate);
+ }
+ if (selection == 3) { // Freeze
+ rootDevice->setPowerState(TDESystemPowerState::Freeze);
+ }
+ }
+#endif
+ }
+ }
+
+ if ( logoutConfirmed ) {
+ SHUTDOWN_MARKER("Shutdown initiated");
+ shutdownType = sdtype;
+ shutdownMode = sdmode;
+ bootOption = bopt;
+ shutdownNotifierIPDlg = 0;
+ if (showLogoutStatusDlg) {
+ shutdownNotifierIPDlg = KSMShutdownIPDlg::showShutdownIP();
+ if (shutdownNotifierIPDlg) {
+ connect(shutdownNotifierIPDlg, SIGNAL(abortLogoutClicked()), this, SLOT(cancelShutdown()));
+ connect(shutdownNotifierIPDlg, SIGNAL(skipNotificationClicked()), this, SLOT(forceSkipSaveYourself()));
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying applications of logout request..."));
+ notificationTimer.start( KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT, true );
+ }
+ }
+
+ // shall we save the session on logout?
+ saveSession = ( config->readEntry( "loginMode", "restorePreviousLogout" ) == "restorePreviousLogout" );
+
+ if ( saveSession ) {
+ sessionGroup = TQString("Session: ") + SESSION_PREVIOUS_LOGOUT;
+ }
+
+ // Set the real desktop background to black so that exit looks
+ // clean regardless of what was on "our" desktop.
+ if (!showLogoutStatusDlg) {
+ TQT_TQWIDGET(kapp->desktop())->setBackgroundColor( Qt::black );
+ }
+ state = Shutdown;
+ wmPhase1WaitingCount = 0;
+ saveType = saveSession?SmSaveBoth:SmSaveGlobal;
+ performLegacySessionSave();
+ SHUTDOWN_MARKER("Legacy save complete");
+ startProtection();
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ c->resetState();
+ // Whoever came with the idea of phase 2 got it backwards
+ // unfortunately. Window manager should be the very first
+ // one saving session data, not the last one, as possible
+ // user interaction during session save may alter
+ // window positions etc.
+ // Moreover, KWin's focus stealing prevention would lead
+ // to undesired effects while session saving (dialogs
+ // wouldn't be activated), so it needs be assured that
+ // KWin will turn it off temporarily before any other
+ // user interaction takes place.
+ // Therefore, make sure the WM finishes its phase 1
+ // before others a chance to change anything.
+ // KWin will check if the session manager is ksmserver,
+ // and if yes it will save in phase 1 instead of phase 2.
+ if( isWM( c )) {
+ ++wmPhase1WaitingCount;
+ SmsSaveYourself( c->connection(), saveType,
+ true, SmInteractStyleAny, false );
+ }
+
+ }
+ if( wmPhase1WaitingCount == 0 ) { // no WM, simply start them all
+ for ( KSMClient* c = clients.first(); c; c = clients.next() )
+ SmsSaveYourself( c->connection(), saveType,
+ true, SmInteractStyleAny, false );
+ }
+ if ( clients.isEmpty() ) {
+ completeShutdownOrCheckpoint();
+ }
+ }
+ else {
+ if (showLogoutStatusDlg) {
+ KSMShutdownIPFeedback::stop();
+ }
+ }
+ dialogActive = false;
+}
+
+void KSMServer::shutdown( TDEApplication::ShutdownConfirm confirm,
+ TDEApplication::ShutdownType sdtype, TDEApplication::ShutdownMode sdmode )
+{
+ shutdownInternal( confirm, sdtype, sdmode );
+}
+
+#include <tdemessagebox.h>
+
+void KSMServer::logoutTimed( int sdtype, int sdmode, TQString bootOption )
+{
+ int confirmDelay = 0;
+
+ TDEConfig* config = TDEGlobal::config();
+ config->reparseConfiguration(); // config may have changed in the KControl module
+ config->setGroup( "General" );
+
+ if ( sdtype == TDEApplication::ShutdownTypeHalt ) {
+ confirmDelay = config->readNumEntry( "confirmShutdownDelay", 31 );
+ }
+ else if ( sdtype == TDEApplication::ShutdownTypeReboot ) {
+ confirmDelay = config->readNumEntry( "confirmRebootDelay", 31 );
+ }
+ else {
+ if(config->readBoolEntry("confirmLogout", true)) {
+ confirmDelay = config->readNumEntry( "confirmLogoutDelay", 31 );
+ }
+ }
+
+ bool result = true;
+ if (confirmDelay > 0) {
+ if(config->readBoolEntry("doFancyLogout", true)) {
+ KSMShutdownFeedback::start(); // make the screen gray
+ }
+ result = KSMDelayedMessageBox::showTicker( (TDEApplication::ShutdownType)sdtype, bootOption, confirmDelay );
+ if(config->readBoolEntry("doFancyLogout", true)) {
+ KSMShutdownFeedback::stop(); // make the screen become normal again
+ }
+ }
+
+ if ( result )
+ shutdownInternal( TDEApplication::ShutdownConfirmNo,
+ (TDEApplication::ShutdownType)sdtype,
+ (TDEApplication::ShutdownMode)sdmode,
+ bootOption );
+}
+
+void KSMServer::pendingShutdownTimeout()
+{
+ shutdown( pendingShutdown_confirm, pendingShutdown_sdtype, pendingShutdown_sdmode );
+}
+
+void KSMServer::saveCurrentSession()
+{
+ if ( state != Idle || dialogActive )
+ return;
+
+ if ( currentSession().isEmpty() || currentSession() == SESSION_PREVIOUS_LOGOUT )
+ sessionGroup = TQString("Session: ") + SESSION_BY_USER;
+
+ state = Checkpoint;
+ wmPhase1WaitingCount = 0;
+ saveType = SmSaveLocal;
+ saveSession = true;
+ performLegacySessionSave();
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ c->resetState();
+ if( isWM( c )) {
+ ++wmPhase1WaitingCount;
+ SmsSaveYourself( c->connection(), saveType, false, SmInteractStyleNone, false );
+ }
+ }
+ if( wmPhase1WaitingCount == 0 ) {
+ for ( KSMClient* c = clients.first(); c; c = clients.next() )
+ SmsSaveYourself( c->connection(), saveType, false, SmInteractStyleNone, false );
+ }
+ if ( clients.isEmpty() )
+ completeShutdownOrCheckpoint();
+}
+
+void KSMServer::saveCurrentSessionAs( TQString session )
+{
+ if ( state != Idle || dialogActive )
+ return;
+ sessionGroup = "Session: " + session;
+ saveCurrentSession();
+}
+
+// callbacks
+void KSMServer::saveYourselfDone( KSMClient* client, bool success )
+{
+ if ( state == Idle ) {
+ // State saving when it's not shutdown or checkpoint. Probably
+ // a shutdown was cancelled and the client is finished saving
+ // only now. Discard the saved state in order to avoid
+ // the saved data building up.
+ TQStringList discard = client->discardCommand();
+ if( !discard.isEmpty())
+ executeCommand( discard );
+ return;
+ }
+ if ( success ) {
+ client->saveYourselfDone = true;
+ completeShutdownOrCheckpoint();
+ } else {
+ // fake success to make KDE's logout not block with broken
+ // apps. A perfect ksmserver would display a warning box at
+ // the very end.
+ client->saveYourselfDone = true;
+ completeShutdownOrCheckpoint();
+ }
+ startProtection();
+ if( isWM( client ) && !client->wasPhase2 && wmPhase1WaitingCount > 0 ) {
+ --wmPhase1WaitingCount;
+ // WM finished its phase1, save the rest
+ if( wmPhase1WaitingCount == 0 ) {
+ for ( KSMClient* c = clients.first(); c; c = clients.next() )
+ if( !isWM( c ))
+ SmsSaveYourself( c->connection(), saveType, saveType != SmSaveLocal,
+ saveType != SmSaveLocal ? SmInteractStyleAny : SmInteractStyleNone,
+ false );
+ }
+ }
+
+ notificationTimer.stop();
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->hideNotificationActionButtons();
+ }
+
+ updateLogoutStatusDialog();
+}
+
+void KSMServer::updateLogoutStatusDialog()
+{
+ bool inPhase2 = true;
+ bool pendingInteraction = false;
+ for( KSMClient* c = clients.first(); c; c = clients.next()) {
+ if ( !c->saveYourselfDone && !c->waitForPhase2 ) {
+ inPhase2 = false;
+ }
+ if ( c->pendingInteraction ) {
+ pendingInteraction = true;
+ }
+ }
+ if (clientInteracting) {
+ pendingInteraction = true;
+ }
+
+ if (shutdownNotifierIPDlg) {
+ int waitingClients = 0;
+ TQString nextClientToKill;
+ TQDateTime currentDateTime = TQDateTime::currentDateTime();
+ TQDateTime oldestFoundDateTime = currentDateTime;
+ for( KSMClient* c = clients.first(); c; c = clients.next()) {
+ if (c->saveYourselfDone) {
+ continue;
+ }
+ if( isWM( c ) || isCM( c ) || isNotifier( c ) || isDesktop( c ) ) {
+ continue;
+ }
+ waitingClients++;
+ if (c->program() != "") {
+ if (c->terminationRequestTimeStamp < oldestFoundDateTime) {
+ nextClientToKill = c->program();
+ oldestFoundDateTime = c->terminationRequestTimeStamp;
+ }
+ }
+ }
+ if (inPhase2) {
+ if (phase2ClientCount > 0) {
+ if (!notificationTimer.isActive()) {
+ notificationTimer.start( KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT, true );
+ }
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setNotificationActionButtonsSkipText(i18n("Skip Notification (%1)").arg(((KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT - (protectionTimerCounter*1000))/1000)+1));
+ if (nextClientToKill == "") {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying remaining applications of logout request (%1/%2)...").arg(phase2ClientCount-waitingClients).arg(phase2ClientCount));
+ }
+ else {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying remaining applications of logout request (%1/%2, %3)...").arg(phase2ClientCount-waitingClients).arg(phase2ClientCount).arg(nextClientToKill));
+ }
+ }
+ }
+ else {
+ if (pendingInteraction) {
+#if 0
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setNotificationActionButtonsSkipText(i18n("Ignore and Resume Logout"));
+#else
+ // Hide dialog and buttons
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->hide();
+ notificationTimer.stop();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->hideNotificationActionButtons();
+#endif
+ if (nextClientToKill == "") {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("An application is requesting attention, logout paused..."));
+ }
+ else {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("%3 is requesting attention, logout paused...").arg(nextClientToKill));
+ }
+ }
+ else {
+ if (!notificationTimer.isActive()) {
+ notificationTimer.start( KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT, true );
+ }
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setNotificationActionButtonsSkipText(i18n("Skip Notification (%1)").arg(((KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT - (protectionTimerCounter*1000))/1000)+1));
+ if (nextClientToKill == "") {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying applications of logout request (%1/%2)...").arg(clients.count()-waitingClients).arg(clients.count()));
+ }
+ else {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying applications of logout request (%1/%2, %3)...").arg(clients.count()-waitingClients).arg(clients.count()).arg(nextClientToKill));
+ }
+ }
+ }
+ }
+}
+
+void KSMServer::interactRequest( KSMClient* client, int /*dialogType*/ )
+{
+ if ( state == Shutdown )
+ client->pendingInteraction = true;
+ else
+ SmsInteract( client->connection() );
+
+ handlePendingInteractions();
+}
+
+void KSMServer::interactDone( KSMClient* client, bool cancelShutdown_ )
+{
+ if ( client != clientInteracting )
+ return; // should not happen
+ clientInteracting = 0;
+ if ( cancelShutdown_ )
+ cancelShutdown( client );
+ else
+ handlePendingInteractions();
+}
+
+
+void KSMServer::phase2Request( KSMClient* client )
+{
+ client->waitForPhase2 = true;
+ client->wasPhase2 = true;
+ completeShutdownOrCheckpoint();
+ if( isWM( client ) && wmPhase1WaitingCount > 0 ) {
+ --wmPhase1WaitingCount;
+ // WM finished its phase1 and requests phase2, save the rest
+ if( wmPhase1WaitingCount == 0 ) {
+ for ( KSMClient* c = clients.first(); c; c = clients.next() )
+ if( !isWM( c ))
+ SmsSaveYourself( c->connection(), saveType, saveType != SmSaveLocal,
+ saveType != SmSaveLocal ? SmInteractStyleAny : SmInteractStyleNone,
+ false );
+ }
+ }
+}
+
+void KSMServer::handlePendingInteractions()
+{
+ if ( clientInteracting )
+ return;
+
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ if ( c->pendingInteraction ) {
+ clientInteracting = c;
+ c->pendingInteraction = false;
+ break;
+ }
+ }
+ if ( clientInteracting ) {
+ endProtection();
+ SmsInteract( clientInteracting->connection() );
+ } else {
+ startProtection();
+ }
+}
+
+void KSMServer::cancelShutdown( TQString cancellationText )
+{
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->closeSMDialog();
+ shutdownNotifierIPDlg=0;
+ }
+ KNotifyClient::event( 0, "cancellogout", cancellationText);
+ clientInteracting = 0;
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ SmsShutdownCancelled( c->connection() );
+ if( c->saveYourselfDone ) {
+ // Discard also saved state.
+ TQStringList discard = c->discardCommand();
+ if( !discard.isEmpty())
+ executeCommand( discard );
+ }
+ }
+ state = Idle;
+}
+
+void KSMServer::cancelShutdown( KSMClient* c )
+{
+ kdDebug( 1218 ) << "Client " << c->program() << " (" << c->clientId() << ") canceled shutdown." << endl;
+ cancelShutdown(i18n( "Logout canceled by '%1'" ).arg( c->program()));
+}
+
+void KSMServer::cancelShutdown()
+{
+ kdDebug( 1218 ) << "User canceled shutdown." << endl;
+ cancelShutdown(i18n( "Logout canceled by user" ));
+}
+
+void KSMServer::startProtection()
+{
+ protectionTimerCounter = 0;
+ protectionTimer.start( 1000, true );
+}
+
+void KSMServer::endProtection()
+{
+ protectionTimerCounter = 0;
+ protectionTimer.stop();
+}
+
+void KSMServer::protectionTimerTick()
+{
+ protectionTimerCounter++;
+ if ((protectionTimerCounter*1000) > KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT) {
+ protectionTimerCounter = 0;
+ protectionTimeout();
+ }
+ else {
+ protectionTimer.start( 1000, true );
+ }
+ updateLogoutStatusDialog();
+}
+
+/*
+ Internal protection slot, invoked when clients do not react during
+ shutdown.
+ */
+void KSMServer::protectionTimeout()
+{
+ if ( ( state != Shutdown && state != Checkpoint ) || clientInteracting )
+ return;
+
+ handleProtectionTimeout();
+
+ startProtection();
+}
+
+void KSMServer::forceSkipSaveYourself()
+{
+ SHUTDOWN_MARKER("forceSkipSaveYourself");
+
+ handleProtectionTimeout();
+
+ startProtection();
+}
+
+void KSMServer::handleProtectionTimeout()
+{
+ SHUTDOWN_MARKER("handleProtectionTimeout");
+
+ notificationTimer.stop();
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->hideNotificationActionButtons();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Forcing interacting application termination").append("..."));
+ }
+
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ if ( !c->saveYourselfDone && !c->waitForPhase2 ) {
+ kdDebug( 1218 ) << "protectionTimeout: client " << c->program() << "(" << c->clientId() << ")" << endl;
+ c->saveYourselfDone = true;
+ }
+ }
+ completeShutdownOrCheckpoint();
+}
+
+void KSMServer::notificationTimeout()
+{
+ if (shutdownNotifierIPDlg) {
+ // Display the buttons in the logout dialog
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->showNotificationActionButtons();
+ }
+}
+
+void KSMServer::completeShutdownOrCheckpoint()
+{
+ SHUTDOWN_MARKER("completeShutdownOrCheckpoint");
+ if ( state != Shutdown && state != Checkpoint ) {
+ SHUTDOWN_MARKER("completeShutdownOrCheckpoint state not Shutdown or Checkpoint");
+ return;
+ }
+
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ if ( !c->saveYourselfDone && !c->waitForPhase2 ) {
+ SHUTDOWN_MARKER("completeShutdownOrCheckpoint state not done yet");
+ return; // not done yet
+ }
+ }
+
+ // do phase 2
+ phase2ClientCount = 0;
+ bool waitForPhase2 = false;
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ if ( !c->saveYourselfDone && c->waitForPhase2 ) {
+ c->waitForPhase2 = false;
+ phase2ClientCount++;
+ SmsSaveYourselfPhase2( c->connection() );
+ waitForPhase2 = true;
+ }
+ }
+ if ( waitForPhase2 ) {
+ SHUTDOWN_MARKER("completeShutdownOrCheckpoint state still waiting for Phase 2");
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying remaining applications of logout request..."));
+ notificationTimer.start( KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT, true );
+ }
+ return;
+ }
+ SHUTDOWN_MARKER("Phase 2 complete");
+
+ bool showLogoutStatusDlg = TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("showLogoutStatusDlg", true);
+ if (showLogoutStatusDlg && state != Checkpoint) {
+ KSMShutdownIPFeedback::showit(); // hide the UGLY logout process from the user
+ if (!shutdownNotifierIPDlg) {
+ shutdownNotifierIPDlg = KSMShutdownIPDlg::showShutdownIP();
+ if (shutdownNotifierIPDlg) {
+ connect(shutdownNotifierIPDlg, SIGNAL(abortLogoutClicked()), this, SLOT(cancelShutdown()));
+ connect(shutdownNotifierIPDlg, SIGNAL(skipNotificationClicked()), this, SLOT(forceSkipSaveYourself()));
+ }
+ }
+ while (!KSMShutdownIPFeedback::ispainted()) {
+ tqApp->processEvents();
+ }
+ }
+
+ notificationTimer.stop();
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->hideNotificationActionButtons();
+ }
+
+ // synchronize any folders that were requested for shutdown sync
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Synchronizing remote folders").append("..."));
+ }
+ KRsync krs(this, "");
+ krs.executeLogoutAutoSync();
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Saving your settings..."));
+ }
+
+ if ( saveSession ) {
+ storeSession();
+ SHUTDOWN_MARKER("Session stored");
+ }
+ else {
+ discardSession();
+ SHUTDOWN_MARKER("Session discarded");
+ }
+
+ if ( state == Shutdown ) {
+ bool waitForKNotify = true;
+ if( !kapp->dcopClient()->connectDCOPSignal( "knotify", "",
+ "notifySignal(TQString,TQString,TQString,TQString,TQString,int,int,int,int)",
+ "ksmserver", "notifySlot(TQString,TQString,TQString,TQString,TQString,int,int,int,int)", false )) {
+ waitForKNotify = false;
+ }
+ if( !kapp->dcopClient()->connectDCOPSignal( "knotify", "",
+ "playingFinished(int,int)",
+ "ksmserver", "logoutSoundFinished(int,int)", false )) {
+ waitForKNotify = false;
+ }
+ // event() can return -1 if KNotifyClient short-circuits and avoids KNotify
+ logoutSoundEvent = KNotifyClient::event( 0, "exitkde" ); // KDE says good bye
+ if( logoutSoundEvent <= 0 ) {
+ waitForKNotify = false;
+ }
+ initialClientCount = clients.count();
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ TQString nextClientToKill;
+ TQDateTime currentDateTime = TQDateTime::currentDateTime();
+ TQDateTime oldestFoundDateTime = currentDateTime;
+ for( KSMClient* c = clients.first(); c; c = clients.next()) {
+ if( isWM( c ) || isCM( c ) || isNotifier( c ) || isDesktop( c ) ) {
+ continue;
+ }
+ if (c->program() != "") {
+ if (c->terminationRequestTimeStamp < oldestFoundDateTime) {
+ nextClientToKill = c->program();
+ oldestFoundDateTime = c->terminationRequestTimeStamp;
+ }
+ }
+ }
+ KSMShutdownIPDlg *shutdownNotifierDlg=static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg);
+ shutdownNotifierDlg->setProgressBarTotalSteps(initialClientCount);
+ shutdownNotifierDlg->setProgressBarProgress(initialClientCount-clients.count());
+ if (nextClientToKill == "") {
+ shutdownNotifierDlg->setStatusMessage(i18n("Closing applications (%1/%2)...").arg(initialClientCount-clients.count()).arg(initialClientCount));
+ }
+ else {
+ shutdownNotifierDlg->setStatusMessage(i18n("Closing applications (%1/%2, %3)...").arg(initialClientCount-clients.count()).arg(initialClientCount).arg(nextClientToKill));
+ }
+ }
+ if( waitForKNotify ) {
+ state = WaitingForKNotify;
+ knotifyTimeoutTimer.start( 20000, true );
+ return;
+ }
+ startKilling();
+ }
+ else if ( state == Checkpoint ) {
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ SmsSaveComplete( c->connection());
+ }
+ state = Idle;
+ }
+ SHUTDOWN_MARKER("Fully shutdown");
+}
+
+void KSMServer::startKilling()
+{
+ SHUTDOWN_MARKER("startKilling");
+ knotifyTimeoutTimer.stop();
+ // kill all clients
+ state = Killing;
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ if( isWM( c ) || isCM( c ) || isNotifier( c ) || isDesktop( c ) ) { // kill the WM and CM as the last one in order to reduce flicker. Also wait to kill knotify to avoid logout delays
+ continue;
+ }
+ kdDebug( 1218 ) << "completeShutdown: client " << c->program() << "(" << c->clientId() << ")" << endl;
+ c->terminationRequestTimeStamp = TQDateTime::currentDateTime();
+ SmsDie( c->connection() );
+ }
+
+ kdDebug( 1218 ) << " We killed all clients. We have now clients.count()=" << clients.count() << endl;
+ completeKilling();
+ shutdownTimer.start( KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT, TRUE );
+}
+
+void KSMServer::completeKilling()
+{
+ // Activity detected; reset forcible shutdown timer...
+ if (shutdownTimer.isActive()) {
+ shutdownTimer.start( KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT, TRUE );
+ }
+ SHUTDOWN_MARKER("completeKilling");
+ kdDebug( 1218 ) << "KSMServer::completeKilling clients.count()=" << clients.count() << endl;
+ if( state == Killing ) {
+ bool wait = false;
+ TQString nextClientToKill;
+ TQDateTime currentDateTime = TQDateTime::currentDateTime();
+ TQDateTime oldestFoundDateTime = currentDateTime;
+ for( KSMClient* c = clients.first(); c; c = clients.next()) {
+ if( isWM( c ) || isCM( c ) || isNotifier( c ) || isDesktop( c ) ) {
+ continue;
+ }
+ if (c->program() != "") {
+ if (c->terminationRequestTimeStamp < oldestFoundDateTime) {
+ nextClientToKill = c->program();
+ oldestFoundDateTime = c->terminationRequestTimeStamp;
+ }
+ wait = true; // still waiting for clients to go away
+ }
+ }
+ if( wait ) {
+ if (shutdownNotifierIPDlg) {
+ KSMShutdownIPDlg *shutdownNotifierDlg=static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg);
+ shutdownNotifierDlg->setProgressBarTotalSteps(initialClientCount);
+ shutdownNotifierDlg->setProgressBarProgress(initialClientCount-clients.count());
+ shutdownNotifierDlg->show();
+ if (nextClientToKill == "") {
+ shutdownNotifierDlg->setStatusMessage(i18n("Closing applications (%1/%2)...").arg(initialClientCount-clients.count()).arg(initialClientCount));
+ }
+ else {
+ shutdownNotifierDlg->setStatusMessage(i18n("Closing applications (%1/%2, %3)...").arg(initialClientCount-clients.count()).arg(initialClientCount).arg(nextClientToKill));
+ }
+ }
+ return;
+ }
+ else {
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->show();
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->setStatusMessage(i18n("Terminating services..."));
+ }
+ }
+ killWM();
+ }
+}
+
+void KSMServer::killWM()
+{
+ SHUTDOWN_MARKER("killWM");
+ state = KillingWM;
+ bool iswm = false;
+ if (shutdownNotifierIPDlg) {
+ static_cast<KSMShutdownIPDlg*>(shutdownNotifierIPDlg)->closeSMDialog();
+ shutdownNotifierIPDlg=0;
+ }
+ for ( KSMClient* c = clients.first(); c; c = clients.next() ) {
+ if( isDesktop( c )) {
+ iswm = true;
+ c->terminationRequestTimeStamp = TQDateTime::currentDateTime();
+ SmsDie( c->connection() );
+ }
+ if( isNotifier( c )) {
+ iswm = true;
+ c->terminationRequestTimeStamp = TQDateTime::currentDateTime();
+ SmsDie( c->connection() );
+ }
+ if( isCM( c )) {
+ iswm = true;
+ c->terminationRequestTimeStamp = TQDateTime::currentDateTime();
+ SmsDie( c->connection() );
+ }
+ if( isWM( c )) {
+ iswm = true;
+ kdDebug( 1218 ) << "killWM: client " << c->program() << "(" << c->clientId() << ")" << endl;
+ c->terminationRequestTimeStamp = TQDateTime::currentDateTime();
+ SmsDie( c->connection() );
+ }
+ }
+ if( iswm ) {
+ completeKillingWM();
+ TQTimer::singleShot( 5000, this, TQT_SLOT( timeoutWMQuit() ) );
+ }
+ else {
+ killingCompleted();
+ }
+}
+
+void KSMServer::completeKillingWM()
+{
+ SHUTDOWN_MARKER("completeKillingWM");
+ kdDebug( 1218 ) << "KSMServer::completeKillingWM clients.count()=" << clients.count() << endl;
+ if( state == KillingWM ) {
+ if( clients.isEmpty()) {
+ killingCompleted();
+ }
+ }
+}
+
+// shutdown is fully complete
+void KSMServer::killingCompleted()
+{
+ SHUTDOWN_MARKER("killingCompleted");
+ DM dmObject;
+ int dmType = dmObject.type();
+ if ((dmType == DM::NewTDM) || (dmType == DM::OldTDM) || (dmType == DM::GDM)) {
+ // Hide any remaining windows until the X server is terminated by the display manager
+ pid_t child;
+ child = fork();
+ if (child != 0) {
+ kapp->quit();
+ }
+ else if (child == 0) {
+ // If any remaining client(s) do not exit quickly (e.g. drkonqui) terminate so that they can be seen and interacted with
+ sleep(30);
+ exit(0);
+ }
+ }
+ else {
+ kapp->quit();
+ }
+}
+
+// called when KNotify performs notification for logout (not when sound is finished though)
+void KSMServer::notifySlot(TQString event ,TQString app,TQString,TQString,TQString,int present,int,int,int)
+{
+ SHUTDOWN_MARKER("notifySlot");
+ if( state != WaitingForKNotify ) {
+ SHUTDOWN_MARKER("notifySlot state != WaitingForKNotify");
+ return;
+ }
+ if( event != "exitkde" || app != "ksmserver" ) {
+ SHUTDOWN_MARKER("notifySlot event != \"exitkde\" || app != \"ksmserver\"");
+ return;
+ }
+ if( present & KNotifyClient::Sound ) { // logoutSoundFinished() will be called
+ SHUTDOWN_MARKER("notifySlot present & KNotifyClient::Sound");
+ return;
+ }
+ startKilling();
+}
+
+// This is stupid. The normal DCOP signal connected to notifySlot() above should be simply
+// emitted in KNotify only after the sound is finished playing.
+void KSMServer::logoutSoundFinished( int event, int )
+{
+ SHUTDOWN_MARKER("logoutSoundFinished");
+ if( state != WaitingForKNotify ) {
+ return;
+ }
+ if( event != logoutSoundEvent ) {
+ return;
+ }
+ startKilling();
+}
+
+void KSMServer::knotifyTimeout()
+{
+ SHUTDOWN_MARKER("knotifyTimeout");
+ if( state != WaitingForKNotify ) {
+ return;
+ }
+ startKilling();
+}
+
+void KSMServer::timeoutQuit()
+{
+ SHUTDOWN_MARKER("timeoutQuit");
+ for (KSMClient *c = clients.first(); c; c = clients.next()) {
+ SHUTDOWN_MARKER(TQString("SmsDie timeout, client %1 (%2)").arg(c->program()).arg(c->clientId()).ascii());
+ kdWarning( 1218 ) << "SmsDie timeout, client " << c->program() << "(" << c->clientId() << ")" << endl;
+ }
+ killWM();
+}
+
+void KSMServer::timeoutWMQuit()
+{
+ SHUTDOWN_MARKER("timeoutWMQuit");
+ if( state == KillingWM ) {
+ kdWarning( 1218 ) << "SmsDie WM timeout" << endl;
+ }
+ killingCompleted();
+}
diff --git a/ksmserver/shutdown.png b/ksmserver/shutdown.png
new file mode 100644
index 000000000..956f6cc3d
--- /dev/null
+++ b/ksmserver/shutdown.png
Binary files differ
diff --git a/ksmserver/shutdowndlg.cpp b/ksmserver/shutdowndlg.cpp
new file mode 100644
index 000000000..5c50602cb
--- /dev/null
+++ b/ksmserver/shutdowndlg.cpp
@@ -0,0 +1,1525 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2012 Serghei Amelian <[email protected]>
+Copyright (C) 2010 Timothy Pearson <[email protected]>
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#include "shutdowndlg.h"
+
+#include <tqapplication.h>
+#include <tqlayout.h>
+#include <tqgroupbox.h>
+#include <tqvbuttongroup.h>
+#include <tqlabel.h>
+#include <tqvbox.h>
+#include <tqtimer.h>
+#include <tqstyle.h>
+#include <tqcombobox.h>
+#include <tqcursor.h>
+#include <tqmessagebox.h>
+#include <tqbuttongroup.h>
+#include <tqiconset.h>
+#include <tqpixmap.h>
+#include <tqpopupmenu.h>
+#include <tqtooltip.h>
+#include <tqimage.h>
+#include <tqpainter.h>
+#include <tqfontmetrics.h>
+#include <tqregexp.h>
+#include <tqeventloop.h>
+
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+#ifdef __TDE_HAVE_TDEHWLIB
+#include <tdehardwaredevices.h>
+#endif
+#include <kdebug.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kguiitem.h>
+#include <kiconloader.h>
+#include <tdeglobalsettings.h>
+#include <twin.h>
+#include <kuser.h>
+#include <kpixmap.h>
+#include <kimageeffect.h>
+#include <kdialog.h>
+#include <kseparator.h>
+#include <tdeconfig.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dmctl.h>
+#include <tdeaction.h>
+#include <netwm.h>
+
+#include <X11/Xlib.h>
+
+#include "shutdowndlg.moc"
+
+KSMShutdownFeedback * KSMShutdownFeedback::s_pSelf = 0L;
+
+KSMShutdownFeedback::KSMShutdownFeedback()
+ : TQWidget( 0L, "feedbackwidget", WType_Popup ),
+ m_currentY( 0 ),
+ m_grayOpacity( 0.0f ),
+ m_compensation( 0.0f ),
+ m_fadeBackwards( FALSE ),
+ m_unfadedImage(),
+ m_grayImage(),
+ m_fadeTime(),
+ m_pmio(),
+ m_greyImageCreated( FALSE )
+
+{
+ if (kapp->isX11CompositionAvailable()) {
+ m_grayImage = TQImage( TQApplication::desktop()->width(), TQApplication::desktop()->height(), 32 );
+ m_grayImage = m_grayImage.convertDepth(32);
+ m_grayImage.setAlphaBuffer(false);
+ m_grayImage.fill(0); // Set the alpha buffer to 0 (fully transparent)
+ m_grayImage.setAlphaBuffer(true);
+ }
+ else {
+ // The hacks below aren't needed any more because Qt3 supports true transparency for the fading logout screen when composition is available
+ DCOPRef("kicker", "KMenu").call("hideMenu"); // Make sure the TDE Menu is completely removed from the screen before taking a snapshot...
+ m_grayImage = TQPixmap(TQPixmap::grabWindow(tqt_xrootwin(), 0, 0, TQApplication::desktop()->width(), TQApplication::desktop()->height())).convertToImage();
+ }
+ m_unfadedImage = m_grayImage;
+ resize(0, 0);
+ setShown(true);
+ TQTimer::singleShot( 500, this, TQT_SLOT( slotPaintEffect() ) );
+}
+
+// called after stopping shutdown-feedback -> smooth fade-back to color-mode
+void KSMShutdownFeedback::fadeBack( void )
+{
+ m_fadeTime.restart();
+ m_fadeBackwards = TRUE;
+ // its possible that we have to fade back, before all is completely gray, so we cannot start
+ // with completely gray when fading back...
+ m_compensation = 1.0f - m_grayOpacity;
+ // wait until we're completely back in color-mode...
+ while ( m_grayOpacity > 0.0f )
+ slotPaintEffect();
+}
+
+void KSMShutdownFeedback::slotPaintEffect()
+{
+ // determine which fade to use
+ if ( (TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("doFadeaway", true)) &&
+ (TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("doFancyLogout", true)) ) {
+ // fancy logout fade
+ float doFancyLogoutAdditionalDarkness = (float)TDEConfigGroup(TDEGlobal::config(), "Logout").readDoubleNumEntry("doFancyLogoutAdditionalDarkness", 0.6);
+ float doFancyLogoutFadeTime = (float)TDEConfigGroup(TDEGlobal::config(), "Logout").readDoubleNumEntry("doFancyLogoutFadeTime", 4000);
+ float doFancyLogoutFadeBackTime = (float)TDEConfigGroup(TDEGlobal::config(), "Logout").readDoubleNumEntry("doFancyLogoutFadeBackTime", 1000);
+
+ if (kapp->isX11CompositionAvailable()) {
+ // We can do this in a different (simpler) manner because we have compositing support!
+ // if slotPaintEffect() is called first time, we have to initialize the gray image
+ // we also could do that in the constructor, but then the displaying of the
+ // logout-UI would be too much delayed...
+ if ( m_greyImageCreated == false )
+ {
+ m_greyImageCreated = true;
+
+ // eliminate nasty flicker on first show
+ m_root.resize( width(), height() );
+ TQImage blendedImage = m_grayImage;
+ TQPainter p;
+ p.begin( &m_root );
+ blendedImage.setAlphaBuffer(false);
+ p.drawImage( 0, 0, blendedImage );
+ p.end();
+
+ setBackgroundPixmap( m_root );
+ setGeometry( TQApplication::desktop()->geometry() );
+ setBackgroundMode( TQWidget::NoBackground );
+
+ m_unfadedImage = m_grayImage.copy();
+
+ register uchar * r = m_grayImage.bits();
+ uchar * end = m_grayImage.bits() + m_grayImage.numBytes();
+
+ while ( r != end ) {
+ *reinterpret_cast<TQRgb*>(r) = tqRgba(0, 0, 0, 128);
+ r += 4;
+ }
+
+ // start timer which is used for cpu-speed-independent fading
+ m_fadeTime.start();
+ m_rowsDone = 0;
+ }
+
+ // return if fading is completely done...
+ if ( ( m_grayOpacity >= 1.0f && m_fadeBackwards == FALSE ) || ( m_grayOpacity <= 0.0f && m_fadeBackwards == TRUE ) )
+ return;
+
+
+ if ( m_fadeBackwards == FALSE )
+ {
+ m_grayOpacity = m_fadeTime.elapsed() / doFancyLogoutFadeTime;
+ if ( m_grayOpacity > 1.0f )
+ m_grayOpacity = 1.0f;
+ }
+ else
+ {
+ m_grayOpacity = 1.0f - m_fadeTime.elapsed() / doFancyLogoutFadeBackTime - m_compensation;
+ if ( m_grayOpacity < 0.0f )
+ m_grayOpacity = 0.0f;
+ }
+
+ const int imgWidth = m_unfadedImage.width();
+ int imgHeight = m_unfadedImage.height();
+ int heightUnit = imgHeight / 3;
+ if( heightUnit < 1 )
+ heightUnit = 1;
+
+ int y1 = static_cast<int>( imgHeight*m_grayOpacity - heightUnit + m_grayOpacity*heightUnit*2.0f );
+ if( y1 > imgHeight )
+ y1 = imgHeight;
+
+ int y2 = y1+heightUnit;
+ if( y2 > imgHeight )
+ y2 = imgHeight;
+
+ if( m_fadeBackwards == FALSE )
+ {
+ if( y1 > 0 && y1 < imgHeight && y1-m_rowsDone > 0 && m_rowsDone < imgHeight )
+ {
+ TQImage img( imgWidth, y1-m_rowsDone, 32 );
+ memcpy( img.bits(), m_grayImage.scanLine( m_rowsDone ), imgWidth*(y1-m_rowsDone)*4 );
+ bitBlt( this, 0, m_rowsDone, &img );
+ m_rowsDone = y1;
+ }
+ }
+ else
+ {
+ // when fading back we have to blit area which isnt gray anymore to unfaded image
+ if( y2 > 0 && y2 < imgHeight && m_rowsDone > y2 )
+ {
+ TQImage img( imgWidth, m_rowsDone-y2, 32 );
+ memcpy( img.bits(), m_unfadedImage.scanLine( y2 ), imgWidth*(m_rowsDone-y2)*4 );
+ bitBlt( this, 0, y2, &img );
+ m_rowsDone = y2;
+ }
+ }
+
+ int start_y1 = y1;
+ if( start_y1 < 0 )
+ start_y1 = 0;
+ if( y2 > start_y1 )
+ {
+ TQImage img( imgWidth, y2-start_y1, 32 );
+ memcpy( img.bits(), m_grayImage.scanLine( start_y1 ), ( y2-start_y1 ) * imgWidth * 4 );
+ register uchar * rs = m_unfadedImage.scanLine( start_y1 );
+ register uchar * rd = img.bits();
+ for( int y = start_y1; y < y2; ++y )
+ {
+ // linear gradients look bad, so use cos-function
+ short int opac = static_cast<short int>( 128 - cosf( M_PI*(y-y1)/heightUnit )*128.0f );
+ for( short int x = 0; x < imgWidth; ++x )
+ {
+ *reinterpret_cast<TQRgb*>(rd) = tqRgba(0, 0, 0, ((255.0-opac)/(255.0/127.0)));
+ rs += 4; rd += 4;
+ }
+ }
+ bitBlt( this, 0, start_y1, &img );
+ }
+
+ TQTimer::singleShot( 5, this, TQT_SLOT( slotPaintEffect() ) );
+ }
+ else {
+ // if slotPaintEffect() is called first time, we have to initialize the gray image
+ // we also could do that in the constructor, but then the displaying of the
+ // logout-UI would be too much delayed...
+ if ( m_greyImageCreated == false )
+ {
+ m_greyImageCreated = true;
+
+ setBackgroundMode( TQWidget::NoBackground );
+ setGeometry( TQApplication::desktop()->geometry() );
+ m_root.resize( width(), height() ); // for the default logout
+
+ m_unfadedImage = m_grayImage.copy();
+
+ register uchar * r = m_grayImage.bits();
+ register uchar * g = m_grayImage.bits() + 1;
+ register uchar * b = m_grayImage.bits() + 2;
+ uchar * end = m_grayImage.bits() + m_grayImage.numBytes();
+
+ while ( r != end ) {
+ *r = *g = *b = (uchar) ( ( (*r)*11 + ((*g)<<4) + (*b)*5 ) * doFancyLogoutAdditionalDarkness / 32.0f );
+ r += 4;
+ g += 4;
+ b += 4;
+ }
+
+ // start timer which is used for cpu-speed-independent fading
+ m_fadeTime.start();
+ m_rowsDone = 0;
+ }
+
+ // return if fading is completely done...
+ if ( ( m_grayOpacity >= 1.0f && m_fadeBackwards == FALSE ) || ( m_grayOpacity <= 0.0f && m_fadeBackwards == TRUE ) )
+ return;
+
+
+ if ( m_fadeBackwards == FALSE )
+ {
+ m_grayOpacity = m_fadeTime.elapsed() / doFancyLogoutFadeTime;
+ if ( m_grayOpacity > 1.0f )
+ m_grayOpacity = 1.0f;
+ }
+ else
+ {
+ m_grayOpacity = 1.0f - m_fadeTime.elapsed() / doFancyLogoutFadeBackTime - m_compensation;
+ if ( m_grayOpacity < 0.0f )
+ m_grayOpacity = 0.0f;
+ }
+
+ const int imgWidth = m_unfadedImage.width();
+ int imgHeight = m_unfadedImage.height();
+ int heightUnit = imgHeight / 3;
+ if( heightUnit < 1 )
+ heightUnit = 1;
+
+ int y1 = static_cast<int>( imgHeight*m_grayOpacity - heightUnit + m_grayOpacity*heightUnit*2.0f );
+ if( y1 > imgHeight )
+ y1 = imgHeight;
+
+ int y2 = y1+heightUnit;
+ if( y2 > imgHeight )
+ y2 = imgHeight;
+
+ if( m_fadeBackwards == FALSE )
+ {
+ if( y1 > 0 && y1 < imgHeight && y1-m_rowsDone > 0 && m_rowsDone < imgHeight )
+ {
+ TQImage img( imgWidth, y1-m_rowsDone, 32 );
+ memcpy( img.bits(), m_grayImage.scanLine( m_rowsDone ), imgWidth*(y1-m_rowsDone)*4 );
+ // conversion is slow as hell if desktop-depth != 24bpp...
+ //Pixmap pm = m_pmio.convertToPixmap( img );
+ //bitBlt( this, 0, m_rowsDone, &pm );
+ //TQImage pm = m_pmio.convertToImage( img );
+ bitBlt( this, 0, m_rowsDone, &img );
+ m_rowsDone = y1;
+ }
+ }
+ else
+ {
+ // when fading back we have to blit area which isnt gray anymore to unfaded image
+ if( y2 > 0 && y2 < imgHeight && m_rowsDone > y2 )
+ {
+ TQImage img( imgWidth, m_rowsDone-y2, 32 );
+ memcpy( img.bits(), m_unfadedImage.scanLine( y2 ), imgWidth*(m_rowsDone-y2)*4 );
+ // conversion is slow as hell if desktop-depth != 24bpp...
+ //TQPixmap pm = m_pmio.convertToPixmap( img );
+ //bitBlt( this, 0, y2, &pm );
+ bitBlt( this, 0, y2, &img );
+ m_rowsDone = y2;
+ }
+ }
+
+ int start_y1 = y1;
+ if( start_y1 < 0 )
+ start_y1 = 0;
+ if( y2 > start_y1 )
+ {
+ TQImage img( imgWidth, y2-start_y1, 32 );
+ memcpy( img.bits(), m_grayImage.scanLine( start_y1 ), ( y2-start_y1 ) * imgWidth * 4 );
+ register uchar * rs = m_unfadedImage.scanLine( start_y1 );
+ register uchar * gs = rs + 1;
+ register uchar * bs = gs + 1;
+ register uchar * rd = img.bits();
+ register uchar * gd = rd + 1;
+ register uchar * bd = gd + 1;
+ for( int y = start_y1; y < y2; ++y )
+ {
+ // linear gradients look bad, so use cos-function
+ short int opac = static_cast<short int>( 128 - cosf( M_PI*(y-y1)/heightUnit )*128.0f );
+ for( short int x = 0; x < imgWidth; ++x )
+ {
+ *rd += ( ( ( *rs - *rd ) * opac ) >> 8 );
+ rs += 4; rd += 4;
+ *gd += ( ( ( *gs - *gd ) * opac ) >> 8 );
+ gs += 4; gd += 4;
+ *bd += ( ( ( *bs - *bd ) * opac ) >> 8 );
+ bs += 4; bd += 4;
+ }
+ }
+ // conversion is slow as hell if desktop-depth != 24bpp...
+ //TQPixmap pm = m_pmio.convertToPixmap( img );
+ //bitBlt( this, 0, start_y1, &pm );
+ bitBlt( this, 0, start_y1, &img );
+ }
+
+ TQTimer::singleShot( 5, this, TQT_SLOT( slotPaintEffect() ) );
+ }
+ }
+ else {
+ if (TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("doFadeaway", true)) {
+ // standard logout fade
+ if (kapp->isX11CompositionAvailable()) {
+ // We can do this in a different (simpler) manner because we have compositing support!
+ // The end effect will be very similar to the old style logout
+ float doFancyLogoutFadeTime = 1000;
+ float doFancyLogoutFadeBackTime = 0;
+ if ( m_greyImageCreated == false ) {
+ m_greyImageCreated = true;
+
+ // eliminate nasty flicker on first show
+ m_root.resize( width(), height() );
+ TQImage blendedImage = m_grayImage;
+ TQPainter p;
+ p.begin( &m_root );
+ blendedImage.setAlphaBuffer(false);
+ p.drawImage( 0, 0, blendedImage );
+ p.end();
+
+ setBackgroundPixmap( m_root );
+ setGeometry( TQApplication::desktop()->geometry() );
+ setBackgroundMode( TQWidget::NoBackground );
+
+ m_unfadedImage = m_grayImage.copy();
+
+ register uchar * r = m_grayImage.bits();
+ uchar * end = m_grayImage.bits() + m_grayImage.numBytes();
+
+ while ( r != end ) {
+ *reinterpret_cast<TQRgb*>(r) = tqRgba(0, 0, 0, 107);
+ r += 4;
+ }
+
+ // start timer which is used for cpu-speed-independent fading
+ m_fadeTime.start();
+ m_rowsDone = 0;
+ }
+
+ // return if fading is completely done...
+ if ( ( m_grayOpacity >= 1.0f && m_fadeBackwards == FALSE ) || ( m_grayOpacity <= 0.0f && m_fadeBackwards == TRUE ) ) {
+ return;
+ }
+
+ if ( m_fadeBackwards == FALSE ) {
+ m_grayOpacity = m_fadeTime.elapsed() / doFancyLogoutFadeTime;
+ if ( m_grayOpacity > 1.0f )
+ m_grayOpacity = 1.0f;
+ }
+ else {
+ m_grayOpacity = 1.0f - m_fadeTime.elapsed() / doFancyLogoutFadeBackTime - m_compensation;
+ if ( m_grayOpacity < 0.0f )
+ m_grayOpacity = 0.0f;
+ }
+
+ const int imgWidth = m_unfadedImage.width();
+ int imgHeight = m_unfadedImage.height();
+ int heightUnit = imgHeight / 3;
+ if( heightUnit < 1 )
+ heightUnit = 1;
+
+ int y1 = static_cast<int>( imgHeight*m_grayOpacity - heightUnit + m_grayOpacity*heightUnit*2.0f );
+ if( y1 > imgHeight ) {
+ y1 = imgHeight;
+ }
+
+ int y2 = y1+heightUnit;
+ if( y2 > imgHeight ) {
+ y2 = imgHeight;
+ }
+
+ if( m_fadeBackwards == FALSE )
+ {
+ if( y1 > 0 && y1 < imgHeight && y1-m_rowsDone > 0 && m_rowsDone < imgHeight )
+ {
+ TQImage img( imgWidth, y1-m_rowsDone, 32 );
+ memcpy( img.bits(), m_grayImage.scanLine( m_rowsDone ), imgWidth*(y1-m_rowsDone)*4 );
+ bitBlt( this, 0, m_rowsDone, &img );
+ m_rowsDone = y1;
+ }
+ }
+ else {
+ // when fading back we have to blit area which isnt gray anymore to unfaded image
+ if( y2 > 0 && y2 < imgHeight && m_rowsDone > y2 )
+ {
+ TQImage img( imgWidth, m_rowsDone-y2, 32 );
+ memcpy( img.bits(), m_unfadedImage.scanLine( y2 ), imgWidth*(m_rowsDone-y2)*4 );
+ bitBlt( this, 0, y2, &img );
+ m_rowsDone = y2;
+ }
+ }
+
+ int start_y1 = y1;
+ if( start_y1 < 0 ) {
+ start_y1 = 0;
+ }
+ if( y2 > start_y1 ) {
+ TQImage img( imgWidth, y2-start_y1, 32 );
+ memcpy( img.bits(), m_grayImage.scanLine( start_y1 ), ( y2-start_y1 ) * imgWidth * 4 );
+ register uchar * rs = m_unfadedImage.scanLine( start_y1 );
+ register uchar * rd = img.bits();
+ for( int y = start_y1; y < y2; ++y )
+ {
+ // linear gradients look bad, so use cos-function
+ for( short int x = 0; x < imgWidth; ++x )
+ {
+ *reinterpret_cast<TQRgb*>(rd) = tqRgba(0, 0, 0, 107);
+ rs += 4; rd += 4;
+ }
+ }
+ bitBlt( this, 0, start_y1, &img );
+ }
+
+ TQTimer::singleShot( 1, this, TQT_SLOT( slotPaintEffect() ) );
+ }
+ else {
+ if ( m_currentY >= height() ) {
+ if ( backgroundMode() == TQWidget::NoBackground ) {
+ setBackgroundMode( TQWidget::NoBackground );
+ setBackgroundPixmap( m_root );
+ }
+ return;
+ }
+
+ if ( m_currentY == 0 ) {
+ setBackgroundMode( TQWidget::NoBackground );
+ setGeometry( TQApplication::desktop()->geometry() );
+ m_root.resize( width(), height() ); // for the default logout
+
+ KPixmap pixmap;
+ pixmap = TQPixmap(TQPixmap::grabWindow( tqt_xrootwin(), 0, 0, width(), height() ));
+ bitBlt( this, 0, 0, &pixmap );
+ bitBlt( &m_root, 0, 0, &pixmap );
+ }
+
+ KPixmap pixmap;
+ pixmap = TQPixmap(TQPixmap::grabWindow( tqt_xrootwin(), 0, m_currentY, width(), 10 ));
+ TQImage image = pixmap.convertToImage();
+ KImageEffect::blend( Qt::black, image, 0.4 );
+ KImageEffect::toGray( image, true );
+ pixmap.convertFromImage( image );
+ bitBlt( this, 0, m_currentY, &pixmap );
+ bitBlt( &m_root, 0, m_currentY, &pixmap );
+ m_currentY += 10;
+ TQTimer::singleShot( 1, this, TQT_SLOT( slotPaintEffect() ) );
+ }
+ }
+ }
+
+}
+
+//////
+
+KSMShutdownIPFeedback * KSMShutdownIPFeedback::s_pSelf = 0L;
+
+KSMShutdownIPFeedback::KSMShutdownIPFeedback()
+: TQWidget( 0L, "systemmodaldialogclass", Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_StaysOnTop ), m_timeout(0), m_isPainted(false), m_paintedFromSharedRootPixmap(false), m_sharedRootPixmap(NULL), mPixmapTimeout(0)
+
+{
+ setShown(false);
+ hide();
+
+ enableExports();
+
+ m_sharedRootPixmap = new KRootPixmap(this);
+ m_sharedRootPixmap->setCustomPainting(true);
+ connect(m_sharedRootPixmap, TQT_SIGNAL(backgroundUpdated(const TQPixmap &)), this, TQT_SLOT(slotSetBackgroundPixmap(const TQPixmap &)));
+
+ if (TQPaintDevice::x11AppDepth() == 32) {
+ // The shared pixmap is 24 bits, but we are 32 bits
+ // Therefore our only option is to use a 24-bit Xorg application to dump the shared pixmap in a common (png) format for loading later
+ TQString filename = getenv("USER");
+ filename.prepend("/tmp/tde-");
+ filename.append("/krootbacking.png");
+ remove(filename.ascii());
+ system("krootbacking &");
+ }
+
+ m_screenGeometry = TQApplication::desktop()->geometry();
+
+ // eliminate nasty flicker on first show
+ m_root.resize(m_screenGeometry.width(), m_screenGeometry.height());
+ TQPainter p;
+ p.begin( &m_root );
+ p.fillRect( 0, 0, m_root.width(), m_root.height(), TQBrush(tqRgba(0, 0, 0, 0)) );
+ p.end();
+
+ setBackgroundPixmap( m_root );
+ setGeometry( m_screenGeometry );
+ setBackgroundMode( TQWidget::NoBackground );
+}
+
+void KSMShutdownIPFeedback::showNow()
+{
+ setShown(true);
+
+ if (!m_isPainted) {
+ setGeometry( TQApplication::desktop()->geometry() );
+ TQTimer::singleShot( 0, this, SLOT(slotPaintEffect()) );
+ }
+}
+
+void KSMShutdownIPFeedback::enableExports()
+{
+#ifdef Q_WS_X11
+ kdDebug(270) << k_lineinfo << "activating background exports.\n";
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isAttached()) {
+ client->attach();
+ }
+ TQByteArray data;
+ TQDataStream args( data, IO_WriteOnly );
+ args << 1;
+
+ TQCString appname( "kdesktop" );
+ int screen_number = DefaultScreen(tqt_xdisplay());
+ if ( screen_number )
+ appname.sprintf("kdesktop-screen-%d", screen_number );
+
+ client->send( appname, "KBackgroundIface", "setExport(int)", data );
+#endif
+}
+
+KSMShutdownIPFeedback::~KSMShutdownIPFeedback()
+{
+ if (m_sharedRootPixmap) {
+ m_sharedRootPixmap->stop();
+ delete m_sharedRootPixmap;
+ m_sharedRootPixmap = NULL;
+ }
+}
+
+void KSMShutdownIPFeedback::fadeBack( void ) {
+ //
+}
+
+void KSMShutdownIPFeedback::resizeEvent(TQResizeEvent* re) {
+ if (m_isPainted) {
+ // Resist all attempts to change size
+ setGeometry( m_screenGeometry );
+ }
+}
+
+void KSMShutdownIPFeedback::slotSetBackgroundPixmap(const TQPixmap &rpm) {
+ m_rootPixmap = rpm;
+}
+
+void KSMShutdownIPFeedback::slotPaintEffect()
+{
+ if (m_isPainted && m_paintedFromSharedRootPixmap) {
+ return;
+ }
+
+ TQPixmap pm = m_rootPixmap;
+ if (mPixmapTimeout == 0) {
+ if (TQPaintDevice::x11AppDepth() != 32) {
+ m_sharedRootPixmap->start();
+ }
+
+ TQTimer::singleShot( 100, this, SLOT(slotPaintEffect()) );
+ mPixmapTimeout++;
+ return;
+ }
+ if (TQPaintDevice::x11AppDepth() == 32) {
+ TQString filename = getenv("USER");
+ filename.prepend("/tmp/tde-");
+ filename.append("/krootbacking.png");
+ bool success = pm.load(filename, "PNG");
+ if (!success) {
+ pm = TQPixmap();
+ }
+ }
+ if ((pm.isNull()) || (pm.width() != kapp->desktop()->width()) || (pm.height() != kapp->desktop()->height())) {
+ if (mPixmapTimeout < 10) {
+ TQTimer::singleShot( 100, this, SLOT(slotPaintEffect()) );
+ mPixmapTimeout++;
+ return;
+ }
+ else {
+ pm = TQPixmap(kapp->desktop()->width(), kapp->desktop()->height());
+ pm.fill(Qt::black);
+ m_paintedFromSharedRootPixmap = false;
+ }
+ }
+ else {
+ m_paintedFromSharedRootPixmap = true;
+ if (m_sharedRootPixmap) {
+ m_sharedRootPixmap->stop();
+ delete m_sharedRootPixmap;
+ m_sharedRootPixmap = NULL;
+ }
+ }
+
+ if (TQPaintDevice::x11AppDepth() == 32) {
+ // Remove the alpha components from the image
+ TQImage correctedImage = pm.convertToImage();
+ correctedImage = correctedImage.convertDepth(32);
+ correctedImage.setAlphaBuffer(true);
+ int w = correctedImage.width();
+ int h = correctedImage.height();
+ for (int y = 0; y < h; ++y) {
+ TQRgb *ls = (TQRgb *)correctedImage.scanLine( y );
+ for (int x = 0; x < w; ++x) {
+ TQRgb l = ls[x];
+ int r = int( tqRed( l ) );
+ int g = int( tqGreen( l ) );
+ int b = int( tqBlue( l ) );
+ int a = int( 255 );
+ ls[x] = tqRgba( r, g, b, a );
+ }
+ }
+ pm.convertFromImage(correctedImage);
+ }
+
+ setBackgroundPixmap( pm );
+ move(0,0);
+ setWindowState(WindowFullScreen);
+ m_screenGeometry = TQApplication::desktop()->geometry();
+ setGeometry( m_screenGeometry );
+
+ repaint(true);
+ tqApp->flushX();
+
+ m_isPainted = true;
+}
+
+//////
+
+KSMShutdownDlg::KSMShutdownDlg( TQWidget* parent,
+ bool maysd, bool mayrb, TDEApplication::ShutdownType sdtype, int* selection )
+ : TQDialog( parent, 0, TRUE, (WFlags)WType_Popup ), targets(0), m_selection(selection)
+ // this is a WType_Popup on purpose. Do not change that! Not
+ // having a popup here has severe side effects.
+
+{
+ TQVBoxLayout* vbox = new TQVBoxLayout( this );
+
+ if (m_selection) {
+ *m_selection = 0;
+ }
+
+ TQFrame* frame = new TQFrame( this );
+ frame->setFrameStyle( TQFrame::StyledPanel | TQFrame::Raised );
+ frame->setLineWidth( style().pixelMetric( TQStyle::PM_DefaultFrameWidth, frame ) );
+ // we need to set the minimum size for the logout box, since it
+ // gets too small if there isn't all options available
+ frame->setMinimumWidth(400);
+ vbox->addWidget( frame );
+ vbox = new TQVBoxLayout( frame, 2 * KDialog::marginHint(),
+ 2 * KDialog::spacingHint() );
+
+ // default factor
+ bool doUbuntuLogout = TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("doUbuntuLogout", false);
+
+ // slighty more space for the new logout
+ int factor = 2;
+
+ if(doUbuntuLogout)
+ {
+ factor = 8;
+ }
+ else {
+ TQLabel* label = new TQLabel( i18n("End Session for \"%1\"").arg(KUser().loginName()), frame );
+ TQFont fnt = label->font();
+ fnt.setBold( true );
+ fnt.setPointSize( fnt.pointSize() * 3 / 2 );
+ label->setFont( fnt );
+ vbox->addWidget( label, 0, AlignHCenter );
+ }
+
+ // for the basic layout, within this box either the ubuntu dialog or
+ // standard konqy+buttons will be placed.
+ TQHBoxLayout* hbox = new TQHBoxLayout( vbox, factor * KDialog::spacingHint() );
+
+ // from here on we have to adapt to the two different dialogs
+ TQFrame* lfrm;
+ TQVBoxLayout* buttonlay;
+ TQHBoxLayout* hbuttonbox;
+ TQFont btnFont;
+
+ if(doUbuntuLogout)
+ {
+ // first line of buttons
+ hbuttonbox = new TQHBoxLayout( hbox, factor * KDialog::spacingHint() );
+ hbuttonbox->setAlignment( Qt::AlignHCenter );
+ // End session
+ FlatButton* btnLogout = new FlatButton( frame );
+ btnLogout->setTextLabel( TQString("&") + i18n("Log out"), false );
+ btnLogout->setPixmap( DesktopIcon( "back") );
+ int i = btnLogout->textLabel().find( TQRegExp("\\&"), 0 ); // i == 1
+ btnLogout->setAccel( "ALT+" + btnLogout->textLabel().lower()[i+1] ) ;
+ hbuttonbox->addWidget ( btnLogout );
+ connect(btnLogout, TQT_SIGNAL(clicked()), TQT_SLOT(slotLogout()));
+
+ }
+ else
+ {
+
+ // konqy
+ lfrm = new TQFrame( frame );
+ lfrm->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
+ hbox->addWidget( lfrm, AlignCenter );
+
+ buttonlay = new TQVBoxLayout( hbox, factor * KDialog::spacingHint() );
+ buttonlay->setAlignment( Qt::AlignHCenter );
+
+ TQLabel* icon = new TQLabel( lfrm );
+ if (TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("doNotUseKonqyPicture", false)) {
+ icon->setPixmap( UserIcon( "shutdown" ) );
+ }
+ else {
+ icon->setPixmap( UserIcon( "shutdownkonq" ) );
+ }
+ lfrm->setFixedSize( icon->sizeHint());
+ icon->setFixedSize( icon->sizeHint());
+
+ buttonlay->addStretch( 1 );
+ // End session
+ KPushButton* btnLogout = new KPushButton( KGuiItem( i18n("&End Current Session"), "edit-undo"), frame );
+ TQToolTip::add( btnLogout, i18n( "<qt><h3>End Current Session</h3><p>Log out of the current session to login with a different user</p></qt>" ) );
+ btnFont = btnLogout->font();
+ buttonlay->addWidget( btnLogout );
+ connect(btnLogout, TQT_SIGNAL(clicked()), TQT_SLOT(slotLogout()));
+ }
+
+#ifdef COMPILE_HALBACKEND
+ m_halCtx = NULL;
+#endif
+
+ if ((maysd) || (mayrb)) {
+
+ // respect lock on resume & disable suspend/hibernate settings
+ // from power-manager
+ TDEConfig config("power-managerrc");
+ bool disableSuspend = config.readBoolEntry("disableSuspend", false);
+ bool disableHibernate = config.readBoolEntry("disableHibernate", false);
+ m_lockOnResume = config.readBoolEntry("lockOnResume", true);
+
+ bool canFreeze = false;
+ bool canSuspend = false;
+ bool canHibernate = false;
+
+#if defined(COMPILE_HALBACKEND)
+ // Query HAL for suspend/resume support
+ m_halCtx = libhal_ctx_new();
+
+ DBusError error;
+ dbus_error_init(&error);
+ m_dbusConn = dbus_connection_open_private(DBUS_SYSTEM_BUS, &error);
+ if (!m_dbusConn)
+ {
+ dbus_error_free(&error);
+ libhal_ctx_free(m_halCtx);
+ m_halCtx = NULL;
+ }
+ else
+ {
+ dbus_bus_register(m_dbusConn, &error);
+ if (dbus_error_is_set(&error))
+ {
+ dbus_error_free(&error);
+ libhal_ctx_free(m_halCtx);
+ m_dbusConn = NULL;
+ m_halCtx = NULL;
+ }
+ else
+ {
+ libhal_ctx_set_dbus_connection(m_halCtx, m_dbusConn);
+ if (!libhal_ctx_init(m_halCtx, &error))
+ {
+ if (dbus_error_is_set(&error))
+ dbus_error_free(&error);
+ libhal_ctx_free(m_halCtx);
+ m_dbusConn = NULL;
+ m_halCtx = NULL;
+ }
+ }
+ }
+
+ if (m_halCtx)
+ {
+ if (libhal_device_get_property_bool(m_halCtx,
+ "/org/freedesktop/Hal/devices/computer",
+ "power_management.can_suspend",
+ NULL))
+ {
+ canSuspend = true;
+ }
+
+ if (libhal_device_get_property_bool(m_halCtx,
+ "/org/freedesktop/Hal/devices/computer",
+ "power_management.can_hibernate",
+ NULL))
+ {
+ canHibernate = true;
+ }
+ }
+#elif defined(__TDE_HAVE_TDEHWLIB) // COMPILE_HALBACKEND
+ TDERootSystemDevice* rootDevice = TDEGlobal::hardwareDevices()->rootSystemDevice();
+ if (rootDevice) {
+ canFreeze = rootDevice->canFreeze();
+ canSuspend = rootDevice->canSuspend();
+ canHibernate = rootDevice->canHibernate();
+ }
+ else {
+ canFreeze = false;
+ canSuspend = false;
+ canHibernate = false;
+ }
+#endif // COMPILE_HALBACKEND
+
+ if(doUbuntuLogout) {
+
+ if (canFreeze && !disableSuspend)
+ {
+ // Freeze
+ FlatButton* btnFreeze = new FlatButton( frame );
+ btnFreeze->setTextLabel( i18n("&Freeze"), false );
+ btnFreeze->setPixmap( DesktopIcon( "suspend") );
+ int i = btnFreeze->textLabel().find( TQRegExp("\\&"), 0 ); // i == 1
+ btnFreeze->setAccel( "ALT+" + btnFreeze->textLabel().lower()[i+1] ) ;
+ hbuttonbox->addWidget ( btnFreeze);
+ connect(btnFreeze, TQT_SIGNAL(clicked()), TQT_SLOT(slotFreeze()));
+ }
+
+ if (canSuspend && !disableSuspend)
+ {
+ // Suspend
+ FlatButton* btnSuspend = new FlatButton( frame );
+ btnSuspend->setTextLabel( i18n("&Suspend"), false );
+ btnSuspend->setPixmap( DesktopIcon( "suspend") );
+ int i = btnSuspend->textLabel().find( TQRegExp("\\&"), 0 ); // i == 1
+ btnSuspend->setAccel( "ALT+" + btnSuspend->textLabel().lower()[i+1] ) ;
+ hbuttonbox->addWidget ( btnSuspend);
+ connect(btnSuspend, TQT_SIGNAL(clicked()), TQT_SLOT(slotSuspend()));
+ }
+
+ if (canHibernate && !disableHibernate)
+ {
+ // Hibernate
+ FlatButton* btnHibernate = new FlatButton( frame );
+ btnHibernate->setTextLabel( i18n("&Hibernate"), false );
+ btnHibernate->setPixmap( DesktopIcon( "hibernate") );
+ int i = btnHibernate->textLabel().find( TQRegExp("\\&"), 0 ); // i == 1
+ btnHibernate->setAccel( "ALT+" + btnHibernate->textLabel().lower()[i+1] ) ;
+ hbuttonbox->addWidget ( btnHibernate);
+ connect(btnHibernate, TQT_SIGNAL(clicked()), TQT_SLOT(slotHibernate()));
+ }
+
+ // Separator (within buttonlay)
+ vbox->addWidget( new KSeparator( frame ) );
+
+ // bottom buttons
+ TQHBoxLayout* hbuttonbox2 = new TQHBoxLayout( vbox, factor * KDialog::spacingHint() );
+ hbuttonbox2->setAlignment( Qt::AlignHCenter );
+
+ if (mayrb) {
+ // Reboot
+ FlatButton* btnReboot = new FlatButton( frame );
+ btnReboot->setTextLabel( i18n("&Restart"), false );
+ btnReboot->setPixmap( DesktopIcon( "reload") );
+ int i = btnReboot->textLabel().find( TQRegExp("\\&"), 0 ); // i == 1
+ btnReboot->setAccel( "ALT+" + btnReboot->textLabel().lower()[i+1] ) ;
+ hbuttonbox2->addWidget ( btnReboot);
+ connect(btnReboot, TQT_SIGNAL(clicked()), TQT_SLOT(slotReboot()));
+ if ( sdtype == TDEApplication::ShutdownTypeReboot ) {
+ btnReboot->setFocus();
+ }
+
+ // BAD KARMA .. this code is copied line by line from standard konqy dialog
+ int def, cur;
+ if ( DM().bootOptions( rebootOptions, def, cur ) ) {
+ btnReboot->setPopupDelay(300); // visually add dropdown
+ targets = new TQPopupMenu( frame );
+ if ( cur == -1 ) {
+ cur = def;
+ }
+
+ int index = 0;
+ for (TQStringList::ConstIterator it = rebootOptions.begin(); it != rebootOptions.end(); ++it, ++index) {
+ TQString label = (*it);
+ label=label.replace('&',"&&");
+ if (index == cur) {
+ targets->insertItem( label + i18n("current option in boot loader", " (current)"), index);
+ }
+ else {
+ targets->insertItem( label, index );
+ }
+ }
+
+ btnReboot->setPopup(targets);
+ connect( targets, TQT_SIGNAL(activated(int)), TQT_SLOT(slotReboot(int)) );
+ }
+ // BAD KARMA .. this code is copied line by line from standard konqy dialog [EOF]
+ }
+
+ if (maysd) {
+ // Shutdown
+ FlatButton* btnHalt = new FlatButton( frame );
+ btnHalt->setTextLabel( i18n("&Turn Off"), false );
+ btnHalt->setPixmap( DesktopIcon( "system-log-out") );
+ int i = btnHalt->textLabel().find( TQRegExp("\\&"), 0 ); // i == 1
+ btnHalt->setAccel( "ALT+" + btnHalt->textLabel().lower()[i+1] ) ;
+ hbuttonbox2->addWidget ( btnHalt );
+ connect(btnHalt, TQT_SIGNAL(clicked()), TQT_SLOT(slotHalt()));
+ if ( sdtype == TDEApplication::ShutdownTypeHalt ) {
+ btnHalt->setFocus();
+ }
+ }
+
+ // cancel buttonbox
+ TQHBoxLayout* hbuttonbox3 = new TQHBoxLayout( vbox, factor * KDialog::spacingHint() );
+ hbuttonbox3->setAlignment( Qt::AlignRight );
+
+ // Back to Desktop
+ KSMPushButton* btnBack = new KSMPushButton( KStdGuiItem::cancel(), frame );
+ hbuttonbox3->addWidget( btnBack );
+ connect(btnBack, TQT_SIGNAL(clicked()), TQT_SLOT(reject()));
+
+ }
+ else
+ {
+ if (maysd) {
+ // Shutdown
+ KPushButton* btnHalt = new KPushButton( KGuiItem( i18n("&Turn Off Computer"), "system-log-out"), frame );
+ TQToolTip::add( btnHalt, i18n( "<qt><h3>Turn Off Computer</h3><p>Log out of the current session and turn off the computer</p></qt>" ) );
+ btnHalt->setFont( btnFont );
+ buttonlay->addWidget( btnHalt );
+ connect(btnHalt, TQT_SIGNAL(clicked()), TQT_SLOT(slotHalt()));
+ if ( sdtype == TDEApplication::ShutdownTypeHalt || getenv("TDM_AUTOLOGIN") ) {
+ btnHalt->setFocus();
+ }
+ }
+
+ if (mayrb) {
+ // Reboot
+ KSMDelayedPushButton* btnReboot = new KSMDelayedPushButton( KGuiItem( i18n("&Restart Computer"), "reload"), frame );
+ TQToolTip::add( btnReboot, i18n( "<qt><h3>Restart Computer</h3><p>Log out of the current session and restart the computer</p><p>Hold the mouse button or the space bar for a short while to get a list of options what to boot</p></qt>" ) );
+ btnReboot->setFont( btnFont );
+ buttonlay->addWidget( btnReboot );
+
+ connect(btnReboot, TQT_SIGNAL(clicked()), TQT_SLOT(slotReboot()));
+ if ( sdtype == TDEApplication::ShutdownTypeReboot ) {
+ btnReboot->setFocus();
+ }
+
+ // this section is copied as-is into ubuntulogout as well
+ int def, cur;
+ if ( DM().bootOptions( rebootOptions, def, cur ) ) {
+ targets = new TQPopupMenu( frame );
+ if ( cur == -1 ) {
+ cur = def;
+ }
+
+ int index = 0;
+ for (TQStringList::ConstIterator it = rebootOptions.begin(); it != rebootOptions.end(); ++it, ++index) {
+ TQString label = (*it);
+ label=label.replace('&',"&&");
+ if (index == cur) {
+ targets->insertItem( label + i18n("current option in boot loader", " (current)"), index);
+ }
+ else {
+ targets->insertItem( label, index );
+ }
+ }
+
+ btnReboot->setPopup(targets);
+ connect( targets, TQT_SIGNAL(activated(int)), TQT_SLOT(slotReboot(int)) );
+ }
+ }
+
+ if (canFreeze && !disableSuspend)
+ {
+ KPushButton* btnFreeze = new KPushButton( KGuiItem( i18n("&Freeze Computer"), "suspend"), frame );
+ btnFreeze->setFont( btnFont );
+ buttonlay->addWidget( btnFreeze );
+ connect(btnFreeze, TQT_SIGNAL(clicked()), TQT_SLOT(slotFreeze()));
+ }
+
+ if (canSuspend && !disableSuspend)
+ {
+ KPushButton* btnSuspend = new KPushButton( KGuiItem( i18n("&Suspend Computer"), "suspend"), frame );
+ btnSuspend->setFont( btnFont );
+ buttonlay->addWidget( btnSuspend );
+ connect(btnSuspend, TQT_SIGNAL(clicked()), TQT_SLOT(slotSuspend()));
+ }
+
+ if (canHibernate && !disableHibernate)
+ {
+ KPushButton* btnHibernate = new KPushButton( KGuiItem( i18n("&Hibernate Computer"), "hibernate"), frame );
+ btnHibernate->setFont( btnFont );
+ buttonlay->addWidget( btnHibernate );
+ connect(btnHibernate, TQT_SIGNAL(clicked()), TQT_SLOT(slotHibernate()));
+ }
+
+ buttonlay->addStretch( 1 );
+
+ // Separator
+ buttonlay->addWidget( new KSeparator( frame ) );
+
+ // Back to Desktop
+ KPushButton* btnBack = new KPushButton( KStdGuiItem::cancel(), frame );
+ buttonlay->addWidget( btnBack );
+ connect(btnBack, TQT_SIGNAL(clicked()), TQT_SLOT(reject()));
+
+ }
+
+ }
+ else {
+ // finish the dialog correctly
+ if(doUbuntuLogout)
+ {
+ // cancel buttonbox
+ TQHBoxLayout* hbuttonbox3 = new TQHBoxLayout( vbox, factor * KDialog::spacingHint() );
+ hbuttonbox3->setAlignment( Qt::AlignRight );
+
+ // Back to Desktop
+ KSMPushButton* btnBack = new KSMPushButton( KStdGuiItem::cancel(), frame );
+ hbuttonbox3->addWidget( btnBack );
+
+ connect(btnBack, TQT_SIGNAL(clicked()), TQT_SLOT(reject()));
+ }
+ else
+ {
+ // Separator
+ buttonlay->addWidget( new KSeparator( frame ) );
+
+ // Back to Desktop
+ KPushButton* btnBack = new KPushButton( KStdGuiItem::cancel(), frame );
+ buttonlay->addWidget( btnBack );
+
+ connect(btnBack, TQT_SIGNAL(clicked()), TQT_SLOT(reject()));
+ }
+
+
+ }
+
+
+}
+
+
+KSMShutdownDlg::~KSMShutdownDlg()
+{
+#ifdef COMPILE_HALBACKEND
+ if (m_halCtx)
+ {
+ DBusError error;
+ dbus_error_init(&error);
+ libhal_ctx_shutdown(m_halCtx, &error);
+ libhal_ctx_free(m_halCtx);
+ }
+#endif
+}
+
+
+void KSMShutdownDlg::slotLogout()
+{
+ m_shutdownType = TDEApplication::ShutdownTypeNone;
+ accept();
+}
+
+
+void KSMShutdownDlg::slotReboot()
+{
+ // no boot option selected -> current
+ m_bootOption = TQString::null;
+ m_shutdownType = TDEApplication::ShutdownTypeReboot;
+ accept();
+}
+
+void KSMShutdownDlg::slotReboot(int opt)
+{
+ if (int(rebootOptions.size()) > opt)
+ m_bootOption = rebootOptions[opt];
+ m_shutdownType = TDEApplication::ShutdownTypeReboot;
+ accept();
+}
+
+
+void KSMShutdownDlg::slotHalt()
+{
+ m_bootOption = TQString::null;
+ m_shutdownType = TDEApplication::ShutdownTypeHalt;
+ accept();
+}
+
+void KSMShutdownDlg::slotSuspend()
+{
+#ifndef COMPILE_HALBACKEND
+ *m_selection = 1; // Suspend
+#else
+ if (m_dbusConn)
+ {
+ DBusMessage *msg = dbus_message_new_method_call(
+ "org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/computer",
+ "org.freedesktop.Hal.Device.SystemPowerManagement",
+ "Suspend");
+
+ int wakeup=0;
+ dbus_message_append_args(msg, DBUS_TYPE_INT32, &wakeup, DBUS_TYPE_INVALID);
+
+ dbus_connection_send(m_dbusConn, msg, NULL);
+
+ dbus_message_unref(msg);
+ }
+#endif
+ reject(); // continue on resume
+}
+
+void KSMShutdownDlg::slotHibernate()
+{
+#ifndef COMPILE_HALBACKEND
+ *m_selection = 2; // Hibernate
+#else
+ if (m_dbusConn)
+ {
+ DBusMessage *msg = dbus_message_new_method_call(
+ "org.freedesktop.Hal",
+ "/org/freedesktop/Hal/devices/computer",
+ "org.freedesktop.Hal.Device.SystemPowerManagement",
+ "Hibernate");
+
+ dbus_connection_send(m_dbusConn, msg, NULL);
+
+ dbus_message_unref(msg);
+ }
+#endif
+ reject(); // continue on resume
+}
+
+void KSMShutdownDlg::slotFreeze()
+{
+ *m_selection = 3; // Freeze
+ reject();
+}
+
+bool KSMShutdownDlg::confirmShutdown( bool maysd, bool mayrb, TDEApplication::ShutdownType& sdtype, TQString& bootOption, int* selection )
+{
+ kapp->enableStyles();
+ KSMShutdownDlg* l = new KSMShutdownDlg( 0 /*KSMShutdownFeedback::self()*/, maysd, mayrb, sdtype, selection );
+
+ // Show dialog (will save the background in showEvent)
+ TQSize sh = l->sizeHint();
+ TQRect rect = TDEGlobalSettings::desktopGeometry(TQCursor::pos());
+
+ l->move(rect.x() + (rect.width() - sh.width())/2, rect.y() + (rect.height() - sh.height())/2);
+ bool result = l->exec();
+ sdtype = l->m_shutdownType;
+ bootOption = l->m_bootOption;
+
+ delete l;
+
+ kapp->disableStyles();
+ return result;
+}
+
+TQWidget* KSMShutdownIPDlg::showShutdownIP()
+{
+ kapp->enableStyles();
+ KSMShutdownIPDlg* l = new KSMShutdownIPDlg( 0 );
+
+ kapp->disableStyles();
+
+ return l;
+}
+
+void KSMShutdownIPDlg::showNotificationActionButtons()
+{
+ m_button1->show();
+ m_button2->show();
+ m_buttonframe->show();
+
+ m_gridlayout->invalidate();
+}
+
+void KSMShutdownIPDlg::hideNotificationActionButtons()
+{
+ m_button1->hide();
+ m_button2->hide();
+ m_buttonframe->hide();
+
+ m_gridlayout->invalidate();
+}
+
+void KSMShutdownIPDlg::setNotificationActionButtonsSkipText(TQString text)
+{
+ m_button1->setText(text);
+}
+
+void KSMShutdownIPDlg::setProgressBarTotalSteps(int total_steps)
+{
+ m_progressbar->setTotalSteps(total_steps);
+}
+
+void KSMShutdownIPDlg::setProgressBarProgress(int step)
+{
+ m_progressbar->setProgress(step);
+}
+
+KSMShutdownIPDlg::KSMShutdownIPDlg(TQWidget* parent)
+ : KSMModalDialog( parent )
+
+{
+ m_progressbar = new TQProgressBar(this);
+ m_progressbar->show();
+ m_gridlayout->expand(4,3);
+ m_gridlayout->remove(m_buttonframe);
+ m_gridlayout->addMultiCellWidget( m_progressbar, 3, 3, 0, 2);
+ m_gridlayout->addMultiCellWidget( m_buttonframe, 4, 4, 0, 2, 0 );
+ m_gridlayout->invalidate();
+ setFixedSize(sizeHint());
+
+ setStatusMessage(i18n("Saving your settings..."));
+
+ setNotificationActionButtonsSkipText(i18n("Skip Notification"));
+ m_button2->setText(i18n("Abort Logout"));
+ connect(m_button1, SIGNAL(clicked()), this, SIGNAL(skipNotificationClicked()));
+ connect(m_button2, SIGNAL(clicked()), this, SIGNAL(abortLogoutClicked()));
+
+ show();
+ setActiveWindow();
+
+// KWin::setOnAllDesktops( winId(), true );
+}
+
+KSMShutdownIPDlg::~KSMShutdownIPDlg()
+{
+}
+
+KSMDelayedPushButton::KSMDelayedPushButton( const KGuiItem &item,
+ TQWidget *parent,
+ const char *name)
+ : KPushButton( item, parent, name), pop(0), popt(0)
+{
+ connect(this, TQT_SIGNAL(pressed()), TQT_SLOT(slotPressed()));
+ connect(this, TQT_SIGNAL(released()), TQT_SLOT(slotReleased()));
+ popt = new TQTimer(this);
+ connect(popt, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimeout()));
+}
+
+void KSMDelayedPushButton::setPopup(TQPopupMenu *p)
+{
+ pop = p;
+ setIsMenuButton(p != 0);
+}
+
+void KSMDelayedPushButton::slotPressed()
+{
+ if (pop)
+ popt->start(TQApplication::startDragTime());
+}
+
+void KSMDelayedPushButton::slotReleased()
+{
+ popt->stop();
+}
+
+void KSMDelayedPushButton::slotTimeout()
+{
+ TQPoint bl = mapToGlobal(rect().bottomLeft());
+ pop->popup( bl );
+ popt->stop();
+ setDown(false);
+}
+
+KSMDelayedMessageBox::KSMDelayedMessageBox( TDEApplication::ShutdownType sdtype, const TQString &bootOption, int confirmDelay )
+ : TimedLogoutDlg( 0, 0, true, (WFlags)WType_Popup ), m_remaining(confirmDelay)
+{
+ if ( sdtype == TDEApplication::ShutdownTypeHalt )
+ {
+ m_title->setText( i18n( "Would you like to turn off your computer?" ) );
+ m_template = i18n( "This computer will turn off automatically\n"
+ "after %1 seconds." );
+ m_logo->setPixmap( BarIcon( "system-log-out", 48 ) );
+ } else if ( sdtype == TDEApplication::ShutdownTypeReboot )
+ {
+ if (bootOption.isEmpty())
+ m_title->setText( i18n( "Would you like to reboot your computer?" ) );
+ else
+ m_title->setText( i18n( "Would you like to reboot to \"%1\"?" ).arg(bootOption) );
+ m_template = i18n( "This computer will reboot automatically\n"
+ "after %1 seconds." );
+ m_logo->setPixmap( BarIcon( "reload", 48 ) );
+ } else {
+ m_title->setText( i18n( "Would you like to end your current session?" ) );
+ m_template = i18n( "This session will end\n"
+ "after %1 seconds automatically." );
+ m_logo->setPixmap( BarIcon( "go-previous", 48 ) );
+ }
+
+ updateText();
+ adjustSize();
+ if ( double( height() ) / width() < 0.25 )
+ {
+ setFixedHeight( tqRound( width() * 0.3 ) );
+ adjustSize();
+ }
+ TQTimer *timer = new TQTimer( this );
+ timer->start( 1000 );
+ connect( timer, TQT_SIGNAL( timeout() ), TQT_SLOT( updateText() ) );
+ KDialog::centerOnScreen(this);
+}
+
+void KSMDelayedMessageBox::updateText()
+{
+ m_remaining--;
+ if ( m_remaining == 0 )
+ {
+ accept();
+ return;
+ }
+ m_text->setText( m_template.arg( m_remaining ) );
+}
+
+bool KSMDelayedMessageBox::showTicker( TDEApplication::ShutdownType sdtype, const TQString &bootOption, int confirmDelay )
+{
+ kapp->enableStyles();
+ KSMDelayedMessageBox msg( sdtype, bootOption, confirmDelay );
+ TQSize sh = msg.sizeHint();
+ TQRect rect = TDEGlobalSettings::desktopGeometry(TQCursor::pos());
+
+ msg.move(rect.x() + (rect.width() - sh.width())/2,
+ rect.y() + (rect.height() - sh.height())/2);
+ bool result = msg.exec();
+
+ kapp->disableStyles();
+ return result;
+}
+
+KSMPushButton::KSMPushButton( const KGuiItem &item,
+ TQWidget *parent,
+ const char *name)
+ : KPushButton( item, parent, name),
+ m_pressed(false)
+{
+ setDefault( false );
+ setAutoDefault ( false );
+}
+
+
+void KSMPushButton::keyPressEvent( TQKeyEvent* e )
+{
+switch ( e->key() )
+ {
+ case Key_Enter:
+ case Key_Return:
+ case Key_Space:
+ m_pressed = TRUE;
+ setDown(true);
+ emit pressed();
+ break;
+ case Key_Escape:
+ e->ignore();
+ break;
+ default:
+ e->ignore();
+ }
+
+ TQPushButton::keyPressEvent(e);
+}
+
+
+void KSMPushButton::keyReleaseEvent( TQKeyEvent* e )
+{
+ switch ( e->key() )
+ {
+ case Key_Space:
+ case Key_Enter:
+ case Key_Return:
+ if ( m_pressed )
+ {
+ setDown(false);
+ m_pressed = FALSE;
+ emit released();
+ emit clicked();
+ }
+ break;
+ case Key_Escape:
+ e->ignore();
+ break;
+ default:
+ e->ignore();
+ }
+
+}
+
+
+
+
+FlatButton::FlatButton( TQWidget *parent, const char *name )
+ : TQToolButton( parent, name/*, TQt::WNoAutoErase*/ ),
+ m_pressed(false)
+{
+ init();
+}
+
+
+FlatButton::~FlatButton() {}
+
+
+void FlatButton::init()
+{
+ setUsesTextLabel(true);
+ setUsesBigPixmap(true);
+ setAutoRaise(true);
+ setTextPosition( TQToolButton::Under );
+ setFocusPolicy(TQ_StrongFocus);
+ }
+
+
+void FlatButton::keyPressEvent( TQKeyEvent* e )
+{
+ switch ( e->key() )
+ {
+ case Key_Enter:
+ case Key_Return:
+ case Key_Space:
+ m_pressed = TRUE;
+ setDown(true);
+ emit pressed();
+ break;
+ case Key_Escape:
+ e->ignore();
+ break;
+ default:
+ e->ignore();
+ }
+
+ TQToolButton::keyPressEvent(e);
+}
+
+
+void FlatButton::keyReleaseEvent( TQKeyEvent* e )
+{
+ switch ( e->key() )
+ {
+ case Key_Space:
+ case Key_Enter:
+ case Key_Return:
+ if ( m_pressed )
+ {
+ setDown(false);
+ m_pressed = FALSE;
+ emit released();
+ emit clicked();
+ }
+ break;
+ case Key_Escape:
+ e->ignore();
+ break;
+ default:
+ e->ignore();
+ }
+
+}
+
+
diff --git a/ksmserver/shutdowndlg.h b/ksmserver/shutdowndlg.h
new file mode 100644
index 000000000..a3864e616
--- /dev/null
+++ b/ksmserver/shutdowndlg.h
@@ -0,0 +1,270 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2012 Serghei Amelian <[email protected]>
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#ifndef SHUTDOWNDLG_H
+#define SHUTDOWNDLG_H
+
+#include <tqpixmap.h>
+#include <tqimage.h>
+#include <tqdatetime.h>
+#include <kdialog.h>
+#include <kpushbutton.h>
+#include <tqpushbutton.h>
+#include <tqframe.h>
+#include <kguiitem.h>
+#include <tqtoolbutton.h>
+#include <krootpixmap.h>
+#include <ntqprogressbar.h>
+
+class TQPushButton;
+class TQVButtonGroup;
+class TQPopupMenu;
+class TQTimer;
+class TQPainter;
+class TQString;
+class TDEAction;
+
+#include "timed.h"
+#include <tdeapplication.h>
+#include <kpixmapio.h>
+
+#include <config.h>
+
+#ifdef COMPILE_HALBACKEND
+ #ifndef NO_QT3_DBUS_SUPPORT
+ /* We acknowledge the the dbus API is unstable */
+ #define DBUS_API_SUBJECT_TO_CHANGE
+ #include <dbus/connection.h>
+ #endif // NO_QT3_DBUS_SUPPORT
+
+ #include <hal/libhal.h>
+#endif // COMPILE_HALBACKEND
+
+// The (singleton) widget that makes/fades the desktop gray.
+class KSMShutdownFeedback : public TQWidget
+{
+ Q_OBJECT
+
+public:
+ static void start() { s_pSelf = new KSMShutdownFeedback(); }
+ static void stop() { if ( s_pSelf != 0L ) s_pSelf->fadeBack(); delete s_pSelf; s_pSelf = 0L; }
+ static KSMShutdownFeedback * self() { return s_pSelf; }
+
+protected:
+ ~KSMShutdownFeedback() {}
+
+private slots:
+ void slotPaintEffect();
+
+private:
+ static KSMShutdownFeedback * s_pSelf;
+ KSMShutdownFeedback();
+ int m_currentY;
+ TQPixmap m_root;
+ void fadeBack( void );
+ float m_grayOpacity;
+ float m_compensation;
+ bool m_fadeBackwards;
+ bool m_readDelayComplete;
+ TQImage m_unfadedImage;
+ TQImage m_grayImage;
+ TQTime m_fadeTime;
+ int m_rowsDone;
+ KPixmapIO m_pmio;
+ bool m_greyImageCreated;
+
+};
+
+// The (singleton) widget that shows either pretty pictures or a black screen during logout
+class KSMShutdownIPFeedback : public TQWidget
+{
+ Q_OBJECT
+
+public:
+ static void start() { s_pSelf = new KSMShutdownIPFeedback(); }
+ static void showit() { if ( s_pSelf != 0L ) s_pSelf->showNow(); }
+ static void stop() { if ( s_pSelf != 0L ) s_pSelf->fadeBack(); delete s_pSelf; s_pSelf = 0L; }
+ static KSMShutdownIPFeedback * self() { return s_pSelf; }
+ static bool ispainted() { if ( s_pSelf != 0L ) return s_pSelf->m_isPainted; else return false; }
+
+protected:
+ ~KSMShutdownIPFeedback();
+ virtual void resizeEvent(TQResizeEvent* re);
+
+public slots:
+ void slotPaintEffect();
+ void slotSetBackgroundPixmap(const TQPixmap &);
+
+private:
+ /**
+ * Asks KDesktop to export the desktop background as a TDESharedPixmap.
+ * This method uses DCOP to call KBackgroundIface/setExport(int).
+ */
+ void enableExports();
+
+private:
+ static KSMShutdownIPFeedback * s_pSelf;
+ KSMShutdownIPFeedback();
+ int m_currentY;
+ TQPixmap m_root;
+ void fadeBack( void );
+ void showNow( void );
+ int m_timeout;
+ bool m_isPainted;
+ bool m_paintedFromSharedRootPixmap;
+ KRootPixmap* m_sharedRootPixmap;
+ TQPixmap m_rootPixmap;
+ int mPixmapTimeout;
+ TQRect m_screenGeometry;
+};
+
+// The confirmation dialog
+class KSMShutdownDlg : public TQDialog
+{
+ Q_OBJECT
+
+public:
+ static bool confirmShutdown( bool maysd, bool mayrb, TDEApplication::ShutdownType& sdtype, TQString& bopt, int* selection=0 );
+
+public slots:
+ void slotLogout();
+ void slotHalt();
+ void slotReboot();
+ void slotReboot(int);
+ void slotSuspend();
+ void slotHibernate();
+ void slotFreeze();
+
+protected:
+ ~KSMShutdownDlg();
+
+private:
+ KSMShutdownDlg( TQWidget* parent, bool maysd, bool mayrb, TDEApplication::ShutdownType sdtype, int* selection=0 );
+ TDEApplication::ShutdownType m_shutdownType;
+ TQString m_bootOption;
+ TQPopupMenu *targets;
+ TQStringList rebootOptions;
+#ifdef COMPILE_HALBACKEND
+ LibHalContext* m_halCtx;
+ DBusConnection *m_dbusConn;
+#endif
+ bool m_lockOnResume;
+ int* m_selection;
+};
+
+// The shutdown-in-progress dialog
+class KSMShutdownIPDlg : public KSMModalDialog
+{
+ Q_OBJECT
+
+public:
+ static TQWidget* showShutdownIP();
+
+ void showNotificationActionButtons();
+ void hideNotificationActionButtons();
+ void setNotificationActionButtonsSkipText(TQString text);
+ void setProgressBarTotalSteps(int total_steps);
+ void setProgressBarProgress(int step);
+
+signals:
+ void abortLogoutClicked();
+ void skipNotificationClicked();
+
+protected:
+ ~KSMShutdownIPDlg();
+
+private:
+ KSMShutdownIPDlg( TQWidget* parent );
+
+ TQProgressBar *m_progressbar;
+};
+
+class KSMDelayedPushButton : public KPushButton
+{
+ Q_OBJECT
+
+public:
+
+ KSMDelayedPushButton( const KGuiItem &item, TQWidget *parent, const char *name = 0 );
+ void setPopup( TQPopupMenu *pop);
+
+private slots:
+ void slotTimeout();
+ void slotPressed();
+ void slotReleased();
+
+private:
+ TQPopupMenu *pop;
+ TQTimer *popt;
+};
+
+class KSMPushButton : public KPushButton
+{
+ Q_OBJECT
+
+public:
+
+ KSMPushButton( const KGuiItem &item, TQWidget *parent, const char *name = 0 );
+
+protected:
+ virtual void keyPressEvent(TQKeyEvent*e);
+ virtual void keyReleaseEvent(TQKeyEvent*e);
+
+private:
+
+ bool m_pressed;
+
+};
+
+
+
+class FlatButton : public TQToolButton
+{
+ Q_OBJECT
+
+ public:
+
+ FlatButton( TQWidget *parent = 0, const char *name = 0 );
+ ~FlatButton();
+
+ protected:
+ virtual void keyPressEvent(TQKeyEvent*e);
+ virtual void keyReleaseEvent(TQKeyEvent*e);
+
+ private slots:
+
+ private:
+ void init();
+
+ bool m_pressed;
+ TQString m_text;
+ TQPixmap m_pixmap;
+
+};
+
+
+
+
+class TQLabel;
+
+class KSMDelayedMessageBox : public TimedLogoutDlg
+{
+ Q_OBJECT
+
+public:
+ KSMDelayedMessageBox( TDEApplication::ShutdownType sdtype, const TQString &bootOption, int confirmDelay );
+ static bool showTicker( TDEApplication::ShutdownType sdtype, const TQString &bootOption, int confirmDelay );
+
+protected slots:
+ void updateText();
+
+private:
+ TQString m_template;
+ int m_remaining;
+};
+
+#endif
diff --git a/ksmserver/shutdownkonq.png b/ksmserver/shutdownkonq.png
new file mode 100644
index 000000000..8442adc42
--- /dev/null
+++ b/ksmserver/shutdownkonq.png
Binary files differ
diff --git a/ksmserver/startup.cpp b/ksmserver/startup.cpp
new file mode 100644
index 000000000..b1ed9992e
--- /dev/null
+++ b/ksmserver/startup.cpp
@@ -0,0 +1,489 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+Copyright (C) 2005 Lubos Lunak <[email protected]>
+
+relatively small extensions by Oswald Buddenhagen <[email protected]>
+
+some code taken from the dcopserver (part of the KDE libraries), which is
+Copyright (c) 1999 Matthias Ettrich <[email protected]>
+Copyright (c) 1999 Preston Brown <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <tqfile.h>
+#include <tqtextstream.h>
+#include <tqdatastream.h>
+#include <tqptrstack.h>
+#include <tqpushbutton.h>
+#include <tqmessagebox.h>
+#include <tqguardedptr.h>
+#include <tqtimer.h>
+
+#include <tdelocale.h>
+#include <tdeglobal.h>
+#include <tdeconfig.h>
+#include <kstandarddirs.h>
+#include <unistd.h>
+#include <tdeapplication.h>
+#include <kstaticdeleter.h>
+#include <tdetempfile.h>
+#include <kprocess.h>
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <twinmodule.h>
+#include <knotifyclient.h>
+
+#include "server.h"
+#include "global.h"
+#include "startupdlg.h"
+#include "client.h"
+
+#include <kdebug.h>
+
+// shall we show a nice fancy login screen?
+bool showFancyLogin = FALSE;
+bool trinity_startup_main_sequence_done = FALSE;
+
+/*! Restores the previous session. Ensures the window manager is
+ running (if specified).
+ */
+void KSMServer::restoreSession( TQString sessionName )
+{
+ showFancyLogin = TDEConfigGroup(TDEGlobal::config(), "Login").readBoolEntry("showFancyLogin", true);
+ TDEConfig ksplashcfg( "ksplashrc", true );
+ ksplashcfg.setGroup( "KSplash" );
+ if ( ksplashcfg.readEntry( "Theme", "Default" ) != TQString("Unified") )
+ showFancyLogin = false;
+
+ if( state != Idle )
+ return;
+ state = LaunchingWM;
+
+ kdDebug( 1218 ) << "KSMServer::restoreSession " << sessionName << endl;
+ upAndRunning( "restore session");
+ TDEConfig* config = TDEGlobal::config();
+
+ sessionGroup = "Session: " + sessionName;
+
+ config->setGroup( sessionGroup );
+ int count = config->readNumEntry( "count" );
+ appsToStart = count;
+
+ TQValueList<TQStringList> wmCommands;
+ if ( !wm.isEmpty() ) {
+ for ( int i = 1; i <= count; i++ ) {
+ TQString n = TQString::number(i);
+ if ( wm == config->readEntry( TQString("program")+n ) ) {
+ wmCommands << config->readListEntry( TQString("restartCommand")+n );
+ }
+ }
+ }
+ if ( wmCommands.isEmpty() )
+ wmCommands << ( TQStringList() << wm );
+
+ publishProgress( appsToStart, true );
+ connectDCOPSignal( launcher, launcher, "autoStart0Done()",
+ "autoStart0Done()", true);
+ connectDCOPSignal( launcher, launcher, "autoStart1Done()",
+ "autoStart1Done()", true);
+ connectDCOPSignal( launcher, launcher, "autoStart2Done()",
+ "autoStart2Done()", true);
+ upAndRunning( "ksmserver" );
+
+ if ( !wmCommands.isEmpty() ) {
+ // when we have a window manager, we start it first and give
+ // it some time before launching other processes. Results in a
+ // visually more appealing startup.
+ for (uint i = 0; i < wmCommands.count(); i++)
+ startApplication( wmCommands[i] );
+ if ((showFancyLogin) && (!startupNotifierIPDlg)) {
+ startupNotifierIPDlg = KSMStartupIPDlg::showStartupIP();
+ }
+ TQTimer::singleShot( 4000, this, TQT_SLOT( autoStart0() ) );
+ } else {
+ if ((showFancyLogin) && (!startupNotifierIPDlg)) {
+ startupNotifierIPDlg = KSMStartupIPDlg::showStartupIP();
+ }
+ autoStart0();
+ }
+}
+
+/*!
+ Starts the default session.
+
+ Currently, that's the window manager only (if specified).
+ */
+void KSMServer::startDefaultSession()
+{
+ showFancyLogin = TDEConfigGroup(TDEGlobal::config(), "Login").readBoolEntry("showFancyLogin", true);
+ TDEConfig ksplashcfg( "ksplashrc", true );
+ ksplashcfg.setGroup( "KSplash" );
+ if ( ksplashcfg.readEntry( "Theme", "Default" ) != TQString("None") )
+ showFancyLogin = false;
+
+ if( state != Idle )
+ return;
+
+ state = LaunchingWM;
+ sessionGroup = "";
+ publishProgress( 0, true );
+ upAndRunning( "ksmserver" );
+ connectDCOPSignal( launcher, launcher, "autoStart0Done()",
+ "autoStart0Done()", true);
+ connectDCOPSignal( launcher, launcher, "autoStart1Done()",
+ "autoStart1Done()", true);
+ connectDCOPSignal( launcher, launcher, "autoStart2Done()",
+ "autoStart2Done()", true);
+ if (!wmAddArgs.isEmpty()) {
+ TQStringList wmstartupcommand;
+ wmstartupcommand.split(" ", wmAddArgs);
+ wmstartupcommand.prepend(wm);
+ startApplication( wmstartupcommand );
+ }
+ else {
+ startApplication( wm );
+ }
+ if ((showFancyLogin) && (!startupNotifierIPDlg)) {
+ startupNotifierIPDlg = KSMStartupIPDlg::showStartupIP();
+ }
+ TQTimer::singleShot( 4000, this, TQT_SLOT( autoStart0() ) );
+}
+
+
+void KSMServer::clientSetProgram( KSMClient* client )
+{
+ if ( !wm.isEmpty() && client->program() == wm )
+ autoStart0();
+}
+
+void KSMServer::autoStart0()
+{
+ if( state != LaunchingWM )
+ return;
+ if( !checkStartupSuspend())
+ return;
+ state = AutoStart0;
+ DCOPRef( launcher ).send( "autoStart", (int) 0 );
+}
+
+void KSMServer::autoStart0Done()
+{
+ if( state != AutoStart0 )
+ return;
+ disconnectDCOPSignal( launcher, launcher, "autoStart0Done()",
+ "autoStart0Done()");
+ if( !checkStartupSuspend())
+ return;
+ kdDebug( 1218 ) << "Autostart 0 done" << endl;
+ upAndRunning( "kdesktop" );
+ upAndRunning( "kicker" );
+ connectDCOPSignal( "kcminit", "kcminit", "phase1Done()",
+ "kcmPhase1Done()", true);
+ state = KcmInitPhase1;
+ TQTimer::singleShot( 10000, this, TQT_SLOT( kcmPhase1Timeout())); // protection
+ DCOPRef( "kcminit", "kcminit" ).send( "runPhase1" );
+}
+
+void KSMServer::kcmPhase1Done()
+{
+ if( state != KcmInitPhase1 )
+ return;
+ kdDebug( 1218 ) << "Kcminit phase 1 done" << endl;
+ disconnectDCOPSignal( "kcminit", "kcminit", "phase1Done()",
+ "kcmPhase1Done()" );
+ autoStart1();
+}
+
+void KSMServer::kcmPhase1Timeout()
+{
+ if( state != KcmInitPhase1 )
+ return;
+ kdDebug( 1218 ) << "Kcminit phase 1 timeout" << endl;
+ kcmPhase1Done();
+}
+
+void KSMServer::autoStart1()
+{
+ if( state != KcmInitPhase1 )
+ return;
+ state = AutoStart1;
+ DCOPRef( launcher ).send( "autoStart", (int) 1 );
+}
+
+void KSMServer::autoStart1Done()
+{
+ if( state != AutoStart1 )
+ return;
+ disconnectDCOPSignal( launcher, launcher, "autoStart1Done()",
+ "autoStart1Done()");
+ if( !checkStartupSuspend())
+ return;
+ kdDebug( 1218 ) << "Autostart 1 done" << endl;
+ lastAppStarted = 0;
+ lastIdStarted = TQString::null;
+ state = Restoring;
+ if( defaultSession()) {
+ autoStart2();
+ return;
+ }
+ tryRestoreNext();
+}
+
+void KSMServer::clientRegistered( const char* previousId )
+{
+ if ( previousId && lastIdStarted == previousId )
+ tryRestoreNext();
+}
+
+void KSMServer::tryRestoreNext()
+{
+ if( state != Restoring )
+ return;
+ restoreTimer.stop();
+ TDEConfig* config = TDEGlobal::config();
+ config->setGroup( sessionGroup );
+
+ while ( lastAppStarted < appsToStart ) {
+ publishProgress ( appsToStart - lastAppStarted );
+ lastAppStarted++;
+ TQString n = TQString::number(lastAppStarted);
+ TQStringList restartCommand = config->readListEntry( TQString("restartCommand")+n );
+ if ( restartCommand.isEmpty() ||
+ (config->readNumEntry( TQString("restartStyleHint")+n ) == SmRestartNever)) {
+ continue;
+ }
+ if ( wm == config->readEntry( TQString("program")+n ) )
+ continue; // wm already started
+ if( config->readBoolEntry( TQString( "wasWm" )+n, false ))
+ continue; // it was wm before, but not now, don't run it (some have --replace in command :( )
+ startApplication( restartCommand,
+ config->readEntry( TQString("clientMachine")+n ),
+ config->readEntry( TQString("userId")+n ));
+ lastIdStarted = config->readEntry( TQString("clientId")+n );
+ if ( !lastIdStarted.isEmpty() ) {
+ restoreTimer.start( 2000, TRUE );
+ return; // we get called again from the clientRegistered handler
+ }
+ }
+
+ appsToStart = 0;
+ lastIdStarted = TQString::null;
+ publishProgress( 0 );
+
+ autoStart2();
+}
+
+void KSMServer::autoStart2()
+{
+ if( state != Restoring )
+ return;
+ if( !checkStartupSuspend())
+ return;
+ state = FinishingStartup;
+ waitAutoStart2 = true;
+ waitKcmInit2 = true;
+ DCOPRef( launcher ).send( "autoStart", (int) 2 );
+ DCOPRef( "kded", "kded" ).send( "loadSecondPhase" );
+ DCOPRef( "kdesktop", "KDesktopIface" ).send( "runAutoStart" );
+ connectDCOPSignal( "kcminit", "kcminit", "phase2Done()",
+ "kcmPhase2Done()", true);
+ TQTimer::singleShot( 10000, this, TQT_SLOT( kcmPhase2Timeout())); // protection
+ DCOPRef( "kcminit", "kcminit" ).send( "runPhase2" );
+ if( !defaultSession())
+ restoreLegacySession( TDEGlobal::config());
+ KNotifyClient::event( 0, "starttde" ); // this is the time KDE is up, more or less
+}
+
+void KSMServer::autoStart2Done()
+{
+ if( state != FinishingStartup )
+ return;
+ disconnectDCOPSignal( launcher, launcher, "autoStart2Done()",
+ "autoStart2Done()");
+ kdDebug( 1218 ) << "Autostart 2 done" << endl;
+ waitAutoStart2 = false;
+ finishStartup();
+}
+
+void KSMServer::kcmPhase2Done()
+{
+ if( state != FinishingStartup )
+ return;
+ kdDebug( 1218 ) << "Kcminit phase 2 done" << endl;
+ disconnectDCOPSignal( "kcminit", "kcminit", "phase2Done()",
+ "kcmPhase2Done()");
+ waitKcmInit2 = false;
+ finishStartup();
+}
+
+void KSMServer::kcmPhase2Timeout()
+{
+ if( !waitKcmInit2 )
+ return;
+ kdDebug( 1218 ) << "Kcminit phase 2 timeout" << endl;
+ kcmPhase2Done();
+}
+
+void KSMServer::finishStartup()
+{
+ if( state != FinishingStartup )
+ return;
+ if( waitAutoStart2 || waitKcmInit2 )
+ return;
+
+ upAndRunning( "session ready" );
+ DCOPRef( "knotify" ).send( "sessionReady" ); // knotify startup optimization
+
+ state = Idle;
+
+ // [FIXME] When this fires applications are still being loaded, especially the task tray apps
+ // See if there is a way to detect when all session managed applications have been fully started and wait to fire this until that point!
+ if (startupNotifierIPDlg) {
+ static_cast<KSMStartupIPDlg*>(startupNotifierIPDlg)->closeSMDialog();
+ startupNotifierIPDlg=0;
+ }
+
+ setupXIOErrorHandler(); // From now on handle X errors as normal shutdown.
+}
+
+bool KSMServer::checkStartupSuspend()
+{
+ if( startupSuspendCount.isEmpty())
+ return true;
+ // wait for the phase to finish
+ if( !startupSuspendTimeoutTimer.isActive())
+ startupSuspendTimeoutTimer.start( 10000, true );
+ return false;
+}
+
+void KSMServer::suspendStartup( TQCString app )
+{
+ if( !startupSuspendCount.contains( app ))
+ startupSuspendCount[ app ] = 0;
+ ++startupSuspendCount[ app ];
+}
+
+void KSMServer::resumeStartup( TQCString app )
+{
+ if( !startupSuspendCount.contains( app ))
+ return;
+ if( --startupSuspendCount[ app ] == 0 ) {
+ startupSuspendCount.remove( app );
+ if( startupSuspendCount.isEmpty() && startupSuspendTimeoutTimer.isActive()) {
+ startupSuspendTimeoutTimer.stop();
+ resumeStartupInternal();
+ }
+ }
+}
+
+void KSMServer::startupSuspendTimeout()
+{
+ kdDebug( 1218 ) << "Startup suspend timeout:" << state << endl;
+ resumeStartupInternal();
+}
+
+void KSMServer::resumeStartupInternal()
+{
+ startupSuspendCount.clear();
+ switch( state ) {
+ case LaunchingWM:
+ autoStart0();
+ break;
+ case AutoStart0:
+ autoStart0Done();
+ break;
+ case AutoStart1:
+ autoStart1Done();
+ break;
+ case Restoring:
+ autoStart2();
+ break;
+ default:
+ kdWarning( 1218 ) << "Unknown resume startup state" << endl;
+ break;
+ }
+}
+
+void KSMServer::publishProgress( int progress, bool max )
+{
+ DCOPRef( "ksplash" ).send( max ? "setMaxProgress" : "setProgress", progress );
+}
+
+
+void KSMServer::upAndRunning( const TQString& msg )
+{
+ if (startupNotifierIPDlg) {
+ static_cast<KSMStartupIPDlg*>(startupNotifierIPDlg)->setStartupPhase(msg);
+ if (msg == TQString("session ready")) {
+ trinity_startup_main_sequence_done = TRUE;
+ }
+ }
+ DCOPRef( "ksplash" ).send( "upAndRunning", msg );
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = XInternAtom( tqt_xdisplay(), "_KDE_SPLASH_PROGRESS", False );
+ e.xclient.display = tqt_xdisplay();
+ e.xclient.window = tqt_xrootwin();
+ e.xclient.format = 8;
+ assert( strlen( msg.latin1()) < 20 );
+ strcpy( e.xclient.data.b, msg.latin1());
+ XSendEvent( tqt_xdisplay(), tqt_xrootwin(), False, SubstructureNotifyMask, &e );
+}
+
+// these two are in the DCOP interface but I have no idea what uses them
+// Remove for KDE4
+void KSMServer::restoreSessionInternal()
+{
+ autoStart1Done();
+}
+
+void KSMServer::restoreSessionDoneInternal()
+{
+ autoStart2Done();
+}
diff --git a/ksmserver/startupdlg.cpp b/ksmserver/startupdlg.cpp
new file mode 100644
index 000000000..e236ddfee
--- /dev/null
+++ b/ksmserver/startupdlg.cpp
@@ -0,0 +1,86 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2010-2011 Timothy Pearson <[email protected]>
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#include "startupdlg.h"
+#include <tqapplication.h>
+#include <tqlayout.h>
+#include <tqgroupbox.h>
+#include <tqvbuttongroup.h>
+#include <tqlabel.h>
+#include <tqvbox.h>
+#include <tqtimer.h>
+#include <tqstyle.h>
+#include <tqcombobox.h>
+#include <tqcursor.h>
+#include <tqmessagebox.h>
+#include <tqbuttongroup.h>
+#include <tqiconset.h>
+#include <tqpixmap.h>
+#include <tqpopupmenu.h>
+#include <tqtooltip.h>
+#include <tqimage.h>
+#include <tqpainter.h>
+#include <tqfontmetrics.h>
+#include <tqregexp.h>
+#include <tqeventloop.h>
+
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+#include <kdebug.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <kguiitem.h>
+#include <kiconloader.h>
+#include <tdeglobalsettings.h>
+#include <twin.h>
+#include <kuser.h>
+#include <kpixmap.h>
+#include <kimageeffect.h>
+#include <kdialog.h>
+#include <kseparator.h>
+#include <tdeconfig.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dmctl.h>
+#include <tdeaction.h>
+#include <netwm.h>
+
+#include <X11/Xlib.h>
+
+#include "startupdlg.moc"
+
+TQWidget* KSMStartupIPDlg::showStartupIP()
+{
+ kapp->enableStyles();
+ KSMStartupIPDlg* l = new KSMStartupIPDlg( 0 );
+
+ kapp->disableStyles();
+
+ return l;
+}
+
+KSMStartupIPDlg::KSMStartupIPDlg(TQWidget* parent)
+ : KSMModalDialog( parent )
+
+{
+ setStatusMessage(i18n("Loading your settings").append("..."));
+
+ show();
+ setActiveWindow();
+}
+
+KSMStartupIPDlg::~KSMStartupIPDlg()
+{
+}
diff --git a/ksmserver/startupdlg.h b/ksmserver/startupdlg.h
new file mode 100644
index 000000000..a18a121d6
--- /dev/null
+++ b/ksmserver/startupdlg.h
@@ -0,0 +1,49 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright (C) 2000 Matthias Ettrich <[email protected]>
+******************************************************************/
+
+#ifndef STARTUPDLG_H
+#define STARTUPDLG_H
+
+#include <tqpixmap.h>
+#include <tqimage.h>
+#include <tqdatetime.h>
+#include <kdialog.h>
+#include <kpushbutton.h>
+#include <tqpushbutton.h>
+#include <tqframe.h>
+#include <kguiitem.h>
+#include <tqtoolbutton.h>
+#include <ksharedpixmap.h>
+
+class TQPushButton;
+class TQVButtonGroup;
+class TQPopupMenu;
+class TQTimer;
+class TQPainter;
+class TQString;
+class TDEAction;
+
+#include "timed.h"
+#include <tdeapplication.h>
+#include <kpixmapio.h>
+
+
+// The startup-in-progress dialog
+class KSMStartupIPDlg : public KSMModalDialog
+{
+ Q_OBJECT
+
+public:
+ static TQWidget* showStartupIP();
+
+protected:
+ ~KSMStartupIPDlg();
+
+private:
+ KSMStartupIPDlg( TQWidget* parent );
+};
+
+#endif
diff --git a/ksmserver/test.cpp b/ksmserver/test.cpp
new file mode 100644
index 000000000..3349809a2
--- /dev/null
+++ b/ksmserver/test.cpp
@@ -0,0 +1,32 @@
+#include "shutdowndlg.h"
+#include <tdecmdlineargs.h>
+#include <tdeaboutdata.h>
+#include <tdeapplication.h>
+#include <kiconloader.h>
+
+int
+main(int argc, char *argv[])
+{
+ TDEAboutData about("kapptest", "kapptest", "version");
+ TDECmdLineArgs::init(argc, argv, &about);
+
+ TDEApplication a;
+ a.iconLoader()->addAppDir("ksmserver");
+ KSMShutdownFeedback::start();
+
+ // ShutdownTypeNone == Logout == 0
+ // ShutdownTypeReboot == 1
+ // ShutdownTypeHalt == 2
+ TDEApplication::ShutdownType sdtype = TDEApplication::ShutdownTypeNone;
+ TQString bopt;
+ KSMDelayedMessageBox::showTicker( sdtype );
+ /*
+ (void)KSMShutdownDlg::confirmShutdown( true,
+ sdtype,
+ bopt );*/
+/* (void)KSMShutdownDlg::confirmShutdown( false,
+ sdtype,
+ bopt ); */
+
+ KSMShutdownFeedback::stop();
+}
diff --git a/ksmserver/timed.ui b/ksmserver/timed.ui
new file mode 100644
index 000000000..fe217c476
--- /dev/null
+++ b/ksmserver/timed.ui
@@ -0,0 +1,352 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>TimedLogoutDlg</class>
+<widget class="TQDialog">
+ <property name="name">
+ <cstring>TimedLogoutDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>381</width>
+ <height>131</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Confirmation</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQFrame">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="lineWidth">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="midLineWidth">
+ <number>0</number>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>m_logo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>48</width>
+ <height>48</height>
+ </size>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>7</number>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>m_title</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Would you like to shutdown your computer?</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>m_text</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>If you do not act, your computer will shutdown
+after X automatically.</string>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>90</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>pushButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Confirm</string>
+ </property>
+ <property name="on">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>90</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQPushButton">
+ <property name="name">
+ <cstring>pushButton2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>90</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>pushButton1</sender>
+ <signal>clicked()</signal>
+ <receiver>TimedLogoutDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>pushButton2</sender>
+ <signal>clicked()</signal>
+ <receiver>TimedLogoutDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>