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 ******************************************************************/
35 #include "ksmserverinterfaceadaptor.h"
37 #include <config-workspace.h>
38 #include <config-unix.h> // HAVE_LIMITS_H
39 #include <config-ksmserver.h>
41 #include <sys/types.h>
42 #include <sys/param.h>
44 #ifdef HAVE_SYS_TIME_H
47 #include <sys/socket.h>
65 #include <QPushButton>
67 #include <QtDBus/QtDBus>
68 #include <QSocketNotifier>
73 #include <kdesktopfile.h>
74 #include <kstandarddirs.h>
75 #include <kapplication.h>
76 #include <ktemporaryfile.h>
77 #include <kconfiggroup.h>
85 #include <kdisplaymanager.h>
88 #include "klauncher_interface.h"
90 KSMServer
* the_server
= 0;
92 KSMServer
* KSMServer::self()
97 /*! Utility function to execute a command on the local machine. Used
98 * to restart applications.
100 KProcess
* KSMServer::startApplication( const QStringList
& cmd
, const QString
& clientMachine
,
101 const QString
& userId
)
103 QStringList command
= cmd
;
104 if ( command
.isEmpty() )
106 if ( !userId
.isEmpty()) {
107 struct passwd
* pw
= getpwuid( getuid());
108 if( pw
!= NULL
&& userId
!= QString::fromLocal8Bit( pw
->pw_name
)) {
109 command
.prepend( "--" );
110 command
.prepend( userId
);
111 command
.prepend( "-u" );
112 command
.prepend( KStandardDirs::findExe("kdesu") );
115 if ( !clientMachine
.isEmpty() && clientMachine
!= "localhost" ) {
116 command
.prepend( clientMachine
);
117 command
.prepend( xonCommand
); // "xon" by default
119 KProcess
* process
= new KProcess( this );
121 // make it auto-delete
122 connect( process
, SIGNAL( error( QProcess::ProcessError
)), process
, SLOT( deleteLater()));
123 connect( process
, SIGNAL( finished( int, QProcess::ExitStatus
)), process
, SLOT( deleteLater()));
128 /*! Utility function to execute a command on the local machine. Used
129 * to discard session data
131 void KSMServer::executeCommand( const QStringList
& command
)
133 if ( command
.isEmpty() )
136 KProcess::execute( command
);
139 IceAuthDataEntry
*authDataEntries
= 0;
141 static KTemporaryFile
*remTempFile
= 0;
143 static IceListenObj
*listenObjs
= 0;
144 int numTransports
= 0;
145 static bool only_local
= 0;
147 static Bool
HostBasedAuthProc ( char* /*hostname*/)
156 Status
KSMRegisterClientProc (
157 SmsConn
/* smsConn */,
158 SmPointer managerData
,
162 KSMClient
* client
= (KSMClient
*) managerData
;
163 client
->registerClient( previousId
);
167 void KSMInteractRequestProc (
168 SmsConn
/* smsConn */,
169 SmPointer managerData
,
173 the_server
->interactRequest( (KSMClient
*) managerData
, dialogType
);
176 void KSMInteractDoneProc (
177 SmsConn
/* smsConn */,
178 SmPointer managerData
,
182 the_server
->interactDone( (KSMClient
*) managerData
, cancelShutdown
);
185 void KSMSaveYourselfRequestProc (
187 SmPointer
/* managerData */,
196 the_server
->shutdown( fast
?
197 KWorkSpace::ShutdownConfirmNo
:
198 KWorkSpace::ShutdownConfirmDefault
,
199 KWorkSpace::ShutdownTypeDefault
,
200 KWorkSpace::ShutdownModeDefault
);
201 } else if ( !global
) {
202 SmsSaveYourself( smsConn
, saveType
, false, interactStyle
, fast
);
203 SmsSaveComplete( smsConn
);
205 // else checkpoint only, ksmserver does not yet support this
206 // mode. Will come for KDE 3.1
209 void KSMSaveYourselfPhase2RequestProc (
210 SmsConn
/* smsConn */,
211 SmPointer managerData
214 the_server
->phase2Request( (KSMClient
*) managerData
);
217 void KSMSaveYourselfDoneProc (
218 SmsConn
/* smsConn */,
219 SmPointer managerData
,
223 the_server
->saveYourselfDone( (KSMClient
*) managerData
, success
);
226 void KSMCloseConnectionProc (
228 SmPointer managerData
,
233 the_server
->deleteClient( ( KSMClient
* ) managerData
);
235 SmFreeReasons( count
, reasonMsgs
);
236 IceConn iceConn
= SmsGetIceConnection( smsConn
);
237 SmsCleanUp( smsConn
);
238 IceSetShutdownNegotiation (iceConn
, False
);
239 IceCloseConnection( iceConn
);
242 void KSMSetPropertiesProc (
243 SmsConn
/* smsConn */,
244 SmPointer managerData
,
249 KSMClient
* client
= ( KSMClient
* ) managerData
;
250 for ( int i
= 0; i
< numProps
; i
++ ) {
251 SmProp
*p
= client
->property( props
[i
]->name
);
253 client
->properties
.removeAll( p
);
256 client
->properties
.append( props
[i
] );
257 if ( !qstrcmp( props
[i
]->name
, SmProgram
) )
258 the_server
->clientSetProgram( client
);
266 void KSMDeletePropertiesProc (
267 SmsConn
/* smsConn */,
268 SmPointer managerData
,
273 KSMClient
* client
= ( KSMClient
* ) managerData
;
274 for ( int i
= 0; i
< numProps
; i
++ ) {
275 SmProp
*p
= client
->property( propNames
[i
] );
277 client
->properties
.removeAll( p
);
283 void KSMGetPropertiesProc (
285 SmPointer managerData
288 KSMClient
* client
= ( KSMClient
* ) managerData
;
289 SmProp
** props
= new SmProp
*[client
->properties
.count()];
291 foreach( SmProp
*prop
, client
->properties
)
294 SmsReturnProperties( smsConn
, i
, props
);
299 class KSMListener
: public QSocketNotifier
302 KSMListener( IceListenObj obj
)
303 : QSocketNotifier( IceGetListenConnectionNumber( obj
),
304 QSocketNotifier::Read
)
309 IceListenObj listenObj
;
312 class KSMConnection
: public QSocketNotifier
315 KSMConnection( IceConn conn
)
316 : QSocketNotifier( IceConnectionNumber( conn
),
317 QSocketNotifier::Read
)
326 /* for printing hex digits */
327 static void fprintfhex (FILE *fp
, unsigned int len
, char *cp
)
329 static const char hexchars
[] = "0123456789abcdef";
331 for (; len
> 0; len
--, cp
++) {
332 unsigned char s
= *cp
;
333 putc(hexchars
[s
>> 4], fp
);
334 putc(hexchars
[s
& 0x0f], fp
);
339 * We use temporary files which contain commands to add/remove entries from
340 * the .ICEauthority file.
342 static void write_iceauth (FILE *addfp
, FILE *removefp
, IceAuthDataEntry
*entry
)
345 "add %s \"\" %s %s ",
346 entry
->protocol_name
,
349 fprintfhex (addfp
, entry
->auth_data_length
, entry
->auth_data
);
350 fprintf (addfp
, "\n");
353 "remove protoname=%s protodata=\"\" netid=%s authname=%s\n",
354 entry
->protocol_name
,
360 #define MAGIC_COOKIE_LEN 16
362 Status
SetAuthentication_local (int count
, IceListenObj
*listenObjs
)
365 for (i
= 0; i
< count
; i
++) {
366 char *prot
= IceGetListenConnectionString(listenObjs
[i
]);
368 char *host
= strchr(prot
, '/');
373 sock
= strchr(host
, ':');
379 kDebug( 1218 ) << "KSMServer: SetAProc_loc: conn " << (unsigned)i
<< ", prot=" << prot
<< ", file=" << sock
;
380 if (sock
&& !strcmp(prot
, "local")) {
383 IceSetHostBasedAuthProc (listenObjs
[i
], HostBasedAuthProc
);
389 Status
SetAuthentication (int count
, IceListenObj
*listenObjs
,
390 IceAuthDataEntry
**authDataEntries
)
392 KTemporaryFile addTempFile
;
393 remTempFile
= new KTemporaryFile
;
395 if (!addTempFile
.open() || !remTempFile
->open())
398 if ((*authDataEntries
= (IceAuthDataEntry
*) malloc (
399 count
* 2 * sizeof (IceAuthDataEntry
))) == NULL
)
402 FILE *addAuthFile
= fopen(QFile::encodeName(addTempFile
.fileName()), "r+");
403 FILE *remAuthFile
= fopen(QFile::encodeName(remTempFile
->fileName()), "r+");
405 for (int i
= 0; i
< numTransports
* 2; i
+= 2) {
406 (*authDataEntries
)[i
].network_id
=
407 IceGetListenConnectionString (listenObjs
[i
/2]);
408 (*authDataEntries
)[i
].protocol_name
= (char *) "ICE";
409 (*authDataEntries
)[i
].auth_name
= (char *) "MIT-MAGIC-COOKIE-1";
411 (*authDataEntries
)[i
].auth_data
=
412 IceGenerateMagicCookie (MAGIC_COOKIE_LEN
);
413 (*authDataEntries
)[i
].auth_data_length
= MAGIC_COOKIE_LEN
;
415 (*authDataEntries
)[i
+1].network_id
=
416 IceGetListenConnectionString (listenObjs
[i
/2]);
417 (*authDataEntries
)[i
+1].protocol_name
= (char *) "XSMP";
418 (*authDataEntries
)[i
+1].auth_name
= (char *) "MIT-MAGIC-COOKIE-1";
420 (*authDataEntries
)[i
+1].auth_data
=
421 IceGenerateMagicCookie (MAGIC_COOKIE_LEN
);
422 (*authDataEntries
)[i
+1].auth_data_length
= MAGIC_COOKIE_LEN
;
424 write_iceauth (addAuthFile
, remAuthFile
, &(*authDataEntries
)[i
]);
425 write_iceauth (addAuthFile
, remAuthFile
, &(*authDataEntries
)[i
+1]);
427 IceSetPaAuthData (2, &(*authDataEntries
)[i
]);
429 IceSetHostBasedAuthProc (listenObjs
[i
/2], HostBasedAuthProc
);
434 QString iceAuth
= KGlobal::dirs()->findExe("iceauth");
435 if (iceAuth
.isEmpty())
437 qWarning("KSMServer: could not find iceauth");
442 p
<< iceAuth
<< "source" << addTempFile
.fileName();
449 * Free up authentication data.
451 void FreeAuthenticationData(int count
, IceAuthDataEntry
*authDataEntries
)
453 /* Each transport has entries for ICE and XSMP */
457 for (int i
= 0; i
< count
* 2; i
++) {
458 free (authDataEntries
[i
].network_id
);
459 free (authDataEntries
[i
].auth_data
);
462 free (authDataEntries
);
464 QString iceAuth
= KGlobal::dirs()->findExe("iceauth");
465 if (iceAuth
.isEmpty())
467 qWarning("KSMServer: could not find iceauth");
474 p
<< iceAuth
<< "source" << remTempFile
->fileName();
482 static int Xio_ErrorHandler( Display
* )
484 qWarning("ksmserver: Fatal IO error: client killed");
486 // Don't do anything that might require the X connection
489 KSMServer
*server
= the_server
;
492 // Don't delete server!!
495 exit(0); // Don't report error, it's not our fault.
496 return 0; // Bogus return value, notreached
499 void KSMServer::setupXIOErrorHandler()
501 XSetIOErrorHandler(Xio_ErrorHandler
);
504 static void sighandler(int sig
)
507 signal(SIGHUP
, sighandler
);
513 KSMServer
*server
= the_server
;
525 void KSMWatchProc ( IceConn iceConn
, IcePointer client_data
, Bool opening
, IcePointer
* watch_data
)
527 KSMServer
* ds
= ( KSMServer
*) client_data
;
530 *watch_data
= (IcePointer
) ds
->watchConnection( iceConn
);
533 ds
->removeConnection( (KSMConnection
*) *watch_data
);
537 static Status
KSMNewClientProc ( SmsConn conn
, SmPointer manager_data
,
538 unsigned long* mask_ret
, SmsCallbacks
* cb
, char** failure_reason_ret
)
540 *failure_reason_ret
= 0;
542 void* client
= ((KSMServer
*) manager_data
)->newClient( conn
);
544 cb
->register_client
.callback
= KSMRegisterClientProc
;
545 cb
->register_client
.manager_data
= client
;
546 cb
->interact_request
.callback
= KSMInteractRequestProc
;
547 cb
->interact_request
.manager_data
= client
;
548 cb
->interact_done
.callback
= KSMInteractDoneProc
;
549 cb
->interact_done
.manager_data
= client
;
550 cb
->save_yourself_request
.callback
= KSMSaveYourselfRequestProc
;
551 cb
->save_yourself_request
.manager_data
= client
;
552 cb
->save_yourself_phase2_request
.callback
= KSMSaveYourselfPhase2RequestProc
;
553 cb
->save_yourself_phase2_request
.manager_data
= client
;
554 cb
->save_yourself_done
.callback
= KSMSaveYourselfDoneProc
;
555 cb
->save_yourself_done
.manager_data
= client
;
556 cb
->close_connection
.callback
= KSMCloseConnectionProc
;
557 cb
->close_connection
.manager_data
= client
;
558 cb
->set_properties
.callback
= KSMSetPropertiesProc
;
559 cb
->set_properties
.manager_data
= client
;
560 cb
->delete_properties
.callback
= KSMDeletePropertiesProc
;
561 cb
->delete_properties
.manager_data
= client
;
562 cb
->get_properties
.callback
= KSMGetPropertiesProc
;
563 cb
->get_properties
.manager_data
= client
;
565 *mask_ret
= SmsRegisterClientProcMask
|
566 SmsInteractRequestProcMask
|
567 SmsInteractDoneProcMask
|
568 SmsSaveYourselfRequestProcMask
|
569 SmsSaveYourselfP2RequestProcMask
|
570 SmsSaveYourselfDoneProcMask
|
571 SmsCloseConnectionProcMask
|
572 SmsSetPropertiesProcMask
|
573 SmsDeletePropertiesProcMask
|
574 SmsGetPropertiesProcMask
;
579 #ifdef HAVE__ICETRANSNOLISTEN
580 extern "C" int _IceTransNoListen(const char * protocol
);
583 KSMServer::KSMServer( const QString
& windowManager
, bool _only_local
)
586 , logoutEffectWidget( NULL
)
588 new KSMServerInterfaceAdaptor( this );
589 QDBusConnection::sessionBus().registerObject("/KSMServer", this);
590 klauncherSignals
= new OrgKdeKLauncherInterface(QLatin1String("org.kde.klauncher"),
591 QLatin1String("/KLauncher"), QDBusConnection::sessionBus());
592 kcminitSignals
= NULL
;
596 shutdownType
= KWorkSpace::ShutdownTypeNone
;
599 dialogActive
= false;
601 wmPhase1WaitingCount
= 0;
602 KConfigGroup
config(KGlobal::config(), "General");
603 clientInteracting
= 0;
604 xonCommand
= config
.readEntry( "xonCommand", "xon" );
606 KGlobal::dirs()->addResourceType( "windowmanagers", "data", "ksmserver/windowmanagers" );
607 selectWm( windowManager
);
609 connect( &startupSuspendTimeoutTimer
, SIGNAL( timeout()), SLOT( startupSuspendTimeout()));
610 connect( &pendingShutdown
, SIGNAL( timeout()), SLOT( pendingShutdownTimeout()));
612 only_local
= _only_local
;
613 #ifdef HAVE__ICETRANSNOLISTEN
615 _IceTransNoListen("tcp");
621 if (!SmsInitialize ( (char*) KSMVendorString
, (char*) KSMReleaseString
,
624 HostBasedAuthProc
, 256, errormsg
) ) {
626 qWarning("KSMServer: could not register XSM protocol");
629 if (!IceListenForConnections (&numTransports
, &listenObjs
,
632 qWarning("KSMServer: Error listening for connections: %s", errormsg
);
633 qWarning("KSMServer: Aborting.");
638 // publish available transports.
639 QByteArray fName
= QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
640 QString display
= ::getenv("DISPLAY");
641 // strip the screen number from the display
642 display
.replace(QRegExp("\\.[0-9]+$"), "");
644 while( (i
= display
.indexOf(':')) >= 0)
647 fName
+= '_'+display
.toLocal8Bit();
649 f
= ::fopen(fName
.data(), "w+");
652 qWarning("KSMServer: cannot open %s: %s", fName
.data(), strerror(errno
));
653 qWarning("KSMServer: Aborting.");
656 char* session_manager
= IceComposeNetworkIdList(numTransports
, listenObjs
);
657 fprintf(f
, "%s\n%i\n", session_manager
, getpid());
659 setenv( "SESSION_MANAGER", session_manager
, true );
660 // Pass env. var to kdeinit.
661 org::kde::KLauncher
klauncher("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus());
662 klauncher
.setLaunchEnv( "SESSION_MANAGER", (const char*) session_manager
);
666 if (!SetAuthentication_local(numTransports
, listenObjs
))
667 qFatal("KSMSERVER: authentication setup failed.");
669 if (!SetAuthentication(numTransports
, listenObjs
, &authDataEntries
))
670 qFatal("KSMSERVER: authentication setup failed.");
673 IceAddConnectionWatch (KSMWatchProc
, (IcePointer
) this);
676 for ( int i
= 0; i
< numTransports
; i
++) {
677 fcntl( IceGetListenConnectionNumber( listenObjs
[i
] ), F_SETFD
, FD_CLOEXEC
);
678 con
= new KSMListener( listenObjs
[i
] );
679 listener
.append( con
);
680 connect( con
, SIGNAL( activated(int) ), this, SLOT( newConnection(int) ) );
683 signal(SIGHUP
, sighandler
);
684 signal(SIGTERM
, sighandler
);
685 signal(SIGINT
, sighandler
);
686 signal(SIGPIPE
, SIG_IGN
);
688 connect( &protectionTimer
, SIGNAL( timeout() ), this, SLOT( protectionTimeout() ) );
689 connect( &restoreTimer
, SIGNAL( timeout() ), this, SLOT( tryRestoreNext() ) );
690 connect( qApp
, SIGNAL( aboutToQuit() ), this, SLOT( cleanUp() ) );
693 KSMServer::~KSMServer()
695 qDeleteAll( listener
);
700 void KSMServer::cleanUp()
704 IceFreeListenObjs (numTransports
, listenObjs
);
706 QByteArray fName
= QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
707 QString display
= QString::fromLocal8Bit(::getenv("DISPLAY"));
708 // strip the screen number from the display
709 display
.replace(QRegExp("\\.[0-9]+$"), "");
711 while( (i
= display
.indexOf(':')) >= 0)
714 fName
+= '_'+display
.toLocal8Bit();
715 ::unlink(fName
.data());
717 FreeAuthenticationData(numTransports
, authDataEntries
);
718 signal(SIGTERM
, SIG_DFL
);
719 signal(SIGINT
, SIG_DFL
);
721 KDisplayManager().shutdown( shutdownType
, shutdownMode
, bootOption
);
726 void* KSMServer::watchConnection( IceConn iceConn
)
728 KSMConnection
* conn
= new KSMConnection( iceConn
);
729 connect( conn
, SIGNAL( activated(int) ), this, SLOT( processData(int) ) );
733 void KSMServer::removeConnection( KSMConnection
* conn
)
740 Called from our IceIoErrorHandler
742 void KSMServer::ioError( IceConn
/*iceConn*/ )
746 void KSMServer::processData( int /*socket*/ )
748 IceConn iceConn
= ((KSMConnection
*)sender())->iceConn
;
749 IceProcessMessagesStatus status
= IceProcessMessages( iceConn
, 0, 0 );
750 if ( status
== IceProcessMessagesIOError
) {
751 IceSetShutdownNegotiation( iceConn
, False
);
752 QList
<KSMClient
*>::iterator it
= clients
.begin();
753 QList
<KSMClient
*>::iterator
const itEnd
= clients
.end();
754 while ( ( it
!= itEnd
) && *it
&& ( SmsGetIceConnection( ( *it
)->connection() ) != iceConn
) )
756 if ( ( it
!= itEnd
) && *it
) {
757 SmsConn smsConn
= (*it
)->connection();
759 SmsCleanUp( smsConn
);
761 (void) IceCloseConnection( iceConn
);
765 KSMClient
* KSMServer::newClient( SmsConn conn
)
767 KSMClient
* client
= new KSMClient( conn
);
768 clients
.append( client
);
772 void KSMServer::deleteClient( KSMClient
* client
)
774 if ( !clients
.contains( client
) ) // paranoia
776 clients
.removeAll( client
);
777 if ( client
== clientInteracting
) {
778 clientInteracting
= 0;
779 handlePendingInteractions();
782 if ( state
== Shutdown
|| state
== Checkpoint
)
783 completeShutdownOrCheckpoint();
784 if ( state
== Killing
)
786 if ( state
== KillingWM
)
790 void KSMServer::newConnection( int /*socket*/ )
792 IceAcceptStatus status
;
793 IceConn iceConn
= IceAcceptConnection( ((KSMListener
*)sender())->listenObj
, &status
);
794 IceSetShutdownNegotiation( iceConn
, False
);
795 IceConnectStatus cstatus
;
796 while ((cstatus
= IceConnectionStatus (iceConn
))==IceConnectPending
) {
797 (void) IceProcessMessages( iceConn
, 0, 0 );
800 if (cstatus
!= IceConnectAccepted
) {
801 if (cstatus
== IceConnectIOError
)
802 kDebug( 1218 ) << "IO error opening ICE Connection!";
804 kDebug( 1218 ) << "ICE Connection rejected!";
805 (void )IceCloseConnection (iceConn
);
809 fcntl( IceConnectionNumber(iceConn
), F_SETFD
, FD_CLOEXEC
);
813 QString
KSMServer::currentSession()
815 if ( sessionGroup
.startsWith( "Session: " ) )
816 return sessionGroup
.mid( 9 );
817 return ""; // empty, not null, since used for KConfig::setGroup
820 void KSMServer::discardSession()
822 KConfigGroup
config(KGlobal::config(), sessionGroup
);
823 int count
= config
.readEntry( "count", 0 );
824 foreach ( KSMClient
*c
, clients
) {
825 QStringList discardCommand
= c
->discardCommand();
826 if ( discardCommand
.isEmpty())
828 // check that non of the old clients used the exactly same
829 // discardCommand before we execute it. This used to be the
830 // case up to KDE and Qt < 3.1
832 while ( i
<= count
&&
833 config
.readPathEntry( QString("discardCommand") + QString::number(i
), QStringList() ) != discardCommand
)
836 executeCommand( discardCommand
);
840 void KSMServer::storeSession()
842 KSharedConfig::Ptr config
= KGlobal::config();
843 config
->reparseConfiguration(); // config may have changed in the KControl module
844 KConfigGroup
generalGroup(config
, "General");
845 excludeApps
= generalGroup
.readEntry( "excludeApps" ).toLower().split( QRegExp( "[,:]" ), QString::SkipEmptyParts
);
846 KConfigGroup
configSessionGroup(config
, sessionGroup
);
847 int count
= configSessionGroup
.readEntry( "count", 0 );
848 for ( int i
= 1; i
<= count
; i
++ ) {
849 QStringList discardCommand
= configSessionGroup
.readPathEntry( QLatin1String("discardCommand") + QString::number(i
), QStringList() );
850 if ( discardCommand
.isEmpty())
852 // check that non of the new clients uses the exactly same
853 // discardCommand before we execute it. This used to be the
854 // case up to KDE and Qt < 3.1
855 QList
<KSMClient
*>::iterator it
= clients
.begin();
856 QList
<KSMClient
*>::iterator
const itEnd
= clients
.end();
857 while ( ( it
!= itEnd
) && *it
&& (discardCommand
!= ( *it
)->discardCommand() ) )
859 if ( ( it
!= itEnd
) && *it
)
861 executeCommand( discardCommand
);
863 config
->deleteGroup( sessionGroup
); //### does not work with global config object...
864 KConfigGroup
cg( config
, sessionGroup
);
868 foreach ( KSMClient
*c
, clients
)
869 if ( c
->program() == wm
) {
870 clients
.removeAll( c
);
871 clients
.prepend( c
);
875 foreach ( KSMClient
*c
, clients
) {
876 int restartHint
= c
->restartStyleHint();
877 if (restartHint
== SmRestartNever
)
879 QString program
= c
->program();
880 QStringList restartCommand
= c
->restartCommand();
881 if (program
.isEmpty() && restartCommand
.isEmpty())
883 if (excludeApps
.contains( program
.toLower()))
887 QString n
= QString::number(count
);
888 cg
.writeEntry( QString("program")+n
, program
);
889 cg
.writeEntry( QString("clientId")+n
, c
->clientId() );
890 cg
.writeEntry( QString("restartCommand")+n
, restartCommand
);
891 cg
.writePathEntry( QString("discardCommand")+n
, c
->discardCommand() );
892 cg
.writeEntry( QString("restartStyleHint")+n
, restartHint
);
893 cg
.writeEntry( QString("userId")+n
, c
->userId() );
894 cg
.writeEntry( QString("wasWm")+n
, isWM( c
));
896 cg
.writeEntry( "count", count
);
898 KConfigGroup
cg2( config
, "General");
899 cg2
.writeEntry( "screenCount", ScreenCount(QX11Info::display()));
901 storeLegacySession(config
.data());
905 QStringList
KSMServer::sessionList()
907 QStringList
sessions ( "default" );
908 KSharedConfig::Ptr config
= KGlobal::config();
909 const QStringList groups
= config
->groupList();
910 for ( QStringList::ConstIterator it
= groups
.constBegin(); it
!= groups
.constEnd(); it
++ )
911 if ( (*it
).startsWith( "Session: " ) )
912 sessions
<< (*it
).mid( 9 );
916 bool KSMServer::isWM( const KSMClient
* client
) const
918 return isWM( client
->program());
921 bool KSMServer::isWM( const QString
& command
) const
923 return command
== wm
;
926 bool KSMServer::defaultSession() const
928 return sessionGroup
.isEmpty();
932 // - $KDEWM is set - use that
933 // - a wm is selected using the kcm - use that
934 // - if that fails, just use KWin
935 void KSMServer::selectWm( const QString
& kdewm
)
937 wm
= "kwin"; // defaults
938 wmCommands
= ( QStringList() << "kwin" );
939 if( qstrcmp( getenv( "KDE_FAILSAFE" ), "1" ) == 0 )
940 return; // failsafe, force kwin
941 if( !kdewm
.isEmpty())
943 wmCommands
= ( QStringList() << kdewm
);
947 KConfigGroup
config(KGlobal::config(), "General");
948 QString cfgwm
= config
.readEntry( "windowManager", "kwin" );
949 KDesktopFile
file( "windowmanagers", cfgwm
+ ".desktop" );
950 if( file
.noDisplay())
954 QString testexec
= file
.desktopGroup().readEntry( "X-KDE-WindowManagerTestExec" );
955 if( !testexec
.isEmpty())
958 proc
.setShellCommand( testexec
);
959 if( proc
.execute() != 0 )
962 QStringList cfgWmCommands
= KShell::splitArgs( file
.desktopGroup().readEntry( "Exec" ));
963 if( cfgWmCommands
.isEmpty())
965 QString smname
= file
.desktopGroup().readEntry( "X-KDE-WindowManagerId" );
967 wm
= smname
.isEmpty() ? cfgwm
: smname
;
968 wmCommands
= cfgWmCommands
;
971 void KSMServer::wmChanged()
973 KGlobal::config()->reparseConfiguration();