1 /*****************************************************************
2 ksmserver - the KDE session management server
4 Copyright 2000 Matthias Ettrich <ettrich@kde.org>
5 Copyright 2005 Lubos Lunak <l.lunak@kde.org>
7 relatively small extensions by Oswald Buddenhagen <ob6@inf.tu-dresden.de>
9 some code taken from the dcopserver (part of the KDE libraries), which is
10 Copyright 1999 Matthias Ettrich <ettrich@kde.org>
11 Copyright 1999 Preston Brown <pbrown@kde.org>
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
20 The above copyright notice and this permission notice shall be included in
21 all copies or substantial portions of the Software.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
27 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 ******************************************************************/
33 #include <config-workspace.h>
34 #include <config-unix.h> // HAVE_LIMITS_H
35 #include <config-ksmserver.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
40 #ifdef HAVE_SYS_TIME_H
43 #include <sys/socket.h>
60 #include <QPushButton>
62 #include <QtDBus/QtDBus>
63 #include <QSocketNotifier>
68 #include <kstandarddirs.h>
69 #include <kapplication.h>
70 #include <ktemporaryfile.h>
71 #include <kconfiggroup.h>
78 #include "ksmserverinterfaceadaptor.h"
84 #include <kdisplaymanager.h>
87 #include "klauncher_interface.h"
89 KSMServer
* the_server
= 0;
91 KSMServer
* KSMServer::self()
96 /*! Utility function to execute a command on the local machine. Used
97 * to restart applications.
99 void KSMServer::startApplication( QStringList
& command
, const QString
& clientMachine
,
100 const QString
& userId
)
102 if ( command
.isEmpty() )
104 if ( !userId
.isEmpty()) {
105 struct passwd
* pw
= getpwuid( getuid());
106 if( pw
!= NULL
&& userId
!= QString::fromLocal8Bit( pw
->pw_name
)) {
107 command
.prepend( "--" );
108 command
.prepend( userId
);
109 command
.prepend( "-u" );
110 command
.prepend( KStandardDirs::findExe("kdesu") );
113 if ( !clientMachine
.isEmpty() && clientMachine
!= "localhost" ) {
114 command
.prepend( clientMachine
);
115 command
.prepend( xonCommand
); // "xon" by default
117 int n
= command
.count();
118 org::kde::KLauncher
klauncher("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus());
119 QString app
= command
[0];
121 for ( int i
=1; i
< n
; i
++)
122 argList
.append( command
[i
]);
123 klauncher
.exec_blind(app
, argList
);
126 /*! Utility function to execute a command on the local machine. Used
127 * to discard session data
129 void KSMServer::executeCommand( const QStringList
& command
)
131 if ( command
.isEmpty() )
134 KProcess::execute( command
);
137 IceAuthDataEntry
*authDataEntries
= 0;
139 static KTemporaryFile
*remTempFile
= 0;
141 static IceListenObj
*listenObjs
= 0;
142 int numTransports
= 0;
143 static bool only_local
= 0;
145 static Bool
HostBasedAuthProc ( char* /*hostname*/)
154 Status
KSMRegisterClientProc (
155 SmsConn
/* smsConn */,
156 SmPointer managerData
,
160 KSMClient
* client
= (KSMClient
*) managerData
;
161 client
->registerClient( previousId
);
165 void KSMInteractRequestProc (
166 SmsConn
/* smsConn */,
167 SmPointer managerData
,
171 the_server
->interactRequest( (KSMClient
*) managerData
, dialogType
);
174 void KSMInteractDoneProc (
175 SmsConn
/* smsConn */,
176 SmPointer managerData
,
180 the_server
->interactDone( (KSMClient
*) managerData
, cancelShutdown
);
183 void KSMSaveYourselfRequestProc (
185 SmPointer
/* managerData */,
194 the_server
->shutdown( fast
?
195 KWorkSpace::ShutdownConfirmNo
:
196 KWorkSpace::ShutdownConfirmDefault
,
197 KWorkSpace::ShutdownTypeDefault
,
198 KWorkSpace::ShutdownModeDefault
);
199 } else if ( !global
) {
200 SmsSaveYourself( smsConn
, saveType
, false, interactStyle
, fast
);
201 SmsSaveComplete( smsConn
);
203 // else checkpoint only, ksmserver does not yet support this
204 // mode. Will come for KDE 3.1
207 void KSMSaveYourselfPhase2RequestProc (
208 SmsConn
/* smsConn */,
209 SmPointer managerData
212 the_server
->phase2Request( (KSMClient
*) managerData
);
215 void KSMSaveYourselfDoneProc (
216 SmsConn
/* smsConn */,
217 SmPointer managerData
,
221 the_server
->saveYourselfDone( (KSMClient
*) managerData
, success
);
224 void KSMCloseConnectionProc (
226 SmPointer managerData
,
231 the_server
->deleteClient( ( KSMClient
* ) managerData
);
233 SmFreeReasons( count
, reasonMsgs
);
234 IceConn iceConn
= SmsGetIceConnection( smsConn
);
235 SmsCleanUp( smsConn
);
236 IceSetShutdownNegotiation (iceConn
, False
);
237 IceCloseConnection( iceConn
);
240 void KSMSetPropertiesProc (
241 SmsConn
/* smsConn */,
242 SmPointer managerData
,
247 KSMClient
* client
= ( KSMClient
* ) managerData
;
248 for ( int i
= 0; i
< numProps
; i
++ ) {
249 SmProp
*p
= client
->property( props
[i
]->name
);
251 client
->properties
.removeAll( p
);
254 client
->properties
.append( props
[i
] );
255 if ( !qstrcmp( props
[i
]->name
, SmProgram
) )
256 the_server
->clientSetProgram( client
);
264 void KSMDeletePropertiesProc (
265 SmsConn
/* smsConn */,
266 SmPointer managerData
,
271 KSMClient
* client
= ( KSMClient
* ) managerData
;
272 for ( int i
= 0; i
< numProps
; i
++ ) {
273 SmProp
*p
= client
->property( propNames
[i
] );
275 client
->properties
.removeAll( p
);
281 void KSMGetPropertiesProc (
283 SmPointer managerData
286 KSMClient
* client
= ( KSMClient
* ) managerData
;
287 SmProp
** props
= new SmProp
*[client
->properties
.count()];
289 foreach( SmProp
*prop
, client
->properties
)
292 SmsReturnProperties( smsConn
, i
, props
);
297 class KSMListener
: public QSocketNotifier
300 KSMListener( IceListenObj obj
)
301 : QSocketNotifier( IceGetListenConnectionNumber( obj
),
302 QSocketNotifier::Read
)
307 IceListenObj listenObj
;
310 class KSMConnection
: public QSocketNotifier
313 KSMConnection( IceConn conn
)
314 : QSocketNotifier( IceConnectionNumber( conn
),
315 QSocketNotifier::Read
)
324 /* for printing hex digits */
325 static void fprintfhex (FILE *fp
, unsigned int len
, char *cp
)
327 static const char hexchars
[] = "0123456789abcdef";
329 for (; len
> 0; len
--, cp
++) {
330 unsigned char s
= *cp
;
331 putc(hexchars
[s
>> 4], fp
);
332 putc(hexchars
[s
& 0x0f], fp
);
337 * We use temporary files which contain commands to add/remove entries from
338 * the .ICEauthority file.
340 static void write_iceauth (FILE *addfp
, FILE *removefp
, IceAuthDataEntry
*entry
)
343 "add %s \"\" %s %s ",
344 entry
->protocol_name
,
347 fprintfhex (addfp
, entry
->auth_data_length
, entry
->auth_data
);
348 fprintf (addfp
, "\n");
351 "remove protoname=%s protodata=\"\" netid=%s authname=%s\n",
352 entry
->protocol_name
,
358 #define MAGIC_COOKIE_LEN 16
360 Status
SetAuthentication_local (int count
, IceListenObj
*listenObjs
)
363 for (i
= 0; i
< count
; i
++) {
364 char *prot
= IceGetListenConnectionString(listenObjs
[i
]);
366 char *host
= strchr(prot
, '/');
371 sock
= strchr(host
, ':');
377 kDebug( 1218 ) << "KSMServer: SetAProc_loc: conn " << (unsigned)i
<< ", prot=" << prot
<< ", file=" << sock
;
378 if (sock
&& !strcmp(prot
, "local")) {
381 IceSetHostBasedAuthProc (listenObjs
[i
], HostBasedAuthProc
);
387 Status
SetAuthentication (int count
, IceListenObj
*listenObjs
,
388 IceAuthDataEntry
**authDataEntries
)
390 KTemporaryFile addTempFile
;
391 remTempFile
= new KTemporaryFile
;
393 if (!addTempFile
.open() || !remTempFile
->open())
396 if ((*authDataEntries
= (IceAuthDataEntry
*) malloc (
397 count
* 2 * sizeof (IceAuthDataEntry
))) == NULL
)
400 FILE *addAuthFile
= fopen(addTempFile
.fileName().toAscii(), "r+");
401 FILE *remAuthFile
= fopen(remTempFile
->fileName().toAscii(), "r+");
403 for (int i
= 0; i
< numTransports
* 2; i
+= 2) {
404 (*authDataEntries
)[i
].network_id
=
405 IceGetListenConnectionString (listenObjs
[i
/2]);
406 (*authDataEntries
)[i
].protocol_name
= (char *) "ICE";
407 (*authDataEntries
)[i
].auth_name
= (char *) "MIT-MAGIC-COOKIE-1";
409 (*authDataEntries
)[i
].auth_data
=
410 IceGenerateMagicCookie (MAGIC_COOKIE_LEN
);
411 (*authDataEntries
)[i
].auth_data_length
= MAGIC_COOKIE_LEN
;
413 (*authDataEntries
)[i
+1].network_id
=
414 IceGetListenConnectionString (listenObjs
[i
/2]);
415 (*authDataEntries
)[i
+1].protocol_name
= (char *) "XSMP";
416 (*authDataEntries
)[i
+1].auth_name
= (char *) "MIT-MAGIC-COOKIE-1";
418 (*authDataEntries
)[i
+1].auth_data
=
419 IceGenerateMagicCookie (MAGIC_COOKIE_LEN
);
420 (*authDataEntries
)[i
+1].auth_data_length
= MAGIC_COOKIE_LEN
;
422 write_iceauth (addAuthFile
, remAuthFile
, &(*authDataEntries
)[i
]);
423 write_iceauth (addAuthFile
, remAuthFile
, &(*authDataEntries
)[i
+1]);
425 IceSetPaAuthData (2, &(*authDataEntries
)[i
]);
427 IceSetHostBasedAuthProc (listenObjs
[i
/2], HostBasedAuthProc
);
432 QString iceAuth
= KGlobal::dirs()->findExe("iceauth");
433 if (iceAuth
.isEmpty())
435 qWarning("KSMServer: could not find iceauth");
440 p
<< iceAuth
<< "source" << addTempFile
.fileName();
447 * Free up authentication data.
449 void FreeAuthenticationData(int count
, IceAuthDataEntry
*authDataEntries
)
451 /* Each transport has entries for ICE and XSMP */
455 for (int i
= 0; i
< count
* 2; i
++) {
456 free (authDataEntries
[i
].network_id
);
457 free (authDataEntries
[i
].auth_data
);
460 free (authDataEntries
);
462 QString iceAuth
= KGlobal::dirs()->findExe("iceauth");
463 if (iceAuth
.isEmpty())
465 qWarning("KSMServer: could not find iceauth");
472 p
<< iceAuth
<< "source" << remTempFile
->fileName();
480 static int Xio_ErrorHandler( Display
* )
482 qWarning("ksmserver: Fatal IO error: client killed");
484 // Don't do anything that might require the X connection
487 KSMServer
*server
= the_server
;
490 // Don't delete server!!
493 exit(0); // Don't report error, it's not our fault.
494 return 0; // Bogus return value, notreached
497 void KSMServer::setupXIOErrorHandler()
499 XSetIOErrorHandler(Xio_ErrorHandler
);
502 static void sighandler(int sig
)
505 signal(SIGHUP
, sighandler
);
511 KSMServer
*server
= the_server
;
523 void KSMWatchProc ( IceConn iceConn
, IcePointer client_data
, Bool opening
, IcePointer
* watch_data
)
525 KSMServer
* ds
= ( KSMServer
*) client_data
;
528 *watch_data
= (IcePointer
) ds
->watchConnection( iceConn
);
531 ds
->removeConnection( (KSMConnection
*) *watch_data
);
535 static Status
KSMNewClientProc ( SmsConn conn
, SmPointer manager_data
,
536 unsigned long* mask_ret
, SmsCallbacks
* cb
, char** failure_reason_ret
)
538 *failure_reason_ret
= 0;
540 void* client
= ((KSMServer
*) manager_data
)->newClient( conn
);
542 cb
->register_client
.callback
= KSMRegisterClientProc
;
543 cb
->register_client
.manager_data
= client
;
544 cb
->interact_request
.callback
= KSMInteractRequestProc
;
545 cb
->interact_request
.manager_data
= client
;
546 cb
->interact_done
.callback
= KSMInteractDoneProc
;
547 cb
->interact_done
.manager_data
= client
;
548 cb
->save_yourself_request
.callback
= KSMSaveYourselfRequestProc
;
549 cb
->save_yourself_request
.manager_data
= client
;
550 cb
->save_yourself_phase2_request
.callback
= KSMSaveYourselfPhase2RequestProc
;
551 cb
->save_yourself_phase2_request
.manager_data
= client
;
552 cb
->save_yourself_done
.callback
= KSMSaveYourselfDoneProc
;
553 cb
->save_yourself_done
.manager_data
= client
;
554 cb
->close_connection
.callback
= KSMCloseConnectionProc
;
555 cb
->close_connection
.manager_data
= client
;
556 cb
->set_properties
.callback
= KSMSetPropertiesProc
;
557 cb
->set_properties
.manager_data
= client
;
558 cb
->delete_properties
.callback
= KSMDeletePropertiesProc
;
559 cb
->delete_properties
.manager_data
= client
;
560 cb
->get_properties
.callback
= KSMGetPropertiesProc
;
561 cb
->get_properties
.manager_data
= client
;
563 *mask_ret
= SmsRegisterClientProcMask
|
564 SmsInteractRequestProcMask
|
565 SmsInteractDoneProcMask
|
566 SmsSaveYourselfRequestProcMask
|
567 SmsSaveYourselfP2RequestProcMask
|
568 SmsSaveYourselfDoneProcMask
|
569 SmsCloseConnectionProcMask
|
570 SmsSetPropertiesProcMask
|
571 SmsDeletePropertiesProcMask
|
572 SmsGetPropertiesProcMask
;
577 #ifdef HAVE__ICETRANSNOLISTEN
578 extern "C" int _IceTransNoListen(const char * protocol
);
581 KSMServer::KSMServer( const QString
& windowManager
, bool _only_local
)
583 , logoutEffectWidget( NULL
)
585 new KSMServerInterfaceAdaptor( this );
586 QDBusConnection::sessionBus().registerObject("/KSMServer", this);
587 klauncherSignals
= new OrgKdeKLauncherInterface(QLatin1String("org.kde.klauncher"),
588 QLatin1String("/KLauncher"), QDBusConnection::sessionBus());
589 kcminitSignals
= NULL
;
594 shutdownType
= KWorkSpace::ShutdownTypeNone
;
597 dialogActive
= false;
599 wmPhase1WaitingCount
= 0;
600 KConfigGroup
config(KGlobal::config(), "General");
601 clientInteracting
= 0;
602 xonCommand
= config
.readEntry( "xonCommand", "xon" );
604 connect( &startupSuspendTimeoutTimer
, SIGNAL( timeout()), SLOT( startupSuspendTimeout()));
605 connect( &pendingShutdown
, SIGNAL( timeout()), SLOT( pendingShutdownTimeout()));
607 only_local
= _only_local
;
608 #ifdef HAVE__ICETRANSNOLISTEN
610 _IceTransNoListen("tcp");
616 if (!SmsInitialize ( (char*) KSMVendorString
, (char*) KSMReleaseString
,
619 HostBasedAuthProc
, 256, errormsg
) ) {
621 qWarning("KSMServer: could not register XSM protocol");
624 if (!IceListenForConnections (&numTransports
, &listenObjs
,
627 qWarning("KSMServer: Error listening for connections: %s", errormsg
);
628 qWarning("KSMServer: Aborting.");
633 // publish available transports.
634 QByteArray fName
= QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
635 QString display
= ::getenv("DISPLAY");
636 // strip the screen number from the display
637 display
.replace(QRegExp("\\.[0-9]+$"), "");
639 while( (i
= display
.indexOf(':')) >= 0)
642 fName
+= '_'+display
.toLocal8Bit();
644 f
= ::fopen(fName
.data(), "w+");
647 qWarning("KSMServer: cannot open %s: %s", fName
.data(), strerror(errno
));
648 qWarning("KSMServer: Aborting.");
651 char* session_manager
= IceComposeNetworkIdList(numTransports
, listenObjs
);
652 fprintf(f
, "%s\n%i\n", session_manager
, getpid());
654 setenv( "SESSION_MANAGER", session_manager
, true );
655 // Pass env. var to kdeinit.
656 org::kde::KLauncher
klauncher("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus());
657 klauncher
.setLaunchEnv( "SESSION_MANAGER", (const char*) session_manager
);
661 if (!SetAuthentication_local(numTransports
, listenObjs
))
662 qFatal("KSMSERVER: authentication setup failed.");
664 if (!SetAuthentication(numTransports
, listenObjs
, &authDataEntries
))
665 qFatal("KSMSERVER: authentication setup failed.");
668 IceAddConnectionWatch (KSMWatchProc
, (IcePointer
) this);
671 for ( int i
= 0; i
< numTransports
; i
++) {
672 con
= new KSMListener( listenObjs
[i
] );
673 listener
.append( con
);
674 connect( con
, SIGNAL( activated(int) ), this, SLOT( newConnection(int) ) );
677 signal(SIGHUP
, sighandler
);
678 signal(SIGTERM
, sighandler
);
679 signal(SIGINT
, sighandler
);
680 signal(SIGPIPE
, SIG_IGN
);
682 connect( &protectionTimer
, SIGNAL( timeout() ), this, SLOT( protectionTimeout() ) );
683 connect( &restoreTimer
, SIGNAL( timeout() ), this, SLOT( tryRestoreNext() ) );
684 connect( qApp
, SIGNAL( aboutToQuit() ), this, SLOT( cleanUp() ) );
687 KSMServer::~KSMServer()
689 qDeleteAll( listener
);
694 void KSMServer::cleanUp()
698 IceFreeListenObjs (numTransports
, listenObjs
);
700 QByteArray fName
= QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
701 QString display
= QString::fromLocal8Bit(::getenv("DISPLAY"));
702 // strip the screen number from the display
703 display
.replace(QRegExp("\\.[0-9]+$"), "");
705 while( (i
= display
.indexOf(':')) >= 0)
708 fName
+= '_'+display
.toLocal8Bit();
709 ::unlink(fName
.data());
711 FreeAuthenticationData(numTransports
, authDataEntries
);
712 signal(SIGTERM
, SIG_DFL
);
713 signal(SIGINT
, SIG_DFL
);
715 KDisplayManager().shutdown( shutdownType
, shutdownMode
, bootOption
);
720 void* KSMServer::watchConnection( IceConn iceConn
)
722 KSMConnection
* conn
= new KSMConnection( iceConn
);
723 connect( conn
, SIGNAL( activated(int) ), this, SLOT( processData(int) ) );
727 void KSMServer::removeConnection( KSMConnection
* conn
)
734 Called from our IceIoErrorHandler
736 void KSMServer::ioError( IceConn
/*iceConn*/ )
740 void KSMServer::processData( int /*socket*/ )
742 IceConn iceConn
= ((KSMConnection
*)sender())->iceConn
;
743 IceProcessMessagesStatus status
= IceProcessMessages( iceConn
, 0, 0 );
744 if ( status
== IceProcessMessagesIOError
) {
745 IceSetShutdownNegotiation( iceConn
, False
);
746 QList
<KSMClient
*>::iterator it
= clients
.begin();
747 QList
<KSMClient
*>::iterator
const itEnd
= clients
.end();
748 while ( ( it
!= itEnd
) && *it
&& ( SmsGetIceConnection( ( *it
)->connection() ) != iceConn
) )
750 if ( ( it
!= itEnd
) && *it
) {
751 SmsConn smsConn
= (*it
)->connection();
753 SmsCleanUp( smsConn
);
755 (void) IceCloseConnection( iceConn
);
759 KSMClient
* KSMServer::newClient( SmsConn conn
)
761 KSMClient
* client
= new KSMClient( conn
);
762 clients
.append( client
);
766 void KSMServer::deleteClient( KSMClient
* client
)
768 if ( !clients
.contains( client
) ) // paranoia
770 clients
.removeAll( client
);
771 if ( client
== clientInteracting
) {
772 clientInteracting
= 0;
773 handlePendingInteractions();
776 if ( state
== Shutdown
|| state
== Checkpoint
)
777 completeShutdownOrCheckpoint();
778 if ( state
== Killing
)
780 if ( state
== KillingWM
)
784 void KSMServer::newConnection( int /*socket*/ )
786 IceAcceptStatus status
;
787 IceConn iceConn
= IceAcceptConnection( ((KSMListener
*)sender())->listenObj
, &status
);
788 IceSetShutdownNegotiation( iceConn
, False
);
789 IceConnectStatus cstatus
;
790 while ((cstatus
= IceConnectionStatus (iceConn
))==IceConnectPending
) {
791 (void) IceProcessMessages( iceConn
, 0, 0 );
794 if (cstatus
!= IceConnectAccepted
) {
795 if (cstatus
== IceConnectIOError
)
796 kDebug( 1218 ) << "IO error opening ICE Connection!";
798 kDebug( 1218 ) << "ICE Connection rejected!";
799 (void )IceCloseConnection (iceConn
);
804 QString
KSMServer::currentSession()
806 if ( sessionGroup
.startsWith( "Session: " ) )
807 return sessionGroup
.mid( 9 );
808 return ""; // empty, not null, since used for KConfig::setGroup
811 void KSMServer::discardSession()
813 KConfigGroup
config(KGlobal::config(), sessionGroup
);
814 int count
= config
.readEntry( "count", 0 );
815 foreach ( KSMClient
*c
, clients
) {
816 QStringList discardCommand
= c
->discardCommand();
817 if ( discardCommand
.isEmpty())
819 // check that non of the old clients used the exactly same
820 // discardCommand before we execute it. This used to be the
821 // case up to KDE and Qt < 3.1
823 while ( i
<= count
&&
824 config
.readPathEntry( QString("discardCommand") + QString::number(i
), QStringList() ) != discardCommand
)
827 executeCommand( discardCommand
);
831 void KSMServer::storeSession()
833 KSharedConfig::Ptr config
= KGlobal::config();
834 config
->reparseConfiguration(); // config may have changed in the KControl module
835 KConfigGroup
generalGroup(config
, "General");
836 excludeApps
= generalGroup
.readEntry( "excludeApps" ).toLower().split( QRegExp( "[,:]" ), QString::SkipEmptyParts
);
837 KConfigGroup
configSessionGroup(config
, sessionGroup
);
838 int count
= configSessionGroup
.readEntry( "count", 0 );
839 for ( int i
= 1; i
<= count
; i
++ ) {
840 QStringList discardCommand
= configSessionGroup
.readPathEntry( QLatin1String("discardCommand") + QString::number(i
), QStringList() );
841 if ( discardCommand
.isEmpty())
843 // check that non of the new clients uses the exactly same
844 // discardCommand before we execute it. This used to be the
845 // case up to KDE and Qt < 3.1
846 QList
<KSMClient
*>::iterator it
= clients
.begin();
847 QList
<KSMClient
*>::iterator
const itEnd
= clients
.end();
848 while ( ( it
!= itEnd
) && *it
&& (discardCommand
!= ( *it
)->discardCommand() ) )
850 if ( ( it
!= itEnd
) && *it
)
852 executeCommand( discardCommand
);
854 config
->deleteGroup( sessionGroup
); //### does not work with global config object...
855 KConfigGroup
cg( config
, sessionGroup
);
858 if ( !wm
.isEmpty() ) {
860 foreach ( KSMClient
*c
, clients
)
861 if ( c
->program() == wm
) {
862 clients
.removeAll( c
);
863 clients
.prepend( c
);
868 foreach ( KSMClient
*c
, clients
) {
869 int restartHint
= c
->restartStyleHint();
870 if (restartHint
== SmRestartNever
)
872 QString program
= c
->program();
873 QStringList restartCommand
= c
->restartCommand();
874 if (program
.isEmpty() && restartCommand
.isEmpty())
876 if (excludeApps
.contains( program
.toLower()))
880 QString n
= QString::number(count
);
881 cg
.writeEntry( QString("program")+n
, program
);
882 cg
.writeEntry( QString("clientId")+n
, c
->clientId() );
883 cg
.writeEntry( QString("restartCommand")+n
, restartCommand
);
884 cg
.writePathEntry( QString("discardCommand")+n
, c
->discardCommand() );
885 cg
.writeEntry( QString("restartStyleHint")+n
, restartHint
);
886 cg
.writeEntry( QString("userId")+n
, c
->userId() );
888 cg
.writeEntry( "count", count
);
890 KConfigGroup
cg2( config
, "General");
891 cg2
.writeEntry( "screenCount", ScreenCount(QX11Info::display()));
893 storeLegacySession(config
.data());
897 QStringList
KSMServer::sessionList()
899 QStringList
sessions ( "default" );
900 KSharedConfig::Ptr config
= KGlobal::config();
901 QStringList groups
= config
->groupList();
902 for ( QStringList::ConstIterator it
= groups
.begin(); it
!= groups
.end(); it
++ )
903 if ( (*it
).startsWith( "Session: " ) )
904 sessions
<< (*it
).mid( 9 );
908 bool KSMServer::isWM( const KSMClient
* client
) const
910 return isWM( client
->program());
913 bool KSMServer::isWM( const QString
& command
) const
915 // KWin relies on ksmserver's special treatment in phase1,
916 // therefore make sure it's recognized even if ksmserver
917 // was initially started with different WM, and kwin replaced
919 return command
== wm
|| command
== "kwin";
922 bool KSMServer::defaultSession() const
924 return sessionGroup
.isEmpty();