00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "sm.h"
00013
00014 #include <qsocketnotifier.h>
00015 #include <qsessionmanager.h>
00016 #include <kdebug.h>
00017 #include <unistd.h>
00018 #include <stdlib.h>
00019 #include <pwd.h>
00020 #include <fixx11h.h>
00021 #include <kconfig.h>
00022 #include <kglobal.h>
00023
00024 #include "workspace.h"
00025 #include "client.h"
00026
00027 namespace KWinInternal
00028 {
00029
00030 bool SessionManaged::saveState( QSessionManager& sm )
00031 {
00032
00033
00034
00035
00036
00037
00038 char* sm_vendor = SmcVendor( static_cast< SmcConn >( sm.handle()));
00039 bool ksmserver = qstrcmp( sm_vendor, "KDE" ) == 0;
00040 free( sm_vendor );
00041 if ( !sm.isPhase2() )
00042 {
00043 Workspace::self()->sessionSaveStarted();
00044 if( ksmserver )
00045 Workspace::self()->storeSession( kapp->sessionConfig(), SMSavePhase0 );
00046 sm.release();
00047 sm.requestPhase2();
00048 return true;
00049 }
00050 Workspace::self()->storeSession( kapp->sessionConfig(), ksmserver ? SMSavePhase2 : SMSavePhase2Full );
00051 kapp->sessionConfig()->sync();
00052 return true;
00053 }
00054
00055
00056 bool SessionManaged::commitData( QSessionManager& sm )
00057 {
00058 if ( !sm.isPhase2() )
00059 Workspace::self()->sessionSaveStarted();
00060 return true;
00061 }
00062
00063
00064
00070 void Workspace::storeSession( KConfig* config, SMSavePhase phase )
00071 {
00072 config->setGroup("Session" );
00073 int count = 0;
00074 int active_client = -1;
00075 for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it)
00076 {
00077 Client* c = (*it);
00078 QCString sessionId = c->sessionId();
00079 QCString wmCommand = c->wmCommand();
00080 if ( sessionId.isEmpty() )
00081
00082
00083 if ( wmCommand.isEmpty() )
00084 continue;
00085 count++;
00086 if( c->isActive())
00087 active_client = count;
00088 QString n = QString::number(count);
00089 if( phase == SMSavePhase2 || phase == SMSavePhase2Full )
00090 {
00091 config->writeEntry( QString("sessionId")+n, sessionId.data() );
00092 config->writeEntry( QString("windowRole")+n, c->windowRole().data() );
00093 config->writeEntry( QString("wmCommand")+n, wmCommand.data() );
00094 config->writeEntry( QString("wmClientMachine")+n, c->wmClientMachine().data() );
00095 config->writeEntry( QString("resourceName")+n, c->resourceName().data() );
00096 config->writeEntry( QString("resourceClass")+n, c->resourceClass().data() );
00097 config->writeEntry( QString("geometry")+n, QRect( c->calculateGravitation(TRUE), c->clientSize() ) );
00098 config->writeEntry( QString("restore")+n, c->geometryRestore() );
00099 config->writeEntry( QString("fsrestore")+n, c->geometryFSRestore() );
00100 config->writeEntry( QString("maximize")+n, (int) c->maximizeMode() );
00101 config->writeEntry( QString("fullscreen")+n, (int) c->fullScreenMode() );
00102 config->writeEntry( QString("desktop")+n, c->desktop() );
00103
00104
00105 config->writeEntry( QString("iconified")+n, c->isMinimized() );
00106
00107 config->writeEntry( QString("sticky")+n, c->isOnAllDesktops() );
00108 config->writeEntry( QString("shaded")+n, c->isShade() );
00109
00110 config->writeEntry( QString("staysOnTop")+n, c->keepAbove() );
00111 config->writeEntry( QString("keepBelow")+n, c->keepBelow() );
00112 config->writeEntry( QString("skipTaskbar")+n, c->skipTaskbar( true ) );
00113 config->writeEntry( QString("skipPager")+n, c->skipPager() );
00114 config->writeEntry( QString("userNoBorder")+n, c->isUserNoBorder() );
00115 config->writeEntry( QString("windowType")+n, windowTypeToTxt( c->windowType()));
00116 }
00117 }
00118
00119 if( phase == SMSavePhase0 )
00120 {
00121
00122
00123
00124 session_active_client = active_client;
00125 session_desktop = currentDesktop();
00126 }
00127 else if( phase == SMSavePhase2 )
00128 {
00129 config->writeEntry( "count", count );
00130 config->writeEntry( "active", session_active_client );
00131 config->writeEntry( "desktop", session_desktop );
00132 }
00133 else
00134 {
00135 config->writeEntry( "count", count );
00136 config->writeEntry( "active", session_active_client );
00137 config->writeEntry( "desktop", currentDesktop());
00138 }
00139 }
00140
00141
00147 void Workspace::loadSessionInfo()
00148 {
00149 session.clear();
00150 KConfig* config = kapp->sessionConfig();
00151 config->setGroup("Session" );
00152 int count = config->readNumEntry( "count" );
00153 int active_client = config->readNumEntry( "active" );
00154 for ( int i = 1; i <= count; i++ )
00155 {
00156 QString n = QString::number(i);
00157 SessionInfo* info = new SessionInfo;
00158 session.append( info );
00159 info->sessionId = config->readEntry( QString("sessionId")+n ).latin1();
00160 info->windowRole = config->readEntry( QString("windowRole")+n ).latin1();
00161 info->wmCommand = config->readEntry( QString("wmCommand")+n ).latin1();
00162 info->wmClientMachine = config->readEntry( QString("wmClientMachine")+n ).latin1();
00163 info->resourceName = config->readEntry( QString("resourceName")+n ).latin1();
00164 info->resourceClass = config->readEntry( QString("resourceClass")+n ).lower().latin1();
00165 info->geometry = config->readRectEntry( QString("geometry")+n );
00166 info->restore = config->readRectEntry( QString("restore")+n );
00167 info->fsrestore = config->readRectEntry( QString("fsrestore")+n );
00168 info->maximized = config->readNumEntry( QString("maximize")+n, 0 );
00169 info->fullscreen = config->readNumEntry( QString("fullscreen")+n, 0 );
00170 info->desktop = config->readNumEntry( QString("desktop")+n, 0 );
00171 info->minimized = config->readBoolEntry( QString("iconified")+n, FALSE );
00172 info->onAllDesktops = config->readBoolEntry( QString("sticky")+n, FALSE );
00173 info->shaded = config->readBoolEntry( QString("shaded")+n, FALSE );
00174 info->keepAbove = config->readBoolEntry( QString("staysOnTop")+n, FALSE );
00175 info->keepBelow = config->readBoolEntry( QString("keepBelow")+n, FALSE );
00176 info->skipTaskbar = config->readBoolEntry( QString("skipTaskbar")+n, FALSE );
00177 info->skipPager = config->readBoolEntry( QString("skipPager")+n, FALSE );
00178 info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE );
00179 info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1());
00180 info->active = ( active_client == i );
00181 info->fake = false;
00182 }
00183 }
00184
00185 void Workspace::loadFakeSessionInfo()
00186 {
00187 fakeSession.clear();
00188 KConfig *config = KGlobal::config();
00189 config->setGroup("FakeSession" );
00190 int count = config->readNumEntry( "count" );
00191 for ( int i = 1; i <= count; i++ )
00192 {
00193 QString n = QString::number(i);
00194 SessionInfo* info = new SessionInfo;
00195 fakeSession.append( info );
00196 info->windowRole = config->readEntry( QString("windowRole")+n ).latin1();
00197 info->resourceName = config->readEntry( QString("resourceName")+n ).latin1();
00198 info->resourceClass = config->readEntry( QString("resourceClass")+n ).lower().latin1();
00199 info->wmClientMachine = config->readEntry( QString("clientMachine")+n ).latin1();
00200 info->geometry = config->readRectEntry( QString("geometry")+n );
00201 info->restore = config->readRectEntry( QString("restore")+n );
00202 info->fsrestore = config->readRectEntry( QString("fsrestore")+n );
00203 info->maximized = config->readNumEntry( QString("maximize")+n, 0 );
00204 info->fullscreen = config->readNumEntry( QString("fullscreen")+n, 0 );
00205 info->desktop = config->readNumEntry( QString("desktop")+n, 0 );
00206 info->minimized = config->readBoolEntry( QString("iconified")+n, FALSE );
00207 info->onAllDesktops = config->readBoolEntry( QString("sticky")+n, FALSE );
00208 info->shaded = config->readBoolEntry( QString("shaded")+n, FALSE );
00209 info->keepAbove = config->readBoolEntry( QString("staysOnTop")+n, FALSE );
00210 info->keepBelow = config->readBoolEntry( QString("keepBelow")+n, FALSE );
00211 info->skipTaskbar = config->readBoolEntry( QString("skipTaskbar")+n, FALSE );
00212 info->skipPager = config->readBoolEntry( QString("skipPager")+n, FALSE );
00213 info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE );
00214 info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1());
00215 info->active = false;
00216 info->fake = true;
00217 }
00218 }
00219
00220 void Workspace::storeFakeSessionInfo( Client* c )
00221 {
00222 if ( !c->storeSettings() )
00223 return;
00224 SessionInfo* info = new SessionInfo;
00225 fakeSession.append( info );
00226 info->windowRole = c->windowRole();
00227 info->resourceName = c->resourceName();
00228 info->resourceClass = c->resourceClass();
00229 info->wmClientMachine = c->wmClientMachine();
00230 info->geometry = QRect( c->calculateGravitation(TRUE), c->clientSize() ) ;
00231 info->restore = c->geometryRestore();
00232 info->fsrestore = c->geometryFSRestore();
00233 info->maximized = (int)c->maximizeMode();
00234 info->fullscreen = (int)c->fullScreenMode();
00235 info->desktop = c->desktop();
00236 info->minimized = c->isMinimized();
00237 info->onAllDesktops = c->isOnAllDesktops();
00238 info->shaded = c->isShade();
00239 info->keepAbove = c->keepAbove();
00240 info->keepBelow = c->keepBelow();
00241 info->skipTaskbar = c->skipTaskbar( true );
00242 info->skipPager = c->skipPager();
00243 info->userNoBorder = c->isUserNoBorder();
00244 info->windowType = c->windowType();
00245 info->active = false;
00246 info->fake = true;
00247 }
00248
00249 void Workspace::writeFakeSessionInfo()
00250 {
00251 KConfig *config = KGlobal::config();
00252 config->setGroup("FakeSession" );
00253 int count = 0;
00254 for ( SessionInfo* info = fakeSession.first(); info; info = fakeSession.next() )
00255 {
00256 count++;
00257 QString n = QString::number(count);
00258 config->writeEntry( QString("windowRole")+n, info->windowRole.data() );
00259 config->writeEntry( QString("resourceName")+n, info->resourceName.data() );
00260 config->writeEntry( QString("resourceClass")+n, info->resourceClass.data() );
00261 config->writeEntry( QString("clientMachine")+n, info->wmClientMachine.data() );
00262 config->writeEntry( QString("geometry")+n, info->geometry );
00263 config->writeEntry( QString("restore")+n, info->restore );
00264 config->writeEntry( QString("fsrestore")+n, info->fsrestore );
00265 config->writeEntry( QString("maximize")+n, info->maximized );
00266 config->writeEntry( QString("fullscreen")+n, info->fullscreen );
00267 config->writeEntry( QString("desktop")+n, info->desktop );
00268 config->writeEntry( QString("iconified")+n, info->minimized );
00269 config->writeEntry( QString("onAllDesktops")+n, info->onAllDesktops );
00270 config->writeEntry( QString("shaded")+n, info->shaded );
00271 config->writeEntry( QString("staysOnTop")+n, info->keepAbove );
00272 config->writeEntry( QString("keepBelow")+n, info->keepBelow );
00273 config->writeEntry( QString("skipTaskbar")+n, info->skipTaskbar );
00274 config->writeEntry( QString("skipPager")+n, info->skipPager );
00275 config->writeEntry( QString("userNoBorder")+n, info->userNoBorder );
00276 config->writeEntry( QString("windowType")+n, windowTypeToTxt( info->windowType ));
00277 }
00278 config->writeEntry( "count", count );
00279 }
00280
00292 SessionInfo* Workspace::takeSessionInfo( Client* c )
00293 {
00294 SessionInfo *realInfo = 0;
00295 SessionInfo *fakeInfo = 0;
00296 QCString sessionId = c->sessionId();
00297 QCString windowRole = c->windowRole();
00298 QCString wmCommand = c->wmCommand();
00299 QCString wmClientMachine = c->wmClientMachine();
00300 QCString resourceName = c->resourceName();
00301 QCString resourceClass = c->resourceClass();
00302
00303
00304 if (! sessionId.isEmpty() )
00305 {
00306
00307 for (SessionInfo* info = session.first(); info && !realInfo; info = session.next() )
00308 if ( info->sessionId == sessionId && sessionInfoWindowTypeMatch( c, info ))
00309 {
00310 if ( ! windowRole.isEmpty() )
00311 {
00312 if ( info->windowRole == windowRole )
00313 realInfo = session.take();
00314 }
00315 else
00316 {
00317 if ( info->windowRole.isEmpty() &&
00318 info->resourceName == resourceName &&
00319 info->resourceClass == resourceClass )
00320 realInfo = session.take();
00321 }
00322 }
00323 }
00324 else
00325 {
00326
00327 for (SessionInfo* info = session.first(); info && !realInfo; info = session.next() )
00328 if ( info->resourceName == resourceName &&
00329 info->resourceClass == resourceClass &&
00330 info->wmClientMachine == wmClientMachine &&
00331 sessionInfoWindowTypeMatch( c, info ))
00332 if ( wmCommand.isEmpty() || info->wmCommand == wmCommand )
00333 realInfo = session.take();
00334 }
00335
00336
00337 for (SessionInfo* info = fakeSession.first(); info && !fakeInfo; info = fakeSession.next() )
00338 if ( info->resourceName == resourceName &&
00339 info->resourceClass == resourceClass &&
00340 ( windowRole.isEmpty() || windowRole == info->windowRole ) &&
00341 sessionInfoWindowTypeMatch( c, info ))
00342 fakeInfo = fakeSession.take();
00343
00344
00345 if (fakeInfo)
00346 c->setStoreSettings( TRUE );
00347 if (fakeInfo && realInfo)
00348 delete fakeInfo;
00349 if (realInfo)
00350 return realInfo;
00351 if (fakeInfo)
00352 return fakeInfo;
00353 return 0;
00354 }
00355
00356 bool Workspace::sessionInfoWindowTypeMatch( Client* c, SessionInfo* info )
00357 {
00358 if( info->windowType == -2 )
00359 {
00360 return !c->isSpecialWindow() || c->isOverride();
00361 }
00362 return info->windowType == c->windowType();
00363 }
00364
00365
00366 #if 0
00367
00368
00369
00370
00371 bool Workspace::windowRoleMatch( const QCString& role1, const QCString& role2 )
00372 {
00373 if( role1.isEmpty() && role2.isEmpty())
00374 return true;
00375 int pos1 = role1.find( '#' );
00376 int pos2 = role2.find( '#' );
00377 bool ret;
00378 if( pos1 < 0 || pos2 < 0 || pos1 != pos2 )
00379 ret = role1 == role2;
00380 else
00381 ret = qstrncmp( role1, role2, pos1 ) == 0;
00382 kdDebug() << "WR:" << role1 << ":" << pos1 << ":" << role2 << ":" << pos2 << ":::" << ret << endl;
00383 return ret;
00384 }
00385 #endif
00386
00387 static const char* const window_type_names[] =
00388 {
00389 "Unknown", "Normal" , "Desktop", "Dock", "Toolbar", "Menu", "Dialog",
00390 "Override", "TopMenu", "Utility", "Splash"
00391 };
00392
00393
00394 const char* Workspace::windowTypeToTxt( NET::WindowType type )
00395 {
00396 if( type >= NET::Unknown && type <= NET::Splash )
00397 return window_type_names[ type + 1 ];
00398 if( type == -2 )
00399 return "Undefined";
00400 kdFatal() << "Unknown Window Type" << endl;
00401 return NULL;
00402 }
00403
00404 NET::WindowType Workspace::txtToWindowType( const char* txt )
00405 {
00406 for( int i = NET::Unknown;
00407 i <= NET::Splash;
00408 ++i )
00409 if( qstrcmp( txt, window_type_names[ i + 1 ] ) == 0 )
00410 return static_cast< NET::WindowType >( i );
00411 return static_cast< NET::WindowType >( -2 );
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 static void save_yourself( SmcConn conn_P, SmPointer ptr, int, Bool, int, Bool )
00425 {
00426 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00427 if( conn_P != session->connection())
00428 return;
00429 SmcSaveYourselfDone( conn_P, True );
00430 }
00431
00432 static void die( SmcConn conn_P, SmPointer ptr )
00433 {
00434 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00435 if( conn_P != session->connection())
00436 return;
00437
00438 session->close();
00439 }
00440
00441 static void save_complete( SmcConn conn_P, SmPointer ptr )
00442 {
00443 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00444 if( conn_P != session->connection())
00445 return;
00446 session->saveDone();
00447 }
00448
00449 static void shutdown_cancelled( SmcConn conn_P, SmPointer ptr )
00450 {
00451 SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00452 if( conn_P != session->connection())
00453 return;
00454
00455 session->saveDone();
00456 }
00457
00458 void SessionSaveDoneHelper::saveDone()
00459 {
00460 Workspace::self()->sessionSaveDone();
00461 }
00462
00463 SessionSaveDoneHelper::SessionSaveDoneHelper()
00464 {
00465 SmcCallbacks calls;
00466 calls.save_yourself.callback = save_yourself;
00467 calls.save_yourself.client_data = reinterpret_cast< SmPointer >(this);
00468 calls.die.callback = die;
00469 calls.die.client_data = reinterpret_cast< SmPointer >(this);
00470 calls.save_complete.callback = save_complete;
00471 calls.save_complete.client_data = reinterpret_cast< SmPointer >(this);
00472 calls.shutdown_cancelled.callback = shutdown_cancelled;
00473 calls.shutdown_cancelled.client_data = reinterpret_cast< SmPointer >(this);
00474 char* id = NULL;
00475 char err[ 11 ];
00476 conn = SmcOpenConnection( NULL, 0, 1, 0,
00477 SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
00478 | SmcShutdownCancelledProcMask, &calls, NULL, &id, 10, err );
00479 if( id != NULL )
00480 free( id );
00481 if( conn == NULL )
00482 return;
00483
00484 SmPropValue propvalue[ 5 ];
00485 SmProp props[ 5 ];
00486 propvalue[ 0 ].length = sizeof( int );
00487 int value0 = SmRestartNever;
00488 propvalue[ 0 ].value = &value0;
00489 props[ 0 ].name = const_cast< char* >( SmRestartStyleHint );
00490 props[ 0 ].type = const_cast< char* >( SmCARD8 );
00491 props[ 0 ].num_vals = 1;
00492 props[ 0 ].vals = &propvalue[ 0 ];
00493 struct passwd* entry = getpwuid( geteuid() );
00494 propvalue[ 1 ].length = entry != NULL ? strlen( entry->pw_name ) : 0;
00495 propvalue[ 1 ].value = (SmPointer)( entry != NULL ? entry->pw_name : "" );
00496 props[ 1 ].name = const_cast< char* >( SmUserID );
00497 props[ 1 ].type = const_cast< char* >( SmARRAY8 );
00498 props[ 1 ].num_vals = 1;
00499 props[ 1 ].vals = &propvalue[ 1 ];
00500 propvalue[ 2 ].length = 0;
00501 propvalue[ 2 ].value = (SmPointer)( "" );
00502 props[ 2 ].name = const_cast< char* >( SmRestartCommand );
00503 props[ 2 ].type = const_cast< char* >( SmLISTofARRAY8 );
00504 props[ 2 ].num_vals = 1;
00505 props[ 2 ].vals = &propvalue[ 2 ];
00506 propvalue[ 3 ].length = 0;
00507 propvalue[ 3 ].value = qApp->argv()[ 0 ];
00508 props[ 3 ].name = const_cast< char* >( SmProgram );
00509 props[ 3 ].type = const_cast< char* >( SmARRAY8 );
00510 props[ 3 ].num_vals = 1;
00511 props[ 3 ].vals = &propvalue[ 3 ];
00512 propvalue[ 4 ].length = 0;
00513 propvalue[ 4 ].value = (SmPointer)( "" );
00514 props[ 4 ].name = const_cast< char* >( SmCloneCommand );
00515 props[ 4 ].type = const_cast< char* >( SmLISTofARRAY8 );
00516 props[ 4 ].num_vals = 1;
00517 props[ 4 ].vals = &propvalue[ 4 ];
00518 SmProp* p[ 5 ] = { &props[ 0 ], &props[ 1 ], &props[ 2 ], &props[ 3 ], &props[ 4 ] };
00519 SmcSetProperties( conn, 5, p );
00520 notifier = new QSocketNotifier( IceConnectionNumber( SmcGetIceConnection( conn )),
00521 QSocketNotifier::Read, this );
00522 connect( notifier, SIGNAL( activated( int )), SLOT( processData()));
00523 }
00524
00525 SessionSaveDoneHelper::~SessionSaveDoneHelper()
00526 {
00527 close();
00528 }
00529
00530 void SessionSaveDoneHelper::close()
00531 {
00532 if( conn != NULL )
00533 {
00534 delete notifier;
00535 SmcCloseConnection( conn, 0, NULL );
00536 }
00537 conn = NULL;
00538 }
00539
00540 void SessionSaveDoneHelper::processData()
00541 {
00542 if( conn != NULL )
00543 IceProcessMessages( SmcGetIceConnection( conn ), 0, 0 );
00544 }
00545
00546 }
00547
00548 #include "sm.moc"