Implemented a shutdown window. Since we're quitting all user applications

in parallel, it displays the mini icons of all still running apps. Doesn't
look that great, though. Also, quitting the apps in parallel speeds up the
shutdown process, but has the disadvantage, that all apps will throw their
"Save changes...?" alerts at the user at once, which might not be a
desirable experience. I'll probably revert to the way Be did it.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13488 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2005-07-06 10:29:42 +00:00
parent 26ffd9e208
commit b285c0542c
2 changed files with 719 additions and 27 deletions

View File

@ -14,18 +14,26 @@
#include <signal.h>
#include <unistd.h>
#include <AppFileInfo.h>
#include <Autolock.h>
#include <Bitmap.h>
#include <Button.h>
#include <File.h>
#include <Message.h>
#include <MessagePrivate.h>
#include <RegistrarDefs.h>
#include <Roster.h> // for B_REQUEST_QUIT
#include <Screen.h>
#include <TextView.h>
#include <View.h>
#include <Window.h>
#include <TokenSpace.h>
#include <util/DoublyLinkedList.h>
#ifdef __HAIKU__
#include <syscalls.h>
#endif
#ifdef __HAIKU__
#include <syscalls.h>
#endif
#include "AppInfoListMessagingTargetSet.h"
#include "Debug.h"
@ -54,8 +62,11 @@ static const bigtime_t NON_APPS_QUIT_TIMEOUT = 500000; // 0.5 s
// message what fields
enum {
MSG_PHASE_TIMED_OUT = 'phto',
MSG_DONE = 'done',
MSG_PHASE_TIMED_OUT = 'phto',
MSG_DONE = 'done',
MSG_KILL_APPLICATION = 'kill',
MSG_CANCEL_SHUTDOWN = 'cncl',
MSG_REBOOT_SYSTEM = 'rbot',
};
// internal events
@ -65,6 +76,8 @@ enum {
TIMEOUT_EVENT,
USER_APP_QUIT_EVENT,
SYSTEM_APP_QUIT_EVENT,
KILL_APP_EVENT,
REBOOT_SYSTEM_EVENT,
};
// phases
@ -182,6 +195,429 @@ private:
};
// ShutdownWindow
class ShutdownProcess::ShutdownWindow : public BWindow {
public:
ShutdownWindow()
: BWindow(BRect(0, 0, 200, 100), "Shutdown Status",
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_MINIMIZABLE
| B_NOT_ZOOMABLE | B_NOT_CLOSABLE, B_ALL_WORKSPACES),
fKillAppMessage(NULL)
{
}
~ShutdownWindow()
{
for (int32 i = 0; AppInfo *info = (AppInfo*)fAppInfos.ItemAt(i); i++)
delete info;
}
status_t Init(BMessenger target)
{
// create the views
// root view
BView *rootView = new(nothrow) BView(BRect(0, 0, 100, 15), "app icons",
B_FOLLOW_NONE, 0);
if (!rootView)
return B_NO_MEMORY;
rootView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(rootView);
// app icons view
fAppIconsView = new(nothrow) AppIconsView(fAppInfos);
if (!fAppIconsView)
return B_NO_MEMORY;
rootView->AddChild(fAppIconsView);
// current app icon view
fCurrentAppIconView = new(nothrow) CurrentAppIconView;
if (!fCurrentAppIconView)
return B_NO_MEMORY;
rootView->AddChild(fCurrentAppIconView);
// text view
fTextView = new(nothrow) BTextView(BRect(0, 0, 10, 10), "text",
BRect(0, 0, 10, 10), B_FOLLOW_NONE);
if (!fTextView)
return B_NO_MEMORY;
fTextView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fTextView->MakeEditable(false);
fTextView->MakeSelectable(false);
fTextView->SetWordWrap(true);
rootView->AddChild(fTextView);
// kill app button
fKillAppButton = new(nothrow) BButton(BRect(0, 0, 10, 10), "kill app",
"Kill Application", NULL, B_FOLLOW_NONE);
if (!fKillAppButton)
return B_NO_MEMORY;
rootView->AddChild(fKillAppButton);
BMessage *message = new BMessage(MSG_KILL_APPLICATION);
if (!message)
return B_NO_MEMORY;
message->AddInt32("team", -1);
fKillAppMessage = message;
fKillAppButton->SetMessage(message);
fKillAppButton->SetTarget(target);
// cancel shutdown button
fCancelShutdownButton = new(nothrow) BButton(BRect(0, 0, 10, 10),
"cancel shutdown", "Cancel Shutdown", NULL, B_FOLLOW_NONE);
if (!fCancelShutdownButton)
return B_NO_MEMORY;
rootView->AddChild(fCancelShutdownButton);
message = new BMessage(MSG_CANCEL_SHUTDOWN);
if (!message)
return B_NO_MEMORY;
fCancelShutdownButton->SetMessage(message);
fCancelShutdownButton->SetTarget(target);
// reboot system button
fRebootSystemButton = new(nothrow) BButton(BRect(0, 0, 10, 10),
"reboot", "Reboot System", NULL, B_FOLLOW_NONE);
if (!fRebootSystemButton)
return B_NO_MEMORY;
fRebootSystemButton->Hide();
rootView->AddChild(fRebootSystemButton);
message = new BMessage(MSG_REBOOT_SYSTEM);
if (!message)
return B_NO_MEMORY;
fRebootSystemButton->SetMessage(message);
fRebootSystemButton->SetTarget(target);
// compute the sizes
static const int kHSpacing = 10;
static const int kVSpacing = 10;
static const int kInnerHSpacing = 5;
static const int kInnerVSpacing = 5;
// buttons
fKillAppButton->ResizeToPreferred();
fCancelShutdownButton->ResizeToPreferred();
fRebootSystemButton->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;
// text view
fTextView->SetText("two\nlines");
int textHeight = (int)fTextView->TextHeight(0, 2) + 1;
// app icons view
int appIconsHeight = fAppIconsView->Frame().IntegerHeight() + 1;
// current app icon view
int currentAppIconWidth = fCurrentAppIconView->Frame().IntegerWidth()
+ 1;
int currentAppIconHeight = fCurrentAppIconView->Frame().IntegerHeight()
+ 1;
int currentAppIconX = kHSpacing;
int rightPartX = currentAppIconX + currentAppIconWidth + kInnerHSpacing;
int appIconsY = kVSpacing;
int textY = appIconsY + appIconsHeight + kInnerVSpacing;
int buttonsY = textY + textHeight + kInnerVSpacing;
int rightPartWidth = 2 * buttonWidth + kInnerHSpacing;
int width = rightPartX + rightPartWidth + kHSpacing;
int height = buttonsY + buttonHeight + kVSpacing;
// now layout the views
// current app icon view
fCurrentAppIconView->MoveTo(currentAppIconX,
textY + (textHeight - currentAppIconHeight) / 2);
// app icons view
fAppIconsView->MoveTo(rightPartX, kVSpacing);
fAppIconsView->ResizeTo(rightPartWidth - 1, appIconsHeight - 1);
// text view
fTextView->MoveTo(rightPartX, textY);
fTextView->ResizeTo(rightPartWidth - 1, textHeight - 1);
fTextView->SetTextRect(fTextView->Bounds());
// buttons
fKillAppButton->MoveTo(rightPartX, buttonsY);
fKillAppButton->ResizeTo(buttonWidth - 1, buttonHeight - 1);
fCancelShutdownButton->MoveTo(
rightPartX + buttonWidth + kInnerVSpacing - 1,
buttonsY);
fCancelShutdownButton->ResizeTo(buttonWidth - 1, buttonHeight - 1);
fRebootSystemButton->MoveTo(
(width - fRebootSystemButton->Frame().IntegerWidth()) / 2,
buttonsY);
// set the root view and window size
rootView->ResizeTo(width - 1, height - 1);
ResizeTo(width - 1, height - 1);
// center the window on screen
BScreen screen;
if (screen.IsValid()) {
BRect screenFrame = screen.Frame();
int screenWidth = screenFrame.IntegerWidth() + 1;
int screenHeight = screenFrame.IntegerHeight() + 1;
MoveTo((screenWidth - width) / 2, (screenHeight - height) / 2);
} else {
MoveTo(20, 20);
}
return B_OK;
}
status_t AddApp(team_id team, BBitmap *miniIcon, BBitmap *largeIcon)
{
AppInfo *info = new(nothrow) AppInfo;
if (!info) {
delete miniIcon;
delete largeIcon;
return B_NO_MEMORY;
}
info->team = team;
info->miniIcon = miniIcon;
info->largeIcon = largeIcon;
if (!fAppInfos.AddItem(info)) {
delete info;
return B_NO_MEMORY;
}
fAppIconsView->Invalidate();
return B_OK;
}
void RemoveApp(team_id team)
{
int32 index = _AppInfoIndexOf(team);
if (index < 0)
return;
AppInfo *info = (AppInfo*)fAppInfos.RemoveItem(index);
delete info;
fAppIconsView->Invalidate();
}
void SetCurrentApp(team_id team)
{
AppInfo *info = (team >= 0 ? _AppInfoFor(team) : NULL);
fCurrentAppIconView->SetAppInfo(info);
fKillAppMessage->ReplaceInt32("team", team);
}
void SetText(const char *text)
{
fTextView->SetText(text);
}
void SetCancelShutdownButtonEnabled(bool enable)
{
fCancelShutdownButton->SetEnabled(enable);
}
void SetKillAppButtonEnabled(bool enable)
{
if (enable != fKillAppButton->IsEnabled()) {
fKillAppButton->SetEnabled(enable);
if (enable)
fKillAppButton->Show();
else
fKillAppButton->Hide();
}
}
void SetWaitForShutdown()
{
fAppIconsView->Hide();
fCurrentAppIconView->Hide();
fKillAppButton->Hide();
fCancelShutdownButton->Hide();
fRebootSystemButton->Show();
// TODO: Temporary work-around for a Haiku bug.
fRebootSystemButton->Invalidate();
SetTitle("System is Shut Down");
fTextView->SetText("It's now safe to turn off the computer.");
}
private:
struct AppInfo {
team_id team;
BBitmap *miniIcon;
BBitmap *largeIcon;
~AppInfo()
{
delete miniIcon;
delete largeIcon;
}
};
int32 _AppInfoIndexOf(team_id team)
{
for (int32 i = 0; AppInfo *info = (AppInfo*)fAppInfos.ItemAt(i); i++) {
if (info->team == team)
return i;
}
return -1;
}
AppInfo *_AppInfoFor(team_id team)
{
int32 index = _AppInfoIndexOf(team);
return (index >= 0 ? (AppInfo*)fAppInfos.ItemAt(index) : NULL);
}
class AppIconsView : public BView {
public:
AppIconsView(const BList &appInfos)
: BView(BRect(0, 0, 100, 15), "app icons", B_FOLLOW_NONE,
B_WILL_DRAW),
fAppInfos(appInfos),
fIconSize(16),
fInnerSpacing(4),
fEllipsisWidth(0)
{
SetViewColor(B_TRANSPARENT_32_BIT);
fBackground = ui_color(B_PANEL_BACKGROUND_COLOR);
}
virtual void Draw(BRect updateRect)
{
// find out, how many icons we can draw
BRect bounds = Bounds();
int width = bounds.IntegerWidth() + 1;
int maxIcons = (width + fInnerSpacing)
/ (fIconSize + fInnerSpacing);
int minIcons = (width - _EllipsisWidth())
/ (fIconSize + fInnerSpacing);
int iconsToDraw = fAppInfos.CountItems();
bool drawEllipsis = false;
if (iconsToDraw > maxIcons) {
iconsToDraw = minIcons;
drawEllipsis = true;
}
// set colors
SetLowColor(fBackground);
rgb_color black = { 0, 0, 0, 255 };
SetHighColor(black);
// draw the icons
int lastX = 0;
for (int i = 0; i < iconsToDraw; i++) {
int x = lastX + (i > 0 ? fInnerSpacing : 0);
int nextX = x + fIconSize;
// clear background
FillRect(BRect(lastX, 0, nextX - 1, bounds.bottom),
B_SOLID_LOW);
// draw the icon
SetDrawingMode(B_OP_OVER);
AppInfo *info = (AppInfo*)fAppInfos.ItemAt(i);
if (info->miniIcon)
DrawBitmap(info->miniIcon, BPoint(x, 0));
lastX = nextX;
}
// clear remaining space
FillRect(BRect(lastX, 0, bounds.right, bounds.bottom), B_SOLID_LOW);
// draw ellipsis, if necessary
if (drawEllipsis) {
int x = lastX + fInnerSpacing;
int y = (fIconSize + 1) / 2;
DrawString(B_UTF8_ELLIPSIS, BPoint(x, y));
}
}
private:
int _EllipsisWidth()
{
// init lazily
if (fEllipsisWidth <= 0) {
BFont font;
GetFont(&font);
fEllipsisWidth = (int)font.StringWidth(B_UTF8_ELLIPSIS);
}
return fEllipsisWidth;
}
private:
const BList &fAppInfos;
rgb_color fBackground;
int fIconSize;
int fInnerSpacing;
int fEllipsisWidth;
};
class CurrentAppIconView : public BView {
public:
CurrentAppIconView()
: BView(BRect(0, 0, 31, 31), "current app icon", B_FOLLOW_NONE,
B_WILL_DRAW),
fAppInfo(NULL)
{
SetViewColor(B_TRANSPARENT_32_BIT);
fBackground = ui_color(B_PANEL_BACKGROUND_COLOR);
}
virtual void Draw(BRect updateRect)
{
if (fAppInfo && fAppInfo->largeIcon) {
DrawBitmap(fAppInfo->largeIcon, BPoint(0, 0));
} else {
SetLowColor(fBackground);
FillRect(Bounds(), B_SOLID_LOW);
}
}
void SetAppInfo(AppInfo *info)
{
fAppInfo = info;
Invalidate();
}
private:
const AppInfo *fAppInfo;
rgb_color fBackground;
};
private:
BList fAppInfos;
AppIconsView *fAppIconsView;
CurrentAppIconView *fCurrentAppIconView;
BTextView *fTextView;
BButton *fKillAppButton;
BButton *fCancelShutdownButton;
BButton *fRebootSystemButton;
BMessage *fKillAppMessage;
};
// #pragma mark -
// constructor
@ -199,13 +635,20 @@ ShutdownProcess::ShutdownProcess(TRoster *roster, EventQueue *eventQueue)
fWorker(-1),
fCurrentPhase(INVALID_PHASE),
fShutdownError(B_ERROR),
fHasGUI(false)
fHasGUI(false),
fWindow(NULL)
{
}
// destructor
ShutdownProcess::~ShutdownProcess()
{
// terminate the GUI
if (fHasGUI) {
fWindow->Lock();
fWindow->Quit();
}
// remove and delete the quit request reply handler
if (fQuitRequestReplyHandler) {
BAutolock _(this);
@ -295,9 +738,6 @@ ShutdownProcess::Init(BMessage *request)
// TODO: sort the system apps by descending registration time
// display alert
// TODO:...
// start the worker thread
fWorker = spawn_thread(_WorkerEntry, "shutdown worker", B_NORMAL_PRIORITY,
this);
@ -378,6 +818,38 @@ ShutdownProcess::MessageReceived(BMessage *message)
break;
}
case MSG_KILL_APPLICATION:
{
team_id team;
if (message->FindInt32("team", &team) != B_OK)
break;
BAutolock _(fWorkerLock);
// post the event
_PushEvent(KILL_APP_EVENT, team, fCurrentPhase);
break;
}
case MSG_CANCEL_SHUTDOWN:
{
BAutolock _(fWorkerLock);
// post the event
_PushEvent(TIMEOUT_EVENT, -1, fCurrentPhase);
break;
}
case MSG_REBOOT_SYSTEM:
{
// post the event
_PushEvent(REBOOT_SYSTEM_EVENT, -1, INVALID_PHASE);
break;
}
case MSG_DONE:
{
// notify the registrar that we're done
@ -453,6 +925,180 @@ ShutdownProcess::_UnlockAppLists()
fWorkerLock.Unlock();
}
// _SetShowShutdownWindow
void
ShutdownProcess::_SetShowShutdownWindow(bool show)
{
if (fHasGUI) {
BAutolock _(fWindow);
if (show == fWindow->IsHidden()) {
if (show)
fWindow->Show();
else
fWindow->Hide();
}
}
}
// _InitShutdownWindow
void
ShutdownProcess::_InitShutdownWindow()
{
// prepare the window
if (fHasGUI) {
fWindow = new(nothrow) ShutdownWindow;
if (fWindow != NULL) {
status_t error = fWindow->Init(BMessenger(this));
if (error != B_OK) {
delete fWindow;
fWindow = NULL;
}
}
// add the applications
if (fWindow) {
BAutolock _(fWorkerLock);
_AddShutdownWindowApps(fUserApps);
_AddShutdownWindowApps(fSystemApps);
} else {
WARNING(("ShutdownProcess::Init(): Failed to create or init "
"shutdown window."));
fHasGUI = false;
}
}
}
// _AddShutdownWindowApps
void
ShutdownProcess::_AddShutdownWindowApps(AppInfoList &infos)
{
if (!fHasGUI)
return;
for (AppInfoList::Iterator it = infos.It(); it.IsValid(); ++it) {
RosterAppInfo *info = *it;
// init an app file info
BFile file;
status_t error = file.SetTo(&info->ref, B_READ_ONLY);
if (error != B_OK) {
WARNING(("ShutdownProcess::_AddShutdownWindowApps(): Failed to "
"open file for app %s: %s\n", info->signature,
strerror(error)));
continue;
}
BAppFileInfo appFileInfo;
error = appFileInfo.SetTo(&file);
if (error != B_OK) {
WARNING(("ShutdownProcess::_AddShutdownWindowApps(): Failed to "
"init app file info for app %s: %s\n", info->signature,
strerror(error)));
}
// get the application icons
// mini icon
BBitmap *miniIcon = new(nothrow) BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
if (miniIcon != NULL) {
error = miniIcon->InitCheck();
if (error == B_OK)
error = appFileInfo.GetTrackerIcon(miniIcon, B_MINI_ICON);
if (error != B_OK) {
delete miniIcon;
miniIcon = NULL;
}
}
// mini icon
BBitmap *largeIcon = new(nothrow) BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
if (largeIcon != NULL) {
error = largeIcon->InitCheck();
if (error == B_OK)
error = appFileInfo.GetTrackerIcon(largeIcon, B_LARGE_ICON);
if (error != B_OK) {
delete largeIcon;
largeIcon = NULL;
}
}
// add the app
error = fWindow->AddApp(info->team, miniIcon, largeIcon);
if (error != B_OK) {
WARNING(("ShutdownProcess::_AddShutdownWindowApps(): Failed to "
"add app to the shutdown window: %s\n", strerror(error)));
}
}
}
// _RemoveShutdownWindowApp
void
ShutdownProcess::_RemoveShutdownWindowApp(team_id team)
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->RemoveApp(team);
}
}
// _SetShutdownWindowCurrentApp
void
ShutdownProcess::_SetShutdownWindowCurrentApp(team_id team)
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->SetCurrentApp(team);
}
}
// _SetShutdownWindowText
void
ShutdownProcess::_SetShutdownWindowText(const char *text)
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->SetText(text);
}
}
// _SetShutdownWindowCancelButtonEnabled
void
ShutdownProcess::_SetShutdownWindowCancelButtonEnabled(bool enabled)
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->SetCancelShutdownButtonEnabled(enabled);
}
}
// _SetShutdownWindowKillButtonEnabled
void
ShutdownProcess::_SetShutdownWindowKillButtonEnabled(bool enabled)
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->SetKillAppButtonEnabled(enabled);
}
}
// _SetShutdownWindowWaitForShutdown
void
ShutdownProcess::_SetShutdownWindowWaitForShutdown()
{
if (fHasGUI) {
BAutolock _(fWindow);
fWindow->SetWaitForShutdown();
}
}
// _NegativeQuitRequestReply
void
ShutdownProcess::_NegativeQuitRequestReply(thread_id thread)
@ -556,6 +1202,10 @@ ShutdownProcess::_GetNextEvent(uint32 &eventType, thread_id &team, int32 &phase,
break;
}
// notify the window, if an app has been removed
if (eventType == USER_APP_QUIT_EVENT || eventType == SYSTEM_APP_QUIT_EVENT)
_RemoveShutdownWindowApp(team);
return B_OK;
}
@ -594,8 +1244,15 @@ ShutdownProcess::_WorkerDoShutdown()
{
PRINT(("ShutdownProcess::_WorkerDoShutdown()\n"));
// TODO: Set alert text to "Tidying things up a bit".
PRINT((" sync()...\n"));
// make the shutdown window ready and show it
_InitShutdownWindow();
_SetShutdownWindowCurrentApp(-1);
_SetShutdownWindowText("Tidying things up a bit.");
_SetShutdownWindowCancelButtonEnabled(true);
_SetShutdownWindowKillButtonEnabled(false);
_SetShowShutdownWindow(true);
// sync
sync();
// phase 1: terminate the user apps
@ -619,15 +1276,35 @@ ShutdownProcess::_WorkerDoShutdown()
PRINT((" _kern_shutdown() failed\n"));
// shutdown failed: This can happen for power off mode -- reboot will
// always work. We close the alert, and display a new one with
// a "Reboot System" button.
// shutdown failed: This can happen for power off mode -- reboot should
// always work.
if (fHasGUI) {
// TODO:...
} else {
// there's no GUI: we enter the kernel debugger instead
// TODO:...
_SetShutdownWindowWaitForShutdown();
// wait for the reboot event
uint32 event;
do {
team_id team;
int32 phase;
status_t error = _GetNextEvent(event, team, phase, true);
if (error != B_OK)
break;
} while (event != REBOOT_SYSTEM_EVENT);
#ifdef __HAIKU__
_kern_shutdown(true);
#endif
}
// either there's no GUI or reboot failed: we enter the kernel debugger
// instead
#ifdef __HAIKU__
// TODO: Introduce the syscall.
// while (true) {
// _kern_kernel_debugger("The system is shut down. It's now safe to turn "
// "off the computer.");
// }
#endif
}
// _QuitUserApps
@ -636,7 +1313,7 @@ ShutdownProcess::_QuitUserApps()
{
PRINT(("ShutdownProcess::_QuitUserApps()\n"));
// TODO: Set alert text to "Asking user applications to quit"
_SetShutdownWindowText("Asking user applications to quit.");
// prepare the shutdown message
BMessage message;
@ -735,8 +1412,6 @@ ShutdownProcess::_KillUserApps()
return;
}
// TODO: Set alert text...
// TODO: check whether the app blocks on a modal alert
if (false) {
// ...
@ -766,7 +1441,7 @@ ShutdownProcess::_QuitSystemApps()
{
PRINT(("ShutdownProcess::_QuitSystemApps()\n"));
// TODO: Disable the abort button.
_SetShutdownWindowCancelButtonEnabled(false);
// check one last time for abort events
uint32 event;
@ -804,12 +1479,15 @@ ShutdownProcess::_QuitSystemApps()
AppInfoList &list = fSystemApps;
team_id team = -1;
port_id port = -1;
char appName[B_FILE_NAME_LENGTH];
if (!list.IsEmpty()) {
RosterAppInfo *info = *list.It();
team = info->team;
port = info->port;
strcpy(appName, info->ref.name);
}
_UnlockAppLists();
if (team < 0) {
@ -817,7 +1495,11 @@ ShutdownProcess::_QuitSystemApps()
return;
}
// TODO: Set alert text...
// set window text
char buffer[1024];
snprintf(buffer, sizeof(buffer), "Asking \"%s\" to quit.", appName);
_SetShutdownWindowText(buffer);
_SetShutdownWindowCurrentApp(team);
// send the shutdown message to the app
PRINT((" sending team %ld (port: %ld) a shutdown message\n", team,
@ -851,8 +1533,6 @@ ShutdownProcess::_QuitSystemApps()
} while (event != NO_EVENT);
// TODO: Set alert text...
// TODO: check whether the app blocks on a modal alert
if (false) {
// ...
@ -882,7 +1562,7 @@ ShutdownProcess::_QuitNonApps()
{
PRINT(("ShutdownProcess::_QuitNonApps()\n"));
// TODO: Set alert text...
_SetShutdownWindowText("Asking other processes to quit.");
// iterate through the remaining teams and send them the HUP signal
int32 cookie = 0;

View File

@ -47,6 +47,16 @@ private:
bool _LockAppLists();
void _UnlockAppLists();
void _InitShutdownWindow();
void _SetShowShutdownWindow(bool show);
void _AddShutdownWindowApps(AppInfoList &infos);
void _RemoveShutdownWindowApp(team_id team);
void _SetShutdownWindowCurrentApp(team_id team);
void _SetShutdownWindowText(const char *text);
void _SetShutdownWindowCancelButtonEnabled(bool enabled);
void _SetShutdownWindowKillButtonEnabled(bool enabled);
void _SetShutdownWindowWaitForShutdown();
static status_t _WorkerEntry(void *data);
status_t _Worker();
@ -62,6 +72,7 @@ private:
class InternalEvent;
struct InternalEventList;
class QuitRequestReplyHandler;
class ShutdownWindow;
friend class QuitRequestReplyHandler;
@ -81,6 +92,7 @@ private:
int32 fCurrentPhase;
status_t fShutdownError;
bool fHasGUI;
ShutdownWindow *fWindow;
};
#endif // SHUTDOWN_PROCESS_H