void KSMServer::saveCurrentSession() { if ( state != Idle || dialogActive ) return; if ( currentSession().isEmpty() || currentSession() == SESSION_PREVIOUS_LOGOUT ) sessionGroup = QString("Session: ") + SESSION_BY_USER; state = Checkpoint; wmPhase1WaitingCount = 0; saveType = SmSaveLocal; saveSession = true; performLegacySessionSave(); for ( KSMClient* c = clients.first(); c; c = clients.next() ) { c->resetState(); if( isWM( c )) { ++wmPhase1WaitingCount; SmsSaveYourself( c->connection(), saveType, false, SmInteractStyleNone, false ); } } if( wmPhase1WaitingCount == 0 ) { for ( KSMClient* c = clients.first(); c; c = clients.next() ) SmsSaveYourself( c->connection(), saveType, false, SmInteractStyleNone, false ); } if ( clients.isEmpty() ) completeShutdownOrCheckpoint(); }
static void do_save_yourself (GsmXSMPClient *client, int save_type, gboolean allow_interact) { g_assert (client->priv->conn != NULL); if (client->priv->next_save_yourself != -1) { /* Either we're currently doing a shutdown and there's a checkpoint * queued after it, or vice versa. Either way, the new SaveYourself * is redundant. */ g_debug ("GsmXSMPClient: skipping redundant SaveYourself for '%s'", client->priv->description); } else if (client->priv->current_save_yourself != -1) { g_debug ("GsmXSMPClient: queuing new SaveYourself for '%s'", client->priv->description); client->priv->next_save_yourself = save_type; client->priv->next_save_yourself_allow_interact = allow_interact; } else { client->priv->current_save_yourself = save_type; /* make sure we don't have anything queued */ client->priv->next_save_yourself = -1; client->priv->next_save_yourself_allow_interact = FALSE; switch (save_type) { case SmSaveLocal: /* Save state */ SmsSaveYourself (client->priv->conn, SmSaveLocal, FALSE, SmInteractStyleNone, FALSE); break; default: /* Logout */ if (!allow_interact) { SmsSaveYourself (client->priv->conn, save_type, /* save type */ TRUE, /* shutdown */ SmInteractStyleNone, /* interact style */ TRUE); /* fast */ } else { SmsSaveYourself (client->priv->conn, save_type, /* save type */ TRUE, /* shutdown */ SmInteractStyleAny, /* interact style */ FALSE /* fast */); } break; } } }
// callbacks void KSMServer::saveYourselfDone( KSMClient* client, bool success ) { if ( state == Idle ) { // State saving when it's not shutdown or checkpoint. Probably // a shutdown was cancelled and the client is finished saving // only now. Discard the saved state in order to avoid // the saved data building up. QStringList discard = client->discardCommand(); if( !discard.isEmpty()) executeCommand( discard ); return; } if ( success ) { client->saveYourselfDone = true; completeShutdownOrCheckpoint(); } else { // fake success to make KDE's logout not block with broken // apps. A perfect ksmserver would display a warning box at // the very end. client->saveYourselfDone = true; completeShutdownOrCheckpoint(); } startProtection(); if( isWM( client ) && !client->wasPhase2 && wmPhase1WaitingCount > 0 ) { --wmPhase1WaitingCount; // WM finished its phase1, save the rest if( wmPhase1WaitingCount == 0 ) { for ( KSMClient* c = clients.first(); c; c = clients.next() ) if( !isWM( c )) SmsSaveYourself( c->connection(), saveType, saveType != SmSaveLocal, saveType != SmSaveLocal ? SmInteractStyleAny : SmInteractStyleNone, false ); } } }
static Status register_client_callback (SmsConn conn, SmPointer manager_data, char *previous_id) { GsmXSMPClient *client = manager_data; gboolean handled; char *id; g_debug ("GsmXSMPClient: Client '%s' received RegisterClient(%s)", client->priv->description, previous_id ? previous_id : "NULL"); /* There are three cases: * 1. id is NULL - we'll use a new one * 2. id is known - we'll use known one * 3. id is unknown - this is an error */ id = g_strdup (previous_id); handled = FALSE; g_signal_emit (client, signals[REGISTER_REQUEST], 0, &id, &handled); if (! handled) { g_debug ("GsmXSMPClient: RegisterClient not handled!"); g_free (id); free (previous_id); g_assert_not_reached (); return FALSE; } if (IS_STRING_EMPTY (id)) { g_debug ("GsmXSMPClient: rejected: invalid previous_id"); free (previous_id); return FALSE; } g_object_set (client, "startup-id", id, NULL); set_description (client); g_debug ("GsmXSMPClient: Sending RegisterClientReply to '%s'", client->priv->description); SmsRegisterClientReply (conn, id); if (IS_STRING_EMPTY (previous_id)) { /* Send the initial SaveYourself. */ g_debug ("GsmXSMPClient: Sending initial SaveYourself"); SmsSaveYourself (conn, SmSaveLocal, False, SmInteractStyleNone, False); client->priv->current_save_yourself = SmSaveLocal; } gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_REGISTERED); g_free (id); free (previous_id); return TRUE; }
void KSMClient::registerClient( const char* previousId ) { id = previousId; if ( !id ) id = safeSmsGenerateClientID( smsConn ); SmsRegisterClientReply( smsConn, (char*) id ); SmsSaveYourself( smsConn, SmSaveLocal, false, SmInteractStyleNone, false ); SmsSaveComplete( smsConn ); KSMServer::self()->clientRegistered( previousId ); }
void KSMServer::phase2Request( KSMClient* client ) { client->waitForPhase2 = true; client->wasPhase2 = true; completeShutdownOrCheckpoint(); if( isWM( client ) && wmPhase1WaitingCount > 0 ) { --wmPhase1WaitingCount; // WM finished its phase1 and requests phase2, save the rest if( wmPhase1WaitingCount == 0 ) { for ( KSMClient* c = clients.first(); c; c = clients.next() ) if( !isWM( c )) SmsSaveYourself( c->connection(), saveType, saveType != SmSaveLocal, saveType != SmSaveLocal ? SmInteractStyleAny : SmInteractStyleNone, false ); } } }
void KSMSaveYourselfRequestProc ( SmsConn smsConn , SmPointer /* managerData */, int saveType, Bool shutdown, int interactStyle, Bool fast, Bool global ) { if ( shutdown ) { the_server->shutdown( fast ? KWorkSpace::ShutdownConfirmNo : KWorkSpace::ShutdownConfirmDefault, KWorkSpace::ShutdownTypeDefault, KWorkSpace::ShutdownModeDefault ); } else if ( !global ) { SmsSaveYourself( smsConn, saveType, false, interactStyle, fast ); SmsSaveComplete( smsConn ); } // else checkpoint only, ksmserver does not yet support this // mode. Will come for KDE 3.1 }
static Status RegisterClientProc(SmsConn smsConn, SmPointer managerData, char *previousId) { ClientRec *client = (ClientRec *) managerData; char *id; List *cl; int send_save; if (verbose) { printf ( "On IceConn fd = %d, received REGISTER CLIENT [Previous Id = %s]\n", IceConnectionNumber (client->ice_conn), previousId ? previousId : "NULL"); printf ("\n"); } if (!previousId) { id = SmsGenerateClientID (smsConn); send_save = 1; } else { int found_match = 0; send_save = 1; for (cl = ListFirst (PendingList); cl; cl = ListNext (cl)) { PendingClient *pendClient = (PendingClient *) cl->thing; if (!strcmp (pendClient->clientId, previousId)) { SetInitialProperties (client, pendClient->props); XtFree (pendClient->clientId); XtFree (pendClient->clientHostname); XtFree ((char *) pendClient); ListFreeOne (cl); found_match = 1; send_save = 0; break; } } if (!found_match) { for (cl = ListFirst (RestartAnywayList); cl; cl = ListNext (cl)) { ClientRec *rClient = (ClientRec *) cl->thing; if (!strcmp (rClient->clientId, previousId)) { SetInitialProperties (client, rClient->props); FreeClient (rClient, False /* don't free props */); ListFreeOne (cl); found_match = 1; send_save = 0; break; } } } if (!found_match) { for (cl = ListFirst (RestartImmedList); cl; cl = ListNext (cl)) { ClientRec *rClient = (ClientRec *) cl->thing; if (!strcmp (rClient->clientId, previousId)) { SetInitialProperties (client, rClient->props); FreeClient (rClient, False /* don't free props */); ListFreeOne (cl); found_match = 1; send_save = 0; break; } } } if (!found_match) { /* * previous-id was bogus: return bad status and the client * should re-register with a NULL previous-id */ free (previousId); return (0); } else { id = previousId; } } SmsRegisterClientReply (smsConn, id); if (verbose) { printf ( "On IceConn fd = %d, sent REGISTER CLIENT REPLY [Client Id = %s]\n", IceConnectionNumber (client->ice_conn), id); printf ("\n"); } client->clientId = id; client->clientHostname = SmsClientHostName (smsConn); client->restarted = (previousId != NULL); if (send_save) { SmsSaveYourself (smsConn, SmSaveLocal, False, SmInteractStyleNone, False); ListAddLast (InitialSaveList, (char *) client); } else if (client_info_visible) { /* We already have all required client info */ UpdateClientList (); XawListHighlight (clientListWidget, current_client_selected); } return (1); }
void KSMServer::shutdown( KApplication::ShutdownConfirm confirm, KApplication::ShutdownType sdtype, KApplication::ShutdownMode sdmode ) { pendingShutdown.stop(); if( dialogActive ) return; if( state >= Shutdown ) // already performing shutdown return; if( state != Idle ) // performing startup { // perform shutdown as soon as startup is finished, in order to avoid saving partial session if( !pendingShutdown.isActive()) { pendingShutdown.start( 1000 ); pendingShutdown_confirm = confirm; pendingShutdown_sdtype = sdtype; pendingShutdown_sdmode = sdmode; } return; } KConfig *config = KGlobal::config(); config->reparseConfiguration(); // config may have changed in the KControl module config->setGroup("General" ); bool logoutConfirmed = (confirm == KApplication::ShutdownConfirmYes) ? false : (confirm == KApplication::ShutdownConfirmNo) ? true : !config->readBoolEntry( "confirmLogout", true ); bool maysd = false; if (config->readBoolEntry( "offerShutdown", true ) && DM().canShutdown()) maysd = true; if (!maysd) { if (sdtype != KApplication::ShutdownTypeNone && sdtype != KApplication::ShutdownTypeDefault && logoutConfirmed) return; /* unsupported fast shutdown */ sdtype = KApplication::ShutdownTypeNone; } else if (sdtype == KApplication::ShutdownTypeDefault) sdtype = (KApplication::ShutdownType) config->readNumEntry( "shutdownType", (int)KApplication::ShutdownTypeNone ); if (sdmode == KApplication::ShutdownModeDefault) sdmode = KApplication::ShutdownModeInteractive; dialogActive = true; QString bopt; if ( !logoutConfirmed ) { KSMShutdownFeedback::start(); // make the screen gray logoutConfirmed = KSMShutdownDlg::confirmShutdown( maysd, sdtype, bopt ); // ###### We can't make the screen remain gray while talking to the apps, // because this prevents interaction ("do you want to save", etc.) // TODO: turn the feedback widget into a list of apps to be closed, // with an indicator of the current status for each. KSMShutdownFeedback::stop(); // make the screen become normal again } if ( logoutConfirmed ) { shutdownType = sdtype; shutdownMode = sdmode; bootOption = bopt; // shall we save the session on logout? saveSession = ( config->readEntry( "loginMode", "restorePreviousLogout" ) == "restorePreviousLogout" ); if ( saveSession ) sessionGroup = QString("Session: ") + SESSION_PREVIOUS_LOGOUT; // Set the real desktop background to black so that exit looks // clean regardless of what was on "our" desktop. kapp->desktop()->setBackgroundColor( Qt::black ); state = Shutdown; wmPhase1WaitingCount = 0; saveType = saveSession?SmSaveBoth:SmSaveGlobal; performLegacySessionSave(); startProtection(); for ( KSMClient* c = clients.first(); c; c = clients.next() ) { c->resetState(); // Whoever came with the idea of phase 2 got it backwards // unfortunately. Window manager should be the very first // one saving session data, not the last one, as possible // user interaction during session save may alter // window positions etc. // Moreover, KWin's focus stealing prevention would lead // to undesired effects while session saving (dialogs // wouldn't be activated), so it needs be assured that // KWin will turn it off temporarily before any other // user interaction takes place. // Therefore, make sure the WM finishes its phase 1 // before others a chance to change anything. // KWin will check if the session manager is ksmserver, // and if yes it will save in phase 1 instead of phase 2. if( isWM( c )) { ++wmPhase1WaitingCount; SmsSaveYourself( c->connection(), saveType, true, SmInteractStyleAny, false ); } } if( wmPhase1WaitingCount == 0 ) { // no WM, simply start them all for ( KSMClient* c = clients.first(); c; c = clients.next() ) SmsSaveYourself( c->connection(), saveType, true, SmInteractStyleAny, false ); } if ( clients.isEmpty() ) completeShutdownOrCheckpoint(); } dialogActive = false; }