* Implemented the BRoster::Shutdown() confirmation feature.

* When an application aborts the shutdown process by refusing to quit, the
  shutdown window says so for 3 seconds before closing.
* Fixed the height of the normal buttons in the shutdown window. They 
  accidentially got the size of a default button.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13564 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2005-07-09 20:26:16 +00:00
parent a13df0dc01
commit 8ddc570d6f
2 changed files with 151 additions and 12 deletions

View File

@ -14,6 +14,7 @@
#include <signal.h>
#include <unistd.h>
#include <Alert.h>
#include <AppFileInfo.h>
#include <AppMisc.h>
#include <Autolock.h>
@ -61,6 +62,10 @@ static const bigtime_t kBackgroundAppQuitTimeout = 3000000; // 3 s
// to them before they get a KILL signal.
static const bigtime_t kNonAppQuitTimeout = 500000; // 0.5 s
// The time span the app that has aborted the shutdown shall be displayed in
// the shutdown window before closing it automatically.
static const bigtime_t kDisplayAbortingAppTimeout = 3000000; // 3 s
// message what fields
enum {
@ -88,7 +93,8 @@ enum {
SYSTEM_APP_TERMINATION_PHASE = 1,
BACKGROUND_APP_TERMINATION_PHASE = 2,
OTHER_PROCESSES_TERMINATION_PHASE = 3,
DONE_PHASE = 4,
ABORTED_PHASE = 4,
DONE_PHASE = 5,
};
@ -309,6 +315,20 @@ public:
fRebootSystemButton->SetMessage(message);
fRebootSystemButton->SetTarget(target);
// aborted OK button
fAbortedOKButton = new(nothrow) BButton(BRect(0, 0, 10, 10),
"ok", "OK", NULL, B_FOLLOW_NONE);
if (!fAbortedOKButton)
return B_NO_MEMORY;
fAbortedOKButton->Hide();
rootView->AddChild(fAbortedOKButton);
message = new BMessage(MSG_CANCEL_SHUTDOWN);
if (!message)
return B_NO_MEMORY;
fAbortedOKButton->SetMessage(message);
fAbortedOKButton->SetTarget(target);
// compute the sizes
static const int kHSpacing = 10;
static const int kVSpacing = 10;
@ -320,15 +340,19 @@ public:
fCancelShutdownButton->ResizeToPreferred();
fRebootSystemButton->MakeDefault(true);
fRebootSystemButton->ResizeToPreferred();
fAbortedOKButton->MakeDefault(true);
fAbortedOKButton->ResizeToPreferred();
BRect rect(fKillAppButton->Frame());
int buttonWidth = rect.IntegerWidth() + 1;
int buttonHeight = rect.IntegerHeight() + 1;
rect = fCancelShutdownButton->Frame();
if (rect.IntegerWidth() >= buttonWidth)
buttonWidth = rect.IntegerWidth() + 1;
int buttonHeight = fRebootSystemButton->Frame().IntegerHeight() + 1;
int defaultButtonHeight
= fRebootSystemButton->Frame().IntegerHeight() + 1;
// text view
fTextView->SetText("two\nlines");
@ -345,9 +369,11 @@ public:
int textX = rightPartX + kInnerHSpacing;
int textY = kVSpacing;
int buttonsY = textY + textHeight + kInnerVSpacing;
int nonDefaultButtonsY = buttonsY
+ (defaultButtonHeight - buttonHeight) / 2;
int rightPartWidth = 2 * buttonWidth + kInnerHSpacing;
int width = rightPartX + rightPartWidth + kHSpacing;
int height = buttonsY + buttonHeight + kVSpacing;
int height = buttonsY + defaultButtonHeight + kVSpacing;
// now layout the views
@ -362,18 +388,22 @@ public:
fTextView->SetTextRect(fTextView->Bounds());
// buttons
fKillAppButton->MoveTo(rightPartX, buttonsY);
fKillAppButton->MoveTo(rightPartX, nonDefaultButtonsY);
fKillAppButton->ResizeTo(buttonWidth - 1, buttonHeight - 1);
fCancelShutdownButton->MoveTo(
rightPartX + buttonWidth + kInnerVSpacing - 1,
buttonsY);
nonDefaultButtonsY);
fCancelShutdownButton->ResizeTo(buttonWidth - 1, buttonHeight - 1);
fRebootSystemButton->MoveTo(
(width - fRebootSystemButton->Frame().IntegerWidth()) / 2,
buttonsY);
fAbortedOKButton->MoveTo(
(width - fAbortedOKButton->Frame().IntegerWidth()) / 2,
buttonsY);
// set the root view and window size
rootView->ResizeTo(width - 1, height - 1);
ResizeTo(width - 1, height - 1);
@ -463,6 +493,7 @@ public:
fCurrentAppIconView->Hide();
fKillAppButton->Hide();
fCancelShutdownButton->Hide();
fRebootSystemButton->MakeDefault(true);
fRebootSystemButton->Show();
// TODO: Temporary work-around for a Haiku bug.
fRebootSystemButton->Invalidate();
@ -471,6 +502,19 @@ public:
fTextView->SetText("It's now safe to turn off the computer.");
}
void SetWaitForAbortedOK()
{
fCurrentAppIconView->Hide();
fKillAppButton->Hide();
fCancelShutdownButton->Hide();
fAbortedOKButton->MakeDefault(true);
fAbortedOKButton->Show();
// TODO: Temporary work-around for a Haiku bug.
fAbortedOKButton->Invalidate();
SetTitle("Shutdown Aborted");
}
private:
struct AppInfo {
team_id team;
@ -544,6 +588,7 @@ private:
BButton *fKillAppButton;
BButton *fCancelShutdownButton;
BButton *fRebootSystemButton;
BButton *fAbortedOKButton;
BMessage *fKillAppMessage;
team_id fCurrentApp;
};
@ -567,6 +612,7 @@ ShutdownProcess::ShutdownProcess(TRoster *roster, EventQueue *eventQueue)
fCurrentPhase(INVALID_PHASE),
fShutdownError(B_ERROR),
fHasGUI(false),
fReboot(false),
fWindow(NULL)
{
}
@ -686,6 +732,9 @@ ShutdownProcess::Init(BMessage *request)
// everything went fine: now we own the request
fRequest = request;
if (fRequest->FindBool("reboot", &fReboot) != B_OK)
fReboot = false;
resume_thread(fWorker);
PRINT(("ShutdownProcess::Init() done\n"));
@ -742,6 +791,7 @@ ShutdownProcess::MessageReceived(BMessage *message)
// get the phase the event is intended for
int32 phase = TimeoutEvent::GetMessagePhase(message);
team_id team = TimeoutEvent::GetMessageTeam(message);;
PRINT(("MSG_PHASE_TIMED_OUT: phase: %ld, team: %ld\n", phase, team));
BAutolock _(fWorkerLock);
@ -1021,6 +1071,17 @@ ShutdownProcess::_SetShutdownWindowWaitForShutdown()
}
}
// _SetShutdownWindowWaitForAbortedOK
void
ShutdownProcess::_SetShutdownWindowWaitForAbortedOK()
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->SetWaitForAbortedOK();
}
}
// _NegativeQuitRequestReply
void
ShutdownProcess::_NegativeQuitRequestReply(thread_id thread)
@ -1047,13 +1108,8 @@ ShutdownProcess::_PrepareShutdownMessage(BMessage &message) const
status_t
ShutdownProcess::_ShutDown()
{
// get the reboot flag
bool reboot;
if (fRequest->FindBool("reboot", &reboot) != B_OK)
reboot = false;
#ifdef __HAIKU__
return _kern_shutdown(reboot);
return _kern_shutdown(fReboot);
#else
// we can't do anything on R5
return B_ERROR;
@ -1166,6 +1222,18 @@ ShutdownProcess::_WorkerDoShutdown()
{
PRINT(("ShutdownProcess::_WorkerDoShutdown()\n"));
// ask the user to confirm the shutdown, if desired
bool askUser;
if (fHasGUI && fRequest->FindBool("confirm", &askUser) == B_OK && askUser) {
BAlert *alert = new BAlert("Shut Down?",
"Do you really want to shut down the system?",
"Shut Down", "Cancel", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
int32 result = alert->Go();
if (result != 0)
throw_error(B_SHUTDOWN_CANCELLED);
}
// make the shutdown window ready and show it
_InitShutdownWindow();
_SetShutdownWindowCurrentApp(-1);
@ -1256,6 +1324,7 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by "
"team %ld (-1 => user)\n", team));
_DisplayAbortingApp(team);
throw_error(B_SHUTDOWN_CANCELLED);
}
@ -1281,6 +1350,7 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by "
"team %ld (-1 => user)\n", team));
_DisplayAbortingApp(team);
throw_error(B_SHUTDOWN_CANCELLED);
}
@ -1348,6 +1418,7 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled "
"by team %ld (-1 => user)\n", eventTeam));
_DisplayAbortingApp(team);
throw_error(B_SHUTDOWN_CANCELLED);
}
}
@ -1599,3 +1670,68 @@ ShutdownProcess::_QuitBlockingApp(AppInfoList &list, team_id team,
}
}
// _DisplayAbortingApp
void
ShutdownProcess::_DisplayAbortingApp(team_id team)
{
// find the app that cancelled the shutdown
char appName[B_FILE_NAME_LENGTH];
bool foundApp = false;
{
BAutolock _(fWorkerLock);
RosterAppInfo *info = fUserApps.InfoFor(team);
if (!info)
info = fSystemApps.InfoFor(team);
if (!info)
fBackgroundApps.InfoFor(team);
if (info) {
foundApp = true;
strcpy(appName, info->ref.name);
}
}
if (!foundApp) {
PRINT(("ShutdownProcess::_DisplayAbortingApp(): Didn't find the app "
"that has cancelled the shutdown.\n"));
return;
}
// compose the text to be displayed
char buffer[1024];
snprintf(buffer, sizeof(buffer), "Application \"%s\" has aborted the shutdown "
"process.", appName);
// set up the window
_SetShutdownWindowCurrentApp(team);
_SetShutdownWindowText(buffer);
_SetShutdownWindowWaitForAbortedOK();
// schedule the timeout event
_SetPhase(ABORTED_PHASE);
_ScheduleTimeoutEvent(kDisplayAbortingAppTimeout);
// wait for the timeout or the user to press the cancel button
while (true) {
uint32 event;
team_id eventTeam;
int32 phase;
status_t error = _GetNextEvent(event, eventTeam, phase, true);
if (error != B_OK)
break;
// stop waiting when the timeout occurs
if (event == TIMEOUT_EVENT)
break;
// stop waiting when the user hit the cancel button
if (event == ABORT_EVENT && phase == ABORTED_PHASE && eventTeam < 0)
break;
// also stop when the responsible app quit
if ((event == APP_QUIT_EVENT) && eventTeam == team)
break;
}
}

View File

@ -56,6 +56,7 @@ private:
void _SetShutdownWindowCancelButtonEnabled(bool enabled);
void _SetShutdownWindowKillButtonEnabled(bool enabled);
void _SetShutdownWindowWaitForShutdown();
void _SetShutdownWindowWaitForAbortedOK();
static status_t _WorkerEntry(void *data);
status_t _Worker();
@ -66,8 +67,9 @@ private:
void _WaitForBackgroundApps();
void _KillBackgroundApps();
void _QuitNonApps();
void _QuitBlockingApp(AppInfoList &list, team_id app, const char *appName,
void _QuitBlockingApp(AppInfoList &list, team_id team, const char *appName,
bool cancelAllowed);
void _DisplayAbortingApp(team_id team);
private:
class TimeoutEvent;
@ -95,6 +97,7 @@ private:
int32 fCurrentPhase;
status_t fShutdownError;
bool fHasGUI;
bool fReboot;
ShutdownWindow *fWindow;
};