Add (and install) svg for the new krunner interface.
[kdebase/uwolfer.git] / workspace / ksmserver / server.cpp
blob90c63bb32fc6c5fb9b46f29c76cec34e921d1ee3
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>
36 #include <pwd.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #ifdef HAVE_SYS_TIME_H
41 #include <sys/time.h>
42 #endif
43 #include <sys/socket.h>
44 #include <sys/un.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <signal.h>
49 #include <time.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <assert.h>
53 #include <kdefakes.h>
55 #ifdef HAVE_LIMITS_H
56 #include <limits.h>
57 #endif
59 #include <QFile>
60 #include <QPushButton>
61 #include <QRegExp>
62 #include <QtDBus/QtDBus>
63 #include <QSocketNotifier>
65 #include <klocale.h>
66 #include <kglobal.h>
67 #include <kconfig.h>
68 #include <kstandarddirs.h>
69 #include <kapplication.h>
70 #include <ktemporaryfile.h>
71 #include <kconfiggroup.h>
72 #include <kprocess.h>
73 #include <kdebug.h>
75 #include "server.h"
76 #include "global.h"
77 #include "client.h"
78 #include "ksmserverinterfaceadaptor.h"
80 #include "server.moc"
82 #include <kdebug.h>
84 #include <kdisplaymanager.h>
85 #include <QX11Info>
86 #include <krandom.h>
87 #include "klauncher_interface.h"
89 KSMServer* the_server = 0;
91 KSMServer* KSMServer::self()
93 return the_server;
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() )
103 return;
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];
120 QStringList argList;
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() )
132 return;
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*/)
147 if (only_local)
148 return true;
149 else
150 return false;
154 Status KSMRegisterClientProc (
155 SmsConn /* smsConn */,
156 SmPointer managerData,
157 char * previousId
160 KSMClient* client = (KSMClient*) managerData;
161 client->registerClient( previousId );
162 return 1;
165 void KSMInteractRequestProc (
166 SmsConn /* smsConn */,
167 SmPointer managerData,
168 int dialogType
171 the_server->interactRequest( (KSMClient*) managerData, dialogType );
174 void KSMInteractDoneProc (
175 SmsConn /* smsConn */,
176 SmPointer managerData,
177 Bool cancelShutdown
180 the_server->interactDone( (KSMClient*) managerData, cancelShutdown );
183 void KSMSaveYourselfRequestProc (
184 SmsConn smsConn ,
185 SmPointer /* managerData */,
186 int saveType,
187 Bool shutdown,
188 int interactStyle,
189 Bool fast,
190 Bool global
193 if ( shutdown ) {
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,
218 Bool success
221 the_server->saveYourselfDone( (KSMClient*) managerData, success );
224 void KSMCloseConnectionProc (
225 SmsConn smsConn,
226 SmPointer managerData,
227 int count,
228 char ** reasonMsgs
231 the_server->deleteClient( ( KSMClient* ) managerData );
232 if ( count )
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,
243 int numProps,
244 SmProp ** props
247 KSMClient* client = ( KSMClient* ) managerData;
248 for ( int i = 0; i < numProps; i++ ) {
249 SmProp *p = client->property( props[i]->name );
250 if ( p ) {
251 client->properties.removeAll( p );
252 SmFreeProperty( p );
254 client->properties.append( props[i] );
255 if ( !qstrcmp( props[i]->name, SmProgram ) )
256 the_server->clientSetProgram( client );
259 if ( numProps )
260 free( props );
264 void KSMDeletePropertiesProc (
265 SmsConn /* smsConn */,
266 SmPointer managerData,
267 int numProps,
268 char ** propNames
271 KSMClient* client = ( KSMClient* ) managerData;
272 for ( int i = 0; i < numProps; i++ ) {
273 SmProp *p = client->property( propNames[i] );
274 if ( p ) {
275 client->properties.removeAll( p );
276 SmFreeProperty( p );
281 void KSMGetPropertiesProc (
282 SmsConn smsConn,
283 SmPointer managerData
286 KSMClient* client = ( KSMClient* ) managerData;
287 SmProp** props = new SmProp*[client->properties.count()];
288 int i = 0;
289 foreach( SmProp *prop, client->properties )
290 props[i++] = prop;
292 SmsReturnProperties( smsConn, i, props );
293 delete [] props;
297 class KSMListener : public QSocketNotifier
299 public:
300 KSMListener( IceListenObj obj )
301 : QSocketNotifier( IceGetListenConnectionNumber( obj ),
302 QSocketNotifier::Read )
304 listenObj = obj;
307 IceListenObj listenObj;
310 class KSMConnection : public QSocketNotifier
312 public:
313 KSMConnection( IceConn conn )
314 : QSocketNotifier( IceConnectionNumber( conn ),
315 QSocketNotifier::Read )
317 iceConn = conn;
320 IceConn iceConn;
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)
342 fprintf (addfp,
343 "add %s \"\" %s %s ",
344 entry->protocol_name,
345 entry->network_id,
346 entry->auth_name);
347 fprintfhex (addfp, entry->auth_data_length, entry->auth_data);
348 fprintf (addfp, "\n");
350 fprintf (removefp,
351 "remove protoname=%s protodata=\"\" netid=%s authname=%s\n",
352 entry->protocol_name,
353 entry->network_id,
354 entry->auth_name);
358 #define MAGIC_COOKIE_LEN 16
360 Status SetAuthentication_local (int count, IceListenObj *listenObjs)
362 int i;
363 for (i = 0; i < count; i ++) {
364 char *prot = IceGetListenConnectionString(listenObjs[i]);
365 if (!prot) continue;
366 char *host = strchr(prot, '/');
367 char *sock = 0;
368 if (host) {
369 *host=0;
370 host++;
371 sock = strchr(host, ':');
372 if (sock) {
373 *sock = 0;
374 sock++;
377 kDebug( 1218 ) << "KSMServer: SetAProc_loc: conn " << (unsigned)i << ", prot=" << prot << ", file=" << sock;
378 if (sock && !strcmp(prot, "local")) {
379 chmod(sock, 0700);
381 IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc);
382 free(prot);
384 return 1;
387 Status SetAuthentication (int count, IceListenObj *listenObjs,
388 IceAuthDataEntry **authDataEntries)
390 KTemporaryFile addTempFile;
391 remTempFile = new KTemporaryFile;
393 if (!addTempFile.open() || !remTempFile->open())
394 return 0;
396 if ((*authDataEntries = (IceAuthDataEntry *) malloc (
397 count * 2 * sizeof (IceAuthDataEntry))) == NULL)
398 return 0;
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);
429 fclose(addAuthFile);
430 fclose(remAuthFile);
432 QString iceAuth = KGlobal::dirs()->findExe("iceauth");
433 if (iceAuth.isEmpty())
435 qWarning("KSMServer: could not find iceauth");
436 return 0;
439 KProcess p;
440 p << iceAuth << "source" << addTempFile.fileName();
441 p.execute();
443 return (1);
447 * Free up authentication data.
449 void FreeAuthenticationData(int count, IceAuthDataEntry *authDataEntries)
451 /* Each transport has entries for ICE and XSMP */
452 if (only_local)
453 return;
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");
466 return;
469 if (remTempFile)
471 KProcess p;
472 p << iceAuth << "source" << remTempFile->fileName();
473 p.execute();
476 delete remTempFile;
477 remTempFile = 0;
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
485 if (the_server)
487 KSMServer *server = the_server;
488 the_server = 0;
489 server->cleanUp();
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)
504 if (sig == SIGHUP) {
505 signal(SIGHUP, sighandler);
506 return;
509 if (the_server)
511 KSMServer *server = the_server;
512 the_server = 0;
513 server->cleanUp();
514 delete server;
517 if (kapp)
518 kapp->quit();
519 //::exit(0);
523 void KSMWatchProc ( IceConn iceConn, IcePointer client_data, Bool opening, IcePointer* watch_data)
525 KSMServer* ds = ( KSMServer*) client_data;
527 if (opening) {
528 *watch_data = (IcePointer) ds->watchConnection( iceConn );
530 else {
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;
573 return 1;
577 #ifdef HAVE__ICETRANSNOLISTEN
578 extern "C" int _IceTransNoListen(const char * protocol);
579 #endif
581 KSMServer::KSMServer( const QString& windowManager, bool _only_local )
582 : sessionGroup( "" )
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;
590 the_server = this;
591 clean = false;
592 wm = windowManager;
594 shutdownType = KWorkSpace::ShutdownTypeNone;
596 state = Idle;
597 dialogActive = false;
598 saveSession = 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
609 if (only_local)
610 _IceTransNoListen("tcp");
611 #else
612 only_local = false;
613 #endif
615 char errormsg[256];
616 if (!SmsInitialize ( (char*) KSMVendorString, (char*) KSMReleaseString,
617 KSMNewClientProc,
618 (SmPointer) this,
619 HostBasedAuthProc, 256, errormsg ) ) {
621 qWarning("KSMServer: could not register XSM protocol");
624 if (!IceListenForConnections (&numTransports, &listenObjs,
625 256, errormsg))
627 qWarning("KSMServer: Error listening for connections: %s", errormsg);
628 qWarning("KSMServer: Aborting.");
629 exit(1);
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]+$"), "");
638 int i;
639 while( (i = display.indexOf(':')) >= 0)
640 display[i] = '_';
642 fName += '_'+display.toLocal8Bit();
643 FILE *f;
644 f = ::fopen(fName.data(), "w+");
645 if (!f)
647 qWarning("KSMServer: cannot open %s: %s", fName.data(), strerror(errno));
648 qWarning("KSMServer: Aborting.");
649 exit(1);
651 char* session_manager = IceComposeNetworkIdList(numTransports, listenObjs);
652 fprintf(f, "%s\n%i\n", session_manager, getpid());
653 fclose(f);
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 );
660 if (only_local) {
661 if (!SetAuthentication_local(numTransports, listenObjs))
662 qFatal("KSMSERVER: authentication setup failed.");
663 } else {
664 if (!SetAuthentication(numTransports, listenObjs, &authDataEntries))
665 qFatal("KSMSERVER: authentication setup failed.");
668 IceAddConnectionWatch (KSMWatchProc, (IcePointer) this);
670 KSMListener* con;
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 );
690 the_server = 0;
691 cleanUp();
694 void KSMServer::cleanUp()
696 if (clean) return;
697 clean = true;
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]+$"), "");
704 int i;
705 while( (i = display.indexOf(':')) >= 0)
706 display[i] = '_';
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) ) );
724 return (void*) conn;
727 void KSMServer::removeConnection( KSMConnection* conn )
729 delete 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 ) )
749 ++it;
750 if ( ( it != itEnd ) && *it ) {
751 SmsConn smsConn = (*it)->connection();
752 deleteClient( *it );
753 SmsCleanUp( smsConn );
755 (void) IceCloseConnection( iceConn );
759 KSMClient* KSMServer::newClient( SmsConn conn )
761 KSMClient* client = new KSMClient( conn );
762 clients.append( client );
763 return client;
766 void KSMServer::deleteClient( KSMClient* client )
768 if ( !clients.contains( client ) ) // paranoia
769 return;
770 clients.removeAll( client );
771 if ( client == clientInteracting ) {
772 clientInteracting = 0;
773 handlePendingInteractions();
775 delete client;
776 if ( state == Shutdown || state == Checkpoint )
777 completeShutdownOrCheckpoint();
778 if ( state == Killing )
779 completeKilling();
780 if ( state == KillingWM )
781 completeKillingWM();
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!";
797 else
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())
818 continue;
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
822 int i = 1;
823 while ( i <= count &&
824 config.readPathEntry( QString("discardCommand") + QString::number(i), QStringList() ) != discardCommand )
825 i++;
826 if ( i <= count )
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())
842 continue;
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() ) )
849 ++it;
850 if ( ( it != itEnd ) && *it )
851 continue;
852 executeCommand( discardCommand );
854 config->deleteGroup( sessionGroup ); //### does not work with global config object...
855 KConfigGroup cg( config, sessionGroup);
856 count = 0;
858 if ( !wm.isEmpty() ) {
859 // put the wm first
860 foreach ( KSMClient *c, clients )
861 if ( c->program() == wm ) {
862 clients.removeAll( c );
863 clients.prepend( c );
864 break;
868 foreach ( KSMClient *c, clients ) {
869 int restartHint = c->restartStyleHint();
870 if (restartHint == SmRestartNever)
871 continue;
872 QString program = c->program();
873 QStringList restartCommand = c->restartCommand();
874 if (program.isEmpty() && restartCommand.isEmpty())
875 continue;
876 if (excludeApps.contains( program.toLower()))
877 continue;
879 count++;
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());
894 config->sync();
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 );
905 return sessions;
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
918 // it later
919 return command == wm || command == "kwin";
922 bool KSMServer::defaultSession() const
924 return sessionGroup.isEmpty();