Index: chrome/browser/ui/gtk/global_error_bubble.cc |
diff --git a/chrome/browser/ui/gtk/global_error_bubble.cc b/chrome/browser/ui/gtk/global_error_bubble.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9ecdf4f79099a0adfe49672ac079ebb392900431 |
--- /dev/null |
+++ b/chrome/browser/ui/gtk/global_error_bubble.cc |
@@ -0,0 +1,149 @@ |
+// Copyright (c) 2011 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/ui/gtk/global_error_bubble.h" |
+ |
+#include "base/i18n/rtl.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/global_error_delegate.h" |
+#include "chrome/browser/ui/gtk/browser_toolbar_gtk.h" |
+#include "chrome/browser/ui/gtk/browser_window_gtk.h" |
+#include "chrome/browser/ui/gtk/gtk_theme_service.h" |
+#include "chrome/browser/ui/gtk/gtk_util.h" |
+#include "ui/base/gtk/gtk_hig_constants.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/gtk_util.h" |
+#include "ui/gfx/image/image.h" |
+ |
+namespace { |
+ |
+// Padding between content and edge of bubble. |
+const int kContentBorder = 7; |
+ |
+// Horizontal spacing between the image view and the label. |
+const int kImageViewSpacing = 5; |
+ |
+// Vertical spacing between labels. |
+const int kInterLineSpacing = 5; |
+ |
+// Text size of the message label. 12.1px = 9pt @ 96dpi. |
+const double kMessageTextSize = 12.1; |
+ |
+// Width of the message label. |
+const int kMessageLabelWidth = 250; |
+ |
+} // namespace |
+ |
+GlobalErrorBubble::GlobalErrorBubble(Profile* profile, |
+ GlobalErrorDelegate* delegate, |
+ GtkWidget* anchor) |
+ : bubble_(NULL), |
+ delegate_(delegate) { |
+ GtkWidget* content = gtk_vbox_new(FALSE, kInterLineSpacing); |
+ gtk_container_set_border_width(GTK_CONTAINER(content), kContentBorder); |
+ g_signal_connect(content, "destroy", |
+ G_CALLBACK(&HandleDestroyThunk), this); |
+ |
+ GtkThemeService* theme_service_ = GtkThemeService::GetFrom(profile); |
+ |
+ int resource_id = delegate->GetBubbleViewIconResourceID(); |
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
+ const SkBitmap* bitmap = rb.GetImageNamed(resource_id).ToSkBitmap(); |
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap); |
+ GtkWidget* image_view = gtk_image_new_from_pixbuf(pixbuf); |
+ |
+ GtkWidget* title_label = theme_service_->BuildLabel( |
+ UTF16ToUTF8(delegate->GetBubbleViewTitle()), |
+ ui::kGdkBlack); |
+ GtkWidget* message_label = theme_service_->BuildLabel( |
+ UTF16ToUTF8(delegate->GetBubbleViewMessage()), |
+ ui::kGdkBlack); |
+ gtk_util::ForceFontSizePixels(message_label, kMessageTextSize); |
+ gtk_util::SetLabelWidth(message_label, kMessageLabelWidth); |
+ GtkWidget* accept_button = gtk_button_new_with_label( |
+ UTF16ToUTF8(delegate->GetBubbleViewAcceptButtonLabel()).c_str()); |
+ string16 cancel_string = delegate->GetBubbleViewCancelButtonLabel(); |
+ GtkWidget* cancel_button = NULL; |
+ if (!cancel_string.empty()) { |
+ cancel_button = |
+ gtk_button_new_with_label(UTF16ToUTF8(cancel_string).c_str()); |
+ } |
+ |
+ // Top, icon and title. |
+ GtkWidget* top = gtk_hbox_new(FALSE, kImageViewSpacing); |
+ gtk_box_pack_start(GTK_BOX(top), image_view, FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(top), title_label, FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(content), top, FALSE, FALSE, 0); |
+ |
+ // Middle, message. |
+ gtk_box_pack_start(GTK_BOX(content), message_label, FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(content), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 0); |
+ |
+ // Bottom, accept and cancel button. |
+ // We want the buttons on the right, so just use an expanding label to fill |
+ // all of the extra space on the left. |
+ GtkWidget* bottom = gtk_hbox_new(FALSE, ui::kControlSpacing); |
+ gtk_box_pack_start(GTK_BOX(bottom), gtk_label_new(NULL), TRUE, TRUE, 0); |
+ if (cancel_button) |
+ gtk_box_pack_start(GTK_BOX(bottom), cancel_button, FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(bottom), accept_button, FALSE, FALSE, 0); |
+ gtk_box_pack_start(GTK_BOX(content), bottom, FALSE, FALSE, 0); |
+ |
+ gtk_widget_grab_focus(accept_button); |
+ |
+ g_signal_connect(accept_button, "clicked", |
+ G_CALLBACK(&HandleAcceptButtonThunk), this); |
+ if (cancel_button) { |
+ g_signal_connect(cancel_button, "clicked", |
+ G_CALLBACK(&HandleCancelButtonThunk), this); |
+ } |
+ |
+ BubbleGtk::ArrowLocationGtk arrow_location = |
+ base::i18n::IsRTL() ? |
+ BubbleGtk::ARROW_LOCATION_TOP_LEFT : |
+ BubbleGtk::ARROW_LOCATION_TOP_RIGHT; |
+ bubble_ = BubbleGtk::Show(anchor, |
+ NULL, |
+ content, |
+ arrow_location, |
+ true, // match_system_theme |
+ true, // grab_input |
+ theme_service_, |
+ this); // delegate |
+} |
+ |
+GlobalErrorBubble::~GlobalErrorBubble() { |
+} |
+ |
+void GlobalErrorBubble::BubbleClosing(BubbleGtk* bubble, |
+ bool closed_by_escape) { |
+} |
+ |
+void GlobalErrorBubble::HandleDestroy(GtkWidget* sender) { |
+ delete this; |
+} |
+ |
+void GlobalErrorBubble::HandleAcceptButton(GtkWidget* sender) { |
+ delegate_->BubbleViewAcceptButtonPressed(); |
+ bubble_->Close(); |
+} |
+ |
+void GlobalErrorBubble::HandleCancelButton(GtkWidget* sender) { |
+ delegate_->BubbleViewCancelButtonPressed(); |
+ bubble_->Close(); |
+} |
+ |
+void GlobalErrorDelegate::ShowBubbleView( |
+ GlobalErrorDelegate* delegate, |
+ Browser* browser, |
+ const gfx::Rect& position_relative_to) { |
+ BrowserWindowGtk* browser_window = |
+ BrowserWindowGtk::GetBrowserWindowForNativeWindow( |
+ browser->window()->GetNativeHandle()); |
+ GtkWidget* anchor = browser_window->GetToolbar()->GetAppMenuButton(); |
+ |
+ // The bubble will be automatically deleted when it's closed. |
+ new GlobalErrorBubble(browser->profile(), delegate, anchor); |
+} |