diff --git a/ksmserver/server.cpp b/ksmserver/server.cpp index 6e3ed44a3..3adcbbade 100644 --- a/ksmserver/server.cpp +++ b/ksmserver/server.cpp @@ -681,6 +681,7 @@ KSMServer::KSMServer( const TQString& windowManager, const TQString& windowManag signal(SIGINT, sighandler); signal(SIGPIPE, SIG_IGN); + connect( ¬ificationTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( notificationTimeout() ) ); connect( &protectionTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( protectionTimeout() ) ); connect( &restoreTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( tryRestoreNext() ) ); connect( &shutdownTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( timeoutQuit() ) ); diff --git a/ksmserver/server.h b/ksmserver/server.h index f850c747c..5dd97ba7c 100644 --- a/ksmserver/server.h +++ b/ksmserver/server.h @@ -109,6 +109,7 @@ private slots: void restoreSessionInternal(); void restoreSessionDoneInternal(); + void notificationTimeout(); void protectionTimeout(); void timeoutQuit(); void timeoutWMQuit(); @@ -123,6 +124,9 @@ private slots: void tryRestoreNext(); void startupSuspendTimeout(); + void cancelShutdown(); + void forceSkipSaveYourself(); + private: void handlePendingInteractions(); void completeShutdownOrCheckpoint(); @@ -131,6 +135,7 @@ private: void completeKilling(); void killWM(); void completeKillingWM(); + void cancelShutdown( TQString cancellationText ); void cancelShutdown( KSMClient* c ); void killingCompleted(); @@ -139,6 +144,7 @@ private: void startProtection(); void endProtection(); + void handleProtectionTimeout(); void startApplication( TQStringList command, const TQString& clientMachine = TQString::null, @@ -214,6 +220,7 @@ private: TQString sessionName; TQCString launcher; TQTimer protectionTimer; + TQTimer notificationTimer; TQTimer restoreTimer; TQTimer shutdownTimer; TQString xonCommand; diff --git a/ksmserver/shutdown.cpp b/ksmserver/shutdown.cpp index 5809cd295..41556dcf2 100644 --- a/ksmserver/shutdown.cpp +++ b/ksmserver/shutdown.cpp @@ -102,6 +102,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // If set too high running applications may be ungracefully terminated on slow machines #define KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT 60000 +// Time to wait before showing manual termination options +// If set too low the user may be confused by buttons briefly flashing up on the screen during an otherwise normal logout process +#define KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT 1000 + void KSMServer::logout( int confirm, int sdtype, int sdmode ) { shutdown( (TDEApplication::ShutdownConfirm)confirm, @@ -253,6 +257,11 @@ void KSMServer::shutdownInternal( TDEApplication::ShutdownConfirm confirm, shutdownMode = sdmode; bootOption = bopt; shutdownNotifierIPDlg = 0; + shutdownNotifierIPDlg = KSMShutdownIPDlg::showShutdownIP(); + if (shutdownNotifierIPDlg) { + static_cast(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying applications of logout request...")); + notificationTimer.start( KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT, true ); + } // shall we save the session on logout? saveSession = ( config->readEntry( "loginMode", "restorePreviousLogout" ) == "restorePreviousLogout" ); @@ -489,11 +498,13 @@ void KSMServer::handlePendingInteractions() } } - -void KSMServer::cancelShutdown( KSMClient* c ) +void KSMServer::cancelShutdown( TQString cancellationText ) { - kdDebug( 1218 ) << "Client " << c->program() << " (" << c->clientId() << ") canceled shutdown." << endl; - KNotifyClient::event( 0, "cancellogout", i18n( "Logout canceled by '%1'" ).arg( c->program())); + if (shutdownNotifierIPDlg) { + static_cast(shutdownNotifierIPDlg)->closeSMDialog(); + shutdownNotifierIPDlg=0; + } + KNotifyClient::event( 0, "cancellogout", cancellationText); clientInteracting = 0; for ( KSMClient* c = clients.first(); c; c = clients.next() ) { SmsShutdownCancelled( c->connection() ); @@ -507,6 +518,18 @@ void KSMServer::cancelShutdown( KSMClient* c ) state = Idle; } +void KSMServer::cancelShutdown( KSMClient* c ) +{ + kdDebug( 1218 ) << "Client " << c->program() << " (" << c->clientId() << ") canceled shutdown." << endl; + cancelShutdown(i18n( "Logout canceled by '%1'" ).arg( c->program())); +} + +void KSMServer::cancelShutdown() +{ + kdDebug( 1218 ) << "User canceled shutdown." << endl; + cancelShutdown(i18n( "Logout canceled by user" )); +} + void KSMServer::startProtection() { protectionTimer.start( KSMSERVER_SHUTDOWN_CLIENT_UNRESPONSIVE_TIMEOUT, true ); @@ -526,6 +549,30 @@ void KSMServer::protectionTimeout() if ( ( state != Shutdown && state != Checkpoint ) || clientInteracting ) return; + handleProtectionTimeout(); + + startProtection(); +} + +void KSMServer::forceSkipSaveYourself() +{ + SHUTDOWN_MARKER("forceSkipSaveYourself"); + + handleProtectionTimeout(); + + startProtection(); +} + +void KSMServer::handleProtectionTimeout() +{ + SHUTDOWN_MARKER("handleProtectionTimeout"); + + notificationTimer.stop(); + static_cast(shutdownNotifierIPDlg)->hideNotificationActionButtons(); + disconnect(shutdownNotifierIPDlg, SIGNAL(abortLogoutClicked()), this, SLOT(cancelShutdown())); + disconnect(shutdownNotifierIPDlg, SIGNAL(skipNotificationClicked()), this, SLOT(forceSkipSaveYourself())); + static_cast(shutdownNotifierIPDlg)->setStatusMessage(i18n("Forcing interacting application termination").append("...")); + for ( KSMClient* c = clients.first(); c; c = clients.next() ) { if ( !c->saveYourselfDone && !c->waitForPhase2 ) { kdDebug( 1218 ) << "protectionTimeout: client " << c->program() << "(" << c->clientId() << ")" << endl; @@ -533,18 +580,27 @@ void KSMServer::protectionTimeout() } } completeShutdownOrCheckpoint(); - startProtection(); +} + +void KSMServer::notificationTimeout() +{ + // Display the buttons in the logout dialog + connect(shutdownNotifierIPDlg, SIGNAL(abortLogoutClicked()), this, SLOT(cancelShutdown())); + connect(shutdownNotifierIPDlg, SIGNAL(skipNotificationClicked()), this, SLOT(forceSkipSaveYourself())); + static_cast(shutdownNotifierIPDlg)->showNotificationActionButtons(); } void KSMServer::completeShutdownOrCheckpoint() { SHUTDOWN_MARKER("completeShutdownOrCheckpoint"); if ( state != Shutdown && state != Checkpoint ) { + SHUTDOWN_MARKER("completeShutdownOrCheckpoint state not Shutdown or Checkpoint"); return; } for ( KSMClient* c = clients.first(); c; c = clients.next() ) { if ( !c->saveYourselfDone && !c->waitForPhase2 ) { + SHUTDOWN_MARKER("completeShutdownOrCheckpoint state not done yet"); return; // not done yet } } @@ -559,6 +615,11 @@ void KSMServer::completeShutdownOrCheckpoint() } } if ( waitForPhase2 ) { + SHUTDOWN_MARKER("completeShutdownOrCheckpoint state still waiting for Phase 2"); + if (shutdownNotifierIPDlg) { + static_cast(shutdownNotifierIPDlg)->setStatusMessage(i18n("Notifying remaining applications of logout request...")); + notificationTimer.start( KSMSERVER_NOTIFICATION_MANUAL_OPTIONS_TIMEOUT, true ); + } return; } SHUTDOWN_MARKER("Phase 2 complete"); @@ -566,12 +627,19 @@ void KSMServer::completeShutdownOrCheckpoint() bool showLogoutStatusDlg = TDEConfigGroup(TDEGlobal::config(), "Logout").readBoolEntry("showLogoutStatusDlg", true); if (showLogoutStatusDlg && state != Checkpoint) { KSMShutdownIPFeedback::showit(); // hide the UGLY logout process from the user - shutdownNotifierIPDlg = KSMShutdownIPDlg::showShutdownIP(); + if (!shutdownNotifierIPDlg) { + shutdownNotifierIPDlg = KSMShutdownIPDlg::showShutdownIP(); + } while (!KSMShutdownIPFeedback::ispainted()) { tqApp->processEvents(); } } + notificationTimer.stop(); + static_cast(shutdownNotifierIPDlg)->hideNotificationActionButtons(); + disconnect(shutdownNotifierIPDlg, SIGNAL(abortLogoutClicked()), this, SLOT(cancelShutdown())); + disconnect(shutdownNotifierIPDlg, SIGNAL(skipNotificationClicked()), this, SLOT(forceSkipSaveYourself())); + // synchronize any folders that were requested for shutdown sync if (shutdownNotifierIPDlg) { static_cast(shutdownNotifierIPDlg)->setStatusMessage(i18n("Synchronizing remote folders").append("...")); diff --git a/ksmserver/shutdowndlg.cpp b/ksmserver/shutdowndlg.cpp index b30e6ec2e..6526bc4b8 100644 --- a/ksmserver/shutdowndlg.cpp +++ b/ksmserver/shutdowndlg.cpp @@ -1201,14 +1201,39 @@ TQWidget* KSMShutdownIPDlg::showShutdownIP() return l; } +void KSMShutdownIPDlg::showNotificationActionButtons() +{ + m_button1->show(); + m_button2->show(); + m_buttonframe->show(); + + m_gridlayout->invalidate(); +} + +void KSMShutdownIPDlg::hideNotificationActionButtons() +{ + m_button1->hide(); + m_button2->hide(); + m_buttonframe->hide(); + + m_gridlayout->invalidate(); +} + KSMShutdownIPDlg::KSMShutdownIPDlg(TQWidget* parent) : KSMModalDialog( parent ) { setStatusMessage(i18n("Saving your settings...")); + m_button1->setText(i18n("Skip Notification")); + m_button2->setText(i18n("Abort Logout")); + connect(m_button1, SIGNAL(clicked()), this, SIGNAL(skipNotificationClicked())); + connect(m_button2, SIGNAL(clicked()), this, SIGNAL(abortLogoutClicked())); + show(); setActiveWindow(); + +// KWin::setOnAllDesktops( winId(), true ); } KSMShutdownIPDlg::~KSMShutdownIPDlg() diff --git a/ksmserver/shutdowndlg.h b/ksmserver/shutdowndlg.h index 3ce851244..5ab9d7c3e 100644 --- a/ksmserver/shutdowndlg.h +++ b/ksmserver/shutdowndlg.h @@ -171,6 +171,13 @@ class KSMShutdownIPDlg : public KSMModalDialog public: static TQWidget* showShutdownIP(); + void showNotificationActionButtons(); + void hideNotificationActionButtons(); + +signals: + void abortLogoutClicked(); + void skipNotificationClicked(); + protected: ~KSMShutdownIPDlg();