diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-14 14:01:58 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-14 14:01:58 +0000 |
commit | 0da19221d7b32e3331ad50b2c9e642697e49ff05 (patch) | |
tree | 19e1cebe40b9e3a21ed67675769ba82284f42e99 /chrome/browser | |
parent | 81c78ac1f4407d0a9b1fa1dbb41916ababa225c7 (diff) | |
download | chromium_src-0da19221d7b32e3331ad50b2c9e642697e49ff05.zip chromium_src-0da19221d7b32e3331ad50b2c9e642697e49ff05.tar.gz chromium_src-0da19221d7b32e3331ad50b2c9e642697e49ff05.tar.bz2 |
Extract Windows-specific parts of TaskManager.
- task_manager.cc compiles on POSIX
- task_manager_unittest.cc passes on Linux
- stub TaskManagerViewImpl for Linux (so that the unit test can pass)
TEST=Task manager should not be obviously broken on Windows.
http://crbug.com/11461
Review URL: http://codereview.chromium.org/115295
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16053 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.vcproj | 4 | ||||
-rw-r--r-- | chrome/browser/task_manager.cc | 515 | ||||
-rw-r--r-- | chrome/browser/task_manager.h | 14 | ||||
-rw-r--r-- | chrome/browser/task_manager_linux.cc | 64 | ||||
-rw-r--r-- | chrome/browser/task_manager_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/browser/task_manager_win.cc | 521 |
6 files changed, 618 insertions, 506 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index dd12b4c..9c7094a 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -806,6 +806,10 @@ > </File> <File + RelativePath=".\task_manager_win.cc" + > + </File> + <File RelativePath=".\task_manager_resource_providers.cc" > </File> diff --git a/chrome/browser/task_manager.cc b/chrome/browser/task_manager.cc index b4c9bbe..43d328d 100644 --- a/chrome/browser/task_manager.cc +++ b/chrome/browser/task_manager.cc @@ -22,31 +22,10 @@ #include "grit/theme_resources.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_job.h" -#include "views/accelerator.h" -#include "views/background.h" -#include "views/controls/button/native_button.h" -#include "views/controls/link.h" -#include "views/controls/menu/menu.h" -#include "views/controls/table/group_table_view.h" -#include "views/standard_layout.h" -#include "views/widget/widget.h" -#include "views/window/dialog_delegate.h" -#include "views/window/window.h" - -// The task manager window default size. -static const int kDefaultWidth = 460; -static const int kDefaultHeight = 270; // The delay between updates of the information (in ms). static const int kUpdateTimeMs = 1000; -// An id for the most important column, made sufficiently large so as not to -// collide with anything else. -static const int64 kNuthMagicNumber = 1737350766; -static const int kBitMask = 0x7FFFFFFF; -static const int kGoatsTeleportedColumn = - (94024 * kNuthMagicNumber) & kBitMask; - template <class T> static int ValueCompare(T value1, T value2) { if (value1 < value2) @@ -225,8 +204,8 @@ int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const { NOTREACHED(); } } - std::wstring title1 = GetResourceTitle(row1); - std::wstring title2 = GetResourceTitle(row2); + string16 title1 = WideToUTF16(GetResourceTitle(row1)); + string16 title2 = WideToUTF16(GetResourceTitle(row2)); UErrorCode compare_status = U_ZERO_ERROR; UCollationResult compare_result = collator->compare( static_cast<const UChar*>(title1.c_str()), @@ -704,467 +683,6 @@ bool TaskManagerModel::GetProcessMetricsForRows( } //////////////////////////////////////////////////////////////////////////////// -// TaskManagerTableModel class -//////////////////////////////////////////////////////////////////////////////// - -class TaskManagerTableModel : public views::GroupTableModel, - public TaskManagerModelObserver { - public: - explicit TaskManagerTableModel(TaskManagerModel* model) - : model_(model), - observer_(NULL) { - model->SetObserver(this); - } - ~TaskManagerTableModel() {} - - // GroupTableModel. - int RowCount(); - std::wstring GetText(int row, int column); - SkBitmap GetIcon(int row); - void GetGroupRangeForItem(int item, views::GroupRange* range); - void SetObserver(views::TableModelObserver* observer); - virtual int CompareValues(int row1, int row2, int column_id); - - // TaskManagerModelObserver. - virtual void OnModelChanged(); - virtual void OnItemsChanged(int start, int length); - virtual void OnItemsAdded(int start, int length); - virtual void OnItemsRemoved(int start, int length); - - private: - const TaskManagerModel* model_; - views::TableModelObserver* observer_; -}; - -int TaskManagerTableModel::RowCount() { - return model_->ResourceCount(); -} - -std::wstring TaskManagerTableModel::GetText(int row, int col_id) { - switch (col_id) { - case IDS_TASK_MANAGER_PAGE_COLUMN: // Process - return model_->GetResourceTitle(row); - - case IDS_TASK_MANAGER_NET_COLUMN: // Net - return model_->GetResourceNetworkUsage(row); - - case IDS_TASK_MANAGER_CPU_COLUMN: // CPU - if (!model_->IsResourceFirstInGroup(row)) - return std::wstring(); - return model_->GetResourceCPUUsage(row); - - case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory - if (!model_->IsResourceFirstInGroup(row)) - return std::wstring(); - return model_->GetResourcePrivateMemory(row); - - case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory - if (!model_->IsResourceFirstInGroup(row)) - return std::wstring(); - return model_->GetResourceSharedMemory(row); - - case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory - if (!model_->IsResourceFirstInGroup(row)) - return std::wstring(); - return model_->GetResourcePhysicalMemory(row); - - case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: - if (!model_->IsResourceFirstInGroup(row)) - return std::wstring(); - return model_->GetResourceProcessId(row); - - case kGoatsTeleportedColumn: // Goats Teleported! - return model_->GetResourceGoatsTeleported(row); - - default: - return model_->GetResourceStatsValue(row, col_id); - } -} - -SkBitmap TaskManagerTableModel::GetIcon(int row) { - return model_->GetResourceIcon(row); -} - -void TaskManagerTableModel::GetGroupRangeForItem(int item, - views::GroupRange* range) { - std::pair<int, int> range_pair = model_->GetGroupRangeForResource(item); - range->start = range_pair.first; - range->length = range_pair.second; -} - -void TaskManagerTableModel::SetObserver(views::TableModelObserver* observer) { - observer_ = observer; -} - -int TaskManagerTableModel::CompareValues(int row1, int row2, int column_id) { - return model_->CompareValues(row1, row2, column_id); -} - -void TaskManagerTableModel::OnModelChanged() { - if (observer_) - observer_->OnModelChanged(); -} - -void TaskManagerTableModel::OnItemsChanged(int start, int length) { - if (observer_) - observer_->OnItemsChanged(start, length); -} - -void TaskManagerTableModel::OnItemsAdded(int start, int length) { - if (observer_) - observer_->OnItemsAdded(start, length); -} - -void TaskManagerTableModel::OnItemsRemoved(int start, int length) { - if (observer_) - observer_->OnItemsRemoved(start, length); -} - -//////////////////////////////////////////////////////////////////////////////// -// TaskManagerContents class -// -// The view containing the different widgets. -// -//////////////////////////////////////////////////////////////////////////////// - -class TaskManagerContents : public views::View, - public views::ButtonListener, - public views::DialogDelegate, - public views::TableViewObserver, - public views::LinkController, - public views::ContextMenuController, - public Menu::Delegate { - public: - TaskManagerContents(TaskManager* task_manager, - TaskManagerModel* model); - virtual ~TaskManagerContents(); - - void Init(TaskManagerModel* model); - virtual void Layout(); - virtual gfx::Size GetPreferredSize(); - virtual void ViewHierarchyChanged(bool is_add, views::View* parent, - views::View* child); - void GetSelection(std::vector<int>* selection); - void GetFocused(std::vector<int>* focused); - - // ButtonListener implementation. - virtual void ButtonPressed(views::Button* sender); - - // views::DialogDelegate - virtual bool CanResize() const; - virtual bool CanMaximize() const; - virtual bool IsAlwaysOnTop() const; - virtual bool HasAlwaysOnTopMenu() const; - virtual std::wstring GetWindowTitle() const; - virtual std::wstring GetWindowName() const; - virtual int GetDialogButtons() const; - virtual void WindowClosing(); - virtual void DeleteDelegate(); - virtual views::View* GetContentsView(); - - // views::TableViewObserver implementation. - virtual void OnSelectionChanged(); - virtual void OnDoubleClick(); - virtual void OnKeyDown(unsigned short virtual_keycode); - - // views::LinkController implementation. - virtual void LinkActivated(views::Link* source, int event_flags); - - // Called by the column picker to pick up any new stat counters that - // may have appeared since last time. - void UpdateStatsCounters(); - - // Menu::Delegate - virtual void ShowContextMenu(views::View* source, - int x, - int y, - bool is_mouse_gesture); - virtual bool IsItemChecked(int id) const; - virtual void ExecuteCommand(int id); - - private: - scoped_ptr<views::NativeButton> kill_button_; - scoped_ptr<views::Link> about_memory_link_; - views::GroupTableView* tab_table_; - - TaskManager* task_manager_; - - // all possible columns, not necessarily visible - std::vector<views::TableColumn> columns_; - - scoped_ptr<TaskManagerTableModel> table_model_; - - DISALLOW_EVIL_CONSTRUCTORS(TaskManagerContents); -}; - -TaskManagerContents::TaskManagerContents(TaskManager* task_manager, - TaskManagerModel* model) - : task_manager_(task_manager) { - Init(model); -} - -TaskManagerContents::~TaskManagerContents() { -} - -void TaskManagerContents::Init(TaskManagerModel* model) { - table_model_.reset(new TaskManagerTableModel(model)); - - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN, - views::TableColumn::LEFT, -1, 1)); - columns_.back().sortable = true; - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, - views::TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, - views::TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, - views::TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_CPU_COLUMN, - views::TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_NET_COLUMN, - views::TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, - views::TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - - tab_table_ = new views::GroupTableView(table_model_.get(), columns_, - views::ICON_AND_TEXT, false, true, - true); - - // Hide some columns by default - tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, false); - tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, false); - tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, false); - - UpdateStatsCounters(); - views::TableColumn col(kGoatsTeleportedColumn, L"Goats Teleported", - views::TableColumn::RIGHT, -1, 0); - col.sortable = true; - columns_.push_back(col); - tab_table_->AddColumn(col); - tab_table_->SetObserver(this); - SetContextMenuController(this); - kill_button_.reset(new views::NativeButton( - this, l10n_util::GetString(IDS_TASK_MANAGER_KILL))); - kill_button_->AddAccelerator(views::Accelerator('E', false, false, false)); - kill_button_->SetAccessibleKeyboardShortcut(L"E"); - about_memory_link_.reset(new views::Link( - l10n_util::GetString(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK))); - about_memory_link_->SetController(this); - - AddChildView(tab_table_); - - // Makes sure our state is consistent. - OnSelectionChanged(); -} - -void TaskManagerContents::UpdateStatsCounters() { - StatsTable* stats = StatsTable::current(); - if (stats != NULL) { - int max = stats->GetMaxCounters(); - // skip the first row (it's header data) - for (int i = 1; i < max; i++) { - const char* row = stats->GetRowName(i); - if (row != NULL && row[0] != '\0' && !tab_table_->HasColumn(i)) { - // TODO(erikkay): Use l10n to get display names for stats. Right - // now we're just displaying the internal counter name. Perhaps - // stat names not in the string table would be filtered out. - // TODO(erikkay): Width is hard-coded right now, so many column - // names are clipped. - views::TableColumn col(i, ASCIIToWide(row), views::TableColumn::RIGHT, - 90, 0); - col.sortable = true; - columns_.push_back(col); - tab_table_->AddColumn(col); - } - } - } -} - -void TaskManagerContents::ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child) { - // Since we want the Kill button and the Memory Details link to show up in - // the same visual row as the close button, which is provided by the - // framework, we must add the buttons to the non-client view, which is the - // parent of this view. Similarly, when we're removed from the view - // hierarchy, we must take care to clean up those items as well. - if (child == this) { - if (is_add) { - parent->AddChildView(kill_button_.get()); - parent->AddChildView(about_memory_link_.get()); - } else { - parent->RemoveChildView(kill_button_.get()); - parent->RemoveChildView(about_memory_link_.get()); - // Note that these items aren't deleted here, since this object is owned - // by the TaskManager, whose lifetime surpasses the window, and the next - // time we are inserted into a window these items will need to be valid. - } - } -} - -void TaskManagerContents::Layout() { - // kPanelHorizMargin is too big. - const int kTableButtonSpacing = 12; - - gfx::Size size = kill_button_->GetPreferredSize(); - int prefered_width = size.width(); - int prefered_height = size.height(); - - tab_table_->SetBounds(x() + kPanelHorizMargin, - y() + kPanelVertMargin, - width() - 2 * kPanelHorizMargin, - height() - 2 * kPanelVertMargin - prefered_height); - - // y-coordinate of button top left. - gfx::Rect parent_bounds = GetParent()->GetLocalBounds(false); - int y_buttons = parent_bounds.bottom() - prefered_height - kButtonVEdgeMargin; - - kill_button_->SetBounds(x() + width() - prefered_width - kPanelHorizMargin, - y_buttons, - prefered_width, - prefered_height); - - size = about_memory_link_->GetPreferredSize(); - int link_prefered_width = size.width(); - int link_prefered_height = size.height(); - // center between the two buttons horizontally, and line up with - // bottom of buttons vertically. - int link_y_offset = std::max(0, prefered_height - link_prefered_height) / 2; - about_memory_link_->SetBounds( - x() + kPanelHorizMargin, - y_buttons + prefered_height - link_prefered_height - link_y_offset, - link_prefered_width, - link_prefered_height); -} - -gfx::Size TaskManagerContents::GetPreferredSize() { - return gfx::Size(kDefaultWidth, kDefaultHeight); -} - -void TaskManagerContents::GetSelection(std::vector<int>* selection) { - DCHECK(selection); - for (views::TableSelectionIterator iter = tab_table_->SelectionBegin(); - iter != tab_table_->SelectionEnd(); ++iter) { - // The TableView returns the selection starting from the end. - selection->insert(selection->begin(), *iter); - } -} - -void TaskManagerContents::GetFocused(std::vector<int>* focused) { - DCHECK(focused); - int row_count = tab_table_->RowCount(); - for (int i = 0; i < row_count; ++i) { - // The TableView returns the selection starting from the end. - if (tab_table_->ItemHasTheFocus(i)) - focused->insert(focused->begin(), i); - } -} - -// ButtonListener implementation. -void TaskManagerContents::ButtonPressed(views::Button* sender) { - if (sender == kill_button_.get()) - task_manager_->KillSelectedProcesses(); -} - -// DialogDelegate implementation. -bool TaskManagerContents::CanResize() const { - return true; -} - -bool TaskManagerContents::CanMaximize() const { - return true; -} - -bool TaskManagerContents::IsAlwaysOnTop() const { - return true; -} - -bool TaskManagerContents::HasAlwaysOnTopMenu() const { - return true; -}; - -std::wstring TaskManagerContents::GetWindowTitle() const { - return l10n_util::GetString(IDS_TASK_MANAGER_TITLE); -} - -std::wstring TaskManagerContents::GetWindowName() const { - return prefs::kTaskManagerWindowPlacement; -} - -int TaskManagerContents::GetDialogButtons() const { - return MessageBoxFlags::DIALOGBUTTON_NONE; -} - -void TaskManagerContents::WindowClosing() { - // Remove the view from its parent to trigger the contents' - // ViewHierarchyChanged notification to unhook the extra buttons from the - // non-client view. - GetParent()->RemoveChildView(this); - task_manager_->Close(); -} - -void TaskManagerContents::DeleteDelegate() { - ReleaseWindow(); -} - -views::View* TaskManagerContents::GetContentsView() { - return this; -} - -// views::TableViewObserver implementation. -void TaskManagerContents::OnSelectionChanged() { - kill_button_->SetEnabled(!task_manager_->BrowserProcessIsSelected() && - tab_table_->SelectedRowCount() > 0); -} - -void TaskManagerContents::OnDoubleClick() { - task_manager_->ActivateFocusedTab(); -} - -void TaskManagerContents::OnKeyDown(unsigned short virtual_keycode) { - if (virtual_keycode == VK_RETURN) - task_manager_->ActivateFocusedTab(); -} - -// views::LinkController implementation -void TaskManagerContents::LinkActivated(views::Link* source, - int event_flags) { - DCHECK(source == about_memory_link_); - Browser* browser = BrowserList::GetLastActive(); - DCHECK(browser); - browser->OpenURL(GURL("about:memory"), GURL(), NEW_FOREGROUND_TAB, - PageTransition::LINK); - // In case the browser window is minimzed, show it. - browser->window()->Show(); -} - -void TaskManagerContents::ShowContextMenu(views::View* source, - int x, - int y, - bool is_mouse_gesture) { - UpdateStatsCounters(); - Menu menu(this, Menu::TOPLEFT, source->GetWidget()->GetNativeView()); - for (std::vector<views::TableColumn>::iterator i = - columns_.begin(); i != columns_.end(); ++i) { - menu.AppendMenuItem(i->id, i->title, Menu::CHECKBOX); - } - menu.RunMenuAt(x, y); -} - -bool TaskManagerContents::IsItemChecked(int id) const { - return tab_table_->IsColumnVisible(id); -} - -void TaskManagerContents::ExecuteCommand(int id) { - tab_table_->SetColumnVisibility(id, !tab_table_->IsColumnVisible(id)); -} - -//////////////////////////////////////////////////////////////////////////////// // TaskManager class //////////////////////////////////////////////////////////////////////////////// @@ -1173,9 +691,8 @@ void TaskManager::RegisterPrefs(PrefService* prefs) { prefs->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement); } -TaskManager::TaskManager() { - model_ = new TaskManagerModel(this); - contents_.reset(new TaskManagerContents(this, model_.get())); +TaskManager::TaskManager() : model_(new TaskManagerModel(this)) { + Init(); } TaskManager::~TaskManager() { @@ -1184,14 +701,7 @@ TaskManager::~TaskManager() { // static void TaskManager::Open() { TaskManager* task_manager = GetInstance(); - if (task_manager->contents_->window()) { - task_manager->contents_->window()->Activate(); - } else { - views::Window::CreateChromeWindow(NULL, gfx::Rect(), - task_manager->contents_.get()); - task_manager->model_->StartUpdating(); - task_manager->contents_->window()->Show(); - } + task_manager->view_->OpenWindow(); } void TaskManager::Close() { @@ -1200,17 +710,18 @@ void TaskManager::Close() { } bool TaskManager::BrowserProcessIsSelected() { - if (!contents_.get()) + if (!view_.get()) return false; std::vector<int> selection; - contents_->GetSelection(&selection); + view_->GetSelection(&selection); for (std::vector<int>::const_iterator iter = selection.begin(); iter != selection.end(); ++iter) { // If some of the selection is out of bounds, ignore. This may happen when // killing a process that manages several pages. if (*iter >= model_->ResourceCount()) continue; - if (model_->GetResourceProcessHandle(*iter) == GetCurrentProcess()) + if (model_->GetResourceProcessHandle(*iter) == + base::GetCurrentProcessHandle()) return true; } return false; @@ -1218,20 +729,20 @@ bool TaskManager::BrowserProcessIsSelected() { void TaskManager::KillSelectedProcesses() { std::vector<int> selection; - contents_->GetSelection(&selection); + view_->GetSelection(&selection); for (std::vector<int>::const_iterator iter = selection.begin(); iter != selection.end(); ++iter) { base::ProcessHandle process = model_->GetResourceProcessHandle(*iter); DCHECK(process); - if (process == GetCurrentProcess()) + if (process == base::GetCurrentProcessHandle()) continue; - TerminateProcess(process, 0); + base::KillProcess(process, base::PROCESS_END_KILLED_BY_USER, false); } } void TaskManager::ActivateFocusedTab() { std::vector<int> focused; - contents_->GetFocused(&focused); + view_->GetFocused(&focused); int focused_size = static_cast<int>(focused.size()); DCHECK(focused_size == 1); diff --git a/chrome/browser/task_manager.h b/chrome/browser/task_manager.h index b01a30f..d58a21e 100644 --- a/chrome/browser/task_manager.h +++ b/chrome/browser/task_manager.h @@ -24,7 +24,7 @@ class MessageLoop; class SkBitmap; class TaskManager; -class TaskManagerContents; +class TaskManagerView; class TaskManagerModel; struct BytesReadParam; @@ -138,7 +138,7 @@ class TaskManager { scoped_refptr<TaskManagerModel> model_; // A container containing the buttons and table. - scoped_ptr<TaskManagerContents> contents_; + scoped_ptr<TaskManagerView> view_; DISALLOW_COPY_AND_ASSIGN(TaskManager); }; @@ -346,4 +346,14 @@ class TaskManagerModel : public URLRequestJobTracker::JobObserver, DISALLOW_COPY_AND_ASSIGN(TaskManagerModel); }; +class TaskManagerView { + public: + virtual ~TaskManagerView() {} + + virtual void GetSelection(std::vector<int>* selection) = 0; + virtual void GetFocused(std::vector<int>* focused) = 0; + + virtual void OpenWindow() = 0; +}; + #endif // CHROME_BROWSER_TASK_MANAGER_H_ diff --git a/chrome/browser/task_manager_linux.cc b/chrome/browser/task_manager_linux.cc new file mode 100644 index 0000000..f4568de --- /dev/null +++ b/chrome/browser/task_manager_linux.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/task_manager.h" + +#include <vector> + +#include "base/logging.h" + +namespace { + +class TaskManagerViewImpl : public TaskManagerView, + public TaskManagerModelObserver { + public: + TaskManagerViewImpl(TaskManagerModel* model) { + model->SetObserver(this); + } + + // TaskManagerView + virtual void GetSelection(std::vector<int>* selection); + virtual void GetFocused(std::vector<int>* focused); + virtual void OpenWindow(); + + // TaskManagerModelObserver + virtual void OnModelChanged(); + virtual void OnItemsChanged(int start, int length); + virtual void OnItemsAdded(int start, int length); + virtual void OnItemsRemoved(int start, int length); +}; + +void TaskManagerViewImpl::GetSelection(std::vector<int>* selection) { + NOTIMPLEMENTED(); +} + +void TaskManagerViewImpl::GetFocused(std::vector<int>* focused) { + NOTIMPLEMENTED(); +} + +void TaskManagerViewImpl::OpenWindow() { + NOTIMPLEMENTED(); +} + +void TaskManagerViewImpl::OnModelChanged() { + NOTIMPLEMENTED(); +} + +void TaskManagerViewImpl::OnItemsChanged(int start, int length) { + NOTIMPLEMENTED(); +} + +void TaskManagerViewImpl::OnItemsAdded(int start, int length) { + NOTIMPLEMENTED(); +} + +void TaskManagerViewImpl::OnItemsRemoved(int start, int length) { + NOTIMPLEMENTED(); +} + +} // namespace + +void TaskManager::Init() { + view_.reset(new TaskManagerViewImpl(model_.get())); +} diff --git a/chrome/browser/task_manager_unittest.cc b/chrome/browser/task_manager_unittest.cc index 4550f8b..70bb710 100644 --- a/chrome/browser/task_manager_unittest.cc +++ b/chrome/browser/task_manager_unittest.cc @@ -7,10 +7,10 @@ #include <string> #include "app/l10n_util.h" +#include "base/process_util.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "testing/gtest/include/gtest/gtest.h" -#include "views/controls/table/table_view.h" namespace { @@ -18,7 +18,9 @@ class TestResource : public TaskManager::Resource { public: virtual std::wstring GetTitle() const { return L"test title"; } virtual SkBitmap GetIcon() const { return SkBitmap(); } - virtual HANDLE GetProcess() const { return NULL; } + virtual base::ProcessHandle GetProcess() const { + return base::GetCurrentProcessHandle(); + } virtual bool SupportNetworkUsage() const { return false; } virtual void SetSupportNetworkUsage() { NOTREACHED(); } }; diff --git a/chrome/browser/task_manager_win.cc b/chrome/browser/task_manager_win.cc new file mode 100644 index 0000000..9fa0eba --- /dev/null +++ b/chrome/browser/task_manager_win.cc @@ -0,0 +1,521 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/task_manager.h" + +#include "base/stats_table.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "views/accelerator.h" +#include "views/background.h" +#include "views/controls/button/native_button.h" +#include "views/controls/link.h" +#include "views/controls/menu/menu.h" +#include "views/controls/table/group_table_view.h" +#include "views/standard_layout.h" +#include "views/widget/widget.h" +#include "views/window/dialog_delegate.h" +#include "views/window/window.h" + +// The task manager window default size. +static const int kDefaultWidth = 460; +static const int kDefaultHeight = 270; + +// An id for the most important column, made sufficiently large so as not to +// collide with anything else. +static const int64 kNuthMagicNumber = 1737350766; +static const int kBitMask = 0x7FFFFFFF; +static const int kGoatsTeleportedColumn = + (94024 * kNuthMagicNumber) & kBitMask; + +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// TaskManagerTableModel class +//////////////////////////////////////////////////////////////////////////////// + +class TaskManagerTableModel : public views::GroupTableModel, + public TaskManagerModelObserver { + public: + explicit TaskManagerTableModel(TaskManagerModel* model) + : model_(model), + observer_(NULL) { + model->SetObserver(this); + } + ~TaskManagerTableModel() {} + + // GroupTableModel. + int RowCount(); + std::wstring GetText(int row, int column); + SkBitmap GetIcon(int row); + void GetGroupRangeForItem(int item, views::GroupRange* range); + void SetObserver(views::TableModelObserver* observer); + virtual int CompareValues(int row1, int row2, int column_id); + + // TaskManagerModelObserver. + virtual void OnModelChanged(); + virtual void OnItemsChanged(int start, int length); + virtual void OnItemsAdded(int start, int length); + virtual void OnItemsRemoved(int start, int length); + + private: + const TaskManagerModel* model_; + views::TableModelObserver* observer_; +}; + +int TaskManagerTableModel::RowCount() { + return model_->ResourceCount(); +} + +std::wstring TaskManagerTableModel::GetText(int row, int col_id) { + switch (col_id) { + case IDS_TASK_MANAGER_PAGE_COLUMN: // Process + return model_->GetResourceTitle(row); + + case IDS_TASK_MANAGER_NET_COLUMN: // Net + return model_->GetResourceNetworkUsage(row); + + case IDS_TASK_MANAGER_CPU_COLUMN: // CPU + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceCPUUsage(row); + + case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourcePrivateMemory(row); + + case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceSharedMemory(row); + + case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: // Memory + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourcePhysicalMemory(row); + + case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceProcessId(row); + + case kGoatsTeleportedColumn: // Goats Teleported! + return model_->GetResourceGoatsTeleported(row); + + default: + return model_->GetResourceStatsValue(row, col_id); + } +} + +SkBitmap TaskManagerTableModel::GetIcon(int row) { + return model_->GetResourceIcon(row); +} + +void TaskManagerTableModel::GetGroupRangeForItem(int item, + views::GroupRange* range) { + std::pair<int, int> range_pair = model_->GetGroupRangeForResource(item); + range->start = range_pair.first; + range->length = range_pair.second; +} + +void TaskManagerTableModel::SetObserver(views::TableModelObserver* observer) { + observer_ = observer; +} + +int TaskManagerTableModel::CompareValues(int row1, int row2, int column_id) { + return model_->CompareValues(row1, row2, column_id); +} + +void TaskManagerTableModel::OnModelChanged() { + if (observer_) + observer_->OnModelChanged(); +} + +void TaskManagerTableModel::OnItemsChanged(int start, int length) { + if (observer_) + observer_->OnItemsChanged(start, length); +} + +void TaskManagerTableModel::OnItemsAdded(int start, int length) { + if (observer_) + observer_->OnItemsAdded(start, length); +} + +void TaskManagerTableModel::OnItemsRemoved(int start, int length) { + if (observer_) + observer_->OnItemsRemoved(start, length); +} + +//////////////////////////////////////////////////////////////////////////////// +// TaskManagerViewImpl class +// +// The view containing the different widgets. +// +//////////////////////////////////////////////////////////////////////////////// + +class TaskManagerViewImpl : public TaskManagerView, + public views::View, + public views::ButtonListener, + public views::DialogDelegate, + public views::TableViewObserver, + public views::LinkController, + public views::ContextMenuController, + public Menu::Delegate { + public: + TaskManagerViewImpl(TaskManager* task_manager, + TaskManagerModel* model); + virtual ~TaskManagerViewImpl(); + + void Init(); + virtual void Layout(); + virtual gfx::Size GetPreferredSize(); + virtual void ViewHierarchyChanged(bool is_add, views::View* parent, + views::View* child); + + // TaskManagerView + virtual void GetSelection(std::vector<int>* selection); + virtual void GetFocused(std::vector<int>* focused); + virtual void OpenWindow(); + + // ButtonListener implementation. + virtual void ButtonPressed(views::Button* sender); + + // views::DialogDelegate + virtual bool CanResize() const; + virtual bool CanMaximize() const; + virtual bool IsAlwaysOnTop() const; + virtual bool HasAlwaysOnTopMenu() const; + virtual std::wstring GetWindowTitle() const; + virtual std::wstring GetWindowName() const; + virtual int GetDialogButtons() const; + virtual void WindowClosing(); + virtual void DeleteDelegate(); + virtual views::View* GetContentsView(); + + // views::TableViewObserver implementation. + virtual void OnSelectionChanged(); + virtual void OnDoubleClick(); + virtual void OnKeyDown(unsigned short virtual_keycode); + + // views::LinkController implementation. + virtual void LinkActivated(views::Link* source, int event_flags); + + // Called by the column picker to pick up any new stat counters that + // may have appeared since last time. + void UpdateStatsCounters(); + + // Menu::Delegate + virtual void ShowContextMenu(views::View* source, + int x, + int y, + bool is_mouse_gesture); + virtual bool IsItemChecked(int id) const; + virtual void ExecuteCommand(int id); + + private: + scoped_ptr<views::NativeButton> kill_button_; + scoped_ptr<views::Link> about_memory_link_; + views::GroupTableView* tab_table_; + + TaskManager* task_manager_; + + TaskManagerModel* model_; + + // all possible columns, not necessarily visible + std::vector<views::TableColumn> columns_; + + scoped_ptr<TaskManagerTableModel> table_model_; + + DISALLOW_COPY_AND_ASSIGN(TaskManagerViewImpl); +}; + +TaskManagerViewImpl::TaskManagerViewImpl(TaskManager* task_manager, + TaskManagerModel* model) + : task_manager_(task_manager), + model_(model) { + Init(); +} + +TaskManagerViewImpl::~TaskManagerViewImpl() { +} + +void TaskManagerViewImpl::Init() { + table_model_.reset(new TaskManagerTableModel(model_)); + + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN, + views::TableColumn::LEFT, -1, 1)); + columns_.back().sortable = true; + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, + views::TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, + views::TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, + views::TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_CPU_COLUMN, + views::TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_NET_COLUMN, + views::TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(views::TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, + views::TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + + tab_table_ = new views::GroupTableView(table_model_.get(), columns_, + views::ICON_AND_TEXT, false, true, + true); + + // Hide some columns by default + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, false); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, false); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, false); + + UpdateStatsCounters(); + views::TableColumn col(kGoatsTeleportedColumn, L"Goats Teleported", + views::TableColumn::RIGHT, -1, 0); + col.sortable = true; + columns_.push_back(col); + tab_table_->AddColumn(col); + tab_table_->SetObserver(this); + SetContextMenuController(this); + kill_button_.reset(new views::NativeButton( + this, l10n_util::GetString(IDS_TASK_MANAGER_KILL))); + kill_button_->AddAccelerator(views::Accelerator('E', false, false, false)); + kill_button_->SetAccessibleKeyboardShortcut(L"E"); + about_memory_link_.reset(new views::Link( + l10n_util::GetString(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK))); + about_memory_link_->SetController(this); + + AddChildView(tab_table_); + + // Makes sure our state is consistent. + OnSelectionChanged(); +} + +void TaskManagerViewImpl::UpdateStatsCounters() { + StatsTable* stats = StatsTable::current(); + if (stats != NULL) { + int max = stats->GetMaxCounters(); + // skip the first row (it's header data) + for (int i = 1; i < max; i++) { + const char* row = stats->GetRowName(i); + if (row != NULL && row[0] != '\0' && !tab_table_->HasColumn(i)) { + // TODO(erikkay): Use l10n to get display names for stats. Right + // now we're just displaying the internal counter name. Perhaps + // stat names not in the string table would be filtered out. + // TODO(erikkay): Width is hard-coded right now, so many column + // names are clipped. + views::TableColumn col(i, ASCIIToWide(row), views::TableColumn::RIGHT, + 90, 0); + col.sortable = true; + columns_.push_back(col); + tab_table_->AddColumn(col); + } + } + } +} + +void TaskManagerViewImpl::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + // Since we want the Kill button and the Memory Details link to show up in + // the same visual row as the close button, which is provided by the + // framework, we must add the buttons to the non-client view, which is the + // parent of this view. Similarly, when we're removed from the view + // hierarchy, we must take care to clean up those items as well. + if (child == this) { + if (is_add) { + parent->AddChildView(kill_button_.get()); + parent->AddChildView(about_memory_link_.get()); + } else { + parent->RemoveChildView(kill_button_.get()); + parent->RemoveChildView(about_memory_link_.get()); + // Note that these items aren't deleted here, since this object is owned + // by the TaskManager, whose lifetime surpasses the window, and the next + // time we are inserted into a window these items will need to be valid. + } + } +} + +void TaskManagerViewImpl::Layout() { + // kPanelHorizMargin is too big. + const int kTableButtonSpacing = 12; + + gfx::Size size = kill_button_->GetPreferredSize(); + int prefered_width = size.width(); + int prefered_height = size.height(); + + tab_table_->SetBounds(x() + kPanelHorizMargin, + y() + kPanelVertMargin, + width() - 2 * kPanelHorizMargin, + height() - 2 * kPanelVertMargin - prefered_height); + + // y-coordinate of button top left. + gfx::Rect parent_bounds = GetParent()->GetLocalBounds(false); + int y_buttons = parent_bounds.bottom() - prefered_height - kButtonVEdgeMargin; + + kill_button_->SetBounds(x() + width() - prefered_width - kPanelHorizMargin, + y_buttons, + prefered_width, + prefered_height); + + size = about_memory_link_->GetPreferredSize(); + int link_prefered_width = size.width(); + int link_prefered_height = size.height(); + // center between the two buttons horizontally, and line up with + // bottom of buttons vertically. + int link_y_offset = std::max(0, prefered_height - link_prefered_height) / 2; + about_memory_link_->SetBounds( + x() + kPanelHorizMargin, + y_buttons + prefered_height - link_prefered_height - link_y_offset, + link_prefered_width, + link_prefered_height); +} + +gfx::Size TaskManagerViewImpl::GetPreferredSize() { + return gfx::Size(kDefaultWidth, kDefaultHeight); +} + +void TaskManagerViewImpl::GetSelection(std::vector<int>* selection) { + DCHECK(selection); + for (views::TableSelectionIterator iter = tab_table_->SelectionBegin(); + iter != tab_table_->SelectionEnd(); ++iter) { + // The TableView returns the selection starting from the end. + selection->insert(selection->begin(), *iter); + } +} + +void TaskManagerViewImpl::GetFocused(std::vector<int>* focused) { + DCHECK(focused); + int row_count = tab_table_->RowCount(); + for (int i = 0; i < row_count; ++i) { + // The TableView returns the selection starting from the end. + if (tab_table_->ItemHasTheFocus(i)) + focused->insert(focused->begin(), i); + } +} + +void TaskManagerViewImpl::OpenWindow() { + if (window()) { + window()->Activate(); + } else { + views::Window::CreateChromeWindow(NULL, gfx::Rect(), this); + model_->StartUpdating(); + window()->Show(); + } +} + +// ButtonListener implementation. +void TaskManagerViewImpl::ButtonPressed(views::Button* sender) { + if (sender == kill_button_.get()) + task_manager_->KillSelectedProcesses(); +} + +// DialogDelegate implementation. +bool TaskManagerViewImpl::CanResize() const { + return true; +} + +bool TaskManagerViewImpl::CanMaximize() const { + return true; +} + +bool TaskManagerViewImpl::IsAlwaysOnTop() const { + return true; +} + +bool TaskManagerViewImpl::HasAlwaysOnTopMenu() const { + return true; +}; + +std::wstring TaskManagerViewImpl::GetWindowTitle() const { + return l10n_util::GetString(IDS_TASK_MANAGER_TITLE); +} + +std::wstring TaskManagerViewImpl::GetWindowName() const { + return prefs::kTaskManagerWindowPlacement; +} + +int TaskManagerViewImpl::GetDialogButtons() const { + return MessageBoxFlags::DIALOGBUTTON_NONE; +} + +void TaskManagerViewImpl::WindowClosing() { + // Remove the view from its parent to trigger the contents' + // ViewHierarchyChanged notification to unhook the extra buttons from the + // non-client view. + GetParent()->RemoveChildView(this); + task_manager_->Close(); +} + +void TaskManagerViewImpl::DeleteDelegate() { + ReleaseWindow(); +} + +views::View* TaskManagerViewImpl::GetContentsView() { + return this; +} + +// views::TableViewObserver implementation. +void TaskManagerViewImpl::OnSelectionChanged() { + kill_button_->SetEnabled(!task_manager_->BrowserProcessIsSelected() && + tab_table_->SelectedRowCount() > 0); +} + +void TaskManagerViewImpl::OnDoubleClick() { + task_manager_->ActivateFocusedTab(); +} + +void TaskManagerViewImpl::OnKeyDown(unsigned short virtual_keycode) { + if (virtual_keycode == VK_RETURN) + task_manager_->ActivateFocusedTab(); +} + +// views::LinkController implementation +void TaskManagerViewImpl::LinkActivated(views::Link* source, + int event_flags) { + DCHECK(source == about_memory_link_); + Browser* browser = BrowserList::GetLastActive(); + DCHECK(browser); + browser->OpenURL(GURL("about:memory"), GURL(), NEW_FOREGROUND_TAB, + PageTransition::LINK); + // In case the browser window is minimzed, show it. + browser->window()->Show(); +} + +void TaskManagerViewImpl::ShowContextMenu(views::View* source, + int x, + int y, + bool is_mouse_gesture) { + UpdateStatsCounters(); + Menu menu(this, Menu::TOPLEFT, source->GetWidget()->GetNativeView()); + for (std::vector<views::TableColumn>::iterator i = + columns_.begin(); i != columns_.end(); ++i) { + menu.AppendMenuItem(i->id, i->title, Menu::CHECKBOX); + } + menu.RunMenuAt(x, y); +} + +bool TaskManagerViewImpl::IsItemChecked(int id) const { + return tab_table_->IsColumnVisible(id); +} + +void TaskManagerViewImpl::ExecuteCommand(int id) { + tab_table_->SetColumnVisibility(id, !tab_table_->IsColumnVisible(id)); +} + +} // namespace + +void TaskManager::Init() { + view_.reset(new TaskManagerViewImpl(this, model_.get())); +} |