diff --git a/src/add-ons/input_server/devices/keyboard/TeamListItem.cpp b/src/add-ons/input_server/devices/keyboard/TeamListItem.cpp index 47931bb5b1..20f22648a5 100644 --- a/src/add-ons/input_server/devices/keyboard/TeamListItem.cpp +++ b/src/add-ons/input_server/devices/keyboard/TeamListItem.cpp @@ -29,7 +29,8 @@ TeamListItem::TeamListItem(team_info &teamInfo) fAppInfo(), fMiniIcon(BRect(0, 0, 15, 15), B_RGBA32), fLargeIcon(BRect(0, 0, 31, 31), B_RGBA32), - fFound(false) + fFound(false), + fRefusingToQuit(false) { int32 cookie = 0; image_info info; @@ -68,6 +69,7 @@ TeamListItem::DrawItem(BView* owner, BRect frame, bool complete) rgb_color kHighlight = { 140, 140, 140, 0 }; rgb_color kBlack = { 0, 0, 0, 0 }; rgb_color kBlue = { 0, 0, 255, 0 }; + rgb_color kRed = { 255, 0, 0, 0 }; BRect r(frame); @@ -96,7 +98,10 @@ TeamListItem::DrawItem(BView* owner, BRect frame, bool complete) owner->SetDrawingMode(B_OP_COPY); frame.left += 16; - owner->SetHighColor(IsSystemServer() ? kBlue : kBlack); + if (fRefusingToQuit) + owner->SetHighColor(kRed); + else + owner->SetHighColor(IsSystemServer() ? kBlue : kBlack); BFont font = be_plain_font; font_height finfo; @@ -175,7 +180,21 @@ TeamListItem::IsSystemServer() bool -TeamListItem::IsApplication() +TeamListItem::IsApplication() const { return fAppInfo.signature[0] != '\0'; } + + +void +TeamListItem::SetRefusingToQuit(bool refusing) +{ + fRefusingToQuit = refusing; +} + + +bool +TeamListItem::IsRefusingToQuit() +{ + return fRefusingToQuit; +} diff --git a/src/add-ons/input_server/devices/keyboard/TeamListItem.h b/src/add-ons/input_server/devices/keyboard/TeamListItem.h index e2376eaf31..79046c22be 100644 --- a/src/add-ons/input_server/devices/keyboard/TeamListItem.h +++ b/src/add-ons/input_server/devices/keyboard/TeamListItem.h @@ -36,11 +36,14 @@ public: const char* AppSignature() { return fAppInfo.signature; }; bool IsSystemServer(); - bool IsApplication(); + bool IsApplication() const; bool Found() const { return fFound; } void SetFound(bool found) { fFound = found; } + void SetRefusingToQuit(bool refusing); + bool IsRefusingToQuit(); + static int32 MinimalHeight(); private: @@ -51,6 +54,7 @@ private: BPath fPath; BString fLocalizedName; bool fFound; + bool fRefusingToQuit; }; diff --git a/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.cpp b/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.cpp index 24e547243e..2f1ae027dc 100644 --- a/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.cpp +++ b/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.cpp @@ -42,8 +42,49 @@ TeamMonitorWindow* gTeamMonitorWindow = NULL; +struct TeamQuitter { + team_id team; + thread_id thread; + BLooper* window; +}; + + +status_t +QuitTeamThreadFunction(void* data) +{ + TeamQuitter* teamQuitter = reinterpret_cast(data); + if (teamQuitter == NULL) + return B_ERROR; + + status_t status; + BMessenger messenger(NULL, teamQuitter->team, &status); + if (status != B_OK) + return status; + + BMessage message(B_QUIT_REQUESTED); + BMessage reply; + + messenger.SendMessage(&message, &reply, 3000000, 3000000); + + bool result; + if (reply.what != B_REPLY + || reply.FindBool("result", &result) != B_OK + || result == false) { + message.what = kMsgQuitFailed; + message.AddPointer("TeamQuitter", teamQuitter); + message.AddInt32("error", reply.what); + if (teamQuitter->window != NULL) + teamQuitter->window->PostMessage(&message); + return reply.what; + } + + return B_OK; +} + + filter_result -FilterLocaleChanged(BMessage* message, BHandler** target, BMessageFilter *filter) +FilterLocaleChanged(BMessage* message, BHandler** target, + BMessageFilter *filter) { if (message->what == B_LOCALE_CHANGED && gTeamMonitorWindow != NULL) gTeamMonitorWindow->LocaleChanged(); @@ -78,6 +119,7 @@ private: IconView* fIconView; const char* fInfoString; const char* fSysComponentString; + const char* fQuitOverdueString; BCardLayout* fLayout; AllShowingTextView* fIconTextView; AllShowingTextView* fInfoTextView; @@ -202,6 +244,15 @@ TeamMonitorWindow::TeamMonitorWindow() TeamMonitorWindow::~TeamMonitorWindow() { + while (fTeamQuitterList.ItemAt(0) != NULL) { + TeamQuitter* teamQuitter = reinterpret_cast + (fTeamQuitterList.RemoveItem((int32) 0)); + if (teamQuitter != NULL) { + status_t status; + wait_for_thread(teamQuitter->thread, &status); + delete teamQuitter; + } + } } @@ -252,12 +303,14 @@ TeamMonitorWindow::MessageReceived(BMessage* msg) TeamListItem* item = dynamic_cast(fListView->ItemAt( fListView->CurrentSelection())); if (item != NULL) { - BMessenger messenger(item->AppSignature(), - item->GetInfo()->team); - messenger.SendMessage(B_QUIT_REQUESTED); + QuitTeam(item); } break; } + case kMsgQuitFailed: + MarkUnquittableTeam(msg); + break; + case TM_RESTART_DESKTOP: { if (!be_roster->IsRunning(kTrackerSignature)) @@ -381,10 +434,15 @@ TeamMonitorWindow::Enable() void TeamMonitorWindow::Disable() { - fListView->DeselectAll(); delete fUpdateRunner; fUpdateRunner = NULL; Hide(); + fListView->DeselectAll(); + for (int32 i = 0; i < fListView->CountItems(); i++) { + TeamListItem* item = dynamic_cast(fListView->ItemAt(i)); + if (item != NULL) + item->SetRefusingToQuit(false); + } } @@ -404,6 +462,64 @@ TeamMonitorWindow::LocaleChanged() } +void +TeamMonitorWindow::QuitTeam(TeamListItem* item) +{ + if (item == NULL) + return; + + TeamQuitter* teamQuitter = new TeamQuitter; + teamQuitter->team = item->GetInfo()->team; + teamQuitter->window = this; + teamQuitter->thread = spawn_thread(QuitTeamThreadFunction, + "team quitter", B_DISPLAY_PRIORITY, teamQuitter); + + if (teamQuitter->thread < 0) { + delete teamQuitter; + return; + } + + fTeamQuitterList.AddItem(teamQuitter); + + if (resume_thread(teamQuitter->thread) != B_OK) { + fTeamQuitterList.RemoveItem(teamQuitter); + delete teamQuitter; + } +} + + +void +TeamMonitorWindow::MarkUnquittableTeam(BMessage* message) +{ + if (message == NULL) + return; + + int32 reply; + if (message->FindInt32("error", &reply) != B_OK) + return; + + TeamQuitter* teamQuitter; + if (message->FindPointer("TeamQuitter", + reinterpret_cast(&teamQuitter)) != B_OK) + return; + + for (int32 i = 0; i < fListView->CountItems(); i++) { + TeamListItem* item + = dynamic_cast(fListView->ItemAt(i)); + if (item != NULL && item->GetInfo()->team == teamQuitter->team) { + item->SetRefusingToQuit(true); + fListView->Select(i); + fListView->InvalidateItem(i); + fDescriptionView->SetItem(item); + break; + } + } + + fTeamQuitterList.RemoveItem(teamQuitter); + delete teamQuitter; +} + + // #pragma mark - @@ -421,6 +537,8 @@ TeamDescriptionView::TeamDescriptionView() "Hold CONTROL+ALT+DELETE for %ld seconds to reboot."); fSysComponentString = B_TRANSLATE("(This team is a system component)"); + fQuitOverdueString = B_TRANSLATE("If the application will not quit " + "you may have to kill it."); fInfoTextView = new AllShowingTextView("info text"); fIconTextView = new AllShowingTextView("icon text"); @@ -494,28 +612,41 @@ void TeamDescriptionView::SetItem(TeamListItem* item) { fItem = item; + int32 styleStart = 0; + int32 styleEnd = 0; + BTextView* view = NULL; if (item == NULL) { BString text; text.SetToFormat(fInfoString, fSeconds); fInfoTextView->SetText(text); - if (fRebootRunner != NULL && fSeconds < 4) { - BFont font; - fInfoTextView->GetFont(&font); - font.SetFace(B_BOLD_FACE); - fInfoTextView->SetStylable(true); - fInfoTextView->SetFontAndColor(text.FindLast('\n'), - text.Length() - 1, &font); + styleStart = text.FindLast('\n'); + styleEnd = text.Length(); } + view = fInfoTextView; } else { BString text = item->Path()->Path(); if (item->IsSystemServer()) text << "\n" << fSysComponentString; + if (item->IsRefusingToQuit()) { + text << "\n\n" << fQuitOverdueString; + styleStart = text.FindLast('\n'); + styleEnd = text.Length(); + } + view = fIconTextView; fIconTextView->SetText(text); fIconView->SetIcon(item->Path()->Path()); } + if (styleStart != styleEnd && view != NULL) { + BFont font; + view->GetFont(&font); + font.SetFace(B_BOLD_FACE); + view->SetStylable(true); + view->SetFontAndColor(styleStart, styleEnd, &font); + } + if (fLayout == NULL) return; diff --git a/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.h b/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.h index 3da638a54f..69c551e4c0 100644 --- a/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.h +++ b/src/add-ons/input_server/devices/keyboard/TeamMonitorWindow.h @@ -33,6 +33,8 @@ public: void Disable(); void DeselectAll(); void LocaleChanged(); + void QuitTeam(TeamListItem* item); + void MarkUnquittableTeam(BMessage* message); private: void UpdateList(); @@ -45,9 +47,11 @@ private: BButton* fQuitButton; BButton* fRestartButton; TeamDescriptionView* fDescriptionView; + BList fTeamQuitterList; }; static const uint32 kMsgCtrlAltDelPressed = 'TMcp'; static const uint32 kMsgDeselectAll = 'TMds'; +static const uint32 kMsgQuitFailed = 'TMqf'; #endif // TEAM_MONITOR_WINDOW_H