From 8f90afd7751345b1b86e15355dffb35aae76110e Mon Sep 17 00:00:00 2001 From: "ben@chromium.org" Date: Mon, 22 Jun 2009 22:44:38 +0000 Subject: Reorganize the way the task manager is constructed. The BrowserWindow creates the task manager UI directly, which uses the TaskManager to populate itself. BUG=none TEST=none Review URL: http://codereview.chromium.org/140044 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18975 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/browser.cc | 7 +- chrome/browser/browser_window.h | 3 + chrome/browser/cocoa/browser_window_cocoa.h | 1 + chrome/browser/cocoa/browser_window_cocoa.mm | 4 + chrome/browser/gtk/browser_window_gtk.cc | 4 + chrome/browser/gtk/browser_window_gtk.h | 1 + chrome/browser/gtk/task_manager_gtk.cc | 42 ++ chrome/browser/task_manager.cc | 81 +--- chrome/browser/task_manager.h | 49 +-- chrome/browser/task_manager_browsertest.cc | 10 +- chrome/browser/task_manager_linux.cc | 75 ---- chrome/browser/task_manager_unittest.cc | 1 - chrome/browser/task_manager_win.cc | 633 -------------------------- chrome/browser/views/browser_dialogs.h | 3 + chrome/browser/views/frame/browser_view.cc | 4 + chrome/browser/views/frame/browser_view.h | 1 + chrome/browser/views/task_manager_view.cc | 634 +++++++++++++++++++++++++++ chrome/chrome.gyp | 4 +- chrome/test/test_browser_window.h | 1 + 19 files changed, 730 insertions(+), 828 deletions(-) create mode 100644 chrome/browser/gtk/task_manager_gtk.cc delete mode 100644 chrome/browser/task_manager_linux.cc delete mode 100644 chrome/browser/task_manager_win.cc create mode 100644 chrome/browser/views/task_manager_view.cc (limited to 'chrome') diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 0fe72e6..4bf03ea 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1103,12 +1103,7 @@ void Browser::OpenJavaScriptConsole() { void Browser::OpenTaskManager() { UserMetrics::RecordAction(L"TaskManager", profile_); -// TODO(port) -#if defined(OS_WIN) - TaskManager::Open(); -#else - NOTIMPLEMENTED(); -#endif + window_->ShowTaskManager(); } void Browser::OpenSelectProfileDialog() { diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index f7999be..d11db56 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -135,6 +135,9 @@ class BrowserWindow { // Shows the About Chrome dialog box. virtual void ShowAboutChromeDialog() = 0; + // Shows the Task manager. + virtual void ShowTaskManager() = 0; + // Shows the Bookmark Manager window. virtual void ShowBookmarkManager() = 0; diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h index 9dc9e72..047a73e 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.h +++ b/chrome/browser/cocoa/browser_window_cocoa.h @@ -55,6 +55,7 @@ class BrowserWindowCocoa : public BrowserWindow, virtual gfx::Rect GetRootWindowResizerRect() const; virtual void ToggleBookmarkBar(); virtual void ShowAboutChromeDialog(); + virtual void ShowTaskManager(); virtual void ShowBookmarkManager(); virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); virtual bool IsDownloadShelfVisible() const; diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index 28f87ae9..047dffc 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -179,6 +179,10 @@ void BrowserWindowCocoa::ShowAboutChromeDialog() { NOTIMPLEMENTED(); } +void BrowserWindowCocoa::ShowTaskManager() { + NOTIMPLEMENTED(); +} + void BrowserWindowCocoa::ShowBookmarkManager() { NOTIMPLEMENTED(); } diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index 246411a..fa3cbd7 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -604,6 +604,10 @@ void BrowserWindowGtk::ShowAboutChromeDialog() { ShowAboutDialogForProfile(window_, browser_->profile()); } +void BrowserWindowGtk::ShowTaskManager() { + NOTIMPLEMENTED(); +} + void BrowserWindowGtk::ShowBookmarkManager() { NOTIMPLEMENTED(); } diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h index b347288..249c695 100644 --- a/chrome/browser/gtk/browser_window_gtk.h +++ b/chrome/browser/gtk/browser_window_gtk.h @@ -75,6 +75,7 @@ class BrowserWindowGtk : public BrowserWindow, virtual gfx::Rect GetRootWindowResizerRect() const; virtual void ToggleBookmarkBar(); virtual void ShowAboutChromeDialog(); + virtual void ShowTaskManager(); virtual void ShowBookmarkManager(); virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); virtual bool IsDownloadShelfVisible() const; diff --git a/chrome/browser/gtk/task_manager_gtk.cc b/chrome/browser/gtk/task_manager_gtk.cc new file mode 100644 index 0000000..511e3a8 --- /dev/null +++ b/chrome/browser/gtk/task_manager_gtk.cc @@ -0,0 +1,42 @@ +// 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 + +#include "base/logging.h" + +namespace { + +class TaskManagerGtk : public TaskManagerModelObserver { + public: + TaskManagerGtk(TaskManagerModel* model) { + model->SetObserver(this); + } + + // 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 TaskManagerGtk::OnModelChanged() { + NOTIMPLEMENTED(); +} + +void TaskManagerGtk::OnItemsChanged(int start, int length) { + NOTIMPLEMENTED(); +} + +void TaskManagerGtk::OnItemsAdded(int start, int length) { + NOTIMPLEMENTED(); +} + +void TaskManagerGtk::OnItemsRemoved(int start, int length) { + NOTIMPLEMENTED(); +} + +} // namespace diff --git a/chrome/browser/task_manager.cc b/chrome/browser/task_manager.cc index 8f174cc..0a671e3 100644 --- a/chrome/browser/task_manager.cc +++ b/chrome/browser/task_manager.cc @@ -698,86 +698,34 @@ void TaskManager::RegisterPrefs(PrefService* prefs) { } TaskManager::TaskManager() - : ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TaskManagerModel(this))), - view_(NULL) { + : ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TaskManagerModel(this))) { } TaskManager::~TaskManager() { } -// static -void TaskManager::Open() { - TaskManager* task_manager = GetInstance(); - if (task_manager->view_) { - task_manager->view_->ActivateWindow(); - } else { - task_manager->CreateView(); - task_manager->view_->OpenWindow(); - } +bool TaskManager::IsBrowserProcess(int index) const { + // If some of the selection is out of bounds, ignore. This may happen when + // killing a process that manages several pages. + return index < model_->ResourceCount() && + model_->GetResourceProcessHandle(index) == + base::GetCurrentProcessHandle(); } -// static -void TaskManager::Close() { - TaskManager* task_manager = GetInstance(); - task_manager->view_->CloseWindow(); -} - -bool TaskManager::BrowserProcessIsSelected() { - if (!view_) - return false; - std::vector selection; - view_->GetSelection(&selection); - for (std::vector::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) == - base::GetCurrentProcessHandle()) - return true; - } - return false; -} - -void TaskManager::KillSelectedProcesses() { - std::vector selection; - view_->GetSelection(&selection); - for (std::vector::const_iterator iter = selection.begin(); - iter != selection.end(); ++iter) { - base::ProcessHandle process = model_->GetResourceProcessHandle(*iter); - DCHECK(process); - if (process == base::GetCurrentProcessHandle()) - continue; +void TaskManager::KillProcess(int index) { + base::ProcessHandle process = model_->GetResourceProcessHandle(index); + DCHECK(process); + if (process != base::GetCurrentProcessHandle()) base::KillProcess(process, base::PROCESS_END_KILLED_BY_USER, false); - } } -void TaskManager::ActivateFocusedTab() { - std::vector focused; - view_->GetFocused(&focused); - int focused_size = static_cast(focused.size()); - - DCHECK(focused_size == 1); - - // Gracefully return if there is not exactly one item in focus. - if (focused_size != 1) - return; - - // Otherwise, the one focused thing should be one the user intends to bring - // forth, so get see if GetTabContents returns non-null. If it does, activate - // those contents. - int index = focused[0]; - +void TaskManager::ActivateProcess(int index) { // GetResourceTabContents returns a pointer to the relevant tab contents for // the resource. If the index doesn't correspond to a Tab (i.e. refers to // the Browser process or a plugin), GetTabContents will return NULL. TabContents* chosen_tab_contents = model_->GetResourceTabContents(index); - - if (!chosen_tab_contents) - return; - - chosen_tab_contents->Activate(); + if (chosen_tab_contents) + chosen_tab_contents->Activate(); } void TaskManager::AddResourceProvider(ResourceProvider* provider) { @@ -799,7 +747,6 @@ void TaskManager::RemoveResource(Resource* resource) { void TaskManager::OnWindowClosed() { model_->StopUpdating(); model_->Clear(); - view_ = NULL; } // static diff --git a/chrome/browser/task_manager.h b/chrome/browser/task_manager.h index c0f312e..c574b4a 100644 --- a/chrome/browser/task_manager.h +++ b/chrome/browser/task_manager.h @@ -24,7 +24,6 @@ class MessageLoop; class SkBitmap; class TaskManager; -class TaskManagerView; class TaskManagerModel; struct BytesReadParam; @@ -89,24 +88,15 @@ class TaskManager { static void RegisterPrefs(PrefService* prefs); - // Call this method to show the Task Manager. - // Only one instance of Task Manager is created, so if the Task Manager has - // already be opened, it is reopened. If it is currently opened, then it is - // moved to the front. - static void Open(); + // Returns true if the process at the specified index is the browser process. + bool IsBrowserProcess(int index) const; - // Close the task manager if it's currently opened. - static void Close(); + // Terminates the process at the specified index. + void KillProcess(int index); - // Returns true if the current selection includes the browser process. - bool BrowserProcessIsSelected(); - - // Terminates the selected tab(s) in the list. - void KillSelectedProcesses(); - - // Activates the browser tab associated with the focused row in the task - // manager table. This happens when the user double clicks or hits return. - void ActivateFocusedTab(); + // Activates the browser tab associated with the process in the specified + // index. + void ActivateProcess(int index); void AddResourceProvider(ResourceProvider* provider); void RemoveResourceProvider(ResourceProvider* provider); @@ -120,6 +110,11 @@ class TaskManager { void OnWindowClosed(); + // Returns the singleton instance (and initializes it if necessary). + static TaskManager* GetInstance(); + + TaskManagerModel* model() const { return model_.get(); } + private: FRIEND_TEST(TaskManagerTest, Basic); FRIEND_TEST(TaskManagerTest, Resources); @@ -130,18 +125,10 @@ class TaskManager { ~TaskManager(); - void CreateView(); - - // Returns the singleton instance (and initializes it if necessary). - static TaskManager* GetInstance(); - // The model used for gathering and processing task data. It is ref counted // because it is passed as a parameter to MessageLoop::InvokeLater(). scoped_refptr model_; - // A container containing the buttons and table. - TaskManagerView* view_; - DISALLOW_COPY_AND_ASSIGN(TaskManager); }; @@ -348,16 +335,4 @@ class TaskManagerModel : public URLRequestJobTracker::JobObserver, DISALLOW_COPY_AND_ASSIGN(TaskManagerModel); }; -class TaskManagerView { - public: - virtual ~TaskManagerView() {} - - virtual void GetSelection(std::vector* selection) = 0; - virtual void GetFocused(std::vector* focused) = 0; - - virtual void OpenWindow() = 0; - virtual void ActivateWindow() = 0; - virtual void CloseWindow() = 0; -}; - #endif // CHROME_BROWSER_TASK_MANAGER_H_ diff --git a/chrome/browser/task_manager_browsertest.cc b/chrome/browser/task_manager_browsertest.cc index 35aa462..8aa343f 100644 --- a/chrome/browser/task_manager_browsertest.cc +++ b/chrome/browser/task_manager_browsertest.cc @@ -4,18 +4,14 @@ #include "chrome/browser/task_manager.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" #include "chrome/test/in_process_browser_test.h" #include "testing/gtest/include/gtest/gtest.h" class TaskManagerBrowserTest : public InProcessBrowserTest { }; -// Regression test for http://crbug.com/11180 -IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, OpenClose) { - TaskManager::Open(); - TaskManager::Close(); -} - IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) { - TaskManager::Open(); + browser()->window()->ShowTaskManager(); } diff --git a/chrome/browser/task_manager_linux.cc b/chrome/browser/task_manager_linux.cc deleted file mode 100644 index 17baa3c..0000000 --- a/chrome/browser/task_manager_linux.cc +++ /dev/null @@ -1,75 +0,0 @@ -// 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 - -#include "base/logging.h" - -namespace { - -class TaskManagerViewImpl : public TaskManagerView, - public TaskManagerModelObserver { - public: - TaskManagerViewImpl(TaskManagerModel* model) { - model->SetObserver(this); - } - - // TaskManagerView - virtual void GetSelection(std::vector* selection); - virtual void GetFocused(std::vector* focused); - virtual void OpenWindow(); - virtual void ActivateWindow(); - virtual void CloseWindow(); - - // 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* selection) { - NOTIMPLEMENTED(); -} - -void TaskManagerViewImpl::GetFocused(std::vector* focused) { - NOTIMPLEMENTED(); -} - -void TaskManagerViewImpl::OpenWindow() { - NOTIMPLEMENTED(); -} - -void TaskManagerViewImpl::ActivateWindow() { - NOTIMPLEMENTED(); -} - -void TaskManagerViewImpl::CloseWindow() { - 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::CreateView() { - DCHECK(!view_); - view_= new TaskManagerViewImpl(model_.get()); -} diff --git a/chrome/browser/task_manager_unittest.cc b/chrome/browser/task_manager_unittest.cc index 70bb710..1ce3e55 100644 --- a/chrome/browser/task_manager_unittest.cc +++ b/chrome/browser/task_manager_unittest.cc @@ -33,7 +33,6 @@ class TaskManagerTest : public testing::Test { TEST_F(TaskManagerTest, Basic) { TaskManager task_manager; TaskManagerModel* model = task_manager.model_; - EXPECT_FALSE(task_manager.BrowserProcessIsSelected()); EXPECT_EQ(0, model->ResourceCount()); } diff --git a/chrome/browser/task_manager_win.cc b/chrome/browser/task_manager_win.cc deleted file mode 100644 index 42b835a..0000000 --- a/chrome/browser/task_manager_win.cc +++ /dev/null @@ -1,633 +0,0 @@ -// 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 "app/l10n_util.h" -#include "app/table_model_observer.h" -#include "base/stats_table.h" -#include "chrome/app/chrome_dll_resource.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_window.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/controls/table/table_view_observer.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(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_; - 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 range_pair = model_->GetGroupRangeForResource(item); - range->start = range_pair.first; - range->length = range_pair.second; -} - -void TaskManagerTableModel::SetObserver(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 views::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* selection); - virtual void GetFocused(std::vector* focused); - virtual void OpenWindow(); - virtual void ActivateWindow(); - virtual void CloseWindow(); - - // ButtonListener implementation. - virtual void ButtonPressed(views::Button* sender); - - // views::DialogDelegate - virtual bool CanResize() const; - virtual bool CanMaximize() const; - virtual bool ExecuteWindowsCommand(int command_id); - 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: - // Initializes the state of the always-on-top setting as the window is shown. - void InitAlwaysOnTopState(); - - // Adds an always on top item to the window's system menu. - void AddAlwaysOnTopSystemMenuItem(); - - // Restores saved always on top state from a previous session. - bool GetSavedAlwaysOnTopState(bool* always_on_top) const; - - views::NativeButton* kill_button_; - views::Link* about_memory_link_; - views::GroupTableView* tab_table_; - - TaskManager* task_manager_; - - TaskManagerModel* model_; - - // all possible columns, not necessarily visible - std::vector columns_; - - scoped_ptr table_model_; - - // True when the Task Manager window should be shown on top of other windows. - bool is_always_on_top_; - - // We need to own the text of the menu, the Windows API does not copy it. - std::wstring always_on_top_menu_text_; - - DISALLOW_COPY_AND_ASSIGN(TaskManagerViewImpl); -}; - -TaskManagerViewImpl::TaskManagerViewImpl(TaskManager* task_manager, - TaskManagerModel* model) - : task_manager_(task_manager), - model_(model), - is_always_on_top_(false) { - Init(); -} - -TaskManagerViewImpl::~TaskManagerViewImpl() { - // Delete child views now, while our table model still exists. - RemoveAllChildViews(true); - - // Prevent the table from accessing the model as part of its destruction, as - // the model might already be destroyed. - tab_table_->SetModel(NULL); -} - -void TaskManagerViewImpl::Init() { - table_model_.reset(new TaskManagerTableModel(model_)); - - columns_.push_back(TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN, - TableColumn::LEFT, -1, 1)); - columns_.back().sortable = true; - columns_.push_back(TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, - TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, - TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, - TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(TableColumn(IDS_TASK_MANAGER_CPU_COLUMN, - TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(TableColumn(IDS_TASK_MANAGER_NET_COLUMN, - TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - columns_.push_back(TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, - TableColumn::RIGHT, -1, 0)); - columns_.back().sortable = true; - - tab_table_ = new views::GroupTableView(table_model_.get(), columns_, - views::ICON_AND_TEXT, false, true, - true); - tab_table_->SetParentOwned(false); - - // 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(); - TableColumn col(kGoatsTeleportedColumn, L"Goats Teleported", - TableColumn::RIGHT, -1, 0); - col.sortable = true; - columns_.push_back(col); - tab_table_->AddColumn(col); - tab_table_->SetObserver(this); - SetContextMenuController(this); - kill_button_ = 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_ = new views::Link( - l10n_util::GetString(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK)); - about_memory_link_->SetController(this); - - // 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. - TableColumn col(i, ASCIIToWide(row), 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_); - parent->AddChildView(about_memory_link_); - AddChildView(tab_table_); - } else { - parent->RemoveChildView(kill_button_); - parent->RemoveChildView(about_memory_link_); - } - } -} - -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* 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* 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() { - DCHECK(!window()); - views::Window::CreateChromeWindow(NULL, gfx::Rect(), this); - InitAlwaysOnTopState(); - model_->StartUpdating(); - window()->Show(); -} - -void TaskManagerViewImpl::ActivateWindow() { - DCHECK(window()); - window()->Activate(); -} - -void TaskManagerViewImpl::CloseWindow() { - if (!window()) - return; - // TODO(phajdan.jr): Destroy the window, not just hide it. - window()->HideWindow(); -} - -// ButtonListener implementation. -void TaskManagerViewImpl::ButtonPressed(views::Button* sender) { - if (sender == kill_button_) - task_manager_->KillSelectedProcesses(); -} - -// DialogDelegate implementation. -bool TaskManagerViewImpl::CanResize() const { - return true; -} - -bool TaskManagerViewImpl::CanMaximize() const { - return true; -} - -bool TaskManagerViewImpl::ExecuteWindowsCommand(int command_id) { - if (command_id == IDC_ALWAYS_ON_TOP) { - is_always_on_top_ = !is_always_on_top_; - - // Change the menu check state. - HMENU system_menu = GetSystemMenu(GetWindow()->GetNativeWindow(), FALSE); - MENUITEMINFO menu_info; - memset(&menu_info, 0, sizeof(MENUITEMINFO)); - menu_info.cbSize = sizeof(MENUITEMINFO); - BOOL r = GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, - FALSE, &menu_info); - DCHECK(r); - menu_info.fMask = MIIM_STATE; - if (is_always_on_top_) - menu_info.fState = MFS_CHECKED; - r = SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info); - - // Now change the actual window's behavior. - window()->SetIsAlwaysOnTop(is_always_on_top_); - - // Save the state. - if (g_browser_process->local_state()) { - DictionaryValue* window_preferences = - g_browser_process->local_state()->GetMutableDictionary( - GetWindowName().c_str()); - window_preferences->SetBoolean(L"always_on_top", is_always_on_top_); - } - return true; - } - return false; -} - -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() { - task_manager_->OnWindowClosed(); -} - -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. If this is an application - // or popup, we can only have one tab, hence we need to process this in a - // tabbed browser window. Currently, |browser| is pointing to the application, - // popup window. Therefore, we have to retrieve the last active tab again, - // since a new window has been used. - if (browser->type() & Browser::TYPE_APP_POPUP) { - browser = BrowserList::GetLastActive(); - DCHECK(browser); - } - browser->window()->Show(); -} - -void TaskManagerViewImpl::ShowContextMenu(views::View* source, - int x, - int y, - bool is_mouse_gesture) { - UpdateStatsCounters(); - scoped_ptr menu(views::Menu::Create( - this, views::Menu::TOPLEFT, source->GetWidget()->GetNativeView())); - for (std::vector::iterator i = - columns_.begin(); i != columns_.end(); ++i) { - menu->AppendMenuItem(i->id, i->title, views::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)); -} - -void TaskManagerViewImpl::InitAlwaysOnTopState() { - is_always_on_top_ = false; - if (GetSavedAlwaysOnTopState(&is_always_on_top_)) - window()->SetIsAlwaysOnTop(is_always_on_top_); - AddAlwaysOnTopSystemMenuItem(); -} - -void TaskManagerViewImpl::AddAlwaysOnTopSystemMenuItem() { - // The Win32 API requires that we own the text. - always_on_top_menu_text_ = l10n_util::GetString(IDS_ALWAYS_ON_TOP); - - // Let's insert a menu to the window. - HMENU system_menu = ::GetSystemMenu(GetWindow()->GetNativeWindow(), FALSE); - int index = ::GetMenuItemCount(system_menu) - 1; - if (index < 0) { - // Paranoia check. - NOTREACHED(); - index = 0; - } - // First we add the separator. - MENUITEMINFO menu_info; - memset(&menu_info, 0, sizeof(MENUITEMINFO)); - menu_info.cbSize = sizeof(MENUITEMINFO); - menu_info.fMask = MIIM_FTYPE; - menu_info.fType = MFT_SEPARATOR; - ::InsertMenuItem(system_menu, index, TRUE, &menu_info); - - // Then the actual menu. - menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE; - menu_info.fType = MFT_STRING; - menu_info.fState = MFS_ENABLED; - if (is_always_on_top_) - menu_info.fState |= MFS_CHECKED; - menu_info.wID = IDC_ALWAYS_ON_TOP; - menu_info.dwTypeData = const_cast(always_on_top_menu_text_.c_str()); - ::InsertMenuItem(system_menu, index, TRUE, &menu_info); -} - -bool TaskManagerViewImpl::GetSavedAlwaysOnTopState(bool* always_on_top) const { - if (!g_browser_process->local_state()) - return false; - - const DictionaryValue* dictionary = - g_browser_process->local_state()->GetDictionary(GetWindowName().c_str()); - return dictionary && - dictionary->GetBoolean(L"always_on_top", always_on_top) && always_on_top; -} - -} // namespace - -void TaskManager::CreateView() { - DCHECK(!view_); - view_ = new TaskManagerViewImpl(this, model_.get()); -} diff --git a/chrome/browser/views/browser_dialogs.h b/chrome/browser/views/browser_dialogs.h index ebd532a..fd81d7b 100644 --- a/chrome/browser/views/browser_dialogs.h +++ b/chrome/browser/views/browser_dialogs.h @@ -82,6 +82,9 @@ void ShowKeywordEditorView(Profile* profile); // Shows the "new profile" dialog box. See NewProfileDialog. void ShowNewProfileDialog(); +// Shows the Task Manager. +void ShowTaskManager(); + } // namespace browser #endif // CHROME_BROWSER_VIEWS_BROWSER_DIALOGS_H_ diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 8aa44b6..bfb85f8 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -817,6 +817,10 @@ void BrowserView::ShowAboutChromeDialog() { browser::ShowAboutChromeView(GetWidget(), browser_->profile()); } +void BrowserView::ShowTaskManager() { + browser::ShowTaskManager(); +} + void BrowserView::ShowBookmarkManager() { browser::ShowBookmarkManagerView(browser_->profile()); } diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index b7a552e..03b75a3 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -215,6 +215,7 @@ class BrowserView : public BrowserWindow, virtual void DisableInactiveFrame(); virtual void ToggleBookmarkBar(); virtual void ShowAboutChromeDialog(); + virtual void ShowTaskManager(); virtual void ShowBookmarkManager(); virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked); virtual void SetDownloadShelfVisible(bool visible); diff --git a/chrome/browser/views/task_manager_view.cc b/chrome/browser/views/task_manager_view.cc new file mode 100644 index 0000000..32fe975 --- /dev/null +++ b/chrome/browser/views/task_manager_view.cc @@ -0,0 +1,634 @@ +// 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 "app/l10n_util.h" +#include "app/table_model_observer.h" +#include "base/stats_table.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/views/browser_dialogs.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/controls/table/table_view_observer.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(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_; + 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 range_pair = model_->GetGroupRangeForResource(item); + range->start = range_pair.first; + range->length = range_pair.second; +} + +void TaskManagerTableModel::SetObserver(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); +} + +// The Task manager UI container. +class TaskManagerView : public views::View, + public views::ButtonListener, + public views::DialogDelegate, + public views::TableViewObserver, + public views::LinkController, + public views::ContextMenuController, + public views::Menu::Delegate { + public: + TaskManagerView(); + virtual ~TaskManagerView(); + + // Shows the Task manager window, or re-activates an existing one. + static void Show(); + + // views::View + virtual void Layout(); + virtual gfx::Size GetPreferredSize(); + virtual void ViewHierarchyChanged(bool is_add, views::View* parent, + views::View* child); + + // ButtonListener implementation. + virtual void ButtonPressed(views::Button* sender); + + // views::DialogDelegate + virtual bool CanResize() const; + virtual bool CanMaximize() const; + virtual bool ExecuteWindowsCommand(int command_id); + 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: + // Creates the child controls. + void Init(); + + // Initializes the state of the always-on-top setting as the window is shown. + void InitAlwaysOnTopState(); + + // Activates the tab associated with the focused row. + void ActivateFocusedTab(); + + // Adds an always on top item to the window's system menu. + void AddAlwaysOnTopSystemMenuItem(); + + // Restores saved always on top state from a previous session. + bool GetSavedAlwaysOnTopState(bool* always_on_top) const; + + views::NativeButton* kill_button_; + views::Link* about_memory_link_; + views::GroupTableView* tab_table_; + + TaskManager* task_manager_; + + TaskManagerModel* model_; + + // all possible columns, not necessarily visible + std::vector columns_; + + scoped_ptr table_model_; + + // True when the Task Manager window should be shown on top of other windows. + bool is_always_on_top_; + + // We need to own the text of the menu, the Windows API does not copy it. + std::wstring always_on_top_menu_text_; + + // An open Task manager window. There can only be one open at a time. This + // is reset to NULL when the window is closed. + static TaskManagerView* instance_; + + DISALLOW_COPY_AND_ASSIGN(TaskManagerView); +}; + +// static +TaskManagerView* TaskManagerView::instance_ = NULL; + + +TaskManagerView::TaskManagerView() + : task_manager_(TaskManager::GetInstance()), + model_(TaskManager::GetInstance()->model()), + is_always_on_top_(false) { + Init(); +} + +TaskManagerView::~TaskManagerView() { + // Delete child views now, while our table model still exists. + RemoveAllChildViews(true); + + // Prevent the table from accessing the model as part of its destruction, as + // the model might already be destroyed. + tab_table_->SetModel(NULL); +} + +void TaskManagerView::Init() { + table_model_.reset(new TaskManagerTableModel(model_)); + + columns_.push_back(TableColumn(IDS_TASK_MANAGER_PAGE_COLUMN, + TableColumn::LEFT, -1, 1)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_CPU_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_NET_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN, + 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(); + TableColumn col(kGoatsTeleportedColumn, L"Goats Teleported", + TableColumn::RIGHT, -1, 0); + col.sortable = true; + columns_.push_back(col); + tab_table_->AddColumn(col); + tab_table_->SetObserver(this); + SetContextMenuController(this); + kill_button_ = 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_ = new views::Link( + l10n_util::GetString(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK)); + about_memory_link_->SetController(this); + + // Makes sure our state is consistent. + OnSelectionChanged(); +} + +void TaskManagerView::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. + TableColumn col(i, ASCIIToWide(row), TableColumn::RIGHT, 90, 0); + col.sortable = true; + columns_.push_back(col); + tab_table_->AddColumn(col); + } + } + } +} + +void TaskManagerView::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_); + parent->AddChildView(about_memory_link_); + AddChildView(tab_table_); + } else { + parent->RemoveChildView(kill_button_); + parent->RemoveChildView(about_memory_link_); + } + } +} + +void TaskManagerView::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 TaskManagerView::GetPreferredSize() { + return gfx::Size(kDefaultWidth, kDefaultHeight); +} + +// static +void TaskManagerView::Show() { + if (instance_) { + // If there's a Task manager window open already, just activate it. + instance_->window()->Activate(); + } else { + instance_ = new TaskManagerView; + views::Window::CreateChromeWindow(NULL, gfx::Rect(), instance_); + instance_->InitAlwaysOnTopState(); + instance_->model_->StartUpdating(); + instance_->window()->Show(); + } +} + +// ButtonListener implementation. +void TaskManagerView::ButtonPressed(views::Button* sender) { + DCHECK(sender == kill_button_); + for (views::TableSelectionIterator iter = tab_table_->SelectionBegin(); + iter != tab_table_->SelectionEnd(); ++iter) { + task_manager_->KillProcess(*iter); + } +} + +// DialogDelegate implementation. +bool TaskManagerView::CanResize() const { + return true; +} + +bool TaskManagerView::CanMaximize() const { + return true; +} + +bool TaskManagerView::ExecuteWindowsCommand(int command_id) { + if (command_id == IDC_ALWAYS_ON_TOP) { + is_always_on_top_ = !is_always_on_top_; + + // Change the menu check state. + HMENU system_menu = GetSystemMenu(GetWindow()->GetNativeWindow(), FALSE); + MENUITEMINFO menu_info; + memset(&menu_info, 0, sizeof(MENUITEMINFO)); + menu_info.cbSize = sizeof(MENUITEMINFO); + BOOL r = GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, + FALSE, &menu_info); + DCHECK(r); + menu_info.fMask = MIIM_STATE; + if (is_always_on_top_) + menu_info.fState = MFS_CHECKED; + r = SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info); + + // Now change the actual window's behavior. + window()->SetIsAlwaysOnTop(is_always_on_top_); + + // Save the state. + if (g_browser_process->local_state()) { + DictionaryValue* window_preferences = + g_browser_process->local_state()->GetMutableDictionary( + GetWindowName().c_str()); + window_preferences->SetBoolean(L"always_on_top", is_always_on_top_); + } + return true; + } + return false; +} + +std::wstring TaskManagerView::GetWindowTitle() const { + return l10n_util::GetString(IDS_TASK_MANAGER_TITLE); +} + +std::wstring TaskManagerView::GetWindowName() const { + return prefs::kTaskManagerWindowPlacement; +} + +int TaskManagerView::GetDialogButtons() const { + return MessageBoxFlags::DIALOGBUTTON_NONE; +} + +void TaskManagerView::WindowClosing() { + // Now that the window is closed, we can allow a new one to be opened. + instance_ = NULL; + task_manager_->OnWindowClosed(); +} + +void TaskManagerView::DeleteDelegate() { + ReleaseWindow(); +} + +views::View* TaskManagerView::GetContentsView() { + return this; +} + +// views::TableViewObserver implementation. +void TaskManagerView::OnSelectionChanged() { + bool selection_contains_browser_process = false; + for (views::TableSelectionIterator iter = tab_table_->SelectionBegin(); + iter != tab_table_->SelectionEnd(); ++iter) { + if (task_manager_->IsBrowserProcess(*iter)) { + selection_contains_browser_process = true; + break; + } + } + kill_button_->SetEnabled(!selection_contains_browser_process && + tab_table_->SelectedRowCount() > 0); +} + +void TaskManagerView::OnDoubleClick() { + ActivateFocusedTab(); +} + +void TaskManagerView::OnKeyDown(unsigned short virtual_keycode) { + if (virtual_keycode == VK_RETURN) + ActivateFocusedTab(); +} + +// views::LinkController implementation +void TaskManagerView::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. If this is an application + // or popup, we can only have one tab, hence we need to process this in a + // tabbed browser window. Currently, |browser| is pointing to the application, + // popup window. Therefore, we have to retrieve the last active tab again, + // since a new window has been used. + if (browser->type() & Browser::TYPE_APP_POPUP) { + browser = BrowserList::GetLastActive(); + DCHECK(browser); + } + browser->window()->Show(); +} + +void TaskManagerView::ShowContextMenu(views::View* source, int x, int y, + bool is_mouse_gesture) { + UpdateStatsCounters(); + scoped_ptr menu(views::Menu::Create( + this, views::Menu::TOPLEFT, source->GetWidget()->GetNativeView())); + for (std::vector::iterator i = + columns_.begin(); i != columns_.end(); ++i) { + menu->AppendMenuItem(i->id, i->title, views::Menu::CHECKBOX); + } + menu->RunMenuAt(x, y); +} + +bool TaskManagerView::IsItemChecked(int id) const { + return tab_table_->IsColumnVisible(id); +} + +void TaskManagerView::ExecuteCommand(int id) { + tab_table_->SetColumnVisibility(id, !tab_table_->IsColumnVisible(id)); +} + +void TaskManagerView::InitAlwaysOnTopState() { + is_always_on_top_ = false; + if (GetSavedAlwaysOnTopState(&is_always_on_top_)) + window()->SetIsAlwaysOnTop(is_always_on_top_); + AddAlwaysOnTopSystemMenuItem(); +} + +void TaskManagerView::ActivateFocusedTab() { + int row_count = tab_table_->RowCount(); + for (int i = 0; i < row_count; ++i) { + if (tab_table_->ItemHasTheFocus(i)) { + task_manager_->ActivateProcess(i); + break; + } + } +} + +void TaskManagerView::AddAlwaysOnTopSystemMenuItem() { + // The Win32 API requires that we own the text. + always_on_top_menu_text_ = l10n_util::GetString(IDS_ALWAYS_ON_TOP); + + // Let's insert a menu to the window. + HMENU system_menu = ::GetSystemMenu(GetWindow()->GetNativeWindow(), FALSE); + int index = ::GetMenuItemCount(system_menu) - 1; + if (index < 0) { + // Paranoia check. + NOTREACHED(); + index = 0; + } + // First we add the separator. + MENUITEMINFO menu_info; + memset(&menu_info, 0, sizeof(MENUITEMINFO)); + menu_info.cbSize = sizeof(MENUITEMINFO); + menu_info.fMask = MIIM_FTYPE; + menu_info.fType = MFT_SEPARATOR; + ::InsertMenuItem(system_menu, index, TRUE, &menu_info); + + // Then the actual menu. + menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE; + menu_info.fType = MFT_STRING; + menu_info.fState = MFS_ENABLED; + if (is_always_on_top_) + menu_info.fState |= MFS_CHECKED; + menu_info.wID = IDC_ALWAYS_ON_TOP; + menu_info.dwTypeData = const_cast(always_on_top_menu_text_.c_str()); + ::InsertMenuItem(system_menu, index, TRUE, &menu_info); +} + +bool TaskManagerView::GetSavedAlwaysOnTopState(bool* always_on_top) const { + if (!g_browser_process->local_state()) + return false; + + const DictionaryValue* dictionary = + g_browser_process->local_state()->GetDictionary(GetWindowName().c_str()); + return dictionary && + dictionary->GetBoolean(L"always_on_top", always_on_top) && always_on_top; +} + +} // namespace + +namespace browser { + +// Declared in browser_dialogs.h so others don't need to depend on our header. +void ShowTaskManager() { + TaskManagerView::Show(); +} + +} // namespace browser + diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 9db0997c..8f28bb0 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1045,6 +1045,7 @@ 'browser/gtk/tabs/tab_renderer_gtk.h', 'browser/gtk/tabs/tab_strip_gtk.cc', 'browser/gtk/tabs/tab_strip_gtk.h', + 'browser/gtk/task_manager_gtk.cc', 'browser/gtk/toolbar_star_toggle_gtk.cc', 'browser/gtk/toolbar_star_toggle_gtk.h', 'browser/hang_monitor/hung_plugin_action.cc', @@ -1443,8 +1444,6 @@ 'browser/tabs/tab_strip_model_order_controller.h', 'browser/task_manager.cc', 'browser/task_manager.h', - 'browser/task_manager_linux.cc', - 'browser/task_manager_win.cc', 'browser/task_manager_resource_providers.cc', 'browser/task_manager_resource_providers.h', 'browser/theme_resources_util.cc', @@ -1662,6 +1661,7 @@ 'browser/views/tabs/tab_renderer.h', 'browser/views/tabs/tab_strip.cc', 'browser/views/tabs/tab_strip.h', + 'browser/views/task_manager_view.cc', 'browser/views/theme_helpers.cc', 'browser/views/theme_helpers.h', 'browser/views/toolbar_star_toggle.cc', diff --git a/chrome/test/test_browser_window.h b/chrome/test/test_browser_window.h index 0e25938..665fd47 100644 --- a/chrome/test/test_browser_window.h +++ b/chrome/test/test_browser_window.h @@ -50,6 +50,7 @@ class TestBrowserWindow : public BrowserWindow { virtual gfx::Rect GetRootWindowResizerRect() const { return gfx::Rect(); } virtual void ToggleBookmarkBar() {} virtual void ShowAboutChromeDialog() {} + virtual void ShowTaskManager() {} virtual void ShowBookmarkManager() {} virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {} virtual bool IsDownloadShelfVisible() const { return false; } -- cgit v1.1