Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: chrome/browser/gtk/task_manager_gtk.cc

Issue 6251001: Move chrome/browser/gtk/ to chrome/browser/ui/gtk/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/gtk/task_manager_gtk.h"
6
7 #include <gdk/gdkkeysyms.h>
8
9 #include <algorithm>
10 #include <set>
11 #include <utility>
12 #include <vector>
13
14 #include "app/l10n_util.h"
15 #include "app/menus/simple_menu_model.h"
16 #include "app/resource_bundle.h"
17 #include "base/auto_reset.h"
18 #include "base/command_line.h"
19 #include "base/logging.h"
20 #include "base/utf_string_conversions.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/defaults.h"
23 #include "chrome/browser/gtk/gtk_chrome_link_button.h"
24 #include "chrome/browser/gtk/gtk_theme_provider.h"
25 #include "chrome/browser/gtk/gtk_tree.h"
26 #include "chrome/browser/gtk/gtk_util.h"
27 #include "chrome/browser/memory_purger.h"
28 #include "chrome/browser/prefs/pref_service.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
31 #include "gfx/gtk_util.h"
32 #include "grit/app_resources.h"
33 #include "grit/chromium_strings.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35
36 #if defined(TOOLKIT_VIEWS)
37 #include "views/controls/menu/menu_2.h"
38 #else
39 #include "chrome/browser/gtk/menu_gtk.h"
40 #endif
41
42 namespace {
43
44 // The task manager window default size.
45 const int kDefaultWidth = 460;
46 const int kDefaultHeight = 270;
47
48 // The resource id for the 'End process' button.
49 const gint kTaskManagerResponseKill = 1;
50
51 // The resource id for the 'Stats for nerds' link button.
52 const gint kTaskManagerAboutMemoryLink = 2;
53
54 // The resource id for the 'Purge Memory' button
55 const gint kTaskManagerPurgeMemory = 3;
56
57 enum TaskManagerColumn {
58 kTaskManagerIcon,
59 kTaskManagerPage,
60 kTaskManagerSharedMem,
61 kTaskManagerPrivateMem,
62 kTaskManagerCPU,
63 kTaskManagerNetwork,
64 kTaskManagerProcessID,
65 kTaskManagerJavaScriptMemory,
66 kTaskManagerWebCoreImageCache,
67 kTaskManagerWebCoreScriptsCache,
68 kTaskManagerWebCoreCssCache,
69 kTaskManagerSqliteMemoryUsed,
70 kTaskManagerGoatsTeleported,
71 kTaskManagerColumnCount,
72 };
73
74 TaskManagerColumn TaskManagerResourceIDToColumnID(int id) {
75 switch (id) {
76 case IDS_TASK_MANAGER_PAGE_COLUMN:
77 return kTaskManagerPage;
78 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
79 return kTaskManagerSharedMem;
80 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
81 return kTaskManagerPrivateMem;
82 case IDS_TASK_MANAGER_CPU_COLUMN:
83 return kTaskManagerCPU;
84 case IDS_TASK_MANAGER_NET_COLUMN:
85 return kTaskManagerNetwork;
86 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
87 return kTaskManagerProcessID;
88 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
89 return kTaskManagerJavaScriptMemory;
90 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
91 return kTaskManagerWebCoreImageCache;
92 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
93 return kTaskManagerWebCoreScriptsCache;
94 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
95 return kTaskManagerWebCoreCssCache;
96 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
97 return kTaskManagerSqliteMemoryUsed;
98 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN:
99 return kTaskManagerGoatsTeleported;
100 default:
101 NOTREACHED();
102 return static_cast<TaskManagerColumn>(-1);
103 }
104 }
105
106 int TaskManagerColumnIDToResourceID(int id) {
107 switch (id) {
108 case kTaskManagerPage:
109 return IDS_TASK_MANAGER_PAGE_COLUMN;
110 case kTaskManagerSharedMem:
111 return IDS_TASK_MANAGER_SHARED_MEM_COLUMN;
112 case kTaskManagerPrivateMem:
113 return IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN;
114 case kTaskManagerCPU:
115 return IDS_TASK_MANAGER_CPU_COLUMN;
116 case kTaskManagerNetwork:
117 return IDS_TASK_MANAGER_NET_COLUMN;
118 case kTaskManagerProcessID:
119 return IDS_TASK_MANAGER_PROCESS_ID_COLUMN;
120 case kTaskManagerJavaScriptMemory:
121 return IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN;
122 case kTaskManagerWebCoreImageCache:
123 return IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN;
124 case kTaskManagerWebCoreScriptsCache:
125 return IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN;
126 case kTaskManagerWebCoreCssCache:
127 return IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN;
128 case kTaskManagerSqliteMemoryUsed:
129 return IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN;
130 case kTaskManagerGoatsTeleported:
131 return IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN;
132 default:
133 NOTREACHED();
134 return -1;
135 }
136 }
137
138 // Should be used for all gtk_tree_view functions that require a column index on
139 // input.
140 //
141 // We need colid - 1 because the gtk_tree_view function is asking for the
142 // column index, not the column id, and both kTaskManagerIcon and
143 // kTaskManagerPage are in the same column index, so all column IDs are off by
144 // one.
145 int TreeViewColumnIndexFromID(TaskManagerColumn colid) {
146 return colid - 1;
147 }
148
149 // Shows or hides a treeview column.
150 void TreeViewColumnSetVisible(GtkWidget* treeview, TaskManagerColumn colid,
151 bool visible) {
152 GtkTreeViewColumn* column = gtk_tree_view_get_column(
153 GTK_TREE_VIEW(treeview), TreeViewColumnIndexFromID(colid));
154 gtk_tree_view_column_set_visible(column, visible);
155 }
156
157 bool TreeViewColumnIsVisible(GtkWidget* treeview, TaskManagerColumn colid) {
158 GtkTreeViewColumn* column = gtk_tree_view_get_column(
159 GTK_TREE_VIEW(treeview), TreeViewColumnIndexFromID(colid));
160 return gtk_tree_view_column_get_visible(column);
161 }
162
163 void TreeViewInsertColumnWithPixbuf(GtkWidget* treeview, int resid) {
164 int colid = TaskManagerResourceIDToColumnID(resid);
165 GtkTreeViewColumn* column = gtk_tree_view_column_new();
166 gtk_tree_view_column_set_title(column,
167 l10n_util::GetStringUTF8(resid).c_str());
168 GtkCellRenderer* image_renderer = gtk_cell_renderer_pixbuf_new();
169 gtk_tree_view_column_pack_start(column, image_renderer, FALSE);
170 gtk_tree_view_column_add_attribute(column, image_renderer,
171 "pixbuf", kTaskManagerIcon);
172 GtkCellRenderer* text_renderer = gtk_cell_renderer_text_new();
173 gtk_tree_view_column_pack_start(column, text_renderer, TRUE);
174 gtk_tree_view_column_add_attribute(column, text_renderer, "text", colid);
175 gtk_tree_view_column_set_resizable(column, TRUE);
176 // This is temporary: we'll turn expanding off after getting the size.
177 gtk_tree_view_column_set_expand(column, TRUE);
178 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
179 gtk_tree_view_column_set_sort_column_id(column, colid);
180 }
181
182 // Inserts a column with a column id of |colid| and |name|.
183 void TreeViewInsertColumnWithName(GtkWidget* treeview,
184 TaskManagerColumn colid, const char* name) {
185 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
186 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), -1,
187 name, renderer,
188 "text", colid,
189 NULL);
190 GtkTreeViewColumn* column = gtk_tree_view_get_column(
191 GTK_TREE_VIEW(treeview), TreeViewColumnIndexFromID(colid));
192 gtk_tree_view_column_set_resizable(column, TRUE);
193 gtk_tree_view_column_set_sort_column_id(column, colid);
194 }
195
196 // Loads the column name from |resid| and uses the corresponding
197 // TaskManagerColumn value as the column id to insert into the treeview.
198 void TreeViewInsertColumn(GtkWidget* treeview, int resid) {
199 TreeViewInsertColumnWithName(treeview, TaskManagerResourceIDToColumnID(resid),
200 l10n_util::GetStringUTF8(resid).c_str());
201 }
202
203 // Set the current width of the column without forcing a minimum width as
204 // gtk_tree_view_column_set_fixed_width() would. This would basically be
205 // gtk_tree_view_column_set_width() except that there is no such function.
206 void TreeViewColumnSetWidth(GtkTreeViewColumn* column, gint width) {
207 column->width = width;
208 column->resized_width = width;
209 column->use_resized_width = TRUE;
210 // Needed for use_resized_width to be effective.
211 gtk_widget_queue_resize(column->tree_view);
212 }
213
214 } // namespace
215
216 class TaskManagerGtk::ContextMenuController
217 : public menus::SimpleMenuModel::Delegate {
218 public:
219 explicit ContextMenuController(TaskManagerGtk* task_manager)
220 : task_manager_(task_manager) {
221 menu_model_.reset(new menus::SimpleMenuModel(this));
222 for (int i = kTaskManagerPage; i < kTaskManagerColumnCount; i++) {
223 menu_model_->AddCheckItemWithStringId(
224 i, TaskManagerColumnIDToResourceID(i));
225 }
226 #if defined(TOOLKIT_VIEWS)
227 menu_.reset(new views::Menu2(menu_model_.get()));
228 #else
229 menu_.reset(new MenuGtk(NULL, menu_model_.get()));
230 #endif
231 }
232
233 virtual ~ContextMenuController() {}
234
235 #if defined(TOOLKIT_VIEWS)
236 void RunMenu(const gfx::Point& point) {
237 menu_->RunContextMenuAt(point);
238 }
239 #else
240 void RunMenu() {
241 menu_->PopupAsContext(gtk_get_current_event_time());
242 }
243 #endif
244
245 void Cancel() {
246 task_manager_ = NULL;
247 #if defined(TOOLKIT_VIEWS)
248 menu_->CancelMenu();
249 #else
250 menu_->Cancel();
251 #endif
252 }
253
254 private:
255 // menus::SimpleMenuModel::Delegate implementation:
256 virtual bool IsCommandIdEnabled(int command_id) const {
257 if (!task_manager_)
258 return false;
259
260 return true;
261 }
262
263 virtual bool IsCommandIdChecked(int command_id) const {
264 if (!task_manager_)
265 return false;
266
267 TaskManagerColumn colid = static_cast<TaskManagerColumn>(command_id);
268 return TreeViewColumnIsVisible(task_manager_->treeview_, colid);
269 }
270
271 virtual bool GetAcceleratorForCommandId(
272 int command_id,
273 menus::Accelerator* accelerator) {
274 return false;
275 }
276
277 virtual void ExecuteCommand(int command_id) {
278 if (!task_manager_)
279 return;
280
281 TaskManagerColumn colid = static_cast<TaskManagerColumn>(command_id);
282 bool visible = !TreeViewColumnIsVisible(task_manager_->treeview_, colid);
283 TreeViewColumnSetVisible(task_manager_->treeview_, colid, visible);
284 }
285
286 // The model and view for the right click context menu.
287 scoped_ptr<menus::SimpleMenuModel> menu_model_;
288 #if defined(TOOLKIT_VIEWS)
289 scoped_ptr<views::Menu2> menu_;
290 #else
291 scoped_ptr<MenuGtk> menu_;
292 #endif
293
294 // The TaskManager the context menu was brought up for. Set to NULL when the
295 // menu is canceled.
296 TaskManagerGtk* task_manager_;
297
298 DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
299 };
300
301 TaskManagerGtk::TaskManagerGtk()
302 : task_manager_(TaskManager::GetInstance()),
303 model_(TaskManager::GetInstance()->model()),
304 dialog_(NULL),
305 treeview_(NULL),
306 process_list_(NULL),
307 process_count_(0),
308 ignore_selection_changed_(false) {
309 Init();
310 }
311
312 // static
313 TaskManagerGtk* TaskManagerGtk::instance_ = NULL;
314
315 TaskManagerGtk::~TaskManagerGtk() {
316 model_->RemoveObserver(this);
317 task_manager_->OnWindowClosed();
318
319 gtk_accel_group_disconnect_key(accel_group_, GDK_w, GDK_CONTROL_MASK);
320 gtk_window_remove_accel_group(GTK_WINDOW(dialog_), accel_group_);
321 g_object_unref(accel_group_);
322 accel_group_ = NULL;
323
324 // Disconnect the destroy signal so it doesn't delete |this|.
325 g_signal_handler_disconnect(G_OBJECT(dialog_), destroy_handler_id_);
326 gtk_widget_destroy(dialog_);
327 }
328
329 ////////////////////////////////////////////////////////////////////////////////
330 // TaskManagerGtk, TaskManagerModelObserver implementation:
331
332 void TaskManagerGtk::OnModelChanged() {
333 // Nothing to do.
334 }
335
336 void TaskManagerGtk::OnItemsChanged(int start, int length) {
337 GtkTreeIter iter;
338 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(process_list_), &iter,
339 NULL, start);
340
341 for (int i = start; i < start + length; i++) {
342 SetRowDataFromModel(i, &iter);
343 gtk_tree_model_iter_next(GTK_TREE_MODEL(process_list_), &iter);
344 }
345 }
346
347 void TaskManagerGtk::OnItemsAdded(int start, int length) {
348 AutoReset<bool> autoreset(&ignore_selection_changed_, true);
349
350 GtkTreeIter iter;
351 if (start == 0) {
352 gtk_list_store_prepend(process_list_, &iter);
353 } else if (start >= process_count_) {
354 gtk_list_store_append(process_list_, &iter);
355 } else {
356 GtkTreeIter sibling;
357 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(process_list_), &sibling,
358 NULL, start);
359 gtk_list_store_insert_before(process_list_, &iter, &sibling);
360 }
361
362 SetRowDataFromModel(start, &iter);
363
364 for (int i = start + 1; i < start + length; i++) {
365 gtk_list_store_insert_after(process_list_, &iter, &iter);
366 SetRowDataFromModel(i, &iter);
367 }
368
369 process_count_ += length;
370 }
371
372 void TaskManagerGtk::OnItemsRemoved(int start, int length) {
373 {
374 AutoReset<bool> autoreset(&ignore_selection_changed_, true);
375
376 GtkTreeIter iter;
377 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(process_list_), &iter,
378 NULL, start);
379
380 for (int i = 0; i < length; i++) {
381 // |iter| is moved to the next valid node when the current node is
382 // removed.
383 gtk_list_store_remove(process_list_, &iter);
384 }
385
386 process_count_ -= length;
387 }
388
389 // It is possible that we have removed the current selection; run selection
390 // changed to detect that case.
391 OnSelectionChanged(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_)));
392 }
393
394 ////////////////////////////////////////////////////////////////////////////////
395 // TaskManagerGtk, public:
396
397 // static
398 void TaskManagerGtk::Show() {
399 if (instance_) {
400 // If there's a Task manager window open already, just activate it.
401 gtk_util::PresentWindow(instance_->dialog_, 0);
402 } else {
403 instance_ = new TaskManagerGtk;
404 instance_->model_->StartUpdating();
405 }
406 }
407
408 ////////////////////////////////////////////////////////////////////////////////
409 // TaskManagerGtk, private:
410
411 void TaskManagerGtk::Init() {
412 dialog_ = gtk_dialog_new_with_buttons(
413 l10n_util::GetStringUTF8(IDS_TASK_MANAGER_TITLE).c_str(),
414 // Task Manager window is shared between all browsers.
415 NULL,
416 GTK_DIALOG_NO_SEPARATOR,
417 NULL);
418
419 // Allow browser windows to go in front of the task manager dialog in
420 // metacity.
421 gtk_window_set_type_hint(GTK_WINDOW(dialog_), GDK_WINDOW_TYPE_HINT_NORMAL);
422
423 if (CommandLine::ForCurrentProcess()->HasSwitch(
424 switches::kPurgeMemoryButton)) {
425 gtk_dialog_add_button(GTK_DIALOG(dialog_),
426 l10n_util::GetStringUTF8(IDS_TASK_MANAGER_PURGE_MEMORY).c_str(),
427 kTaskManagerPurgeMemory);
428 }
429
430 if (browser_defaults::kShowCancelButtonInTaskManager) {
431 gtk_dialog_add_button(GTK_DIALOG(dialog_),
432 l10n_util::GetStringUTF8(IDS_CLOSE).c_str(),
433 GTK_RESPONSE_DELETE_EVENT);
434 }
435
436 gtk_dialog_add_button(GTK_DIALOG(dialog_),
437 l10n_util::GetStringUTF8(IDS_TASK_MANAGER_KILL).c_str(),
438 kTaskManagerResponseKill);
439
440 // The response button should not be sensitive when the dialog is first opened
441 // because the selection is initially empty.
442 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_),
443 kTaskManagerResponseKill, FALSE);
444
445 GtkWidget* link = gtk_chrome_link_button_new(
446 l10n_util::GetStringUTF8(IDS_TASK_MANAGER_ABOUT_MEMORY_LINK).c_str());
447 gtk_dialog_add_action_widget(GTK_DIALOG(dialog_), link,
448 kTaskManagerAboutMemoryLink);
449
450 // Setting the link widget to secondary positions the button on the left side
451 // of the action area (vice versa for RTL layout).
452 gtk_button_box_set_child_secondary(
453 GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), link, TRUE);
454
455 ConnectAccelerators();
456
457 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
458 gtk_util::kContentAreaSpacing);
459
460 destroy_handler_id_ = g_signal_connect(dialog_, "destroy",
461 G_CALLBACK(OnDestroyThunk), this);
462 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
463 g_signal_connect(dialog_, "button-release-event",
464 G_CALLBACK(OnButtonReleaseEventThunk), this);
465 gtk_widget_add_events(dialog_,
466 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
467
468 // Wrap the treeview widget in a scrolled window in order to have a frame.
469 GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
470 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled),
471 GTK_SHADOW_ETCHED_IN);
472 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
473 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
474
475 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), scrolled);
476
477 CreateTaskManagerTreeview();
478 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview_), TRUE);
479 g_signal_connect(treeview_, "row-activated",
480 G_CALLBACK(OnRowActivatedThunk), this);
481
482 // |selection| is owned by |treeview_|.
483 GtkTreeSelection* selection = gtk_tree_view_get_selection(
484 GTK_TREE_VIEW(treeview_));
485 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
486 g_signal_connect(selection, "changed",
487 G_CALLBACK(OnSelectionChangedThunk), this);
488
489 gtk_container_add(GTK_CONTAINER(scrolled), treeview_);
490
491 SetInitialDialogSize();
492 gtk_util::ShowDialog(dialog_);
493
494 // If the model already has resources, we need to add them before we start
495 // observing events.
496 if (model_->ResourceCount() > 0)
497 OnItemsAdded(0, model_->ResourceCount());
498
499 model_->AddObserver(this);
500 }
501
502 void TaskManagerGtk::SetInitialDialogSize() {
503 // Hook up to the realize event so we can size the page column to the
504 // size of the leftover space after packing the other columns.
505 g_signal_connect(treeview_, "realize",
506 G_CALLBACK(OnTreeViewRealizeThunk), this);
507 // If we previously saved the dialog's bounds, use them.
508 if (g_browser_process->local_state()) {
509 const DictionaryValue* placement_pref =
510 g_browser_process->local_state()->GetDictionary(
511 prefs::kTaskManagerWindowPlacement);
512 int top = 0, left = 0, bottom = 1, right = 1;
513 if (placement_pref &&
514 placement_pref->GetInteger("top", &top) &&
515 placement_pref->GetInteger("left", &left) &&
516 placement_pref->GetInteger("bottom", &bottom) &&
517 placement_pref->GetInteger("right", &right)) {
518 gtk_window_resize(GTK_WINDOW(dialog_),
519 std::max(1, right - left),
520 std::max(1, bottom - top));
521 return;
522 }
523 }
524
525 // Otherwise, just set a default size (GTK will override this if it's not
526 // large enough to hold the window's contents).
527 gtk_window_set_default_size(
528 GTK_WINDOW(dialog_), kDefaultWidth, kDefaultHeight);
529 }
530
531 void TaskManagerGtk::ConnectAccelerators() {
532 accel_group_ = gtk_accel_group_new();
533 gtk_window_add_accel_group(GTK_WINDOW(dialog_), accel_group_);
534
535 gtk_accel_group_connect(accel_group_,
536 GDK_w, GDK_CONTROL_MASK, GtkAccelFlags(0),
537 g_cclosure_new(G_CALLBACK(OnGtkAcceleratorThunk),
538 this, NULL));
539 }
540
541 void TaskManagerGtk::CreateTaskManagerTreeview() {
542 process_list_ = gtk_list_store_new(kTaskManagerColumnCount,
543 GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
544 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
545 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
546 G_TYPE_STRING);
547
548 // Support sorting on all columns.
549 process_list_sort_ = gtk_tree_model_sort_new_with_model(
550 GTK_TREE_MODEL(process_list_));
551 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
552 kTaskManagerPage,
553 ComparePage, this, NULL);
554 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
555 kTaskManagerSharedMem,
556 CompareSharedMemory, this, NULL);
557 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
558 kTaskManagerPrivateMem,
559 ComparePrivateMemory, this, NULL);
560 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
561 kTaskManagerJavaScriptMemory,
562 CompareV8Memory, this, NULL);
563 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
564 kTaskManagerCPU,
565 CompareCPU, this, NULL);
566 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
567 kTaskManagerNetwork,
568 CompareNetwork, this, NULL);
569 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
570 kTaskManagerProcessID,
571 CompareProcessID, this, NULL);
572 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
573 kTaskManagerWebCoreImageCache,
574 CompareWebCoreImageCache, this, NULL);
575 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
576 kTaskManagerWebCoreScriptsCache,
577 CompareWebCoreScriptsCache, this, NULL);
578 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
579 kTaskManagerWebCoreCssCache,
580 CompareWebCoreCssCache, this, NULL);
581 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
582 kTaskManagerSqliteMemoryUsed,
583 CompareSqliteMemoryUsed, this, NULL);
584 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(process_list_sort_),
585 kTaskManagerGoatsTeleported,
586 CompareGoatsTeleported, this, NULL);
587 treeview_ = gtk_tree_view_new_with_model(process_list_sort_);
588
589 // Insert all the columns.
590 TreeViewInsertColumnWithPixbuf(treeview_, IDS_TASK_MANAGER_PAGE_COLUMN);
591 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_SHARED_MEM_COLUMN);
592 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN);
593 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_CPU_COLUMN);
594 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_NET_COLUMN);
595 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_PROCESS_ID_COLUMN);
596 TreeViewInsertColumn(treeview_,
597 IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN);
598 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN);
599 TreeViewInsertColumn(treeview_,
600 IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN);
601 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN);
602 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN);
603 TreeViewInsertColumn(treeview_, IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN);
604
605 // Hide some columns by default.
606 TreeViewColumnSetVisible(treeview_, kTaskManagerSharedMem, false);
607 TreeViewColumnSetVisible(treeview_, kTaskManagerProcessID, false);
608 TreeViewColumnSetVisible(treeview_, kTaskManagerJavaScriptMemory, false);
609 TreeViewColumnSetVisible(treeview_, kTaskManagerWebCoreImageCache, false);
610 TreeViewColumnSetVisible(treeview_, kTaskManagerWebCoreScriptsCache, false);
611 TreeViewColumnSetVisible(treeview_, kTaskManagerWebCoreCssCache, false);
612 TreeViewColumnSetVisible(treeview_, kTaskManagerSqliteMemoryUsed, false);
613 TreeViewColumnSetVisible(treeview_, kTaskManagerGoatsTeleported, false);
614
615 g_object_unref(process_list_);
616 g_object_unref(process_list_sort_);
617 }
618
619 bool IsSharedByGroup(int col_id) {
620 switch (col_id) {
621 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
622 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
623 case IDS_TASK_MANAGER_CPU_COLUMN:
624 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
625 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
626 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
627 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
628 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
629 return true;
630 default:
631 return false;
632 }
633 }
634
635 std::string TaskManagerGtk::GetModelText(int row, int col_id) {
636 if (IsSharedByGroup(col_id) && !model_->IsResourceFirstInGroup(row))
637 return std::string();
638
639 switch (col_id) {
640 case IDS_TASK_MANAGER_PAGE_COLUMN: // Process
641 return UTF16ToUTF8(model_->GetResourceTitle(row));
642
643 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: // Memory
644 return UTF16ToUTF8(model_->GetResourcePrivateMemory(row));
645
646 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: // Memory
647 return UTF16ToUTF8(model_->GetResourceSharedMemory(row));
648
649 case IDS_TASK_MANAGER_CPU_COLUMN: // CPU
650 return UTF16ToUTF8(model_->GetResourceCPUUsage(row));
651
652 case IDS_TASK_MANAGER_NET_COLUMN: // Net
653 return UTF16ToUTF8(model_->GetResourceNetworkUsage(row));
654
655 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: // Process ID
656 return UTF16ToUTF8(model_->GetResourceProcessId(row));
657
658 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
659 return UTF16ToUTF8(model_->GetResourceV8MemoryAllocatedSize(row));
660
661 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
662 return UTF16ToUTF8(model_->GetResourceWebCoreImageCacheSize(row));
663
664 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
665 return UTF16ToUTF8(model_->GetResourceWebCoreScriptsCacheSize(row));
666
667 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
668 return UTF16ToUTF8(model_->GetResourceWebCoreCSSCacheSize(row));
669
670 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
671 return UTF16ToUTF8(model_->GetResourceSqliteMemoryUsed(row));
672
673 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: // Goats Teleported!
674 return UTF16ToUTF8(model_->GetResourceGoatsTeleported(row));
675
676 default:
677 NOTREACHED();
678 return std::string();
679 }
680 }
681
682 GdkPixbuf* TaskManagerGtk::GetModelIcon(int row) {
683 SkBitmap icon = model_->GetResourceIcon(row);
684 if (icon.pixelRef() ==
685 ResourceBundle::GetSharedInstance().GetBitmapNamed(
686 IDR_DEFAULT_FAVICON)->pixelRef()) {
687 return static_cast<GdkPixbuf*>(g_object_ref(
688 GtkThemeProvider::GetDefaultFavicon(true)));
689 }
690
691 return gfx::GdkPixbufFromSkBitmap(&icon);
692 }
693
694 void TaskManagerGtk::SetRowDataFromModel(int row, GtkTreeIter* iter) {
695 GdkPixbuf* icon = GetModelIcon(row);
696 std::string page = GetModelText(row, IDS_TASK_MANAGER_PAGE_COLUMN);
697 std::string shared_mem = GetModelText(
698 row, IDS_TASK_MANAGER_SHARED_MEM_COLUMN);
699 std::string priv_mem = GetModelText(row, IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN);
700 std::string cpu = GetModelText(row, IDS_TASK_MANAGER_CPU_COLUMN);
701 std::string net = GetModelText(row, IDS_TASK_MANAGER_NET_COLUMN);
702 std::string procid = GetModelText(row, IDS_TASK_MANAGER_PROCESS_ID_COLUMN);
703
704 // Querying the renderer metrics is slow as it has to do IPC, so only do it
705 // when the columns are visible.
706 std::string javascript_memory;
707 if (TreeViewColumnIsVisible(treeview_, kTaskManagerJavaScriptMemory))
708 javascript_memory = GetModelText(
709 row, IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN);
710 std::string wk_img_cache;
711 if (TreeViewColumnIsVisible(treeview_, kTaskManagerWebCoreImageCache))
712 wk_img_cache = GetModelText(
713 row, IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN);
714 std::string wk_scripts_cache;
715 if (TreeViewColumnIsVisible(treeview_, kTaskManagerWebCoreScriptsCache))
716 wk_scripts_cache = GetModelText(
717 row, IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN);
718 std::string wk_css_cache;
719 if (TreeViewColumnIsVisible(treeview_, kTaskManagerWebCoreCssCache))
720 wk_css_cache = GetModelText(
721 row, IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN);
722 std::string sqlite_memory;
723 if (TreeViewColumnIsVisible(treeview_, kTaskManagerSqliteMemoryUsed))
724 sqlite_memory = GetModelText(
725 row, IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN);
726
727 std::string goats = GetModelText(
728 row, IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN);
729 gtk_list_store_set(process_list_, iter,
730 kTaskManagerIcon, icon,
731 kTaskManagerPage, page.c_str(),
732 kTaskManagerSharedMem, shared_mem.c_str(),
733 kTaskManagerPrivateMem, priv_mem.c_str(),
734 kTaskManagerCPU, cpu.c_str(),
735 kTaskManagerNetwork, net.c_str(),
736 kTaskManagerProcessID, procid.c_str(),
737 kTaskManagerJavaScriptMemory, javascript_memory.c_str(),
738 kTaskManagerWebCoreImageCache, wk_img_cache.c_str(),
739 kTaskManagerWebCoreScriptsCache, wk_scripts_cache.c_str(),
740 kTaskManagerWebCoreCssCache, wk_css_cache.c_str(),
741 kTaskManagerSqliteMemoryUsed, sqlite_memory.c_str(),
742 kTaskManagerGoatsTeleported, goats.c_str(),
743 -1);
744 g_object_unref(icon);
745 }
746
747 void TaskManagerGtk::KillSelectedProcesses() {
748 GtkTreeSelection* selection = gtk_tree_view_get_selection(
749 GTK_TREE_VIEW(treeview_));
750
751 GtkTreeModel* model;
752 GList* paths = gtk_tree_selection_get_selected_rows(selection, &model);
753 for (GList* item = paths; item; item = item->next) {
754 GtkTreePath* path = gtk_tree_model_sort_convert_path_to_child_path(
755 GTK_TREE_MODEL_SORT(process_list_sort_),
756 reinterpret_cast<GtkTreePath*>(item->data));
757 int row = gtk_tree::GetRowNumForPath(path);
758 gtk_tree_path_free(path);
759 task_manager_->KillProcess(row);
760 }
761 g_list_foreach(paths, reinterpret_cast<GFunc>(gtk_tree_path_free), NULL);
762 g_list_free(paths);
763 }
764
765 #if defined(TOOLKIT_VIEWS)
766 void TaskManagerGtk::ShowContextMenu(const gfx::Point& point) {
767 if (!menu_controller_.get())
768 menu_controller_.reset(new ContextMenuController(this));
769
770 menu_controller_->RunMenu(point);
771 }
772 #else
773 void TaskManagerGtk::ShowContextMenu() {
774 if (!menu_controller_.get())
775 menu_controller_.reset(new ContextMenuController(this));
776
777 menu_controller_->RunMenu();
778 }
779 #endif
780
781 void TaskManagerGtk::OnLinkActivated() {
782 task_manager_->OpenAboutMemory();
783 }
784
785 gint TaskManagerGtk::CompareImpl(GtkTreeModel* model, GtkTreeIter* a,
786 GtkTreeIter* b, int id) {
787 int row1 = gtk_tree::GetRowNumForIter(model, b);
788 int row2 = gtk_tree::GetRowNumForIter(model, a);
789
790 // When sorting by non-grouped attributes (e.g., Network), just do a normal
791 // sort.
792 if (!IsSharedByGroup(id))
793 return model_->CompareValues(row1, row2, id);
794
795 // Otherwise, make sure grouped resources are shown together.
796 std::pair<int, int> group_range1 = model_->GetGroupRangeForResource(row1);
797 std::pair<int, int> group_range2 = model_->GetGroupRangeForResource(row2);
798
799 if (group_range1 == group_range2) {
800 // Sort within groups.
801 // We want the first-in-group row at the top, whether we are sorting up or
802 // down.
803 GtkSortType sort_type;
804 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(process_list_sort_),
805 NULL, &sort_type);
806 if (row1 == group_range1.first)
807 return sort_type == GTK_SORT_ASCENDING ? -1 : 1;
808 if (row2 == group_range2.first)
809 return sort_type == GTK_SORT_ASCENDING ? 1 : -1;
810
811 return model_->CompareValues(row1, row2, id);
812 } else {
813 // Sort between groups.
814 // Compare by the first-in-group rows so that the groups will stay together.
815 return model_->CompareValues(group_range1.first, group_range2.first, id);
816 }
817 }
818
819 void TaskManagerGtk::OnDestroy(GtkWidget* dialog) {
820 instance_ = NULL;
821 delete this;
822 }
823
824 void TaskManagerGtk::OnResponse(GtkWidget* dialog, gint response_id) {
825 if (response_id == GTK_RESPONSE_DELETE_EVENT) {
826 // Store the dialog's size so we can restore it the next time it's opened.
827 if (g_browser_process->local_state()) {
828 gfx::Rect dialog_bounds = gtk_util::GetDialogBounds(GTK_WIDGET(dialog));
829
830 DictionaryValue* placement_pref =
831 g_browser_process->local_state()->GetMutableDictionary(
832 prefs::kTaskManagerWindowPlacement);
833 // Note that we store left/top for consistency with Windows, but that we
834 // *don't* restore them.
835 placement_pref->SetInteger("left", dialog_bounds.x());
836 placement_pref->SetInteger("top", dialog_bounds.y());
837 placement_pref->SetInteger("right", dialog_bounds.right());
838 placement_pref->SetInteger("bottom", dialog_bounds.bottom());
839 placement_pref->SetBoolean("maximized", false);
840 }
841
842 instance_ = NULL;
843 delete this;
844 } else if (response_id == kTaskManagerResponseKill) {
845 KillSelectedProcesses();
846 } else if (response_id == kTaskManagerAboutMemoryLink) {
847 OnLinkActivated();
848 } else if (response_id == kTaskManagerPurgeMemory) {
849 MemoryPurger::PurgeAll();
850 }
851 }
852
853 void TaskManagerGtk::OnTreeViewRealize(GtkTreeView* treeview) {
854 // Four columns show by default: the page column, the memory column, the
855 // CPU column, and the network column. Initially we set the page column to
856 // take all the extra space, with the other columns being sized to fit the
857 // column names. Here we turn off the expand property of the first column
858 // (to make the table behave sanely when the user resizes columns) and set
859 // the effective sizes of all four default columns to the automatically
860 // chosen size before any rows are added. This causes them to stay at that
861 // size even if the data would overflow, preventing a horizontal scroll
862 // bar from appearing due to the row data.
863 const TaskManagerColumn dfl_columns[] = {kTaskManagerNetwork, kTaskManagerCPU,
864 kTaskManagerPrivateMem};
865 GtkTreeViewColumn* column = NULL;
866 gint width;
867 for (size_t i = 0; i < arraysize(dfl_columns); ++i) {
868 column = gtk_tree_view_get_column(treeview,
869 TreeViewColumnIndexFromID(dfl_columns[i]));
870 width = gtk_tree_view_column_get_width(column);
871 TreeViewColumnSetWidth(column, width);
872 }
873 // Do the page column separately since it's a little different.
874 column = gtk_tree_view_get_column(treeview,
875 TreeViewColumnIndexFromID(kTaskManagerPage));
876 width = gtk_tree_view_column_get_width(column);
877 // Turn expanding back off to make resizing columns behave sanely.
878 gtk_tree_view_column_set_expand(column, FALSE);
879 TreeViewColumnSetWidth(column, width);
880 }
881
882 void TaskManagerGtk::OnSelectionChanged(GtkTreeSelection* selection) {
883 if (ignore_selection_changed_)
884 return;
885 AutoReset<bool> autoreset(&ignore_selection_changed_, true);
886
887 // The set of groups that should be selected.
888 std::set<std::pair<int, int> > ranges;
889 bool selection_contains_browser_process = false;
890
891 GtkTreeModel* model;
892 GList* paths = gtk_tree_selection_get_selected_rows(selection, &model);
893 for (GList* item = paths; item; item = item->next) {
894 GtkTreePath* path = gtk_tree_model_sort_convert_path_to_child_path(
895 GTK_TREE_MODEL_SORT(process_list_sort_),
896 reinterpret_cast<GtkTreePath*>(item->data));
897 int row = gtk_tree::GetRowNumForPath(path);
898 gtk_tree_path_free(path);
899 if (task_manager_->IsBrowserProcess(row))
900 selection_contains_browser_process = true;
901 ranges.insert(model_->GetGroupRangeForResource(row));
902 }
903 g_list_foreach(paths, reinterpret_cast<GFunc>(gtk_tree_path_free), NULL);
904 g_list_free(paths);
905
906 for (std::set<std::pair<int, int> >::iterator iter = ranges.begin();
907 iter != ranges.end(); ++iter) {
908 for (int i = 0; i < iter->second; ++i) {
909 GtkTreePath* child_path = gtk_tree_path_new_from_indices(iter->first + i,
910 -1);
911 GtkTreePath* sort_path = gtk_tree_model_sort_convert_child_path_to_path(
912 GTK_TREE_MODEL_SORT(process_list_sort_), child_path);
913 gtk_tree_selection_select_path(selection, sort_path);
914 gtk_tree_path_free(child_path);
915 gtk_tree_path_free(sort_path);
916 }
917 }
918
919 bool sensitive = (paths != NULL) && !selection_contains_browser_process;
920 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_),
921 kTaskManagerResponseKill, sensitive);
922 }
923
924 void TaskManagerGtk::OnRowActivated(GtkWidget* widget,
925 GtkTreePath* path,
926 GtkTreeViewColumn* column) {
927 GtkTreePath* child_path = gtk_tree_model_sort_convert_path_to_child_path(
928 GTK_TREE_MODEL_SORT(process_list_sort_), path);
929 int row = gtk_tree::GetRowNumForPath(child_path);
930 gtk_tree_path_free(child_path);
931 task_manager_->ActivateProcess(row);
932 }
933
934 gboolean TaskManagerGtk::OnButtonReleaseEvent(GtkWidget* widget,
935 GdkEventButton* event) {
936 if (event->button == 3) {
937 #if defined(TOOLKIT_VIEWS)
938 gfx::Point pt(event->x_root, event->y_root);
939 ShowContextMenu(pt);
940 #else
941 ShowContextMenu();
942 #endif
943 }
944
945 return FALSE;
946 }
947
948 gboolean TaskManagerGtk::OnGtkAccelerator(GtkAccelGroup* accel_group,
949 GObject* acceleratable,
950 guint keyval,
951 GdkModifierType modifier) {
952 if (keyval == GDK_w && modifier == GDK_CONTROL_MASK) {
953 // The GTK_RESPONSE_DELETE_EVENT response must be sent before the widget
954 // is destroyed. The deleted object will receive gtk signals otherwise.
955 gtk_dialog_response(GTK_DIALOG(dialog_), GTK_RESPONSE_DELETE_EVENT);
956 }
957
958 return TRUE;
959 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/task_manager_gtk.h ('k') | chrome/browser/gtk/theme_install_bubble_view_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698