diff options
author | Kristian Monsen <kristianm@google.com> | 2010-10-27 13:27:14 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2010-10-27 13:27:14 +0100 |
commit | bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293 (patch) | |
tree | e6c803134a90c4535df4b3d8d1c1d8f03405e462 /chrome/browser/gtk | |
parent | 026dcf071380a81f0213473bab11c7db9f367bce (diff) | |
download | external_chromium-bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293.zip external_chromium-bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293.tar.gz external_chromium-bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293.tar.bz2 |
Adding missing files to chrome/browser
These are not used, but added to easier sync with chromium
Change-Id: I54e6f2f49677e29736fd502758a438b2e3d685d8
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/js_modal_dialog_gtk.cc | 234 | ||||
-rw-r--r-- | chrome/browser/gtk/js_modal_dialog_gtk.h | 45 | ||||
-rw-r--r-- | chrome/browser/gtk/owned_widget_gtk.cc | 41 | ||||
-rw-r--r-- | chrome/browser/gtk/owned_widget_gtk.h | 90 | ||||
-rw-r--r-- | chrome/browser/gtk/page_info_bubble_gtk.cc | 323 |
5 files changed, 733 insertions, 0 deletions
diff --git a/chrome/browser/gtk/js_modal_dialog_gtk.cc b/chrome/browser/gtk/js_modal_dialog_gtk.cc new file mode 100644 index 0000000..9a12cc9 --- /dev/null +++ b/chrome/browser/gtk/js_modal_dialog_gtk.cc @@ -0,0 +1,234 @@ +// 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/gtk/js_modal_dialog_gtk.h" + +#include <gtk/gtk.h> + +#include "app/gtk_util.h" +#include "app/l10n_util.h" +#include "app/message_box_flags.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/gtk/gtk_util.h" +#include "chrome/browser/js_modal_dialog.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" + +namespace { + +// We stash pointers to widgets on the gtk_dialog so we can refer to them +// after dialog creation. +const char kPromptTextId[] = "chrome_prompt_text"; +const char kSuppressCheckboxId[] = "chrome_suppress_checkbox"; + +// If there's a text entry in the dialog, get the text from the first one and +// return it. +std::wstring GetPromptText(GtkDialog* dialog) { + GtkWidget* widget = static_cast<GtkWidget*>( + g_object_get_data(G_OBJECT(dialog), kPromptTextId)); + if (widget) + return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(widget))); + return std::wstring(); +} + +// If there's a toggle button in the dialog, return the toggled state. +// Otherwise, return false. +bool ShouldSuppressJSDialogs(GtkDialog* dialog) { + GtkWidget* widget = static_cast<GtkWidget*>( + g_object_get_data(G_OBJECT(dialog), kSuppressCheckboxId)); + if (widget) + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + return false; +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// JSModalDialogGtk, public: + +JSModalDialogGtk::JSModalDialogGtk(JavaScriptAppModalDialog* dialog, + gfx::NativeWindow parent_window) + : dialog_(dialog) { + GtkButtonsType buttons = GTK_BUTTONS_NONE; + GtkMessageType message_type = GTK_MESSAGE_OTHER; + + // We add in the OK button manually later because we want to focus it + // explicitly. + switch (dialog_->dialog_flags()) { + case MessageBoxFlags::kIsJavascriptAlert: + buttons = GTK_BUTTONS_NONE; + message_type = GTK_MESSAGE_WARNING; + break; + + case MessageBoxFlags::kIsJavascriptConfirm: + if (dialog_->is_before_unload_dialog()) { + // onbeforeunload also uses a confirm prompt, it just has custom + // buttons. We add the buttons using gtk_dialog_add_button below. + buttons = GTK_BUTTONS_NONE; + } else { + buttons = GTK_BUTTONS_CANCEL; + } + message_type = GTK_MESSAGE_QUESTION; + break; + + case MessageBoxFlags::kIsJavascriptPrompt: + buttons = GTK_BUTTONS_CANCEL; + message_type = GTK_MESSAGE_QUESTION; + break; + + default: + NOTREACHED(); + } + + // We want the alert to be app modal so put all the browser windows into the + // same window group. + gtk_util::MakeAppModalWindowGroup(); + + gtk_dialog_ = gtk_message_dialog_new(parent_window, + GTK_DIALOG_MODAL, message_type, buttons, "%s", + WideToUTF8(dialog_->message_text()).c_str()); + gtk_util::ApplyMessageDialogQuirks(gtk_dialog_); + gtk_window_set_title(GTK_WINDOW(gtk_dialog_), + WideToUTF8(dialog_->title()).c_str()); + + // Adjust content area as needed. Set up the prompt text entry or + // suppression check box. + if (MessageBoxFlags::kIsJavascriptPrompt == dialog_->dialog_flags()) { + // TODO(tc): Replace with gtk_dialog_get_content_area() when using GTK 2.14+ + GtkWidget* contents_vbox = GTK_DIALOG(gtk_dialog_)->vbox; + GtkWidget* text_box = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(text_box), + WideToUTF8(dialog_->default_prompt_text()).c_str()); + gtk_box_pack_start(GTK_BOX(contents_vbox), text_box, TRUE, TRUE, 0); + g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box); + gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE); + } + + if (dialog_->display_suppress_checkbox()) { + GtkWidget* contents_vbox = GTK_DIALOG(gtk_dialog_)->vbox; + GtkWidget* check_box = gtk_check_button_new_with_label( + l10n_util::GetStringUTF8( + IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION).c_str()); + gtk_box_pack_start(GTK_BOX(contents_vbox), check_box, TRUE, TRUE, 0); + g_object_set_data(G_OBJECT(gtk_dialog_), kSuppressCheckboxId, check_box); + } + + // Adjust buttons/action area as needed. + if (dialog_->is_before_unload_dialog()) { + std::string button_text = l10n_util::GetStringUTF8( + IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL); + gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(), + GTK_RESPONSE_OK); + + button_text = l10n_util::GetStringUTF8( + IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL); + gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(), + GTK_RESPONSE_CANCEL); + } else { + // Add the OK button and focus it. + GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), + GTK_STOCK_OK, GTK_RESPONSE_OK); + if (MessageBoxFlags::kIsJavascriptPrompt != dialog_->dialog_flags()) + gtk_widget_grab_focus(ok_button); + } + + gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK); + g_signal_connect(gtk_dialog_, "response", + G_CALLBACK(JSModalDialogGtk::OnDialogResponse), + reinterpret_cast<JSModalDialogGtk*>(this)); +} + +JSModalDialogGtk::~JSModalDialogGtk() { +} + +//////////////////////////////////////////////////////////////////////////////// +// JSModalDialogGtk, NativeAppModalDialog implementation: + +int JSModalDialogGtk::GetAppModalDialogButtons() const { + switch (dialog_->dialog_flags()) { + case MessageBoxFlags::kIsJavascriptAlert: + return MessageBoxFlags::DIALOGBUTTON_OK; + + case MessageBoxFlags::kIsJavascriptConfirm: + return MessageBoxFlags::DIALOGBUTTON_OK | + MessageBoxFlags::DIALOGBUTTON_CANCEL; + + case MessageBoxFlags::kIsJavascriptPrompt: + return MessageBoxFlags::DIALOGBUTTON_OK; + + default: + NOTREACHED(); + return 0; + } +} + +void JSModalDialogGtk::ShowAppModalDialog() { + gtk_util::ShowModalDialogWithMinLocalizedWidth(GTK_WIDGET(gtk_dialog_), + IDS_ALERT_DIALOG_WIDTH_CHARS); +} + +void JSModalDialogGtk::ActivateAppModalDialog() { + DCHECK(gtk_dialog_); + gtk_window_present(GTK_WINDOW(gtk_dialog_));} + +void JSModalDialogGtk::CloseAppModalDialog() { + DCHECK(gtk_dialog_); + HandleDialogResponse(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_DELETE_EVENT); +} + +void JSModalDialogGtk::AcceptAppModalDialog() { + HandleDialogResponse(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK); +} + +void JSModalDialogGtk::CancelAppModalDialog() { + HandleDialogResponse(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_CANCEL); +} + +//////////////////////////////////////////////////////////////////////////////// +// JSModalDialogGtk, private: + +void JSModalDialogGtk::HandleDialogResponse(GtkDialog* dialog, + gint response_id) { + switch (response_id) { + case GTK_RESPONSE_OK: + // The first arg is the prompt text and the second is true if we want to + // suppress additional popups from the page. + dialog_->OnAccept(GetPromptText(dialog), ShouldSuppressJSDialogs(dialog)); + break; + + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: // User hit the X on the dialog. + dialog_->OnCancel(); + break; + + default: + NOTREACHED(); + } + gtk_widget_destroy(GTK_WIDGET(dialog)); + + // Now that the dialog is gone, we can put all the windows into separate + // window groups so other dialogs are no longer app modal. + gtk_util::AppModalDismissedUngroupWindows(); + delete this; +} + +// static +void JSModalDialogGtk::OnDialogResponse(GtkDialog* gtk_dialog, + gint response_id, + JSModalDialogGtk* dialog) { + dialog->HandleDialogResponse(gtk_dialog, response_id); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeAppModalDialog, public: + +// static +NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt( + JavaScriptAppModalDialog* dialog, + gfx::NativeWindow parent_window) { + return new JSModalDialogGtk(dialog, parent_window); +} + + diff --git a/chrome/browser/gtk/js_modal_dialog_gtk.h b/chrome/browser/gtk/js_modal_dialog_gtk.h new file mode 100644 index 0000000..18d573c --- /dev/null +++ b/chrome/browser/gtk/js_modal_dialog_gtk.h @@ -0,0 +1,45 @@ +// 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. + +#ifndef CHROME_BROWSER_GTK_JS_MODAL_DIALOG_GTK_H_ +#define CHROME_BROWSER_GTK_JS_MODAL_DIALOG_GTK_H_ +#pragma once + +#include <gtk/gtk.h> + +#include "app/gtk_signal.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/native_app_modal_dialog.h" +#include "gfx/native_widget_types.h" + +class JavaScriptAppModalDialog; + +class JSModalDialogGtk : public NativeAppModalDialog { + public: + JSModalDialogGtk(JavaScriptAppModalDialog* dialog, + gfx::NativeWindow parent_window); + virtual ~JSModalDialogGtk(); + + // Overridden from NativeAppModalDialog: + virtual int GetAppModalDialogButtons() const; + virtual void ShowAppModalDialog(); + virtual void ActivateAppModalDialog(); + virtual void CloseAppModalDialog(); + virtual void AcceptAppModalDialog(); + virtual void CancelAppModalDialog(); + + private: + void HandleDialogResponse(GtkDialog* dialog, gint response_id); + static void OnDialogResponse(GtkDialog* gtk_dialog, gint response_id, + JSModalDialogGtk* dialog); + + scoped_ptr<JavaScriptAppModalDialog> dialog_; + GtkWidget* gtk_dialog_; + + DISALLOW_COPY_AND_ASSIGN(JSModalDialogGtk); +}; + +#endif // CHROME_BROWSER_GTK_JS_MODAL_DIALOG_GTK_H_ + diff --git a/chrome/browser/gtk/owned_widget_gtk.cc b/chrome/browser/gtk/owned_widget_gtk.cc new file mode 100644 index 0000000..2315371 --- /dev/null +++ b/chrome/browser/gtk/owned_widget_gtk.cc @@ -0,0 +1,41 @@ +// 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/gtk/owned_widget_gtk.h" + +#include <gtk/gtk.h> + +#include "base/logging.h" + +OwnedWidgetGtk::~OwnedWidgetGtk() { + DCHECK(!widget_) << "You must explicitly call OwnerWidgetGtk::Destroy()."; +} + +void OwnedWidgetGtk::Own(GtkWidget* widget) { + if (!widget) + return; + + DCHECK(!widget_); + // We want to make sure that Own() was called properly, right after the + // widget was created. There should be a floating reference. + DCHECK(g_object_is_floating(widget)); + + // Sink the floating reference, we should now own this reference. + g_object_ref_sink(widget); + widget_ = widget; +} + +void OwnedWidgetGtk::Destroy() { + if (!widget_) + return; + + GtkWidget* widget = widget_; + widget_ = NULL; + gtk_widget_destroy(widget); + + DCHECK(!g_object_is_floating(widget)); + // NOTE: Assumes some implementation details about glib internals. + DCHECK_EQ(G_OBJECT(widget)->ref_count, 1U); + g_object_unref(widget); +} diff --git a/chrome/browser/gtk/owned_widget_gtk.h b/chrome/browser/gtk/owned_widget_gtk.h new file mode 100644 index 0000000..b5299c9 --- /dev/null +++ b/chrome/browser/gtk/owned_widget_gtk.h @@ -0,0 +1,90 @@ +// 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. + +// This class assists you in dealing with a specific situation when managing +// ownership between a C++ object and a GTK widget. It is common to have a +// C++ object which encapsulates a GtkWidget, and that widget is exposed from +// the object for use outside of the class. In this situation, you commonly +// want the GtkWidget's lifetime to match its C++ object's lifetime. Using an +// OwnedWigetGtk will take ownership over the initial reference of the +// GtkWidget, so that it is "owned" by the C++ object. Example usage: +// +// class FooViewGtk() { +// public: +// FooViewGtk() { } +// ~FooViewGtk() { widget_.Destroy(); } +// void Init() { vbox_.Own(gtk_vbox_new()); } +// GtkWidget* widget() { return vbox_.get() }; // Host my widget! +// private: +// OwnedWidgetGtk vbox_; +// }; +// +// This design will ensure that the widget stays alive from the call to Own() +// until the call to Destroy(). +// +// - Details of the problem and OwnedWidgetGtk's solution: +// In order to make passing ownership more convenient for newly created +// widgets, GTK has a concept of a "floating" reference. All GtkObjects (and +// thus GtkWidgets) inherit from GInitiallyUnowned. When they are created, the +// object starts with a reference count of 1, but has its floating flag set. +// When it is put into a container for the first time, that container will +// "sink" the floating reference, and the count will still be 1. Now the +// container owns the widget, and if we remove the widget from the container, +// the widget is destroyed. This style of ownership often causes problems when +// you have an object encapsulating the widget. If we just use a raw +// GtkObject* with no specific ownership management, we push the widget's +// ownership onto the user of the class. Now the C++ object can't depend on +// the widget being valid, since it doesn't manage its lifetime. If the widget +// was removed from a container, removing its only reference, it would be +// destroyed (from the C++ object's perspective) unexpectantly destroyed. The +// solution is fairly simple, make sure that the C++ object owns the widget, +// and thus it is also responsible for destroying it. This boils down to: +// GtkWidget* widget = gtk_widget_new(); +// g_object_ref_sink(widget); // Claim the initial floating reference. +// ... +// gtk_destroy_widget(widget); // Ask all code to destroy their references. +// g_object_unref(widget); // Destroy the initial reference we had claimed. + +#ifndef CHROME_BROWSER_GTK_OWNED_WIDGET_GTK_H_ +#define CHROME_BROWSER_GTK_OWNED_WIDGET_GTK_H_ +#pragma once + +#include "base/basictypes.h" + +typedef struct _GtkWidget GtkWidget; + +class OwnedWidgetGtk { + public: + // Create an instance that isn't managing any ownership. + OwnedWidgetGtk() : widget_(NULL) { } + // Create an instance that owns |widget|. + explicit OwnedWidgetGtk(GtkWidget* widget) : widget_(NULL) { Own(widget); } + + ~OwnedWidgetGtk(); + + // Return the currently owned widget, or NULL if no widget is owned. + GtkWidget* get() const { return widget_; } + GtkWidget* operator->() const { return widget_; } + + // Takes ownership of a widget, by taking the initial floating reference of + // the GtkWidget. It is expected that Own() is called right after the widget + // has been created, and before any other references to the widget might have + // been added. It is valid to never call Own(), in which case Destroy() will + // do nothing. If Own() has been called, you must explicitly call Destroy(). + void Own(GtkWidget* widget); + + // You must call Destroy() after you have called Own(). Calling Destroy() + // will call gtk_widget_destroy(), and drop our reference to the widget. + // After a call to Destroy(), you may call Own() again. NOTE: It is expected + // that after gtk_widget_destroy we will be holding the only reference left + // on the object. We assert this in debug mode to help catch any leaks. + void Destroy(); + + private: + GtkWidget* widget_; + + DISALLOW_COPY_AND_ASSIGN(OwnedWidgetGtk); +}; + +#endif // CHROME_BROWSER_GTK_OWNED_WIDGET_GTK_H_ diff --git a/chrome/browser/gtk/page_info_bubble_gtk.cc b/chrome/browser/gtk/page_info_bubble_gtk.cc new file mode 100644 index 0000000..0417d79 --- /dev/null +++ b/chrome/browser/gtk/page_info_bubble_gtk.cc @@ -0,0 +1,323 @@ +// 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 <gtk/gtk.h> + +#include "build/build_config.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/i18n/rtl.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/certificate_viewer.h" +#include "chrome/browser/gtk/browser_toolbar_gtk.h" +#include "chrome/browser/gtk/browser_window_gtk.h" +#include "chrome/browser/gtk/gtk_chrome_link_button.h" +#include "chrome/browser/gtk/gtk_theme_provider.h" +#include "chrome/browser/gtk/gtk_util.h" +#include "chrome/browser/gtk/info_bubble_gtk.h" +#include "chrome/browser/gtk/location_bar_view_gtk.h" +#include "chrome/browser/page_info_model.h" +#include "chrome/browser/page_info_window.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "gfx/gtk_util.h" +#include "googleurl/src/gurl.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "grit/theme_resources.h" + +class Profile; + +namespace { + +class PageInfoBubbleGtk : public PageInfoModel::PageInfoModelObserver, + public InfoBubbleGtkDelegate, + public NotificationObserver { + public: + PageInfoBubbleGtk(gfx::NativeWindow parent, + Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history); + virtual ~PageInfoBubbleGtk(); + + // PageInfoModelObserver implementation: + virtual void ModelChanged(); + + // NotificationObserver implementation: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // InfoBubbleGtkDelegate implementation: + virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, + bool closed_by_escape); + + private: + // Layouts the different sections retrieved from the model. + void InitContents(); + + // Returns a widget that contains the UI for the passed |section|. + GtkWidget* CreateSection(const PageInfoModel::SectionInfo& section); + + // Link button callbacks. + CHROMEGTK_CALLBACK_0(PageInfoBubbleGtk, void, OnViewCertLinkClicked); + CHROMEGTK_CALLBACK_0(PageInfoBubbleGtk, void, OnHelpLinkClicked); + + // The model containing the different sections to display. + PageInfoModel model_; + + // The url for this dialog. Should be unique among active dialogs. + GURL url_; + + // The id of the certificate for this page. + int cert_id_; + + // Parent window. + GtkWindow* parent_; + + // The virtual box containing the sections. + GtkWidget* contents_; + + // The widget relative to which we are positioned. + GtkWidget* anchor_; + + // Provides colors and stuff. + GtkThemeProvider* theme_provider_; + + // The various elements in the interface we keep track of for theme changes. + std::vector<GtkWidget*> labels_; + std::vector<GtkWidget*> links_; + + InfoBubbleGtk* bubble_; + + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(PageInfoBubbleGtk); +}; + +PageInfoBubbleGtk::PageInfoBubbleGtk(gfx::NativeWindow parent, + Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history) + : ALLOW_THIS_IN_INITIALIZER_LIST(model_(profile, url, ssl, + show_history, this)), + url_(url), + cert_id_(ssl.cert_id()), + parent_(parent), + contents_(NULL), + theme_provider_(GtkThemeProvider::GetFrom(profile)) { + BrowserWindowGtk* browser_window = + BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent); + + anchor_ = browser_window-> + GetToolbar()->GetLocationBarView()->location_icon_widget(); + + registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, + NotificationService::AllSources()); + + InitContents(); + + InfoBubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? + InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : + InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; + bubble_ = InfoBubbleGtk::Show(anchor_, + NULL, // |rect| + contents_, + arrow_location, + true, // |match_system_theme| + true, // |grab_input| + theme_provider_, + this); // |delegate| + if (!bubble_) { + NOTREACHED(); + return; + } +} + +PageInfoBubbleGtk::~PageInfoBubbleGtk() { +} + +void PageInfoBubbleGtk::ModelChanged() { + InitContents(); +} + +void PageInfoBubbleGtk::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::BROWSER_THEME_CHANGED); + + for (std::vector<GtkWidget*>::iterator it = links_.begin(); + it != links_.end(); ++it) { + gtk_chrome_link_button_set_use_gtk_theme( + GTK_CHROME_LINK_BUTTON(*it), + theme_provider_->UseGtkTheme()); + } + + if (theme_provider_->UseGtkTheme()) { + for (std::vector<GtkWidget*>::iterator it = labels_.begin(); + it != labels_.end(); ++it) { + gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, NULL); + } + } else { + for (std::vector<GtkWidget*>::iterator it = labels_.begin(); + it != labels_.end(); ++it) { + gtk_widget_modify_fg(*it, GTK_STATE_NORMAL, &gfx::kGdkBlack); + } + } +} + +void PageInfoBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, + bool closed_by_escape) { + delete this; +} + +void PageInfoBubbleGtk::InitContents() { + if (!contents_) { + contents_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); + gtk_container_set_border_width(GTK_CONTAINER(contents_), + gtk_util::kContentAreaBorder); + } else { + labels_.clear(); + links_.clear(); + gtk_util::RemoveAllChildren(contents_); + } + + for (int i = 0; i < model_.GetSectionCount(); i++) { + gtk_box_pack_start(GTK_BOX(contents_), + CreateSection(model_.GetSectionInfo(i)), + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(contents_), + gtk_hseparator_new(), + FALSE, FALSE, 0); + } + + GtkWidget* help_link = gtk_chrome_link_button_new( + l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK).c_str()); + links_.push_back(help_link); + GtkWidget* help_link_hbox = gtk_hbox_new(FALSE, 0); + // Stick it in an hbox so it doesn't expand to the whole width. + gtk_box_pack_start(GTK_BOX(help_link_hbox), help_link, TRUE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(contents_), help_link_hbox, FALSE, FALSE, 0); + g_signal_connect(help_link, "clicked", + G_CALLBACK(OnHelpLinkClickedThunk), this); + + theme_provider_->InitThemesFor(this); + gtk_widget_show_all(contents_); +} + +GtkWidget* PageInfoBubbleGtk::CreateSection( + const PageInfoModel::SectionInfo& section) { + GtkWidget* section_box = gtk_hbox_new(FALSE, 0); + + if (section.type == PageInfoModel::SECTION_INFO_IDENTITY || + section.type == PageInfoModel::SECTION_INFO_CONNECTION) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + GdkPixbuf* pixbuf = NULL; + switch (section.state) { + case PageInfoModel::SECTION_STATE_OK: + pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_GOOD); + break; + case PageInfoModel::SECTION_STATE_WARNING_MINOR: + DCHECK(section.type == PageInfoModel::SECTION_INFO_CONNECTION); + pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_WARNING_MINOR); + break; + case PageInfoModel::SECTION_STATE_WARNING_MAJOR: + pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_WARNING_MAJOR); + break; + case PageInfoModel::SECTION_STATE_ERROR: + pixbuf = rb.GetPixbufNamed(IDR_PAGEINFO_BAD); + break; + default: + NOTREACHED(); + } + GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf); + gtk_box_pack_start(GTK_BOX(section_box), image, FALSE, FALSE, + gtk_util::kControlSpacing); + gtk_misc_set_alignment(GTK_MISC(image), 0, 0); + } else if (section.type == PageInfoModel::SECTION_INFO_FIRST_VISIT) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + GdkPixbuf* pixbuf = section.state == PageInfoModel::SECTION_STATE_OK ? + rb.GetPixbufNamed(IDR_PAGEINFO_INFO) : + rb.GetPixbufNamed(IDR_PAGEINFO_WARNING_MAJOR); + GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf); + gtk_box_pack_start(GTK_BOX(section_box), image, FALSE, FALSE, + gtk_util::kControlSpacing); + gtk_misc_set_alignment(GTK_MISC(image), 0, 0); + } + + GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(section_box), vbox, TRUE, TRUE, 0); + + if (!section.headline.empty()) { + GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.headline).c_str()); + labels_.push_back(label); + PangoAttrList* attributes = pango_attr_list_new(); + pango_attr_list_insert(attributes, + pango_attr_weight_new(PANGO_WEIGHT_BOLD)); + gtk_label_set_attributes(GTK_LABEL(label), attributes); + pango_attr_list_unref(attributes); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + // Allow linebreaking in the middle of words if necessary, so that extremely + // long hostnames (longer than one line) will still be completely shown. + gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_set_size_request(label, 400, -1); + } + GtkWidget* label = gtk_label_new(UTF16ToUTF8(section.description).c_str()); + labels_.push_back(label); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + // Allow linebreaking in the middle of words if necessary, so that extremely + // long hostnames (longer than one line) will still be completely shown. + gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); + gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_widget_set_size_request(label, 400, -1); + + if (section.type == PageInfoModel::SECTION_INFO_IDENTITY && cert_id_ > 0) { + GtkWidget* view_cert_link = gtk_chrome_link_button_new( + l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str()); + links_.push_back(view_cert_link); + GtkWidget* cert_link_hbox = gtk_hbox_new(FALSE, 0); + // Stick it in an hbox so it doesn't expand to the whole width. + gtk_box_pack_start(GTK_BOX(cert_link_hbox), view_cert_link, + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), cert_link_hbox, FALSE, FALSE, 0); + g_signal_connect(view_cert_link, "clicked", + G_CALLBACK(OnViewCertLinkClickedThunk), this); + } + + return section_box; +} + +void PageInfoBubbleGtk::OnViewCertLinkClicked(GtkWidget* widget) { + ShowCertificateViewerByID(GTK_WINDOW(parent_), cert_id_); + bubble_->Close(); +} + +void PageInfoBubbleGtk::OnHelpLinkClicked(GtkWidget* widget) { + GURL url = GURL(l10n_util::GetStringUTF16(IDS_PAGE_INFO_HELP_CENTER)); + Browser* browser = BrowserList::GetLastActive(); + browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); + bubble_->Close(); +} + +} // namespace + +namespace browser { + +void ShowPageInfoBubble(gfx::NativeWindow parent, + Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history) { + new PageInfoBubbleGtk(parent, profile, url, ssl, show_history); +} + +} // namespace browser |