* Background applications are now ask to quit in parallel.
* Implemented handling of apps blocking on modal windows. * Fixed a few bugs. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13539 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -87,7 +87,6 @@ Registrar::~Registrar()
|
|||||||
void
|
void
|
||||||
Registrar::MessageReceived(BMessage *message)
|
Registrar::MessageReceived(BMessage *message)
|
||||||
{
|
{
|
||||||
// FUNCTION_START();
|
|
||||||
switch (message->what) {
|
switch (message->what) {
|
||||||
// general requests
|
// general requests
|
||||||
case B_REG_GET_MIME_MESSENGER:
|
case B_REG_GET_MIME_MESSENGER:
|
||||||
@@ -214,18 +213,16 @@ Registrar::MessageReceived(BMessage *message)
|
|||||||
break;
|
break;
|
||||||
case B_REG_SHUTDOWN_FINISHED:
|
case B_REG_SHUTDOWN_FINISHED:
|
||||||
if (fShutdownProcess) {
|
if (fShutdownProcess) {
|
||||||
if (fShutdownProcess->Lock()) {
|
fShutdownProcess->PostMessage(B_QUIT_REQUESTED,
|
||||||
fShutdownProcess->Quit();
|
fShutdownProcess);
|
||||||
fShutdownProcess = NULL;
|
fShutdownProcess = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BApplication::MessageReceived(message);
|
BApplication::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// FUNCTION_END();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadyToRun
|
// ReadyToRun
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <AppFileInfo.h>
|
#include <AppFileInfo.h>
|
||||||
|
#include <AppMisc.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Bitmap.h>
|
#include <Bitmap.h>
|
||||||
#include <Button.h>
|
#include <Button.h>
|
||||||
@@ -47,13 +48,18 @@
|
|||||||
|
|
||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
|
|
||||||
// The time span a user application has after the quit message has been
|
// The time span a non-background application has after the quit message has
|
||||||
|
// been delivered (more precisely: has been handed over to the
|
||||||
|
// MessageDeliverer).
|
||||||
|
static const bigtime_t kAppQuitTimeout = 3000000; // 3 s
|
||||||
|
|
||||||
|
// The time span a background application has after the quit message has been
|
||||||
// delivered (more precisely: has been handed over to the MessageDeliverer).
|
// delivered (more precisely: has been handed over to the MessageDeliverer).
|
||||||
static const bigtime_t APP_QUIT_TIMEOUT = 3000000; // 3 s
|
static const bigtime_t kBackgroundAppQuitTimeout = 3000000; // 3 s
|
||||||
|
|
||||||
// The time span non-app processes have after the HUP signal has been send
|
// The time span non-app processes have after the HUP signal has been send
|
||||||
// to them before they get a KILL signal.
|
// to them before they get a KILL signal.
|
||||||
static const bigtime_t NON_APP_QUIT_TIMEOUT = 500000; // 0.5 s
|
static const bigtime_t kNonAppQuitTimeout = 500000; // 0.5 s
|
||||||
|
|
||||||
|
|
||||||
// message what fields
|
// message what fields
|
||||||
@@ -70,8 +76,7 @@ enum {
|
|||||||
NO_EVENT,
|
NO_EVENT,
|
||||||
ABORT_EVENT,
|
ABORT_EVENT,
|
||||||
TIMEOUT_EVENT,
|
TIMEOUT_EVENT,
|
||||||
USER_APP_QUIT_EVENT,
|
APP_QUIT_EVENT,
|
||||||
SYSTEM_APP_QUIT_EVENT,
|
|
||||||
KILL_APP_EVENT,
|
KILL_APP_EVENT,
|
||||||
REBOOT_SYSTEM_EVENT,
|
REBOOT_SYSTEM_EVENT,
|
||||||
};
|
};
|
||||||
@@ -81,9 +86,9 @@ enum {
|
|||||||
INVALID_PHASE = -1,
|
INVALID_PHASE = -1,
|
||||||
USER_APP_TERMINATION_PHASE = 0,
|
USER_APP_TERMINATION_PHASE = 0,
|
||||||
SYSTEM_APP_TERMINATION_PHASE = 1,
|
SYSTEM_APP_TERMINATION_PHASE = 1,
|
||||||
OTHER_PROCESSES_TERMINATION_PHASE = 2,
|
BACKGROUND_APP_TERMINATION_PHASE = 2,
|
||||||
DONE_PHASE = 3,
|
OTHER_PROCESSES_TERMINATION_PHASE = 3,
|
||||||
ABORTED_PHASE = 4,
|
DONE_PHASE = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -99,6 +104,15 @@ inverse_compare_by_registration_time(const RosterAppInfo *info1,
|
|||||||
return (cmp > 0 ? -1 : 0);
|
return (cmp > 0 ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// throw_error
|
||||||
|
/*! \brief Used to avoid type matching problems when throwing a constant.
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void
|
||||||
|
throw_error(status_t error)
|
||||||
|
{
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
// TimeoutEvent
|
// TimeoutEvent
|
||||||
class ShutdownProcess::TimeoutEvent : public MessageEvent {
|
class ShutdownProcess::TimeoutEvent : public MessageEvent {
|
||||||
@@ -213,7 +227,8 @@ public:
|
|||||||
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||||
B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_MINIMIZABLE
|
B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_MINIMIZABLE
|
||||||
| B_NOT_ZOOMABLE | B_NOT_CLOSABLE, B_ALL_WORKSPACES),
|
| B_NOT_ZOOMABLE | B_NOT_CLOSABLE, B_ALL_WORKSPACES),
|
||||||
fKillAppMessage(NULL)
|
fKillAppMessage(NULL),
|
||||||
|
fCurrentApp(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +313,7 @@ public:
|
|||||||
static const int kHSpacing = 10;
|
static const int kHSpacing = 10;
|
||||||
static const int kVSpacing = 10;
|
static const int kVSpacing = 10;
|
||||||
static const int kInnerHSpacing = 5;
|
static const int kInnerHSpacing = 5;
|
||||||
static const int kInnerVSpacing = 2;
|
static const int kInnerVSpacing = 8;
|
||||||
|
|
||||||
// buttons
|
// buttons
|
||||||
fKillAppButton->ResizeToPreferred();
|
fKillAppButton->ResizeToPreferred();
|
||||||
@@ -404,6 +419,9 @@ public:
|
|||||||
if (index < 0)
|
if (index < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (team == fCurrentApp)
|
||||||
|
SetCurrentApp(-1);
|
||||||
|
|
||||||
AppInfo *info = (AppInfo*)fAppInfos.RemoveItem(index);
|
AppInfo *info = (AppInfo*)fAppInfos.RemoveItem(index);
|
||||||
delete info;
|
delete info;
|
||||||
}
|
}
|
||||||
@@ -412,6 +430,7 @@ public:
|
|||||||
{
|
{
|
||||||
AppInfo *info = (team >= 0 ? _AppInfoFor(team) : NULL);
|
AppInfo *info = (team >= 0 ? _AppInfoFor(team) : NULL);
|
||||||
|
|
||||||
|
fCurrentApp = team;
|
||||||
fCurrentAppIconView->SetAppInfo(info);
|
fCurrentAppIconView->SetAppInfo(info);
|
||||||
|
|
||||||
fKillAppMessage->ReplaceInt32("team", team);
|
fKillAppMessage->ReplaceInt32("team", team);
|
||||||
@@ -467,6 +486,9 @@ private:
|
|||||||
|
|
||||||
int32 _AppInfoIndexOf(team_id team)
|
int32 _AppInfoIndexOf(team_id team)
|
||||||
{
|
{
|
||||||
|
if (team < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
for (int32 i = 0; AppInfo *info = (AppInfo*)fAppInfos.ItemAt(i); i++) {
|
for (int32 i = 0; AppInfo *info = (AppInfo*)fAppInfos.ItemAt(i); i++) {
|
||||||
if (info->team == team)
|
if (info->team == team)
|
||||||
return i;
|
return i;
|
||||||
@@ -494,11 +516,13 @@ private:
|
|||||||
|
|
||||||
virtual void Draw(BRect updateRect)
|
virtual void Draw(BRect updateRect)
|
||||||
{
|
{
|
||||||
if (fAppInfo && fAppInfo->largeIcon) {
|
SetDrawingMode(B_OP_COPY);
|
||||||
DrawBitmap(fAppInfo->largeIcon, BPoint(0, 0));
|
|
||||||
} else {
|
|
||||||
SetLowColor(fBackground);
|
SetLowColor(fBackground);
|
||||||
FillRect(Bounds(), B_SOLID_LOW);
|
FillRect(Bounds(), B_SOLID_LOW);
|
||||||
|
|
||||||
|
if (fAppInfo && fAppInfo->largeIcon) {
|
||||||
|
SetDrawingMode(B_OP_OVER);
|
||||||
|
DrawBitmap(fAppInfo->largeIcon, BPoint(0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,6 +545,7 @@ private:
|
|||||||
BButton *fCancelShutdownButton;
|
BButton *fCancelShutdownButton;
|
||||||
BButton *fRebootSystemButton;
|
BButton *fRebootSystemButton;
|
||||||
BMessage *fKillAppMessage;
|
BMessage *fKillAppMessage;
|
||||||
|
team_id fCurrentApp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -569,6 +594,9 @@ ShutdownProcess::~ShutdownProcess()
|
|||||||
delete fTimeoutEvent;
|
delete fTimeoutEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove the application quit watcher
|
||||||
|
fRoster->RemoveWatcher(this);
|
||||||
|
|
||||||
// delete the internal event semaphore
|
// delete the internal event semaphore
|
||||||
if (fInternalEventSemaphore >= 0)
|
if (fInternalEventSemaphore >= 0)
|
||||||
delete_sem(fInternalEventSemaphore);
|
delete_sem(fInternalEventSemaphore);
|
||||||
@@ -635,7 +663,8 @@ ShutdownProcess::Init(BMessage *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get a list of all applications to shut down and sort them
|
// get a list of all applications to shut down and sort them
|
||||||
error = fRoster->GetShutdownApps(fUserApps, fSystemApps, fVitalSystemApps);
|
error = fRoster->GetShutdownApps(fUserApps, fSystemApps, fBackgroundApps,
|
||||||
|
fVitalSystemApps);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fRoster->RemoveWatcher(this);
|
fRoster->RemoveWatcher(this);
|
||||||
fRoster->SetShuttingDown(false);
|
fRoster->SetShuttingDown(false);
|
||||||
@@ -682,26 +711,26 @@ ShutdownProcess::MessageReceived(BMessage *message)
|
|||||||
team));
|
team));
|
||||||
|
|
||||||
// remove the app info from the respective list
|
// remove the app info from the respective list
|
||||||
_LockAppLists();
|
int32 phase;
|
||||||
|
RosterAppInfo *info;
|
||||||
|
{
|
||||||
|
BAutolock _(fWorkerLock);
|
||||||
|
|
||||||
uint32 event;
|
info = fUserApps.InfoFor(team);
|
||||||
|
if (info)
|
||||||
RosterAppInfo *info = fUserApps.InfoFor(team);
|
|
||||||
if (info) {
|
|
||||||
fUserApps.RemoveInfo(info);
|
fUserApps.RemoveInfo(info);
|
||||||
event = USER_APP_QUIT_EVENT;
|
else if ((info = fSystemApps.InfoFor(team)))
|
||||||
} else if ((info = fSystemApps.InfoFor(team))) {
|
|
||||||
fSystemApps.RemoveInfo(info);
|
fSystemApps.RemoveInfo(info);
|
||||||
event = SYSTEM_APP_QUIT_EVENT;
|
else if ((info = fSystemApps.InfoFor(team)))
|
||||||
} else // not found
|
fBackgroundApps.RemoveInfo(info);
|
||||||
|
else // not found
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int32 phase = fCurrentPhase;
|
phase = fCurrentPhase;
|
||||||
|
}
|
||||||
_UnlockAppLists();
|
|
||||||
|
|
||||||
// post the event
|
// post the event
|
||||||
_PushEvent(event, team, phase);
|
_PushEvent(APP_QUIT_EVENT, team, phase);
|
||||||
|
|
||||||
delete info;
|
delete info;
|
||||||
|
|
||||||
@@ -744,7 +773,7 @@ ShutdownProcess::MessageReceived(BMessage *message)
|
|||||||
BAutolock _(fWorkerLock);
|
BAutolock _(fWorkerLock);
|
||||||
|
|
||||||
// post the event
|
// post the event
|
||||||
_PushEvent(TIMEOUT_EVENT, -1, fCurrentPhase);
|
_PushEvent(ABORT_EVENT, -1, fCurrentPhase);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -818,20 +847,6 @@ ShutdownProcess::_ScheduleTimeoutEvent(bigtime_t timeout, team_id team)
|
|||||||
fEventQueue->AddEvent(fTimeoutEvent);
|
fEventQueue->AddEvent(fTimeoutEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// _LockAppLists
|
|
||||||
bool
|
|
||||||
ShutdownProcess::_LockAppLists()
|
|
||||||
{
|
|
||||||
return fWorkerLock.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// _UnlockAppLists
|
|
||||||
void
|
|
||||||
ShutdownProcess::_UnlockAppLists()
|
|
||||||
{
|
|
||||||
fWorkerLock.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// _SetShowShutdownWindow
|
// _SetShowShutdownWindow
|
||||||
void
|
void
|
||||||
ShutdownProcess::_SetShowShutdownWindow(bool show)
|
ShutdownProcess::_SetShowShutdownWindow(bool show)
|
||||||
@@ -1110,7 +1125,7 @@ ShutdownProcess::_GetNextEvent(uint32 &eventType, thread_id &team, int32 &phase,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// notify the window, if an app has been removed
|
// notify the window, if an app has been removed
|
||||||
if (eventType == USER_APP_QUIT_EVENT || eventType == SYSTEM_APP_QUIT_EVENT)
|
if (eventType == APP_QUIT_EVENT)
|
||||||
_RemoveShutdownWindowApp(team);
|
_RemoveShutdownWindowApp(team);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1131,7 +1146,7 @@ ShutdownProcess::_Worker()
|
|||||||
_WorkerDoShutdown();
|
_WorkerDoShutdown();
|
||||||
fShutdownError = B_OK;
|
fShutdownError = B_OK;
|
||||||
} catch (status_t error) {
|
} catch (status_t error) {
|
||||||
PRINT(("ShutdownProcess::_Worker(): caught exception: %s\n",
|
PRINT(("ShutdownProcess::_Worker(): error while shutting down: %s\n",
|
||||||
strerror(error)));
|
strerror(error)));
|
||||||
|
|
||||||
fShutdownError = error;
|
fShutdownError = error;
|
||||||
@@ -1170,10 +1185,17 @@ ShutdownProcess::_WorkerDoShutdown()
|
|||||||
_SetPhase(SYSTEM_APP_TERMINATION_PHASE);
|
_SetPhase(SYSTEM_APP_TERMINATION_PHASE);
|
||||||
_QuitApps(fSystemApps, true);
|
_QuitApps(fSystemApps, true);
|
||||||
|
|
||||||
// phase 3: terminate the other processes
|
// phase 3: terminate the background apps
|
||||||
_SetPhase(OTHER_PROCESSES_TERMINATION_PHASE);
|
_SetPhase(BACKGROUND_APP_TERMINATION_PHASE);
|
||||||
_QuitNonApps();
|
_QuitNonApps();
|
||||||
|
|
||||||
|
// phase 4: terminate the other processes
|
||||||
|
_SetPhase(OTHER_PROCESSES_TERMINATION_PHASE);
|
||||||
|
_QuitBackgroundApps();
|
||||||
|
_ScheduleTimeoutEvent(kBackgroundAppQuitTimeout, -1);
|
||||||
|
_WaitForBackgroundApps();
|
||||||
|
_KillBackgroundApps();
|
||||||
|
|
||||||
// we're through: do the shutdown
|
// we're through: do the shutdown
|
||||||
_SetPhase(DONE_PHASE);
|
_SetPhase(DONE_PHASE);
|
||||||
_ShutDown();
|
_ShutDown();
|
||||||
@@ -1228,10 +1250,14 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
|
|||||||
int32 phase;
|
int32 phase;
|
||||||
status_t error = _GetNextEvent(event, team, phase, false);
|
status_t error = _GetNextEvent(event, team, phase, false);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
throw error;
|
throw_error(error);
|
||||||
|
|
||||||
if (event == ABORT_EVENT)
|
if (event == ABORT_EVENT) {
|
||||||
throw B_SHUTDOWN_CANCELLED;
|
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by "
|
||||||
|
"team %ld (-1 => user)\n", team));
|
||||||
|
|
||||||
|
throw_error(B_SHUTDOWN_CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
} while (event != NO_EVENT);
|
} while (event != NO_EVENT);
|
||||||
}
|
}
|
||||||
@@ -1249,27 +1275,30 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
|
|||||||
int32 phase;
|
int32 phase;
|
||||||
status_t error = _GetNextEvent(event, team, phase, false);
|
status_t error = _GetNextEvent(event, team, phase, false);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
throw error;
|
throw_error(error);
|
||||||
|
|
||||||
if (!disableCancel && event == ABORT_EVENT)
|
if (!disableCancel && event == ABORT_EVENT) {
|
||||||
throw B_SHUTDOWN_CANCELLED;
|
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by "
|
||||||
|
"team %ld (-1 => user)\n", team));
|
||||||
|
|
||||||
|
throw_error(B_SHUTDOWN_CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
} while (event != NO_EVENT);
|
} while (event != NO_EVENT);
|
||||||
|
|
||||||
// get the first app to quit
|
// get the first app to quit
|
||||||
_LockAppLists();
|
|
||||||
|
|
||||||
team_id team = -1;
|
team_id team = -1;
|
||||||
port_id port = -1;
|
port_id port = -1;
|
||||||
char appName[B_FILE_NAME_LENGTH];
|
char appName[B_FILE_NAME_LENGTH];
|
||||||
|
{
|
||||||
|
BAutolock _(fWorkerLock);
|
||||||
if (!list.IsEmpty()) {
|
if (!list.IsEmpty()) {
|
||||||
RosterAppInfo *info = *list.It();
|
RosterAppInfo *info = *list.It();
|
||||||
team = info->team;
|
team = info->team;
|
||||||
port = info->port;
|
port = info->port;
|
||||||
strcpy(appName, info->ref.name);
|
strcpy(appName, info->ref.name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_UnlockAppLists();
|
|
||||||
|
|
||||||
if (team < 0) {
|
if (team < 0) {
|
||||||
PRINT(("ShutdownProcess::_QuitApps() done\n"));
|
PRINT(("ShutdownProcess::_QuitApps() done\n"));
|
||||||
@@ -1289,7 +1318,7 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
|
|||||||
MessageDeliverer::Default()->DeliverMessage(&message, target);
|
MessageDeliverer::Default()->DeliverMessage(&message, target);
|
||||||
|
|
||||||
// schedule a timeout event
|
// schedule a timeout event
|
||||||
_ScheduleTimeoutEvent(APP_QUIT_TIMEOUT, team);
|
_ScheduleTimeoutEvent(kAppQuitTimeout, team);
|
||||||
|
|
||||||
// wait for the app to die or for the timeout to occur
|
// wait for the app to die or for the timeout to occur
|
||||||
bool appGone = false;
|
bool appGone = false;
|
||||||
@@ -1298,9 +1327,9 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
|
|||||||
int32 phase;
|
int32 phase;
|
||||||
status_t error = _GetNextEvent(event, eventTeam, phase, true);
|
status_t error = _GetNextEvent(event, eventTeam, phase, true);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
throw error;
|
throw_error(error);
|
||||||
|
|
||||||
if ((event == SYSTEM_APP_QUIT_EVENT || event == USER_APP_QUIT_EVENT)
|
if ((event == APP_QUIT_EVENT)
|
||||||
&& eventTeam == team) {
|
&& eventTeam == team) {
|
||||||
appGone = true;
|
appGone = true;
|
||||||
}
|
}
|
||||||
@@ -1316,7 +1345,10 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
|
|||||||
if (eventTeam == team)
|
if (eventTeam == team)
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
throw B_SHUTDOWN_CANCELLED;
|
PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled "
|
||||||
|
"by team %ld (-1 => user)\n", eventTeam));
|
||||||
|
|
||||||
|
throw_error(B_SHUTDOWN_CANCELLED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,27 +1361,123 @@ ShutdownProcess::_QuitApps(AppInfoList &list, bool disableCancel)
|
|||||||
// TODO: check whether the app blocks on a modal alert
|
// TODO: check whether the app blocks on a modal alert
|
||||||
if (appGone) {
|
if (appGone) {
|
||||||
// fine: the app finished in an orderly manner
|
// fine: the app finished in an orderly manner
|
||||||
} else if (false) {
|
|
||||||
// app blocks on a modal window
|
|
||||||
// ...
|
|
||||||
} else {
|
} else {
|
||||||
// it does not: kill it
|
// the app is either blocking on a model alert or blocks for another
|
||||||
PRINT((" killing team %ld\n", team));
|
// reason
|
||||||
|
_QuitBlockingApp(list, team, appName, !disableCancel);
|
||||||
kill_team(team);
|
}
|
||||||
|
}
|
||||||
// remove the app (the roster will note eventually and send us
|
|
||||||
// a notification, but we want to be sure)
|
|
||||||
_LockAppLists();
|
|
||||||
|
|
||||||
if (RosterAppInfo *info = list.InfoFor(team)) {
|
|
||||||
list.RemoveInfo(info);
|
|
||||||
delete info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_UnlockAppLists();
|
// _QuitBackgroundApps
|
||||||
|
void
|
||||||
|
ShutdownProcess::_QuitBackgroundApps()
|
||||||
|
{
|
||||||
|
PRINT(("ShutdownProcess::_QuitBackgroundApps()\n"));
|
||||||
|
|
||||||
|
_SetShutdownWindowText("Asking background applications to quit.");
|
||||||
|
|
||||||
|
// prepare the shutdown message
|
||||||
|
BMessage message;
|
||||||
|
_PrepareShutdownMessage(message);
|
||||||
|
|
||||||
|
// send shutdown messages to user apps
|
||||||
|
BAutolock _(fWorkerLock);
|
||||||
|
|
||||||
|
AppInfoListMessagingTargetSet targetSet(fBackgroundApps);
|
||||||
|
|
||||||
|
if (targetSet.HasNext()) {
|
||||||
|
PRINT((" sending shutdown message to %ld apps\n",
|
||||||
|
fBackgroundApps.CountInfos()));
|
||||||
|
|
||||||
|
status_t error = MessageDeliverer::Default()->DeliverMessage(
|
||||||
|
&message, targetSet);
|
||||||
|
if (error != B_OK) {
|
||||||
|
WARNING(("_QuitBackgroundApps::_Worker(): Failed to deliver "
|
||||||
|
"shutdown message to all applications: %s\n",
|
||||||
|
strerror(error)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRINT(("ShutdownProcess::_QuitBackgroundApps() done\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// _WaitForBackgroundApps
|
||||||
|
void
|
||||||
|
ShutdownProcess::_WaitForBackgroundApps()
|
||||||
|
{
|
||||||
|
PRINT(("ShutdownProcess::_WaitForBackgroundApps()\n"));
|
||||||
|
|
||||||
|
// wait for user apps
|
||||||
|
bool moreApps = true;
|
||||||
|
while (moreApps) {
|
||||||
|
{
|
||||||
|
BAutolock _(fWorkerLock);
|
||||||
|
moreApps = !fBackgroundApps.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moreApps) {
|
||||||
|
uint32 event;
|
||||||
|
team_id team;
|
||||||
|
int32 phase;
|
||||||
|
status_t error = _GetNextEvent(event, team, phase, true);
|
||||||
|
if (error != B_OK)
|
||||||
|
throw_error(error);
|
||||||
|
|
||||||
|
if (event == ABORT_EVENT) {
|
||||||
|
// ignore: it's too late to abort the shutdown
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == TIMEOUT_EVENT)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT(("ShutdownProcess::_WaitForBackgroundApps() done\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// _KillBackgroundApps
|
||||||
|
void
|
||||||
|
ShutdownProcess::_KillBackgroundApps()
|
||||||
|
{
|
||||||
|
PRINT(("ShutdownProcess::_KillBackgroundApps()\n"));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// eat events (we need to be responsive for an abort event)
|
||||||
|
uint32 event;
|
||||||
|
do {
|
||||||
|
team_id team;
|
||||||
|
int32 phase;
|
||||||
|
status_t error = _GetNextEvent(event, team, phase, false);
|
||||||
|
if (error != B_OK)
|
||||||
|
throw_error(error);
|
||||||
|
|
||||||
|
} while (event != NO_EVENT);
|
||||||
|
|
||||||
|
// get the first team to kill
|
||||||
|
team_id team = -1;
|
||||||
|
char appName[B_FILE_NAME_LENGTH];
|
||||||
|
AppInfoList &list = fBackgroundApps;
|
||||||
|
{
|
||||||
|
BAutolock _(fWorkerLock);
|
||||||
|
|
||||||
|
if (!list.IsEmpty()) {
|
||||||
|
RosterAppInfo *info = *list.It();
|
||||||
|
team = info->team;
|
||||||
|
strcpy(appName, info->ref.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (team < 0) {
|
||||||
|
PRINT(("ShutdownProcess::_KillBackgroundApps() done\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the app is either blocking on a model alert or blocks for another
|
||||||
|
// reason
|
||||||
|
_QuitBlockingApp(list, team, appName, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _QuitNonApps
|
// _QuitNonApps
|
||||||
@@ -1380,7 +1508,7 @@ ShutdownProcess::_QuitNonApps()
|
|||||||
// give them a bit of time to terminate
|
// give them a bit of time to terminate
|
||||||
// TODO: Instead of just waiting we could periodically check whether the
|
// TODO: Instead of just waiting we could periodically check whether the
|
||||||
// processes are already gone to shorten the process.
|
// processes are already gone to shorten the process.
|
||||||
snooze(NON_APP_QUIT_TIMEOUT);
|
snooze(kNonAppQuitTimeout);
|
||||||
|
|
||||||
// iterate through the remaining teams and kill them
|
// iterate through the remaining teams and kill them
|
||||||
cookie = 0;
|
cookie = 0;
|
||||||
@@ -1400,3 +1528,74 @@ ShutdownProcess::_QuitNonApps()
|
|||||||
PRINT(("ShutdownProcess::_QuitNonApps() done\n"));
|
PRINT(("ShutdownProcess::_QuitNonApps() done\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _QuitBlockingApp
|
||||||
|
void
|
||||||
|
ShutdownProcess::_QuitBlockingApp(AppInfoList &list, team_id team,
|
||||||
|
const char *appName, bool cancelAllowed)
|
||||||
|
{
|
||||||
|
if (BPrivate::is_app_showing_modal_window(team)) {
|
||||||
|
// app blocks on a modal window
|
||||||
|
char buffer[1024];
|
||||||
|
snprintf(buffer, sizeof(buffer), "The application \"%s\" might be "
|
||||||
|
"blocked on a modal panel.", appName);
|
||||||
|
_SetShutdownWindowText(buffer);
|
||||||
|
_SetShutdownWindowCurrentApp(team);
|
||||||
|
_SetShutdownWindowKillButtonEnabled(true);
|
||||||
|
|
||||||
|
// wait for something to happen
|
||||||
|
bool appGone = false;
|
||||||
|
while (true) {
|
||||||
|
uint32 event;
|
||||||
|
team_id eventTeam;
|
||||||
|
int32 phase;
|
||||||
|
status_t error = _GetNextEvent(event, eventTeam, phase, true);
|
||||||
|
if (error != B_OK)
|
||||||
|
throw_error(error);
|
||||||
|
|
||||||
|
if ((event == APP_QUIT_EVENT) && eventTeam == team) {
|
||||||
|
appGone = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == KILL_APP_EVENT && eventTeam == team)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (event == ABORT_EVENT) {
|
||||||
|
if (cancelAllowed) {
|
||||||
|
PRINT(("ShutdownProcess::_QuitBlockingApp(): shutdown "
|
||||||
|
"cancelled by team %ld (-1 => user)\n", eventTeam));
|
||||||
|
|
||||||
|
throw_error(B_SHUTDOWN_CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the app requests aborting the shutdown, we don't need
|
||||||
|
// to wait any longer. It has processed the request and
|
||||||
|
// won't quit by itself. We'll have to kill it.
|
||||||
|
if (eventTeam == team)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_SetShutdownWindowKillButtonEnabled(false);
|
||||||
|
|
||||||
|
if (appGone)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kill the app
|
||||||
|
PRINT((" killing team %ld\n", team));
|
||||||
|
|
||||||
|
kill_team(team);
|
||||||
|
|
||||||
|
// remove the app (the roster will note eventually and send us
|
||||||
|
// a notification, but we want to be sure)
|
||||||
|
{
|
||||||
|
BAutolock _(fWorkerLock);
|
||||||
|
|
||||||
|
if (RosterAppInfo *info = list.InfoFor(team)) {
|
||||||
|
list.RemoveInfo(info);
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,12 @@ private:
|
|||||||
|
|
||||||
void _WorkerDoShutdown();
|
void _WorkerDoShutdown();
|
||||||
void _QuitApps(AppInfoList &list, bool disableCancel);
|
void _QuitApps(AppInfoList &list, bool disableCancel);
|
||||||
|
void _QuitBackgroundApps();
|
||||||
|
void _WaitForBackgroundApps();
|
||||||
|
void _KillBackgroundApps();
|
||||||
void _QuitNonApps();
|
void _QuitNonApps();
|
||||||
|
void _QuitBlockingApp(AppInfoList &list, team_id app, const char *appName,
|
||||||
|
bool cancelAllowed);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class TimeoutEvent;
|
class TimeoutEvent;
|
||||||
@@ -81,6 +86,7 @@ private:
|
|||||||
hash_set<team_id> fVitalSystemApps;
|
hash_set<team_id> fVitalSystemApps;
|
||||||
AppInfoList fSystemApps;
|
AppInfoList fSystemApps;
|
||||||
AppInfoList fUserApps;
|
AppInfoList fUserApps;
|
||||||
|
AppInfoList fBackgroundApps;
|
||||||
TimeoutEvent *fTimeoutEvent;
|
TimeoutEvent *fTimeoutEvent;
|
||||||
InternalEventList *fInternalEvents;
|
InternalEventList *fInternalEvents;
|
||||||
sem_id fInternalEventSemaphore;
|
sem_id fInternalEventSemaphore;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <MessagePrivate.h>
|
#include <MessagePrivate.h>
|
||||||
#include <MessengerPrivate.h>
|
#include <MessengerPrivate.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
|
#include <Roster.h> // for B_BACKGROUND_APP
|
||||||
#include <ServerProtocol.h>
|
#include <ServerProtocol.h>
|
||||||
#include <storage_support.h>
|
#include <storage_support.h>
|
||||||
|
|
||||||
@@ -1287,7 +1288,7 @@ TRoster::SetShuttingDown(bool shuttingDown)
|
|||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
TRoster::GetShutdownApps(AppInfoList &userApps, AppInfoList &systemApps,
|
TRoster::GetShutdownApps(AppInfoList &userApps, AppInfoList &systemApps,
|
||||||
hash_set<team_id> &vitalSystemApps)
|
AppInfoList &backgroundApps, hash_set<team_id> &vitalSystemApps)
|
||||||
{
|
{
|
||||||
BAutolock _(fLock);
|
BAutolock _(fLock);
|
||||||
|
|
||||||
@@ -1317,7 +1318,10 @@ TRoster::GetShutdownApps(AppInfoList &userApps, AppInfoList &systemApps,
|
|||||||
} else {
|
} else {
|
||||||
RosterAppInfo *clonedInfo = info->Clone();
|
RosterAppInfo *clonedInfo = info->Clone();
|
||||||
if (clonedInfo) {
|
if (clonedInfo) {
|
||||||
if (_IsSystemApp(info)) {
|
if (info->flags & B_BACKGROUND_APP) {
|
||||||
|
if (!backgroundApps.AddInfo(clonedInfo))
|
||||||
|
error = B_NO_MEMORY;
|
||||||
|
} else if (_IsSystemApp(info)) {
|
||||||
if (!systemApps.AddInfo(clonedInfo))
|
if (!systemApps.AddInfo(clonedInfo))
|
||||||
error = B_NO_MEMORY;
|
error = B_NO_MEMORY;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public:
|
|||||||
|
|
||||||
void SetShuttingDown(bool shuttingDown);
|
void SetShuttingDown(bool shuttingDown);
|
||||||
status_t GetShutdownApps(AppInfoList &userApps, AppInfoList &systemApps,
|
status_t GetShutdownApps(AppInfoList &userApps, AppInfoList &systemApps,
|
||||||
hash_set<team_id> &vitalSystemApps);
|
AppInfoList &backgroundApps, hash_set<team_id> &vitalSystemApps);
|
||||||
|
|
||||||
status_t AddWatcher(Watcher *watcher);
|
status_t AddWatcher(Watcher *watcher);
|
||||||
void RemoveWatcher(Watcher *watcher);
|
void RemoveWatcher(Watcher *watcher);
|
||||||
|
|||||||
Reference in New Issue
Block a user