summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/hung_renderer_dialog_gtk.cc
diff options
context:
space:
mode:
authortc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-08 00:12:38 +0000
committertc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-08 00:12:38 +0000
commit3e20897713d29f8fd9031347db8153300caf6dbd (patch)
treec84942850fd33d23179ac17d99ec7547effb6367 /chrome/browser/gtk/hung_renderer_dialog_gtk.cc
parentee80b0759ec23970dd3a3d3ec237c437c2f0769e (diff)
downloadchromium_src-3e20897713d29f8fd9031347db8153300caf6dbd.zip
chromium_src-3e20897713d29f8fd9031347db8153300caf6dbd.tar.gz
chromium_src-3e20897713d29f8fd9031347db8153300caf6dbd.tar.bz2
Add hung renderer dialog on linux. Pretty much just follow the
windows view code and do the same thing. BUG=11083 Review URL: http://codereview.chromium.org/115109 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15602 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk/hung_renderer_dialog_gtk.cc')
-rw-r--r--chrome/browser/gtk/hung_renderer_dialog_gtk.cc215
1 files changed, 215 insertions, 0 deletions
diff --git a/chrome/browser/gtk/hung_renderer_dialog_gtk.cc b/chrome/browser/gtk/hung_renderer_dialog_gtk.cc
new file mode 100644
index 0000000..682ab0d
--- /dev/null
+++ b/chrome/browser/gtk/hung_renderer_dialog_gtk.cc
@@ -0,0 +1,215 @@
+// 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/hung_renderer_dialog.h"
+
+#include <gtk/gtk.h>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/process_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/common/gtk_util.h"
+#include "chrome/common/logging_chrome.h"
+#include "chrome/common/result_codes.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// A wrapper class that represents the Gtk dialog.
+class HungRendererDialogGtk {
+ public:
+ HungRendererDialogGtk();
+ void ShowForTabContents(TabContents* hung_contents);
+ void EndForTabContents(TabContents* hung_contents);
+
+ private:
+ // The GtkTreeView column ids.
+ enum {
+ COL_FAVICON,
+ COL_TITLE,
+ COL_COUNT,
+ };
+
+ // Create the gtk dialog and add the widgets.
+ void Init();
+
+ static void OnDialogResponseThunk(GtkDialog* dialog, gint response_id,
+ HungRendererDialogGtk* dialog_gtk) {
+ dialog_gtk->OnDialogResponse(response_id);
+ }
+ void OnDialogResponse(gint response_id);
+
+ GtkDialog* dialog_;
+ GtkListStore* model_;
+ TabContents* contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(HungRendererDialogGtk);
+};
+
+// We only support showing one of these at a time per app.
+HungRendererDialogGtk* g_instance = NULL;
+
+// The response ID for the "Kill pages" button. Anything positive should be
+// fine (the built in GtkResponseTypes are negative numbers).
+const int kKillPagesButtonResponse = 1;
+
+HungRendererDialogGtk::HungRendererDialogGtk()
+ : dialog_(NULL), model_(NULL), contents_(NULL) {
+ Init();
+}
+
+void HungRendererDialogGtk::Init() {
+ dialog_ = GTK_DIALOG(gtk_dialog_new_with_buttons(
+ l10n_util::GetStringUTF8(IDS_PRODUCT_NAME).c_str(),
+ NULL, // No parent because tabs can span multiple windows.
+ GTK_DIALOG_NO_SEPARATOR,
+ l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_END).c_str(),
+ kKillPagesButtonResponse,
+ l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_WAIT).c_str(),
+ GTK_RESPONSE_OK,
+ NULL));
+ gtk_dialog_set_default_response(dialog_, GTK_RESPONSE_OK);
+ g_signal_connect(dialog_, "response", G_CALLBACK(OnDialogResponseThunk),
+ this);
+
+ // We have an hbox with the frozen icon on the left. On the right,
+ // we have a vbox with the unresponsive text on top and a table of
+ // tabs on bottom.
+ // ·-----------------------------------·
+ // |·---------------------------------·|
+ // ||·----·|·------------------------·||
+ // |||icon||| |||
+ // ||·----·|| The folowing page(s).. |||
+ // || || |||
+ // || ||------------------------|||
+ // || || table of tabs |||
+ // || |·------------------------·||
+ // |·---------------------------------·|
+ // | |
+ // | kill button wait button|
+ // ·-----------------------------------·
+ GtkWidget* contents_vbox = dialog_->vbox;
+ gtk_container_set_border_width(GTK_CONTAINER(contents_vbox), 12);
+
+ GtkWidget* hbox = gtk_hbox_new(false, 12);
+ gtk_box_pack_start(GTK_BOX(contents_vbox), hbox, TRUE, TRUE, 0);
+
+ // Wrap the icon in a vbox so it stays top aligned.
+ GtkWidget* icon_vbox = gtk_vbox_new(false, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), icon_vbox, FALSE, FALSE, 0);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ GdkPixbuf* icon_pixbuf = rb.GetPixbufNamed(IDR_FROZEN_TAB_ICON);
+ GtkWidget* icon = gtk_image_new_from_pixbuf(icon_pixbuf);
+ gtk_box_pack_start(GTK_BOX(icon_vbox), icon, FALSE, FALSE, 0);
+
+ GtkWidget* vbox = gtk_vbox_new(false, 6);
+ gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
+
+ GtkWidget* text = gtk_label_new(
+ l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER).c_str());
+ gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, FALSE, 0);
+
+ GtkWidget* scroll_list = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_list),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_box_pack_start(GTK_BOX(vbox), scroll_list, TRUE, TRUE, 0);
+
+ // The list of hung tabs is GtkTreeView with a GtkListStore as the model.
+ model_ = gtk_list_store_new(COL_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING);
+ GtkWidget* tree_view = gtk_tree_view_new_with_model(
+ GTK_TREE_MODEL(model_));
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
+ GtkTreeViewColumn* column = gtk_tree_view_column_new();
+ GtkCellRenderer* renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute(column ,renderer, "pixbuf", COL_FAVICON);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(column ,renderer, "text", COL_TITLE);
+
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
+ gtk_container_add(GTK_CONTAINER(scroll_list), tree_view);
+}
+
+void HungRendererDialogGtk::ShowForTabContents(TabContents* hung_contents) {
+ DCHECK(hung_contents && dialog_);
+ contents_ = hung_contents;
+ gtk_list_store_clear(model_);
+
+ GtkTreeIter tree_iter;
+ for (TabContentsIterator it; !it.done(); ++it) {
+ if (it->process() == hung_contents->process()) {
+ gtk_list_store_append(model_, &tree_iter);
+ std::string title = UTF16ToUTF8(it->GetTitle());
+ if (title.empty())
+ title = l10n_util::GetStringUTF8(IDS_TAB_UNTITLED_TITLE);
+ SkBitmap favicon = it->GetFavIcon();
+
+ gtk_list_store_set(model_, &tree_iter,
+ COL_FAVICON, favicon.width() > 0
+ ? gfx::GdkPixbufFromSkBitmap(&favicon)
+ : NULL,
+ COL_TITLE, title.c_str(),
+ -1);
+ }
+ }
+ gtk_widget_show_all(GTK_WIDGET(dialog_));
+}
+
+void HungRendererDialogGtk::EndForTabContents(TabContents* contents) {
+ DCHECK(contents);
+ if (contents_ && contents_->process() == contents->process()) {
+ gtk_widget_hide(GTK_WIDGET(dialog_));
+ // Since we're closing, we no longer need this TabContents.
+ contents_ = NULL;
+ }
+}
+
+// When the user clicks a button on the dialog or closes the dialog, this
+// callback is called.
+void HungRendererDialogGtk::OnDialogResponse(gint response_id) {
+ DCHECK(g_instance == this);
+ switch (response_id) {
+ case kKillPagesButtonResponse:
+ // Kill the process.
+ base::KillProcess(contents_->process()->process().handle(),
+ ResultCodes::HUNG, false);
+ break;
+
+ case GTK_RESPONSE_OK:
+ case GTK_RESPONSE_DELETE_EVENT:
+ // Start waiting again for responsiveness.
+ if (contents_ && contents_->render_view_host())
+ contents_->render_view_host()->RestartHangMonitorTimeout();
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(dialog_));
+ delete g_instance;
+ g_instance = NULL;
+}
+
+} // namespace
+
+
+// static
+void HungRendererDialog::ShowForTabContents(TabContents* contents) {
+ if (!logging::DialogsAreSuppressed()) {
+ if (!g_instance)
+ g_instance = new HungRendererDialogGtk();
+ g_instance->ShowForTabContents(contents);
+ }
+}
+
+// static
+void HungRendererDialog::HideForTabContents(TabContents* contents) {
+ if (!logging::DialogsAreSuppressed() && g_instance)
+ g_instance->EndForTabContents(contents);
+}