00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "sm.h"
00023
00024 #include <unistd.h>
00025 #include <stdlib.h>
00026 #include <pwd.h>
00027 #include <fixx11h.h>
00028 #include <kconfig.h>
00029 #include <kglobal.h>
00030
00031 #include "workspace.h"
00032 #include "client.h"
00033 #include <QSocketNotifier>
00034 #include <QSessionManager>
00035 #include <kdebug.h>
00036
00037 namespace KWin
00038 {
00039
00040 bool SessionManager::saveState( QSessionManager& sm )
00041 {
00042
00043
00044
00045
00046
00047
00048 char* sm_vendor = SmcVendor( static_cast< SmcConn >( sm.handle()));
00049 bool ksmserver = qstrcmp( sm_vendor, "KDE" ) == 0;
00050 free( sm_vendor );
00051 if ( !sm.isPhase2() )
00052 {
00053 Workspace::self()->sessionSaveStarted();
00054 if( ksmserver )
00055 Workspace::self()->storeSession( kapp->sessionConfig(), SMSavePhase0 );
00056 sm.release();
00057 sm.requestPhase2();
00058 return true;
00059 }
00060 Workspace::self()->storeSession( kapp->sessionConfig(), ksmserver ? SMSavePhase2 : SMSavePhase2Full );
00061 kapp->sessionConfig()->sync();
00062 return true;
00063 }
00064
00065
00066 bool SessionManager::commitData( QSessionManager& sm )
00067 {
00068 if ( !sm.isPhase2() )
00069 Workspace::self()->sessionSaveStarted();
00070 return true;
00071 }
00072
00073
00074
00080 void Workspace::storeSession( KConfig* config, SMSavePhase phase )
00081 {
00082 KConfigGroup cg(config, "Session");
00083 int count = 0;
00084 int active_client = -1;
00085 for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it)
00086 {
00087 Client* c = (*it);
00088 QByteArray sessionId = c->sessionId();
00089 QByteArray wmCommand = c->wmCommand();
00090 if ( sessionId.isEmpty() )
00091
00092
00093 if ( wmCommand.isEmpty() )
00094 continue;
00095 count++;
00096 if( c->isActive())
00097 active_client = count;
00098 QString n = QString::number(count);
00099 if( phase == SMSavePhase2 || phase == SMSavePhase2Full )
00100 {
00101 cg.writeEntry( QString("sessionId")+n, sessionId.constData() );
00102 cg.writeEntry( QString("windowRole")+n, c->windowRole().constData() );
00103 cg.writeEntry( QString("wmCommand")+n, wmCommand.constData() );
00104 cg.writeEntry( QString("wmClientMachine")+n, c->wmClientMachine( true ).constData() );
00105 cg.writeEntry( QString("resourceName")+n, c->resourceName().constData() );
00106 cg.writeEntry( QString("resourceClass")+n, c->resourceClass().constData() );
00107 cg.writeEntry( QString("geometry")+n, QRect( c->calculateGravitation(true), c->clientSize() ) );
00108 cg.writeEntry( QString("restore")+n, c->geometryRestore() );
00109 cg.writeEntry( QString("fsrestore")+n, c->geometryFSRestore() );
00110 cg.writeEntry( QString("maximize")+n, (int) c->maximizeMode() );
00111 cg.writeEntry( QString("fullscreen")+n, (int) c->fullScreenMode() );
00112 cg.writeEntry( QString("desktop")+n, c->desktop() );
00113
00114
00115 cg.writeEntry( QString("iconified")+n, c->isMinimized() );
00116
00117 cg.writeEntry( QString("sticky")+n, c->isOnAllDesktops() );
00118 cg.writeEntry( QString("shaded")+n, c->isShade() );
00119
00120 cg.writeEntry( QString("staysOnTop")+n, c->keepAbove() );
00121 cg.writeEntry( QString("keepBelow")+n, c->keepBelow() );
00122 cg.writeEntry( QString("skipTaskbar")+n, c->skipTaskbar( true ) );
00123 cg.writeEntry( QString("skipPager")+n, c->skipPager() );
00124
00125 cg.writeEntry( QString("userNoBorder")+n, c->noBorder() );
00126 cg.writeEntry( QString("windowType")+n, windowTypeToTxt( c->windowType()));
00127 cg.writeEntry( QString("shortcut")+n, c->shortcut().toString());
00128 cg.writeEntry( QString("stackingOrder")+n, unconstrained_stacking_order.indexOf( c ));
00129 }
00130 }
00131 if( phase == SMSavePhase0 )
00132 {
00133
00134
00135
00136 session_active_client = active_client;
00137 session_desktop = currentDesktop();
00138 }
00139 else if( phase == SMSavePhase2 )
00140 {
00141 cg.writeEntry( "count", count );
00142 cg.writeEntry( "active", session_active_client );
00143 cg.writeEntry( "desktop", session_desktop );
00144 }
00145 else
00146 {
00147 cg.writeEntry( "count", count );
00148 cg.writeEntry( "active", session_active_client );
00149 cg.writeEntry( "desktop", currentDesktop());
00150 }
00151 }
00152
00153
00159 void Workspace::loadSessionInfo()
00160 {
00161 session.clear();
00162 KConfigGroup cg(kapp->sessionConfig(), "Session");
00163 int count = cg.readEntry( "count",0 );
00164 int active_client = cg.readEntry( "active",0 );
00165 for ( int i = 1; i <= count; i++ )
00166 {
00167 QString n = QString::number(i);
00168 SessionInfo* info = new SessionInfo;
00169 session.append( info );
00170 info->sessionId = cg.readEntry( QString("sessionId")+n, QString() ).toLatin1();
00171 info->windowRole = cg.readEntry( QString("windowRole")+n, QString() ).toLatin1();
00172 info->wmCommand = cg.readEntry( QString("wmCommand")+n, QString() ).toLatin1();
00173 info->wmClientMachine = cg.readEntry( QString("wmClientMachine")+n, QString() ).toLatin1();
00174 info->resourceName = cg.readEntry( QString("resourceName")+n, QString() ).toLatin1();
00175 info->resourceClass = cg.readEntry( QString("resourceClass")+n, QString() ).toLower().toLatin1();
00176 info->geometry = cg.readEntry( QString("geometry")+n,QRect() );
00177 info->restore = cg.readEntry( QString("restore")+n,QRect() );
00178 info->fsrestore = cg.readEntry( QString("fsrestore")+n,QRect() );
00179 info->maximized = cg.readEntry( QString("maximize")+n, 0 );
00180 info->fullscreen = cg.readEntry( QString("fullscreen")+n, 0 );
00181 info->desktop = cg.readEntry( QString("desktop")+n, 0 );
00182 info->minimized = cg.readEntry( QString("iconified")+n, false );
00183 info->onAllDesktops = cg.readEntry( QString("sticky")+n, false );
00184 info->shaded = cg.readEntry( QString("shaded")+n, false );
00185 info->keepAbove = cg.readEntry( QString("staysOnTop")+n, false );
00186 info->keepBelow = cg.readEntry( QString("keepBelow")+n, false );
00187 info->skipTaskbar = cg.readEntry( QString("skipTaskbar")+n, false );
00188 info->skipPager = cg.readEntry( QString("skipPager")+n, false );
00189 info->noBorder = cg.readEntry( QString("userNoBorder")+n, false );
00190 info->windowType = txtToWindowType( cg.readEntry( QString("windowType")+n, QString() ).toLatin1());
00191 info->shortcut = cg.readEntry( QString("shortcut")+n, QString() );
00192 info->active = ( active_client == i );
00193 info->stackingOrder = cg.readEntry( QString("stackingOrder")+n, -1 );
00194 }
00195 }
00196
00206 SessionInfo* Workspace::takeSessionInfo( Client* c )
00207 {
00208 SessionInfo *realInfo = 0;
00209 QByteArray sessionId = c->sessionId();
00210 QByteArray windowRole = c->windowRole();
00211 QByteArray wmCommand = c->wmCommand();
00212 QByteArray wmClientMachine = c->wmClientMachine( true );
00213 QByteArray resourceName = c->resourceName();
00214 QByteArray resourceClass = c->resourceClass();
00215
00216
00217 if (! sessionId.isEmpty() )
00218 {
00219
00220 foreach( SessionInfo* info, session )
00221 {
00222 if( realInfo )
00223 break;
00224 if( info->sessionId == sessionId && sessionInfoWindowTypeMatch( c, info ))
00225 {
00226 if( ! windowRole.isEmpty() )
00227 {
00228 if( info->windowRole == windowRole )
00229 {
00230 realInfo = info;
00231 session.removeAll(info);
00232 }
00233 }
00234 else
00235 {
00236 if( info->windowRole.isEmpty()
00237 && info->resourceName == resourceName
00238 && info->resourceClass == resourceClass )
00239 {
00240 realInfo = info;
00241 session.removeAll(info);
00242 }
00243 }
00244 }
00245 }
00246 }
00247 else
00248 {
00249
00250 foreach( SessionInfo* info, session )
00251 {
00252 if( realInfo )
00253 break;
00254 if( info->resourceName == resourceName
00255 && info->resourceClass == resourceClass
00256 && info->wmClientMachine == wmClientMachine
00257 && sessionInfoWindowTypeMatch( c, info ))
00258 {
00259 if ( wmCommand.isEmpty() || info->wmCommand == wmCommand )
00260 {
00261 realInfo = info;
00262 session.removeAll( info );
00263 }
00264 }
00265 }
00266 }
00267 return realInfo;
00268 }
00269
00270 bool Workspace::sessionInfoWindowTypeMatch( Client* c, SessionInfo* info )
00271 {
00272 if( info->windowType == -2 )
00273 {
00274 return !c->isSpecialWindow();
00275 }
00276 return info->windowType == c->windowType();
00277 }
00278
00279 static const char* const window_type_names[] =
00280 {
00281 "Unknown", "Normal" , "Desktop", "Dock", "Toolbar", "Menu", "Dialog",
00282 "Override", "TopMenu", "Utility", "Splash"
00283 };
00284
00285
00286 const char* Workspace::windowTypeToTxt( NET::WindowType type )
00287 {
00288 if( type >= NET::Unknown && type <= NET::Splash )
00289 return window_type_names[ type + 1 ];
00290 if( type == -2 )
00291 return "Undefined";
00292 kFatal() << "Unknown Window Type" ;
00293 return NULL;
00294 }
00295
00296 NET::WindowType Workspace::txtToWindowType( const char* txt )
00297 {
00298 for( int i = NET::Unknown;
00299 i <= NET::Splash;
00300 ++i )
00301 if( qstrcmp( txt, window_type_names[ i + 1 ] ) == 0 )
00302 return static_cast< NET::WindowType >( i );
00303 return static_cast< NET::WindowType >( -2 );
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 static void save_yourself( SmcConn conn_P, SmPointer ptr, int, Bool shutdown, int, Bool )
00325 {
00326 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00327 if( conn_P != session->connection())
00328 return;
00329 if( shutdown )
00330 Workspace::self()->disableRulesUpdates( true );
00331 SmcSaveYourselfDone( conn_P, True );
00332 }
00333
00334 static void die( SmcConn conn_P, SmPointer ptr )
00335 {
00336 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00337 if( conn_P != session->connection())
00338 return;
00339
00340 session->close();
00341 }
00342
00343 static void save_complete( SmcConn conn_P, SmPointer ptr )
00344 {
00345 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00346 if( conn_P != session->connection())
00347 return;
00348 session->saveDone();
00349 }
00350
00351 static void shutdown_cancelled( SmcConn conn_P, SmPointer ptr )
00352 {
00353 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00354 if( conn_P != session->connection())
00355 return;
00356 Workspace::self()->disableRulesUpdates( false );
00357
00358 session->saveDone();
00359 }
00360
00361 void SessionSaveDoneHelper::saveDone()
00362 {
00363 Workspace::self()->sessionSaveDone();
00364 }
00365
00366 SessionSaveDoneHelper::SessionSaveDoneHelper()
00367 {
00368 SmcCallbacks calls;
00369 calls.save_yourself.callback = save_yourself;
00370 calls.save_yourself.client_data = reinterpret_cast< SmPointer >(this);
00371 calls.die.callback = die;
00372 calls.die.client_data = reinterpret_cast< SmPointer >(this);
00373 calls.save_complete.callback = save_complete;
00374 calls.save_complete.client_data = reinterpret_cast< SmPointer >(this);
00375 calls.shutdown_cancelled.callback = shutdown_cancelled;
00376 calls.shutdown_cancelled.client_data = reinterpret_cast< SmPointer >(this);
00377 char* id = NULL;
00378 char err[ 11 ];
00379 conn = SmcOpenConnection( NULL, 0, 1, 0,
00380 SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
00381 | SmcShutdownCancelledProcMask, &calls, NULL, &id, 10, err );
00382 if( id != NULL )
00383 free( id );
00384 if( conn == NULL )
00385 return;
00386
00387 SmPropValue propvalue[ 5 ];
00388 SmProp props[ 5 ];
00389 propvalue[ 0 ].length = sizeof( int );
00390 int value0 = SmRestartNever;
00391 propvalue[ 0 ].value = &value0;
00392 props[ 0 ].name = const_cast< char* >( SmRestartStyleHint );
00393 props[ 0 ].type = const_cast< char* >( SmCARD8 );
00394 props[ 0 ].num_vals = 1;
00395 props[ 0 ].vals = &propvalue[ 0 ];
00396 struct passwd* entry = getpwuid( geteuid() );
00397 propvalue[ 1 ].length = entry != NULL ? strlen( entry->pw_name ) : 0;
00398 propvalue[ 1 ].value = (SmPointer)( entry != NULL ? entry->pw_name : "" );
00399 props[ 1 ].name = const_cast< char* >( SmUserID );
00400 props[ 1 ].type = const_cast< char* >( SmARRAY8 );
00401 props[ 1 ].num_vals = 1;
00402 props[ 1 ].vals = &propvalue[ 1 ];
00403 propvalue[ 2 ].length = 0;
00404 propvalue[ 2 ].value = (SmPointer)( "" );
00405 props[ 2 ].name = const_cast< char* >( SmRestartCommand );
00406 props[ 2 ].type = const_cast< char* >( SmLISTofARRAY8 );
00407 props[ 2 ].num_vals = 1;
00408 props[ 2 ].vals = &propvalue[ 2 ];
00409 propvalue[ 3 ].length = strlen( "kwinsmhelper" );
00410 propvalue[ 3 ].value = (SmPointer)"kwinsmhelper";
00411 props[ 3 ].name = const_cast< char* >( SmProgram );
00412 props[ 3 ].type = const_cast< char* >( SmARRAY8 );
00413 props[ 3 ].num_vals = 1;
00414 props[ 3 ].vals = &propvalue[ 3 ];
00415 propvalue[ 4 ].length = 0;
00416 propvalue[ 4 ].value = (SmPointer)( "" );
00417 props[ 4 ].name = const_cast< char* >( SmCloneCommand );
00418 props[ 4 ].type = const_cast< char* >( SmLISTofARRAY8 );
00419 props[ 4 ].num_vals = 1;
00420 props[ 4 ].vals = &propvalue[ 4 ];
00421 SmProp* p[ 5 ] = { &props[ 0 ], &props[ 1 ], &props[ 2 ], &props[ 3 ], &props[ 4 ] };
00422 SmcSetProperties( conn, 5, p );
00423 notifier = new QSocketNotifier( IceConnectionNumber( SmcGetIceConnection( conn )),
00424 QSocketNotifier::Read, this );
00425 connect( notifier, SIGNAL( activated( int )), SLOT( processData()));
00426 }
00427
00428 SessionSaveDoneHelper::~SessionSaveDoneHelper()
00429 {
00430 close();
00431 }
00432
00433 void SessionSaveDoneHelper::close()
00434 {
00435 if( conn != NULL )
00436 {
00437 delete notifier;
00438 SmcCloseConnection( conn, 0, NULL );
00439 }
00440 conn = NULL;
00441 }
00442
00443 void SessionSaveDoneHelper::processData()
00444 {
00445 if( conn != NULL )
00446 IceProcessMessages( SmcGetIceConnection( conn ), 0, 0 );
00447 }
00448
00449 }
00450
00451 #include "sm.moc"