summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 18:45:56 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 18:45:56 +0000
commit7b9627d188d04b224f972fae709e7cb4f61ae504 (patch)
tree4d37368f881c9dae023e5172013e87f0b7c58676
parent72baf67602ab1dbf95c34a5d8301e0ac5f8b8b41 (diff)
downloadchromium_src-7b9627d188d04b224f972fae709e7cb4f61ae504.zip
chromium_src-7b9627d188d04b224f972fae709e7cb4f61ae504.tar.gz
chromium_src-7b9627d188d04b224f972fae709e7cb4f61ae504.tar.bz2
Render a "sad tab" on tab crash.
Uses the NotificationRegistrar to notice TAB_CONTENTS_[DIS]CONNECTED events. When it disconnects, add a SadTabGtk to the TabContentsView. Delete it when the tab contents reconnects. BUG=http://www.crbug.com/11081 TEST=Open http://about:crash. Verify that the sad tab renders properly. Navigate to another page to make sure the SadTabGtk is correctly replaced with a new RenderWidgetHostViewGtk. Review URL: http://codereview.chromium.org/111003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15435 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc7
-rw-r--r--chrome/browser/gtk/sad_tab_gtk.cc148
-rw-r--r--chrome/browser/gtk/sad_tab_gtk.h51
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.cc62
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.h21
-rw-r--r--chrome/browser/views/sad_tab_view.h9
-rw-r--r--chrome/chrome.gyp2
8 files changed, 277 insertions, 27 deletions
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index dcc8c98..a1ded9e 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -213,9 +213,10 @@ gboolean HandleCustomAccelerator(guint keyval, GdkModifierType modifier,
gboolean OnKeyPress(GtkWindow* window, GdkEventKey* event, Browser* browser) {
TabContents* current_tab_contents =
browser->tabstrip_model()->GetSelectedTabContents();
- // If there is no current tab contents or it is not focused then let the
- // default GtkWindow key handler run.
- if (!current_tab_contents ||
+ // If there is no current tab contents or its view is gone (if the renderview
+ // crashed) or it is not focused then let the default GtkWindow key handler
+ // run.
+ if (!current_tab_contents || !current_tab_contents->GetContentNativeView() ||
!gtk_widget_is_focus(current_tab_contents->GetContentNativeView())) {
return HandleCustomAccelerator(event->keyval,
static_cast<GdkModifierType>(event->state), browser);
diff --git a/chrome/browser/gtk/sad_tab_gtk.cc b/chrome/browser/gtk/sad_tab_gtk.cc
new file mode 100644
index 0000000..594b2ad
--- /dev/null
+++ b/chrome/browser/gtk/sad_tab_gtk.cc
@@ -0,0 +1,148 @@
+// 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/gtk/sad_tab_gtk.h"
+
+#include <string>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/gfx/size.h"
+#include "base/lazy_instance.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils.h"
+#include "skia/include/SkGradientShader.h"
+
+namespace {
+
+// The y offset from the center at which to paint the icon.
+const int kSadTabOffset = -64;
+// The spacing between the icon and the title.
+const int kIconTitleSpacing = 20;
+// The spacing between the title and the message.
+const int kTitleMessageSpacing = 15;
+const SkColor kTitleTextColor = SK_ColorWHITE;
+const SkColor kMessageTextColor = SK_ColorWHITE;
+const SkColor kBackgroundColor = SkColorSetRGB(35, 48, 64);
+const SkColor kBackgroundEndColor = SkColorSetRGB(35, 48, 64);
+
+struct SadTabGtkConstants {
+ SadTabGtkConstants()
+ : sad_tab_bitmap(
+ ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SAD_TAB)),
+ title_font(
+ ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::BaseFont).DeriveFont(2, ChromeFont::BOLD)),
+ message_font(
+ ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::BaseFont).DeriveFont(1)),
+ title(l10n_util::GetString(IDS_SAD_TAB_TITLE)),
+ message(l10n_util::GetString(IDS_SAD_TAB_MESSAGE)) {}
+
+ const SkBitmap* sad_tab_bitmap;
+ ChromeFont title_font;
+ ChromeFont message_font;
+ std::wstring title;
+ std::wstring message;
+};
+
+base::LazyInstance<SadTabGtkConstants>
+ g_sad_tab_constants(base::LINKER_INITIALIZED);
+
+} // namespace
+
+SadTabGtk::SadTabGtk()
+ : width_(0),
+ height_(0),
+ title_y_(0),
+ message_y_(0),
+ widget_(gtk_drawing_area_new()) {
+ gtk_widget_set_double_buffered(widget_.get(), FALSE);
+ g_signal_connect(widget_.get(), "expose-event",
+ G_CALLBACK(OnExposeThunk), this);
+ g_signal_connect(widget_.get(), "configure-event",
+ G_CALLBACK(OnConfigureThunk), this);
+}
+
+SadTabGtk::~SadTabGtk() {
+ widget_.Destroy();
+}
+
+// static
+gboolean SadTabGtk::OnExposeThunk(GtkWidget* widget,
+ GdkEventExpose* event,
+ const SadTabGtk* sad_tab) {
+ return sad_tab->OnExpose(widget, event);
+}
+
+gboolean SadTabGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event) const {
+ ChromeCanvasPaint canvas(event);
+ SkPaint paint;
+ paint.setShader(skia::CreateGradientShader(0, height_,
+ kBackgroundColor,
+ kBackgroundEndColor))->safeUnref();
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas.drawRectCoords(0, 0,
+ SkIntToScalar(width_),
+ SkIntToScalar(height_),
+ paint);
+
+ const SadTabGtkConstants& sad_tab_constants =
+ g_sad_tab_constants.Get();
+
+ // Paint the sad tab icon.
+ canvas.DrawBitmapInt(*sad_tab_constants.sad_tab_bitmap,
+ icon_bounds_.x(),
+ icon_bounds_.y());
+
+ // Paint the "Aw, snap!"
+ canvas.DrawStringInt(sad_tab_constants.title,
+ sad_tab_constants.title_font,
+ kTitleTextColor,
+ 0,
+ title_y_,
+ width_,
+ sad_tab_constants.title_font.height(),
+ ChromeCanvas::TEXT_ALIGN_CENTER);
+
+ // Paint the explanatory message.
+ canvas.DrawStringInt(sad_tab_constants.message,
+ sad_tab_constants.message_font,
+ kMessageTextColor,
+ 0,
+ message_y_,
+ width_,
+ sad_tab_constants.message_font.height(),
+ ChromeCanvas::TEXT_ALIGN_CENTER);
+ return TRUE;
+}
+
+// static
+gboolean SadTabGtk::OnConfigureThunk(GtkWidget* widget,
+ GdkEventConfigure* event,
+ SadTabGtk* sad_tab) {
+ return sad_tab->OnConfigure(widget, event);
+}
+
+gboolean SadTabGtk::OnConfigure(GtkWidget* widget, GdkEventConfigure* event) {
+ const SadTabGtkConstants& sad_tab_constants =
+ g_sad_tab_constants.Get();
+ width_ = event->width;
+ height_= event->height;
+ int icon_width = sad_tab_constants.sad_tab_bitmap->width();
+ int icon_height = sad_tab_constants.sad_tab_bitmap->height();
+ int icon_x = (event->width - icon_width) / 2;
+ int icon_y = ((event->height - icon_height) / 2) + kSadTabOffset;
+ icon_bounds_.SetRect(icon_x, icon_y, icon_width, icon_height);
+
+ title_y_ =
+ icon_bounds_.bottom() + kIconTitleSpacing;
+ int title_height = sad_tab_constants.title_font.height();
+ message_y_ =
+ title_y_ + title_height + kTitleMessageSpacing;
+ return TRUE;
+}
diff --git a/chrome/browser/gtk/sad_tab_gtk.h b/chrome/browser/gtk/sad_tab_gtk.h
new file mode 100644
index 0000000..aed2454
--- /dev/null
+++ b/chrome/browser/gtk/sad_tab_gtk.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CHROME_BROWSER_GTK_SAD_TAB_GTK_H_
+#define CHROME_BROWSER_GTK_SAD_TAB_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "base/basictypes.h"
+#include "base/gfx/rect.h"
+#include "chrome/common/owned_widget_gtk.h"
+
+class SadTabGtk {
+ public:
+ SadTabGtk();
+ ~SadTabGtk();
+
+ GtkWidget* widget() { return widget_.get(); }
+
+ private:
+ // expose-event handler that redraws the SadTabGtk.
+ static gboolean OnExposeThunk(GtkWidget* widget,
+ GdkEventExpose* event,
+ const SadTabGtk* sad_tab);
+
+ gboolean OnExpose(GtkWidget* widget, GdkEventExpose* event) const;
+
+ // configure-event handler that gets the new bounds of the SadTabGtk.
+ static gboolean OnConfigureThunk(GtkWidget* widget,
+ GdkEventConfigure* event,
+ SadTabGtk* sad_tab);
+
+ gboolean OnConfigure(GtkWidget* widget, GdkEventConfigure* event);
+
+ // Track the view's width and height from configure-event signals.
+ int width_;
+ int height_;
+
+ // Regions within the display for different components, set on a
+ // configure-event. These are relative to the bounds of the widget.
+ gfx::Rect icon_bounds_;
+ int title_y_;
+ int message_y_;
+
+ OwnedWidgetGtk widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(SadTabGtk);
+};
+
+#endif // CHROME_BROWSER_GTK_SAD_TAB_GTK_H__
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index 35ac146..a31c70c 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -291,7 +291,7 @@ void RenderWidgetHostViewGtk::DidScrollRect(const gfx::Rect& rect, int dx,
}
void RenderWidgetHostViewGtk::RenderViewGone() {
- NOTIMPLEMENTED();
+ Destroy();
}
void RenderWidgetHostViewGtk::Destroy() {
@@ -374,7 +374,7 @@ void RenderWidgetHostViewGtk::ShowCurrentCursor() {
return;
GdkCursor* gdk_cursor;
- switch(current_cursor_.GetCursorType()) {
+ switch (current_cursor_.GetCursorType()) {
case GDK_CURSOR_IS_PIXMAP:
// TODO(port): WebKit bug https://bugs.webkit.org/show_bug.cgi?id=16388 is
// that calling gdk_window_set_cursor repeatedly is expensive. We should
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
index 9c82b47..a55c8fe 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
@@ -11,6 +11,7 @@
#include "base/gfx/point.h"
#include "base/gfx/rect.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
+#include "chrome/browser/gtk/sad_tab_gtk.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
@@ -18,6 +19,8 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/gtk_util.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
namespace {
@@ -62,8 +65,11 @@ TabContentsView* TabContentsView::Create(TabContents* tab_contents) {
TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents)
: TabContentsView(tab_contents),
- vbox_(gtk_vbox_new(FALSE, 0)),
- content_view_(NULL) {
+ vbox_(gtk_vbox_new(FALSE, 0)) {
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
+ Source<TabContents>(tab_contents));
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
+ Source<TabContents>(tab_contents));
}
TabContentsViewGtk::~TabContentsViewGtk() {
@@ -89,19 +95,19 @@ RenderWidgetHostView* TabContentsViewGtk::CreateViewForWidget(
RenderWidgetHostViewGtk* view =
new RenderWidgetHostViewGtk(render_widget_host);
view->InitAsChild();
- content_view_ = view->native_view();
- g_signal_connect(content_view_, "focus",
+ gfx::NativeView content_view = view->native_view();
+ g_signal_connect(content_view, "focus",
G_CALLBACK(OnFocus), tab_contents());
- g_signal_connect(view->native_view(), "leave-notify-event",
+ g_signal_connect(content_view, "leave-notify-event",
G_CALLBACK(OnLeaveNotify), tab_contents());
- g_signal_connect(view->native_view(), "motion-notify-event",
+ g_signal_connect(content_view, "motion-notify-event",
G_CALLBACK(OnMouseMove), tab_contents());
- gtk_widget_add_events(view->native_view(), GDK_LEAVE_NOTIFY_MASK |
+ gtk_widget_add_events(content_view, GDK_LEAVE_NOTIFY_MASK |
GDK_POINTER_MOTION_MASK);
- g_signal_connect(view->native_view(), "button-press-event",
+ g_signal_connect(content_view, "button-press-event",
G_CALLBACK(OnMouseDown), this);
gfx::RemoveAllChildren(vbox_.get());
- gtk_box_pack_start(GTK_BOX(vbox_.get()), content_view_, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox_.get()), content_view, TRUE, TRUE, 0);
return view;
}
@@ -110,9 +116,12 @@ gfx::NativeView TabContentsViewGtk::GetNativeView() const {
}
gfx::NativeView TabContentsViewGtk::GetContentNativeView() const {
- return content_view_;
+ if (!tab_contents()->render_widget_host_view())
+ return NULL;
+ return tab_contents()->render_widget_host_view()->GetPluginNativeView();
}
+
gfx::NativeWindow TabContentsViewGtk::GetTopLevelNativeWindow() const {
GtkWidget* window = gtk_widget_get_ancestor(GetNativeView(), GTK_TYPE_WINDOW);
return window ? GTK_WINDOW(window) : NULL;
@@ -135,12 +144,13 @@ void TabContentsViewGtk::OnContentsDestroy() {
void TabContentsViewGtk::SetPageTitle(const std::wstring& title) {
// Set the window name to include the page title so it's easier to spot
// when debugging (e.g. via xwininfo -tree).
- if (content_view_ && content_view_->window)
- gdk_window_set_title(content_view_->window, WideToUTF8(title).c_str());
+ gfx::NativeView content_view = GetContentNativeView();
+ if (content_view && content_view->window)
+ gdk_window_set_title(content_view->window, WideToUTF8(title).c_str());
}
void TabContentsViewGtk::Invalidate() {
- NOTIMPLEMENTED();
+ gtk_widget_queue_draw(sad_tab_->widget());
}
void TabContentsViewGtk::SizeContents(const gfx::Size& size) {
@@ -173,7 +183,7 @@ void TabContentsViewGtk::SetInitialFocus() {
if (tab_contents()->FocusLocationBarByDefault())
tab_contents()->delegate()->SetFocusToLocationBar();
else
- gtk_widget_grab_focus(content_view_);
+ gtk_widget_grab_focus(GetContentNativeView());
}
void TabContentsViewGtk::StoreFocus() {
@@ -224,6 +234,30 @@ void TabContentsViewGtk::OnFindReply(int request_id,
NOTIMPLEMENTED();
}
+void TabContentsViewGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type.value) {
+ case NotificationType::TAB_CONTENTS_CONNECTED: {
+ // No need to remove the SadTabGtk's widget from the container since
+ // the new RenderWidgetHostViewGtk instance already removed all the
+ // vbox's children.
+ sad_tab_.reset();
+ break;
+ }
+ case NotificationType::TAB_CONTENTS_DISCONNECTED: {
+ sad_tab_.reset(new SadTabGtk);
+ gtk_box_pack_start(
+ GTK_BOX(vbox_.get()), sad_tab_->widget(), TRUE, TRUE, 0);
+ gtk_widget_show(sad_tab_->widget());
+ break;
+ }
+ default:
+ NOTREACHED() << "Got a notification we didn't register for.";
+ break;
+ }
+}
+
void TabContentsViewGtk::ShowContextMenu(const ContextMenuParams& params) {
context_menu_.reset(new RenderViewContextMenuGtk(tab_contents(), params,
last_mouse_down_time_));
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h
index 6d24598..4137f67 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h
@@ -7,11 +7,15 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
#include "chrome/common/owned_widget_gtk.h"
class RenderViewContextMenuGtk;
+class SadTabGtk;
-class TabContentsViewGtk : public TabContentsView {
+class TabContentsViewGtk : public TabContentsView,
+ public NotificationObserver {
public:
// The corresponding TabContents is passed in the constructor, and manages our
// lifetime. This doesn't need to be the case, but is this way currently
@@ -55,6 +59,13 @@ class TabContentsViewGtk : public TabContentsView {
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update);
+
+ // NotificationObserver implementation ---------------------------------------
+
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
private:
// We keep track of the timestamp of the latest mousedown event.
static gboolean OnMouseDown(GtkWidget* widget,
@@ -63,9 +74,6 @@ class TabContentsViewGtk : public TabContentsView {
// The native widget for the tab.
OwnedWidgetGtk vbox_;
- // The native widget for the contents of the tab. We do not own this widget.
- GtkWidget* content_view_;
-
// The context menu is reset every time we show it, but we keep a pointer to
// between uses so that it won't go out of scope before we're done with it.
scoped_ptr<RenderViewContextMenuGtk> context_menu_;
@@ -74,6 +82,11 @@ class TabContentsViewGtk : public TabContentsView {
// show context menus.
guint32 last_mouse_down_time_;
+ // Used to get notifications about renderers coming and going.
+ NotificationRegistrar registrar_;
+
+ scoped_ptr<SadTabGtk> sad_tab_;
+
DISALLOW_COPY_AND_ASSIGN(TabContentsViewGtk);
};
diff --git a/chrome/browser/views/sad_tab_view.h b/chrome/browser/views/sad_tab_view.h
index 5e9415d..8605c1d 100644
--- a/chrome/browser/views/sad_tab_view.h
+++ b/chrome/browser/views/sad_tab_view.h
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_VIEWS_SAD_TAB_H_
-#define CHROME_BROWSER_VIEWS_SAD_TAB_H_
+#ifndef CHROME_BROWSER_VIEWS_SAD_TAB_VIEW_H_
+#define CHROME_BROWSER_VIEWS_SAD_TAB_VIEW_H_
#include "app/gfx/chrome_font.h"
+#include "base/basictypes.h"
#include "chrome/views/view.h"
class SkBitmap;
@@ -51,7 +52,7 @@ class SadTabView : public views::View {
gfx::Rect title_bounds_;
gfx::Rect message_bounds_;
- DISALLOW_EVIL_CONSTRUCTORS(SadTabView);
+ DISALLOW_COPY_AND_ASSIGN(SadTabView);
};
-#endif // CHROME_BROWSER_VIEWS_SAD_TAB_H__
+#endif // CHROME_BROWSER_VIEWS_SAD_TAB_VIEW_H__
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 212c0b0..45f14d9 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -880,6 +880,8 @@
'browser/gtk/menu_gtk.h',
'browser/gtk/nine_box.cc',
'browser/gtk/nine_box.h',
+ 'browser/gtk/sad_tab_gtk.cc',
+ 'browser/gtk/sad_tab_gtk.h',
'browser/gtk/slide_animator_gtk.cc',
'browser/gtk/slide_animator_gtk.h',
'browser/gtk/standard_menus.cc',