void ShutdownProcess::_QuitBlockingApp(AppInfoList& list, team_id team, const char* appName, bool cancelAllowed) { bool debugged = false; bool modal = false; { BAutolock _(fWorkerLock); if (fDebuggedTeams.find(team) != fDebuggedTeams.end()) debugged = true; } if (!debugged) modal = BPrivate::is_app_showing_modal_window(team); if (modal) { // app blocks on a modal window BString buffer = B_TRANSLATE("The application \"%appName%\" might be " "blocked on a modal panel."); buffer.ReplaceFirst("%appName%", appName); _SetShutdownWindowText(buffer.String()); _SetShutdownWindowCurrentApp(team); _SetShutdownWindowKillButtonEnabled(true); } if (modal || debugged) { // 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 || debugged) { PRINT(("ShutdownProcess::_QuitBlockingApp(): shutdown " "cancelled by team %ld (-1 => user)\n", eventTeam)); if (!debugged) _DisplayAbortingApp(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; } } }
void ShutdownProcess::_QuitApps(AppInfoList& list, bool systemApps) { PRINT(("ShutdownProcess::_QuitApps(%s)\n", (systemApps ? "system" : "user"))); if (systemApps) { _SetShutdownWindowCancelButtonEnabled(false); // check one last time for abort events uint32 event; do { team_id team; int32 phase; status_t error = _GetNextEvent(event, team, phase, false); if (error != B_OK) throw_error(error); if (event == ABORT_EVENT) { PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by " "team %ld (-1 => user)\n", team)); _DisplayAbortingApp(team); throw_error(B_SHUTDOWN_CANCELLED); } } while (event != NO_EVENT); } // prepare the shutdown message BMessage message; _PrepareShutdownMessage(message); // now iterate through the list of apps while (true) { // eat events uint32 event; do { team_id team; int32 phase; status_t error = _GetNextEvent(event, team, phase, false); if (error != B_OK) throw_error(error); if (!systemApps && event == ABORT_EVENT) { PRINT(("ShutdownProcess::_QuitApps(): shutdown cancelled by " "team %ld (-1 => user)\n", team)); _DisplayAbortingApp(team); throw_error(B_SHUTDOWN_CANCELLED); } } while (event != NO_EVENT); // get the first app to quit team_id team = -1; port_id port = -1; char appName[B_FILE_NAME_LENGTH]; { BAutolock _(fWorkerLock); while (!list.IsEmpty()) { RosterAppInfo* info = *list.It(); team = info->team; port = info->port; strcpy(appName, info->ref.name); if (info->IsRunning()) break; list.RemoveInfo(info); delete info; } } if (team < 0) { PRINT(("ShutdownProcess::_QuitApps() done\n")); return; } // set window text BString buffer = B_TRANSLATE("Asking \"%appName%\" to quit."); buffer.ReplaceFirst("%appName%", appName); _SetShutdownWindowText(buffer.String()); _SetShutdownWindowCurrentApp(team); // send the shutdown message to the app PRINT((" sending team %ld (port: %ld) a shutdown message\n", team, port)); SingleMessagingTargetSet target(port, B_PREFERRED_TOKEN); MessageDeliverer::Default()->DeliverMessage(&message, target); // schedule a timeout event _ScheduleTimeoutEvent(kAppQuitTimeout, team); // wait for the app to die or for the timeout to occur bool appGone = _WaitForApp(team, &list, systemApps); if (appGone) { // fine: the app finished in an orderly manner } else { // the app is either blocking on a model alert or blocks for another // reason if (!systemApps) _QuitBlockingApp(list, team, appName, true); else { // This is a system app: remove it from the list BAutolock _(fWorkerLock); if (RosterAppInfo* info = list.InfoFor(team)) { list.RemoveInfo(info); delete info; } } } } }