summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2010-10-27 13:27:14 +0100
committerKristian Monsen <kristianm@google.com>2010-10-27 13:27:14 +0100
commitbda42a81ee5f9b20d2bebedcf0bbef1e30e5b293 (patch)
treee6c803134a90c4535df4b3d8d1c1d8f03405e462 /chrome/browser/gtk
parent026dcf071380a81f0213473bab11c7db9f367bce (diff)
downloadexternal_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.cc234
-rw-r--r--chrome/browser/gtk/js_modal_dialog_gtk.h45
-rw-r--r--chrome/browser/gtk/owned_widget_gtk.cc41
-rw-r--r--chrome/browser/gtk/owned_widget_gtk.h90
-rw-r--r--chrome/browser/gtk/page_info_bubble_gtk.cc323
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