diff options
Diffstat (limited to 'chrome/browser/views/task_manager_view.cc')
-rw-r--r-- | chrome/browser/views/task_manager_view.cc | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/chrome/browser/views/task_manager_view.cc b/chrome/browser/views/task_manager_view.cc new file mode 100644 index 0000000..04590f1 --- /dev/null +++ b/chrome/browser/views/task_manager_view.cc @@ -0,0 +1,683 @@ +// Copyright (c) 2010 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/memory_purger.h" +#include "chrome/browser/pref_service.h" +#include "chrome/browser/views/browser_dialogs.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.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; + +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// TaskManagerTableModel class +//////////////////////////////////////////////////////////////////////////////// + +class TaskManagerTableModel : public views::GroupTableModel, + public TaskManagerModelObserver { + public: + explicit TaskManagerTableModel(TaskManagerModel* model) + : model_(model), + observer_(NULL) { + model_->AddObserver(this); + } + + ~TaskManagerTableModel() { + model_->RemoveObserver(this); + } + + // 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: + 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 IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: // Goats Teleported! + return model_->GetResourceGoatsTeleported(row); + + case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceWebCoreImageCacheSize(row); + + case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceWebCoreScriptsCacheSize(row); + + case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceWebCoreCSSCacheSize(row); + + case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceSqliteMemoryUsed(row); + + case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: + if (!model_->IsResourceFirstInGroup(row)) + return std::wstring(); + return model_->GetResourceV8MemoryAllocatedSize(row); + + default: + NOTREACHED(); + return std::wstring(); + } +} + +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(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, const views::Event& event); + + // 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 views::View* GetContentsView(); + + // views::TableViewObserver implementation. + virtual void OnSelectionChanged(); + virtual void OnDoubleClick(); + virtual void OnKeyDown(base::KeyboardCode 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, + const gfx::Point& p, + 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* purge_memory_button_; + 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<TableColumn> columns_; + + scoped_ptr<TaskManagerTableModel> 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() + : purge_memory_button_(NULL), + 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); +} + +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; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back(TableColumn(IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN, + TableColumn::RIGHT, -1, 0)); + columns_.back().sortable = true; + columns_.push_back( + TableColumn(IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_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); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN, + false); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN, + false); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN, + false); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN, + false); + tab_table_->SetColumnVisibility( + IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN, false); + tab_table_->SetColumnVisibility(IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN, + false); + + UpdateStatsCounters(); + tab_table_->SetObserver(this); + tab_table_->SetContextMenuController(this); + SetContextMenuController(this); + // If we're running with --purge-memory-button, add a "Purge memory" button. + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kPurgeMemoryButton)) { + purge_memory_button_ = new views::NativeButton(this, + l10n_util::GetString(IDS_TASK_MANAGER_PURGE_MEMORY)); + } + kill_button_ = new views::NativeButton( + this, l10n_util::GetString(IDS_TASK_MANAGER_KILL)); + kill_button_->AddAccelerator(views::Accelerator(base::VKEY_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(about_memory_link_); + if (purge_memory_button_) + parent->AddChildView(purge_memory_button_); + parent->AddChildView(kill_button_); + AddChildView(tab_table_); + } else { + parent->RemoveChildView(kill_button_); + if (purge_memory_button_) + parent->RemoveChildView(purge_memory_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); + + if (purge_memory_button_) { + size = purge_memory_button_->GetPreferredSize(); + purge_memory_button_->SetBounds( + kill_button_->x() - size.width() - kUnrelatedControlHorizontalSpacing, + y_buttons, size.width(), size.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, const views::Event& event) { + if (purge_memory_button_ && (sender == purge_memory_button_)) { + MemoryPurger::PurgeAll(); + } else { + DCHECK_EQ(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(); +} + +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(base::KeyboardCode keycode) { + if (keycode == base::VKEY_RETURN) + ActivateFocusedTab(); +} + +// views::LinkController implementation +void TaskManagerView::LinkActivated(views::Link* source, int event_flags) { + DCHECK(source == about_memory_link_); + task_manager_->OpenAboutMemory(); +} + +void TaskManagerView::ShowContextMenu(views::View* source, + const gfx::Point& p, + bool is_mouse_gesture) { + UpdateStatsCounters(); + scoped_ptr<views::Menu> menu(views::Menu::Create( + this, views::Menu::TOPLEFT, source->GetWidget()->GetNativeView())); + for (std::vector<TableColumn>::iterator i = + columns_.begin(); i != columns_.end(); ++i) { + menu->AppendMenuItem(i->id, i->title, views::Menu::CHECKBOX); + } + menu->RunMenuAt(p.x(), p.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<wchar_t*>(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 |