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>
71
#include <kactioncollection.h>
72
#include <kauthorized.h>
76
#include <kdesktopfile.h>
77
#include <kstandarddirs.h>
78
#include <kapplication.h>
79
#include <ktemporaryfile.h>
80
#include <kconfiggroup.h>
87
#include <kdisplaymanager.h>
90
#include <klauncher_iface.h>
92
KSMServer* the_server = 0;
94
KSMServer* KSMServer::self()
99
/*! Utility function to execute a command on the local machine. Used
100
* to restart applications.
102
KProcess* KSMServer::startApplication( const QStringList& cmd, const QString& clientMachine,
103
const QString& userId, bool wm )
105
QStringList command = cmd;
106
if ( command.isEmpty() )
108
if ( !userId.isEmpty()) {
109
struct passwd* pw = getpwuid( getuid());
110
if( pw != NULL && userId != QString::fromLocal8Bit( pw->pw_name )) {
111
command.prepend( "--" );
112
command.prepend( userId );
113
command.prepend( "-u" );
114
command.prepend( KStandardDirs::findExe("kdesu") );
117
if ( !clientMachine.isEmpty() && clientMachine != "localhost" ) {
118
command.prepend( clientMachine );
119
command.prepend( xonCommand ); // "xon" by default
122
// TODO this function actually should not use KProcess at all and use klauncher (kdeinit) instead.
123
// Klauncher should also have support for tracking whether the launched process is still alive
124
// or not, so this should be redone. For now, use KProcess for wm's, as they need to be tracked,
125
// klauncher for the rest where ksmserver doesn't care.
127
KProcess* process = new KProcess( this );
129
// make it auto-delete
130
connect( process, SIGNAL( error( QProcess::ProcessError )), process, SLOT( deleteLater()));
131
connect( process, SIGNAL( finished( int, QProcess::ExitStatus )), process, SLOT( deleteLater()));
135
int n = command.count();
136
org::kde::KLauncher klauncher("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus());
137
QString app = command[0];
139
for ( int i=1; i < n; i++)
140
argList.append( command[i]);
141
klauncher.exec_blind(app, argList );
146
/*! Utility function to execute a command on the local machine. Used
147
* to discard session data
149
void KSMServer::executeCommand( const QStringList& command )
151
if ( command.isEmpty() )
154
KProcess::execute( command );
157
IceAuthDataEntry *authDataEntries = 0;
159
static KTemporaryFile *remTempFile = 0;
161
static IceListenObj *listenObjs = 0;
162
int numTransports = 0;
163
static bool only_local = 0;
165
static Bool HostBasedAuthProc ( char* /*hostname*/)
174
Status KSMRegisterClientProc (
175
SmsConn /* smsConn */,
176
SmPointer managerData,
180
KSMClient* client = (KSMClient*) managerData;
181
client->registerClient( previousId );
185
void KSMInteractRequestProc (
186
SmsConn /* smsConn */,
187
SmPointer managerData,
191
the_server->interactRequest( (KSMClient*) managerData, dialogType );
194
void KSMInteractDoneProc (
195
SmsConn /* smsConn */,
196
SmPointer managerData,
200
the_server->interactDone( (KSMClient*) managerData, cancelShutdown );
203
void KSMSaveYourselfRequestProc (
205
SmPointer /* managerData */,
214
the_server->shutdown( fast ?
215
KWorkSpace::ShutdownConfirmNo :
216
KWorkSpace::ShutdownConfirmDefault,
217
KWorkSpace::ShutdownTypeDefault,
218
KWorkSpace::ShutdownModeDefault );
219
} else if ( !global ) {
220
SmsSaveYourself( smsConn, saveType, false, interactStyle, fast );
221
SmsSaveComplete( smsConn );
223
// else checkpoint only, ksmserver does not yet support this
224
// mode. Will come for KDE 3.1
227
void KSMSaveYourselfPhase2RequestProc (
228
SmsConn /* smsConn */,
229
SmPointer managerData
232
the_server->phase2Request( (KSMClient*) managerData );
235
void KSMSaveYourselfDoneProc (
236
SmsConn /* smsConn */,
237
SmPointer managerData,
241
the_server->saveYourselfDone( (KSMClient*) managerData, success );
244
void KSMCloseConnectionProc (
246
SmPointer managerData,
251
the_server->deleteClient( ( KSMClient* ) managerData );
253
SmFreeReasons( count, reasonMsgs );
254
IceConn iceConn = SmsGetIceConnection( smsConn );
255
SmsCleanUp( smsConn );
256
IceSetShutdownNegotiation (iceConn, False);
257
IceCloseConnection( iceConn );
260
void KSMSetPropertiesProc (
261
SmsConn /* smsConn */,
262
SmPointer managerData,
267
KSMClient* client = ( KSMClient* ) managerData;
268
for ( int i = 0; i < numProps; i++ ) {
269
SmProp *p = client->property( props[i]->name );
271
client->properties.removeAll( p );
274
client->properties.append( props[i] );
275
if ( !qstrcmp( props[i]->name, SmProgram ) )
276
the_server->clientSetProgram( client );
284
void KSMDeletePropertiesProc (
285
SmsConn /* smsConn */,
286
SmPointer managerData,
291
KSMClient* client = ( KSMClient* ) managerData;
292
for ( int i = 0; i < numProps; i++ ) {
293
SmProp *p = client->property( propNames[i] );
295
client->properties.removeAll( p );
301
void KSMGetPropertiesProc (
303
SmPointer managerData
306
KSMClient* client = ( KSMClient* ) managerData;
307
SmProp** props = new SmProp*[client->properties.count()];
309
foreach( SmProp *prop, client->properties )
312
SmsReturnProperties( smsConn, i, props );
317
class KSMListener : public QSocketNotifier
320
KSMListener( IceListenObj obj )
321
: QSocketNotifier( IceGetListenConnectionNumber( obj ),
322
QSocketNotifier::Read )
327
IceListenObj listenObj;
330
class KSMConnection : public QSocketNotifier
333
KSMConnection( IceConn conn )
334
: QSocketNotifier( IceConnectionNumber( conn ),
335
QSocketNotifier::Read )
344
/* for printing hex digits */
345
static void fprintfhex (FILE *fp, unsigned int len, char *cp)
347
static const char hexchars[] = "0123456789abcdef";
349
for (; len > 0; len--, cp++) {
350
unsigned char s = *cp;
351
putc(hexchars[s >> 4], fp);
352
putc(hexchars[s & 0x0f], fp);
357
* We use temporary files which contain commands to add/remove entries from
358
* the .ICEauthority file.
360
static void write_iceauth (FILE *addfp, FILE *removefp, IceAuthDataEntry *entry)
363
"add %s \"\" %s %s ",
364
entry->protocol_name,
367
fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
368
fprintf (addfp, "\n");
371
"remove protoname=%s protodata=\"\" netid=%s authname=%s\n",
372
entry->protocol_name,
378
#define MAGIC_COOKIE_LEN 16
380
Status SetAuthentication_local (int count, IceListenObj *listenObjs)
383
for (i = 0; i < count; i ++) {
384
char *prot = IceGetListenConnectionString(listenObjs[i]);
386
char *host = strchr(prot, '/');
391
sock = strchr(host, ':');
397
kDebug( 1218 ) << "KSMServer: SetAProc_loc: conn " << (unsigned)i << ", prot=" << prot << ", file=" << sock;
398
if (sock && !strcmp(prot, "local")) {
401
IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc);
407
Status SetAuthentication (int count, IceListenObj *listenObjs,
408
IceAuthDataEntry **authDataEntries)
410
KTemporaryFile addTempFile;
411
remTempFile = new KTemporaryFile;
413
if (!addTempFile.open() || !remTempFile->open())
416
if ((*authDataEntries = (IceAuthDataEntry *) malloc (
417
count * 2 * sizeof (IceAuthDataEntry))) == NULL)
420
FILE *addAuthFile = fopen(QFile::encodeName(addTempFile.fileName()), "r+");
421
FILE *remAuthFile = fopen(QFile::encodeName(remTempFile->fileName()), "r+");
423
for (int i = 0; i < numTransports * 2; i += 2) {
424
(*authDataEntries)[i].network_id =
425
IceGetListenConnectionString (listenObjs[i/2]);
426
(*authDataEntries)[i].protocol_name = (char *) "ICE";
427
(*authDataEntries)[i].auth_name = (char *) "MIT-MAGIC-COOKIE-1";
429
(*authDataEntries)[i].auth_data =
430
IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
431
(*authDataEntries)[i].auth_data_length = MAGIC_COOKIE_LEN;
433
(*authDataEntries)[i+1].network_id =
434
IceGetListenConnectionString (listenObjs[i/2]);
435
(*authDataEntries)[i+1].protocol_name = (char *) "XSMP";
436
(*authDataEntries)[i+1].auth_name = (char *) "MIT-MAGIC-COOKIE-1";
438
(*authDataEntries)[i+1].auth_data =
439
IceGenerateMagicCookie (MAGIC_COOKIE_LEN);
440
(*authDataEntries)[i+1].auth_data_length = MAGIC_COOKIE_LEN;
442
write_iceauth (addAuthFile, remAuthFile, &(*authDataEntries)[i]);
443
write_iceauth (addAuthFile, remAuthFile, &(*authDataEntries)[i+1]);
445
IceSetPaAuthData (2, &(*authDataEntries)[i]);
447
IceSetHostBasedAuthProc (listenObjs[i/2], HostBasedAuthProc);
452
QString iceAuth = KGlobal::dirs()->findExe("iceauth");
453
if (iceAuth.isEmpty())
455
qWarning("KSMServer: could not find iceauth");
460
p << iceAuth << "source" << addTempFile.fileName();
467
* Free up authentication data.
469
void FreeAuthenticationData(int count, IceAuthDataEntry *authDataEntries)
471
/* Each transport has entries for ICE and XSMP */
475
for (int i = 0; i < count * 2; i++) {
476
free (authDataEntries[i].network_id);
477
free (authDataEntries[i].auth_data);
480
free (authDataEntries);
482
QString iceAuth = KGlobal::dirs()->findExe("iceauth");
483
if (iceAuth.isEmpty())
485
qWarning("KSMServer: could not find iceauth");
492
p << iceAuth << "source" << remTempFile->fileName();
500
static int Xio_ErrorHandler( Display * )
502
qWarning("ksmserver: Fatal IO error: client killed");
504
// Don't do anything that might require the X connection
507
KSMServer *server = the_server;
510
// Don't delete server!!
513
exit(0); // Don't report error, it's not our fault.
514
return 0; // Bogus return value, notreached
517
void KSMServer::setupXIOErrorHandler()
519
XSetIOErrorHandler(Xio_ErrorHandler);
522
static void sighandler(int sig)
525
signal(SIGHUP, sighandler);
531
KSMServer *server = the_server;
543
void KSMWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
545
KSMServer* ds = ( KSMServer*) client_data;
548
*watch_data = (IcePointer) ds->watchConnection( iceConn );
551
ds->removeConnection( (KSMConnection*) *watch_data );
555
static Status KSMNewClientProc ( SmsConn conn, SmPointer manager_data,
556
unsigned long* mask_ret, SmsCallbacks* cb, char** failure_reason_ret)
558
*failure_reason_ret = 0;
560
void* client = ((KSMServer*) manager_data )->newClient( conn );
562
cb->register_client.callback = KSMRegisterClientProc;
563
cb->register_client.manager_data = client;
564
cb->interact_request.callback = KSMInteractRequestProc;
565
cb->interact_request.manager_data = client;
566
cb->interact_done.callback = KSMInteractDoneProc;
567
cb->interact_done.manager_data = client;
568
cb->save_yourself_request.callback = KSMSaveYourselfRequestProc;
569
cb->save_yourself_request.manager_data = client;
570
cb->save_yourself_phase2_request.callback = KSMSaveYourselfPhase2RequestProc;
571
cb->save_yourself_phase2_request.manager_data = client;
572
cb->save_yourself_done.callback = KSMSaveYourselfDoneProc;
573
cb->save_yourself_done.manager_data = client;
574
cb->close_connection.callback = KSMCloseConnectionProc;
575
cb->close_connection.manager_data = client;
576
cb->set_properties.callback = KSMSetPropertiesProc;
577
cb->set_properties.manager_data = client;
578
cb->delete_properties.callback = KSMDeletePropertiesProc;
579
cb->delete_properties.manager_data = client;
580
cb->get_properties.callback = KSMGetPropertiesProc;
581
cb->get_properties.manager_data = client;
583
*mask_ret = SmsRegisterClientProcMask |
584
SmsInteractRequestProcMask |
585
SmsInteractDoneProcMask |
586
SmsSaveYourselfRequestProcMask |
587
SmsSaveYourselfP2RequestProcMask |
588
SmsSaveYourselfDoneProcMask |
589
SmsCloseConnectionProcMask |
590
SmsSetPropertiesProcMask |
591
SmsDeletePropertiesProcMask |
592
SmsGetPropertiesProcMask;
597
#ifdef HAVE__ICETRANSNOLISTEN
598
extern "C" int _IceTransNoListen(const char * protocol);
601
KSMServer::KSMServer( const QString& windowManager, bool _only_local )
604
, logoutEffectWidget( NULL )
606
new KSMServerInterfaceAdaptor( this );
607
QDBusConnection::sessionBus().registerObject("/KSMServer", this);
608
klauncherSignals = new OrgKdeKLauncherInterface(QLatin1String("org.kde.klauncher"),
609
QLatin1String("/KLauncher"), QDBusConnection::sessionBus());
610
kcminitSignals = NULL;
614
shutdownType = KWorkSpace::ShutdownTypeNone;
617
dialogActive = false;
619
wmPhase1WaitingCount = 0;
620
KConfigGroup config(KGlobal::config(), "General");
621
clientInteracting = 0;
622
xonCommand = config.readEntry( "xonCommand", "xon" );
624
KGlobal::dirs()->addResourceType( "windowmanagers", "data", "ksmserver/windowmanagers" );
625
selectWm( windowManager );
627
connect( &startupSuspendTimeoutTimer, SIGNAL( timeout()), SLOT( startupSuspendTimeout()));
628
connect( &pendingShutdown, SIGNAL( timeout()), SLOT( pendingShutdownTimeout()));
630
only_local = _only_local;
631
#ifdef HAVE__ICETRANSNOLISTEN
633
_IceTransNoListen("tcp");
639
if (!SmsInitialize ( (char*) KSMVendorString, (char*) KSMReleaseString,
642
HostBasedAuthProc, 256, errormsg ) ) {
644
qWarning("KSMServer: could not register XSM protocol");
647
if (!IceListenForConnections (&numTransports, &listenObjs,
650
qWarning("KSMServer: Error listening for connections: %s", errormsg);
651
qWarning("KSMServer: Aborting.");
656
// publish available transports.
657
QByteArray fName = QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
658
QString display = ::getenv("DISPLAY");
659
// strip the screen number from the display
660
display.replace(QRegExp("\\.[0-9]+$"), "");
662
while( (i = display.indexOf(':')) >= 0)
664
while( (i = display.indexOf('/')) >= 0)
667
fName += '_'+display.toLocal8Bit();
669
f = ::fopen(fName.data(), "w+");
672
qWarning("KSMServer: cannot open %s: %s", fName.data(), strerror(errno));
673
qWarning("KSMServer: Aborting.");
676
char* session_manager = IceComposeNetworkIdList(numTransports, listenObjs);
677
fprintf(f, "%s\n%i\n", session_manager, getpid());
679
setenv( "SESSION_MANAGER", session_manager, true );
681
// Pass env. var to kdeinit.
682
org::kde::KLauncher klauncher("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus());
683
klauncher.setLaunchEnv( "SESSION_MANAGER", (const char*) session_manager );
685
free(session_manager);
689
if (!SetAuthentication_local(numTransports, listenObjs))
690
qFatal("KSMSERVER: authentication setup failed.");
692
if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
693
qFatal("KSMSERVER: authentication setup failed.");
696
IceAddConnectionWatch (KSMWatchProc, (IcePointer) this);
699
for ( int i = 0; i < numTransports; i++) {
700
fcntl( IceGetListenConnectionNumber( listenObjs[i] ), F_SETFD, FD_CLOEXEC );
701
con = new KSMListener( listenObjs[i] );
702
listener.append( con );
703
connect( con, SIGNAL( activated(int) ), this, SLOT( newConnection(int) ) );
706
signal(SIGHUP, sighandler);
707
signal(SIGTERM, sighandler);
708
signal(SIGINT, sighandler);
709
signal(SIGPIPE, SIG_IGN);
711
connect( &protectionTimer, SIGNAL( timeout() ), this, SLOT( protectionTimeout() ) );
712
connect( &restoreTimer, SIGNAL( timeout() ), this, SLOT( tryRestoreNext() ) );
713
connect( qApp, SIGNAL( aboutToQuit() ), this, SLOT( cleanUp() ) );
716
KSMServer::~KSMServer()
718
qDeleteAll( listener );
723
void KSMServer::cleanUp()
727
IceFreeListenObjs (numTransports, listenObjs);
729
QByteArray fName = QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
730
QString display = QString::fromLocal8Bit(::getenv("DISPLAY"));
731
// strip the screen number from the display
732
display.replace(QRegExp("\\.[0-9]+$"), "");
734
while( (i = display.indexOf(':')) >= 0)
736
while( (i = display.indexOf('/')) >= 0)
739
fName += '_'+display.toLocal8Bit();
740
::unlink(fName.data());
742
FreeAuthenticationData(numTransports, authDataEntries);
743
signal(SIGTERM, SIG_DFL);
744
signal(SIGINT, SIG_DFL);
746
KDisplayManager().shutdown( shutdownType, shutdownMode, bootOption );
751
void* KSMServer::watchConnection( IceConn iceConn )
753
KSMConnection* conn = new KSMConnection( iceConn );
754
connect( conn, SIGNAL( activated(int) ), this, SLOT( processData(int) ) );
758
void KSMServer::removeConnection( KSMConnection* conn )
765
Called from our IceIoErrorHandler
767
void KSMServer::ioError( IceConn /*iceConn*/ )
771
void KSMServer::processData( int /*socket*/ )
773
IceConn iceConn = ((KSMConnection*)sender())->iceConn;
774
IceProcessMessagesStatus status = IceProcessMessages( iceConn, 0, 0 );
775
if ( status == IceProcessMessagesIOError ) {
776
IceSetShutdownNegotiation( iceConn, False );
777
QList<KSMClient*>::iterator it = clients.begin();
778
QList<KSMClient*>::iterator const itEnd = clients.end();
779
while ( ( it != itEnd ) && *it && ( SmsGetIceConnection( ( *it )->connection() ) != iceConn ) )
781
if ( ( it != itEnd ) && *it ) {
782
SmsConn smsConn = (*it)->connection();
784
SmsCleanUp( smsConn );
786
(void) IceCloseConnection( iceConn );
790
KSMClient* KSMServer::newClient( SmsConn conn )
792
KSMClient* client = new KSMClient( conn );
793
clients.append( client );
797
void KSMServer::deleteClient( KSMClient* client )
799
if ( !clients.contains( client ) ) // paranoia
801
clients.removeAll( client );
802
clientsToKill.removeAll( client );
803
clientsToSave.removeAll( client );
804
if ( client == clientInteracting ) {
805
clientInteracting = 0;
806
handlePendingInteractions();
809
if ( state == Shutdown || state == Checkpoint || state == ClosingSubSession )
810
completeShutdownOrCheckpoint();
811
if ( state == Killing )
813
else if ( state == KillingSubSession )
814
completeKillingSubSession();
815
if ( state == KillingWM )
819
void KSMServer::newConnection( int /*socket*/ )
821
IceAcceptStatus status;
822
IceConn iceConn = IceAcceptConnection( ((KSMListener*)sender())->listenObj, &status);
823
if( iceConn == NULL )
825
IceSetShutdownNegotiation( iceConn, False );
826
IceConnectStatus cstatus;
827
while ((cstatus = IceConnectionStatus (iceConn))==IceConnectPending) {
828
(void) IceProcessMessages( iceConn, 0, 0 );
831
if (cstatus != IceConnectAccepted) {
832
if (cstatus == IceConnectIOError)
833
kDebug( 1218 ) << "IO error opening ICE Connection!";
835
kDebug( 1218 ) << "ICE Connection rejected!";
836
(void )IceCloseConnection (iceConn);
841
fcntl( IceConnectionNumber(iceConn), F_SETFD, FD_CLOEXEC );
845
QString KSMServer::currentSession()
847
if ( sessionGroup.startsWith( "Session: " ) )
848
return sessionGroup.mid( 9 );
849
return ""; // empty, not null, since used for KConfig::setGroup
852
void KSMServer::discardSession()
854
KConfigGroup config(KGlobal::config(), sessionGroup );
855
int count = config.readEntry( "count", 0 );
856
foreach ( KSMClient *c, clients ) {
857
QStringList discardCommand = c->discardCommand();
858
if ( discardCommand.isEmpty())
860
// check that non of the old clients used the exactly same
861
// discardCommand before we execute it. This used to be the
862
// case up to KDE and Qt < 3.1
864
while ( i <= count &&
865
config.readPathEntry( QString("discardCommand") + QString::number(i), QStringList() ) != discardCommand )
868
executeCommand( discardCommand );
872
void KSMServer::storeSession()
874
KSharedConfig::Ptr config = KGlobal::config();
875
config->reparseConfiguration(); // config may have changed in the KControl module
876
KConfigGroup generalGroup(config, "General");
877
excludeApps = generalGroup.readEntry( "excludeApps" ).toLower().split( QRegExp( "[,:]" ), QString::SkipEmptyParts );
878
KConfigGroup configSessionGroup(config, sessionGroup);
879
int count = configSessionGroup.readEntry( "count", 0 );
880
for ( int i = 1; i <= count; i++ ) {
881
QStringList discardCommand = configSessionGroup.readPathEntry( QLatin1String("discardCommand") + QString::number(i), QStringList() );
882
if ( discardCommand.isEmpty())
884
// check that non of the new clients uses the exactly same
885
// discardCommand before we execute it. This used to be the
886
// case up to KDE and Qt < 3.1
887
QList<KSMClient*>::iterator it = clients.begin();
888
QList<KSMClient*>::iterator const itEnd = clients.end();
889
while ( ( it != itEnd ) && *it && (discardCommand != ( *it )->discardCommand() ) )
891
if ( ( it != itEnd ) && *it )
893
executeCommand( discardCommand );
895
config->deleteGroup( sessionGroup ); //### does not work with global config object...
896
KConfigGroup cg( config, sessionGroup);
899
if (state != ClosingSubSession) {
901
foreach ( KSMClient *c, clients )
902
if ( c->program() == wm ) {
903
clients.removeAll( c );
904
clients.prepend( c );
909
foreach ( KSMClient *c, clients ) {
910
int restartHint = c->restartStyleHint();
911
if (restartHint == SmRestartNever)
913
QString program = c->program();
914
QStringList restartCommand = c->restartCommand();
915
if (program.isEmpty() && restartCommand.isEmpty())
917
if (state == ClosingSubSession && ! clientsToSave.contains(c))
919
if (excludeApps.contains( program.toLower()))
923
QString n = QString::number(count);
924
cg.writeEntry( QString("program")+n, program );
925
cg.writeEntry( QString("clientId")+n, c->clientId() );
926
cg.writeEntry( QString("restartCommand")+n, restartCommand );
927
cg.writePathEntry( QString("discardCommand")+n, c->discardCommand() );
928
cg.writeEntry( QString("restartStyleHint")+n, restartHint );
929
cg.writeEntry( QString("userId")+n, c->userId() );
930
cg.writeEntry( QString("wasWm")+n, isWM( c ));
932
cg.writeEntry( "count", count );
934
KConfigGroup cg2( config, "General");
935
cg2.writeEntry( "screenCount", ScreenCount(QX11Info::display()));
937
storeLegacySession(config.data());
941
QStringList KSMServer::sessionList()
943
QStringList sessions ( "default" );
944
KSharedConfig::Ptr config = KGlobal::config();
945
const QStringList groups = config->groupList();
946
for ( QStringList::ConstIterator it = groups.constBegin(); it != groups.constEnd(); it++ )
947
if ( (*it).startsWith( "Session: " ) )
948
sessions << (*it).mid( 9 );
952
bool KSMServer::isWM( const KSMClient* client ) const
954
return isWM( client->program());
957
bool KSMServer::isWM( const QString& command ) const
959
return command == wm;
962
bool KSMServer::defaultSession() const
964
return sessionGroup.isEmpty();
968
// - $KDEWM is set - use that
969
// - a wm is selected using the kcm - use that
970
// - if that fails, just use KWin
971
void KSMServer::selectWm( const QString& kdewm )
973
wm = "kwin"; // defaults
974
wmCommands = ( QStringList() << "kwin" );
975
if( qstrcmp( getenv( "KDE_FAILSAFE" ), "1" ) == 0 )
976
return; // failsafe, force kwin
977
if( !kdewm.isEmpty())
979
wmCommands = ( QStringList() << kdewm );
983
KConfigGroup config(KGlobal::config(), "General");
984
QString cfgwm = config.readEntry( "windowManager", "kwin" );
985
KDesktopFile file( "windowmanagers", cfgwm + ".desktop" );
986
if( file.noDisplay())
990
QString testexec = file.desktopGroup().readEntry( "X-KDE-WindowManagerTestExec" );
991
if( !testexec.isEmpty())
994
proc.setShellCommand( testexec );
995
if( proc.execute() != 0 )
998
QStringList cfgWmCommands = KShell::splitArgs( file.desktopGroup().readEntry( "Exec" ));
999
if( cfgWmCommands.isEmpty())
1001
QString smname = file.desktopGroup().readEntry( "X-KDE-WindowManagerId" );
1003
wm = smname.isEmpty() ? cfgwm : smname;
1004
wmCommands = cfgWmCommands;
1007
void KSMServer::wmChanged()
1009
KGlobal::config()->reparseConfiguration();
1013
void KSMServer::setupShortcuts()
1015
if (KAuthorized::authorize("logout")) {
1016
KActionCollection* actionCollection = new KActionCollection(this);
1018
a = actionCollection->addAction("Log Out");
1019
a->setText(i18n("Log Out"));
1020
a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_Delete));
1021
connect(a, SIGNAL(triggered(bool)), SLOT(defaultLogout()));
1023
a = actionCollection->addAction("Log Out Without Confirmation");
1024
a->setText(i18n("Log Out Without Confirmation"));
1025
a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::SHIFT+Qt::Key_Delete));
1026
connect(a, SIGNAL(triggered(bool)), SLOT(logoutWithoutConfirmation()));
1028
a = actionCollection->addAction("Halt Without Confirmation");
1029
a->setText(i18n("Halt Without Confirmation"));
1030
a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::SHIFT+Qt::Key_PageDown));
1031
connect(a, SIGNAL(triggered(bool)), SLOT(haltWithoutConfirmation()));
1033
a = actionCollection->addAction("Reboot Without Confirmation");
1034
a->setText(i18n("Reboot Without Confirmation"));
1035
a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::SHIFT+Qt::Key_PageUp));
1036
connect(a, SIGNAL(triggered(bool)), SLOT(rebootWithoutConfirmation()));
1040
void KSMServer::defaultLogout()
1042
shutdown(KWorkSpace::ShutdownConfirmYes, KWorkSpace::ShutdownTypeDefault, KWorkSpace::ShutdownModeDefault);
1045
void KSMServer::logoutWithoutConfirmation()
1047
shutdown(KWorkSpace::ShutdownConfirmNo, KWorkSpace::ShutdownTypeNone, KWorkSpace::ShutdownModeDefault);
1050
void KSMServer::haltWithoutConfirmation()
1052
shutdown(KWorkSpace::ShutdownConfirmNo, KWorkSpace::ShutdownTypeHalt, KWorkSpace::ShutdownModeDefault);
1055
void KSMServer::rebootWithoutConfirmation()
1057
shutdown(KWorkSpace::ShutdownConfirmNo, KWorkSpace::ShutdownTypeReboot, KWorkSpace::ShutdownModeDefault);