• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • twin
 

twin

sm.cpp

00001 /*****************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 #include "sm.h"
00013 
00014 #include <tqsocketnotifier.h>
00015 #include <tqsessionmanager.h>
00016 #include <kdebug.h>
00017 #include <unistd.h>
00018 #include <stdlib.h>
00019 #include <pwd.h>
00020 #include <fixx11h.h>
00021 #include <tdeconfig.h>
00022 #include <tdeglobal.h>
00023 
00024 #include "workspace.h"
00025 #include "client.h"
00026 
00027 namespace KWinInternal
00028 {
00029 
00030 bool SessionManaged::saveState( TQSessionManager& sm )
00031     {
00032     // If the session manager is ksmserver, save stacking
00033     // order, active window, active desktop etc. in phase 1,
00034     // as ksmserver assures no interaction will be done
00035     // before the WM finishes phase 1. Saving in phase 2 is
00036     // too late, as possible user interaction may change some things.
00037     // Phase2 is still needed though (ICCCM 5.2)
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 ) // save stacking order etc. before "save file?" etc. dialogs change it
00045             Workspace::self()->storeSession( kapp->sessionConfig(), SMSavePhase0 );
00046         sm.release(); // Qt doesn't automatically release in this case (bug?)
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 // I bet this is broken, just like everywhere else in KDE
00056 bool SessionManaged::commitData( TQSessionManager& sm )
00057     {
00058     if ( !sm.isPhase2() )
00059         Workspace::self()->sessionSaveStarted();
00060     return true;
00061     }
00062 
00063 // Workspace
00064 
00070 void Workspace::storeSession( TDEConfig* 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         TQCString sessionId = c->sessionId();
00079         TQCString wmCommand = c->wmCommand();
00080         if ( sessionId.isEmpty() )
00081         // remember also applications that are not XSMP capable
00082         // and use the obsolete WM_COMMAND / WM_SAVE_YOURSELF
00083             if ( wmCommand.isEmpty() )
00084                 continue;
00085         count++;
00086         if( c->isActive())
00087             active_client = count;
00088         TQString n = TQString::number(count);
00089         if( phase == SMSavePhase2 || phase == SMSavePhase2Full )
00090             {
00091             config->writeEntry( TQString("sessionId")+n, sessionId.data() );
00092             config->writeEntry( TQString("windowRole")+n, c->windowRole().data() );
00093             config->writeEntry( TQString("wmCommand")+n, wmCommand.data() );
00094             config->writeEntry( TQString("wmClientMachine")+n, c->wmClientMachine( true ).data() );
00095             config->writeEntry( TQString("resourceName")+n, c->resourceName().data() );
00096             config->writeEntry( TQString("resourceClass")+n, c->resourceClass().data() );
00097             config->writeEntry( TQString("geometry")+n,  TQRect( c->calculateGravitation(TRUE), c->clientSize() ) ); // FRAME
00098             config->writeEntry( TQString("restore")+n, c->geometryRestore() );
00099             config->writeEntry( TQString("fsrestore")+n, c->geometryFSRestore() );
00100             config->writeEntry( TQString("maximize")+n, (int) c->maximizeMode() );
00101             config->writeEntry( TQString("fullscreen")+n, (int) c->fullScreenMode() );
00102             config->writeEntry( TQString("desktop")+n, c->desktop() );
00103             // the config entry is called "iconified" for back. comp. reasons
00104             // (tdeconf_update script for updating session files would be too complicated)
00105             config->writeEntry( TQString("iconified")+n, c->isMinimized() );
00106             // the config entry is called "sticky" for back. comp. reasons
00107             config->writeEntry( TQString("sticky")+n, c->isOnAllDesktops() );
00108             config->writeEntry( TQString("shaded")+n, c->isShade() );
00109             config->writeEntry( TQString("shadowed")+n, c->isShadowed() );
00110             // the config entry is called "staysOnTop" for back. comp. reasons
00111             config->writeEntry( TQString("staysOnTop")+n, c->keepAbove() );
00112             config->writeEntry( TQString("keepBelow")+n, c->keepBelow() );
00113             config->writeEntry( TQString("skipTaskbar")+n, c->skipTaskbar( true ) );
00114             config->writeEntry( TQString("skipPager")+n, c->skipPager() );
00115             config->writeEntry( TQString("userNoBorder")+n, c->isUserNoBorder() );
00116             config->writeEntry( TQString("windowType")+n, windowTypeToTxt( c->windowType()));
00117             config->writeEntry( TQString("shortcut")+n, c->shortcut().toStringInternal());
00118             }
00119         }
00120     // TODO store also stacking order
00121     if( phase == SMSavePhase0 )
00122         {
00123         // it would be much simpler to save these values to the config file,
00124         // but both Qt and KDE treat phase1 and phase2 separately,
00125         // which results in different sessionkey and different config file :(
00126         session_active_client = active_client;
00127         session_desktop = currentDesktop();
00128         }
00129     else if( phase == SMSavePhase2 )
00130         {
00131         config->writeEntry( "count", count );
00132         config->writeEntry( "active", session_active_client );
00133         config->writeEntry( "desktop", session_desktop );
00134         }
00135     else // SMSavePhase2Full
00136         {
00137         config->writeEntry( "count", count );
00138         config->writeEntry( "active", session_active_client );
00139         config->writeEntry( "desktop", currentDesktop());
00140         }
00141     }
00142 
00143 
00149 void Workspace::loadSessionInfo()
00150     {
00151     session.clear();
00152     TDEConfig* config = kapp->sessionConfig();
00153     config->setGroup("Session" );
00154     int count =  config->readNumEntry( "count" );
00155     int active_client = config->readNumEntry( "active" );
00156     for ( int i = 1; i <= count; i++ ) 
00157         {
00158         TQString n = TQString::number(i);
00159         SessionInfo* info = new SessionInfo;
00160         session.append( info );
00161         info->sessionId = config->readEntry( TQString("sessionId")+n ).latin1();
00162         info->windowRole = config->readEntry( TQString("windowRole")+n ).latin1();
00163         info->wmCommand = config->readEntry( TQString("wmCommand")+n ).latin1();
00164         info->wmClientMachine = config->readEntry( TQString("wmClientMachine")+n ).latin1();
00165         info->resourceName = config->readEntry( TQString("resourceName")+n ).latin1();
00166         info->resourceClass = config->readEntry( TQString("resourceClass")+n ).lower().latin1();
00167         info->geometry = config->readRectEntry( TQString("geometry")+n );
00168         info->restore = config->readRectEntry( TQString("restore")+n );
00169         info->fsrestore = config->readRectEntry( TQString("fsrestore")+n );
00170         info->maximized = config->readNumEntry( TQString("maximize")+n, 0 );
00171         info->fullscreen = config->readNumEntry( TQString("fullscreen")+n, 0 );
00172         info->desktop = config->readNumEntry( TQString("desktop")+n, 0 );
00173         info->minimized = config->readBoolEntry( TQString("iconified")+n, FALSE );
00174         info->onAllDesktops = config->readBoolEntry( TQString("sticky")+n, FALSE );
00175         info->shaded = config->readBoolEntry( TQString("shaded")+n, FALSE );
00176         info->shadowed = config->readBoolEntry( TQString("shadowed")+n, TRUE );
00177         info->keepAbove = config->readBoolEntry( TQString("staysOnTop")+n, FALSE  );
00178         info->keepBelow = config->readBoolEntry( TQString("keepBelow")+n, FALSE  );
00179         info->skipTaskbar = config->readBoolEntry( TQString("skipTaskbar")+n, FALSE  );
00180         info->skipPager = config->readBoolEntry( TQString("skipPager")+n, FALSE  );
00181         info->userNoBorder = config->readBoolEntry( TQString("userNoBorder")+n, FALSE  );
00182         info->windowType = txtToWindowType( config->readEntry( TQString("windowType")+n ).latin1());
00183         info->shortcut = config->readEntry( TQString("shortcut")+n );
00184         info->active = ( active_client == i );
00185         }
00186     }
00187 
00197 SessionInfo* Workspace::takeSessionInfo( Client* c )
00198     {
00199     SessionInfo *realInfo = 0;
00200     TQCString sessionId = c->sessionId();
00201     TQCString windowRole = c->windowRole();
00202     TQCString wmCommand = c->wmCommand();
00203     TQCString wmClientMachine = c->wmClientMachine( true );
00204     TQCString resourceName = c->resourceName();
00205     TQCString resourceClass = c->resourceClass();
00206 
00207     // First search ``session''
00208     if (! sessionId.isEmpty() ) 
00209         {
00210         // look for a real session managed client (algorithm suggested by ICCCM)
00211         for (SessionInfo* info = session.first(); info && !realInfo; info = session.next() )
00212             if ( info->sessionId == sessionId && sessionInfoWindowTypeMatch( c, info )) 
00213             {
00214             if ( ! windowRole.isEmpty() ) 
00215                 {
00216                 if ( info->windowRole == windowRole )
00217                     realInfo = session.take();
00218                 }
00219             else 
00220                 {
00221                 if ( info->windowRole.isEmpty() &&
00222                      info->resourceName == resourceName &&
00223                      info->resourceClass == resourceClass )
00224                     realInfo = session.take();
00225                 }
00226             }
00227         }
00228     else 
00229         {
00230         // look for a sessioninfo with matching features.
00231         for (SessionInfo* info = session.first(); info && !realInfo; info = session.next() )
00232             if ( info->resourceName == resourceName &&
00233                  info->resourceClass == resourceClass &&
00234                  info->wmClientMachine == wmClientMachine &&
00235                  sessionInfoWindowTypeMatch( c, info ))
00236                 if ( wmCommand.isEmpty() || info->wmCommand == wmCommand )
00237                     realInfo = session.take();
00238         }
00239 
00240     return realInfo;
00241     }
00242 
00243 bool Workspace::sessionInfoWindowTypeMatch( Client* c, SessionInfo* info )
00244     {
00245     if( info->windowType == -2 ) 
00246         { // undefined (not really part of NET::WindowType)
00247         return !c->isSpecialWindow();
00248         }
00249     return info->windowType == c->windowType();
00250     }
00251 
00252 // maybe needed later
00253 #if 0
00254 // TDEMainWindow's without name() given have WM_WINDOW_ROLE in the form
00255 // of <appname>-mainwindow#<number>
00256 // when comparing them for fake session info, it's probably better to check
00257 // them without the trailing number
00258 bool Workspace::windowRoleMatch( const TQCString& role1, const TQCString& role2 )
00259     {
00260     if( role1.isEmpty() && role2.isEmpty())
00261         return true;
00262     int pos1 = role1.find( '#' );
00263     int pos2 = role2.find( '#' );
00264     bool ret;
00265     if( pos1 < 0 || pos2 < 0 || pos1 != pos2 )
00266         ret = role1 == role2;
00267     else
00268         ret = tqstrncmp( role1, role2, pos1 ) == 0;
00269     kdDebug() << "WR:" << role1 << ":" << pos1 << ":" << role2 << ":" << pos2 << ":::" << ret << endl;
00270     return ret;
00271     }
00272 #endif
00273 
00274 static const char* const window_type_names[] = 
00275     {
00276     "Unknown", "Normal" , "Desktop", "Dock", "Toolbar", "Menu", "Dialog",
00277     "Override", "TopMenu", "Utility", "Splash"
00278     };
00279     // change also the two functions below when adding new entries
00280 
00281 const char* Workspace::windowTypeToTxt( NET::WindowType type )
00282     {
00283     if( type >= NET::Unknown && type <= NET::Splash )
00284         return window_type_names[ type + 1 ]; // +1 (unknown==-1)
00285     if( type == -2 ) // undefined (not really part of NET::WindowType)
00286         return "Undefined";
00287     kdFatal() << "Unknown Window Type" << endl;
00288     return NULL;
00289     }
00290 
00291 NET::WindowType Workspace::txtToWindowType( const char* txt )
00292     {
00293     for( int i = NET::Unknown;
00294          i <= NET::Splash;
00295          ++i )
00296         if( qstrcmp( txt, window_type_names[ i + 1 ] ) == 0 ) // +1
00297             return static_cast< NET::WindowType >( i );
00298     return static_cast< NET::WindowType >( -2 ); // undefined
00299     }
00300 
00301 
00302 
00303 
00304 // KWin's focus stealing prevention causes problems with user interaction
00305 // during session save, as it prevents possible dialogs from getting focus.
00306 // Therefore it's temporarily disabled during session saving. Start of
00307 // session saving can be detected in SessionManaged::saveState() above,
00308 // but Qt doesn't have API for saying when session saved finished (either
00309 // successfully, or was cancelled). Therefore, create another connection
00310 // to session manager, that will provide this information.
00311 // Similarly the remember feature of window-specific settings should be disabled
00312 // during KDE shutdown when windows may move e.g. because of Kicker going away
00313 // (struts changing). When session saving starts, it can be cancelled, in which
00314 // case the shutdown_cancelled callback is invoked, or it's a checkpoint that
00315 // is immediatelly followed by save_complete, or finally it's a shutdown that
00316 // is immediatelly followed by die callback. So getting save_yourself with shutdown
00317 // set disables window-specific settings remembering, getting shutdown_cancelled
00318 // re-enables, otherwise KWin will go away after die.
00319 static void save_yourself( SmcConn conn_P, SmPointer ptr, int, Bool shutdown, int, Bool )
00320     {
00321     SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00322     if( conn_P != session->connection())
00323         return;
00324     if( shutdown )
00325         Workspace::self()->disableRulesUpdates( true );
00326     SmcSaveYourselfDone( conn_P, True );
00327     }
00328 
00329 static void die( SmcConn conn_P, SmPointer ptr )
00330     {
00331     SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00332     if( conn_P != session->connection())
00333         return;
00334     // session->saveDone(); we will quit anyway
00335     session->close();
00336     }
00337 
00338 static void save_complete( SmcConn conn_P, SmPointer ptr )
00339     {
00340     SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00341     if( conn_P != session->connection())
00342         return;
00343     session->saveDone();
00344     }
00345 
00346 static void shutdown_cancelled( SmcConn conn_P, SmPointer ptr )
00347     {
00348     SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >( ptr );
00349     if( conn_P != session->connection())
00350         return;
00351     Workspace::self()->disableRulesUpdates( false ); // re-enable
00352     // no need to differentiate between successful finish and cancel
00353     session->saveDone();
00354     }
00355 
00356 void SessionSaveDoneHelper::saveDone()
00357     {
00358     Workspace::self()->sessionSaveDone();
00359     }
00360 
00361 SessionSaveDoneHelper::SessionSaveDoneHelper()
00362     {
00363     SmcCallbacks calls;
00364     calls.save_yourself.callback = save_yourself;
00365     calls.save_yourself.client_data = reinterpret_cast< SmPointer >(this);
00366     calls.die.callback = die;
00367     calls.die.client_data = reinterpret_cast< SmPointer >(this);
00368     calls.save_complete.callback = save_complete;
00369     calls.save_complete.client_data = reinterpret_cast< SmPointer >(this);
00370     calls.shutdown_cancelled.callback = shutdown_cancelled;
00371     calls.shutdown_cancelled.client_data = reinterpret_cast< SmPointer >(this);
00372     char* id = NULL;
00373     char err[ 11 ];
00374     conn = SmcOpenConnection( NULL, 0, 1, 0,
00375         SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
00376         | SmcShutdownCancelledProcMask, &calls, NULL, &id, 10, err );
00377     if( id != NULL )
00378         free( id );
00379     if( conn == NULL )
00380         return; // no SM
00381     // set the required properties, mostly dummy values
00382     SmPropValue propvalue[ 5 ];
00383     SmProp props[ 5 ];
00384     propvalue[ 0 ].length = sizeof( int );
00385     int value0 = SmRestartNever; // so that this extra SM connection doesn't interfere
00386     propvalue[ 0 ].value = &value0;
00387     props[ 0 ].name = const_cast< char* >( SmRestartStyleHint );
00388     props[ 0 ].type = const_cast< char* >( SmCARD8 );
00389     props[ 0 ].num_vals = 1;
00390     props[ 0 ].vals = &propvalue[ 0 ];
00391     struct passwd* entry = getpwuid( geteuid() );
00392     propvalue[ 1 ].length = entry != NULL ? strlen( entry->pw_name ) : 0;
00393     propvalue[ 1 ].value = (SmPointer)( entry != NULL ? entry->pw_name : "" );
00394     props[ 1 ].name = const_cast< char* >( SmUserID );
00395     props[ 1 ].type = const_cast< char* >( SmARRAY8 );
00396     props[ 1 ].num_vals = 1;
00397     props[ 1 ].vals = &propvalue[ 1 ];
00398     propvalue[ 2 ].length = 0;
00399     propvalue[ 2 ].value = (SmPointer)( "" );
00400     props[ 2 ].name = const_cast< char* >( SmRestartCommand );
00401     props[ 2 ].type = const_cast< char* >( SmLISTofARRAY8 );
00402     props[ 2 ].num_vals = 1;
00403     props[ 2 ].vals = &propvalue[ 2 ];
00404     propvalue[ 3 ].length = 0;
00405     propvalue[ 3 ].value = tqApp->argv()[ 0 ];
00406     props[ 3 ].name = const_cast< char* >( SmProgram );
00407     props[ 3 ].type = const_cast< char* >( SmARRAY8 );
00408     props[ 3 ].num_vals = 1;
00409     props[ 3 ].vals = &propvalue[ 3 ];
00410     propvalue[ 4 ].length = 0;
00411     propvalue[ 4 ].value = (SmPointer)( "" );
00412     props[ 4 ].name = const_cast< char* >( SmCloneCommand );
00413     props[ 4 ].type = const_cast< char* >( SmLISTofARRAY8 );
00414     props[ 4 ].num_vals = 1;
00415     props[ 4 ].vals = &propvalue[ 4 ];
00416     SmProp* p[ 5 ] = { &props[ 0 ], &props[ 1 ], &props[ 2 ], &props[ 3 ], &props[ 4 ] };
00417     SmcSetProperties( conn, 5, p );
00418     notifier = new TQSocketNotifier( IceConnectionNumber( SmcGetIceConnection( conn )),
00419         TQSocketNotifier::Read, TQT_TQOBJECT(this) );
00420     connect( notifier, TQT_SIGNAL( activated( int )), TQT_SLOT( processData()));
00421     }
00422 
00423 SessionSaveDoneHelper::~SessionSaveDoneHelper()
00424     {
00425     close();
00426     }
00427 
00428 void SessionSaveDoneHelper::close()
00429     {
00430     if( conn != NULL )
00431         {
00432         delete notifier;
00433         SmcCloseConnection( conn, 0, NULL );
00434         }
00435     conn = NULL;
00436     }
00437 
00438 void SessionSaveDoneHelper::processData()
00439     {
00440     if( conn != NULL )
00441         IceProcessMessages( SmcGetIceConnection( conn ), 0, 0 );
00442     }
00443 
00444 } // namespace
00445 
00446 #include "sm.moc"

twin

Skip menu "twin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.7.1
This website is maintained by Timothy Pearson.