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:
parent
26ffd9e208
commit
b285c0542c
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user