summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/browser_toolbar_gtk.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/gtk/browser_toolbar_gtk.cc')
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc397
1 files changed, 397 insertions, 0 deletions
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
new file mode 100644
index 0000000..c011d5c
--- /dev/null
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -0,0 +1,397 @@
+// 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/browser_toolbar_gtk.h"
+
+#include "base/logging.h"
+#include "base/base_paths_linux.h"
+#include "base/path_service.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/browser/gtk/back_forward_menu_model_gtk.h"
+#include "chrome/browser/gtk/standard_menus.h"
+#include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/resource_bundle.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+// TODO(deanm): Remove this when the LocationBarView is used.
+class LocationBar;
+
+const int BrowserToolbarGtk::kToolbarHeight = 38;
+// For the back/forward dropdown menus, the time in milliseconds between
+// when the user clicks and the popup menu appears.
+static const int kMenuTimerDelay = 500;
+
+BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser)
+ : toolbar_(NULL),
+ entry_(NULL),
+ model_(browser->toolbar_model()),
+ browser_(browser),
+ profile_(NULL),
+ show_menu_factory_(this) {
+ browser_->command_updater()->AddCommandObserver(IDC_BACK, this);
+ browser_->command_updater()->AddCommandObserver(IDC_FORWARD, this);
+ browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this);
+ browser_->command_updater()->AddCommandObserver(IDC_HOME, this);
+ browser_->command_updater()->AddCommandObserver(IDC_STAR, this);
+
+ back_menu_model_.reset(new BackForwardMenuModelGtk(
+ browser, BackForwardMenuModel::BACKWARD_MENU_DELEGATE));
+ forward_menu_model_.reset(new BackForwardMenuModelGtk(
+ browser, BackForwardMenuModel::FORWARD_MENU_DELEGATE));
+}
+
+BrowserToolbarGtk::~BrowserToolbarGtk() {
+}
+
+void BrowserToolbarGtk::Init(Profile* profile) {
+ show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this);
+
+ toolbar_ = gtk_hbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(toolbar_), 4);
+ // Demand we're always at least kToolbarHeight tall.
+ // -1 for width means "let GTK do its normal sizing".
+ gtk_widget_set_size_request(toolbar_, -1, kToolbarHeight);
+
+ toolbar_tooltips_ = gtk_tooltips_new();
+
+ back_.reset(BuildBackForwardButton(IDR_BACK, IDR_BACK_P, IDR_BACK_H,
+ IDR_BACK_D,
+ l10n_util::GetString(IDS_TOOLTIP_BACK)));
+ forward_.reset(BuildBackForwardButton(IDR_FORWARD, IDR_FORWARD_P,
+ IDR_FORWARD_H, IDR_FORWARD_D,
+ l10n_util::GetString(IDS_TOOLTIP_FORWARD)));
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);
+
+ reload_.reset(BuildToolbarButton(IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0,
+ l10n_util::GetString(IDS_TOOLTIP_RELOAD)));
+
+ // TODO(port): we need to dynamically react to changes in show_home_button_
+ // and hide/show home appropriately. But we don't have a UI for it yet.
+ if (*show_home_button_)
+ home_.reset(MakeHomeButton());
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);
+
+ star_.reset(BuildToolbarButton(IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D,
+ l10n_util::GetString(IDS_TOOLTIP_STAR)));
+
+ entry_ = gtk_entry_new();
+ gtk_widget_set_size_request(entry_, 0, 27);
+ g_signal_connect(G_OBJECT(entry_), "activate",
+ G_CALLBACK(OnEntryActivate), this);
+ g_signal_connect(G_OBJECT(entry_), "focus",
+ G_CALLBACK(OnEntryFocus), this);
+ g_signal_connect(G_OBJECT(entry_), "focus-in-event",
+ G_CALLBACK(OnEntryFocusIn), this);
+ g_signal_connect(G_OBJECT(entry_), "focus-out-event",
+ G_CALLBACK(OnEntryFocusOut), this);
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), entry_, TRUE, TRUE, 0);
+
+ go_.reset(BuildToolbarButton(IDR_GO, IDR_GO_P, IDR_GO_H, 0, L""));
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);
+
+ page_menu_button_.reset(BuildToolbarMenuButton(IDR_MENU_PAGE,
+ l10n_util::GetString(IDS_PAGEMENU_TOOLTIP)));
+ app_menu_button_.reset(BuildToolbarMenuButton(IDR_MENU_CHROME,
+ l10n_util::GetStringF(IDS_APPMENU_TOOLTIP,
+ l10n_util::GetString(IDS_PRODUCT_NAME))));
+
+ SetProfile(profile);
+}
+
+void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) {
+ gtk_box_pack_start(GTK_BOX(box), toolbar_, FALSE, FALSE, 0);
+}
+
+LocationBar* BrowserToolbarGtk::GetLocationBar() const {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+void BrowserToolbarGtk::FocusLocationBar() {
+ gtk_widget_grab_focus(entry_);
+}
+
+void BrowserToolbarGtk::EnabledStateChangedForCommand(int id, bool enabled) {
+ GtkWidget* widget = NULL;
+ switch (id) {
+ case IDC_BACK:
+ widget = back_->widget();
+ break;
+ case IDC_FORWARD:
+ widget = forward_->widget();
+ break;
+ case IDC_RELOAD:
+ widget = reload_->widget();
+ break;
+ case IDC_GO:
+ widget = go_->widget();
+ break;
+ case IDC_HOME:
+ if (home_.get())
+ widget = home_->widget();
+ break;
+ case IDC_STAR:
+ widget = star_->widget();
+ break;
+ }
+ if (widget)
+ gtk_widget_set_sensitive(widget, enabled);
+}
+
+bool BrowserToolbarGtk::IsCommandEnabled(int command_id) const {
+ return browser_->command_updater()->IsCommandEnabled(command_id);
+}
+
+bool BrowserToolbarGtk::IsItemChecked(int id) const {
+ if (!profile_)
+ return false;
+ if (id == IDC_SHOW_BOOKMARK_BAR)
+ return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
+ // TODO(port): Fix this when we get some items that want checking!
+ return false;
+}
+
+void BrowserToolbarGtk::ExecuteCommand(int id) {
+ browser_->ExecuteCommand(id);
+}
+
+void BrowserToolbarGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::PREF_CHANGED) {
+ std::wstring* pref_name = Details<std::wstring>(details).ptr();
+ if (*pref_name == prefs::kShowHomeButton) {
+ // TODO(port): add/remove home button.
+ NOTIMPLEMENTED();
+ }
+ }
+}
+
+void BrowserToolbarGtk::SetProfile(Profile* profile) {
+ if (profile == profile_)
+ return;
+
+ profile_ = profile;
+ // TODO(erg): location_bar_ is a normal gtk text box right now. Change this
+ // when we get omnibox support.
+ // location_bar_->SetProfile(profile);
+}
+
+void BrowserToolbarGtk::UpdateTabContents(TabContents* contents,
+ bool should_restore_state) {
+ // Extract the UTF-8 representation of the URL.
+ gtk_entry_set_text(GTK_ENTRY(entry_),
+ contents->GetURL().possibly_invalid_spec().c_str());
+}
+
+CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton(
+ int normal_id, int active_id, int highlight_id, int depressed_id,
+ const std::wstring& localized_tooltip) {
+ CustomDrawButton* button = new CustomDrawButton(normal_id, active_id,
+ highlight_id, depressed_id);
+
+ gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
+ GTK_WIDGET(button->widget()),
+ WideToUTF8(localized_tooltip).c_str(),
+ WideToUTF8(localized_tooltip).c_str());
+ g_signal_connect(G_OBJECT(button->widget()), "clicked",
+ G_CALLBACK(OnButtonClick), this);
+ GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS);
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
+ return button;
+}
+
+CustomContainerButton* BrowserToolbarGtk::BuildToolbarMenuButton(
+ int icon_id,
+ const std::wstring& localized_tooltip) {
+ CustomContainerButton* button = new CustomContainerButton;
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ gtk_container_set_border_width(GTK_CONTAINER(button->widget()), 2);
+ gtk_container_add(GTK_CONTAINER(button->widget()),
+ gtk_image_new_from_pixbuf(rb.LoadPixbuf(icon_id)));
+
+ gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
+ GTK_WIDGET(button->widget()),
+ WideToUTF8(localized_tooltip).c_str(),
+ WideToUTF8(localized_tooltip).c_str());
+ g_signal_connect(G_OBJECT(button->widget()), "button-press-event",
+ G_CALLBACK(OnMenuButtonPressEvent), this);
+ GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS);
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
+
+ return button;
+}
+
+// static
+void BrowserToolbarGtk::OnEntryActivate(GtkEntry *entry,
+ BrowserToolbarGtk* toolbar) {
+ GURL dest(URLFixerUpper::FixupURL(std::string(gtk_entry_get_text(entry)),
+ std::string()));
+ toolbar->browser_->GetSelectedTabContents()->
+ OpenURL(dest, GURL(), CURRENT_TAB, PageTransition::TYPED);
+}
+
+// static
+gboolean BrowserToolbarGtk::OnEntryFocus(GtkWidget* widget,
+ GtkDirectionType direction,
+ BrowserToolbarGtk* host) {
+ if (!GTK_WIDGET_HAS_FOCUS(widget)) {
+ gtk_widget_grab_focus(widget);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// static
+gboolean BrowserToolbarGtk::OnEntryFocusIn(GtkWidget* widget,
+ GdkEventFocus* focus,
+ BrowserToolbarGtk* host) {
+ // Set the caret at the end of the text.
+ gtk_editable_set_position(GTK_EDITABLE(widget), -1);
+ return FALSE;
+}
+
+// static
+gboolean BrowserToolbarGtk::OnEntryFocusOut(GtkWidget* widget,
+ GdkEventFocus* focus,
+ BrowserToolbarGtk* host) {
+ // Clear the selected text (if any).
+ gtk_editable_set_position(GTK_EDITABLE(widget), 0);
+ return FALSE;
+}
+
+// static
+void BrowserToolbarGtk::OnButtonClick(GtkWidget* button,
+ BrowserToolbarGtk* toolbar) {
+ int tag = -1;
+ if (button == toolbar->back_->widget())
+ tag = IDC_BACK;
+ else if (button == toolbar->forward_->widget())
+ tag = IDC_FORWARD;
+ else if (button == toolbar->reload_->widget())
+ tag = IDC_RELOAD;
+ else if (button == toolbar->go_->widget())
+ tag = IDC_GO;
+ else if (toolbar->home_.get() && button == toolbar->home_->widget())
+ tag = IDC_HOME;
+ else if (button == toolbar->star_->widget())
+ tag = IDC_STAR;
+
+ if (tag == IDC_BACK || tag == IDC_FORWARD)
+ toolbar->show_menu_factory_.RevokeAll();
+
+ DCHECK(tag != -1) << "Impossible button click callback";
+ toolbar->browser_->ExecuteCommand(tag);
+}
+
+// static
+gboolean BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button,
+ GdkEvent* event,
+ BrowserToolbarGtk* toolbar) {
+ // TODO(port): this never puts the button into the "active" state,
+ // which means we never display the button-pressed-down graphics. I
+ // suspect a better way to do it is just to use a real GtkMenuShell
+ // with our custom drawing.
+ if (event->type == GDK_BUTTON_PRESS) {
+ GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event);
+ if (event_button->button == 1) {
+ // We have a button press we should respond to.
+ if (button == toolbar->page_menu_button_->widget()) {
+ toolbar->RunPageMenu(event);
+ return TRUE;
+ } else if (button == toolbar->app_menu_button_->widget()) {
+ toolbar->RunAppMenu(event);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+CustomDrawButton* BrowserToolbarGtk::BuildBackForwardButton(
+ int normal_id,
+ int active_id,
+ int highlight_id,
+ int depressed_id,
+ const std::wstring& localized_tooltip) {
+ CustomDrawButton* button = new CustomDrawButton(normal_id, active_id,
+ highlight_id, depressed_id);
+
+ // TODO(erg): Mismatch between wstring and string.
+ // gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_),
+ // GTK_WIDGET(back_),
+ // localized_tooltip, localized_tooltip);
+
+ g_signal_connect(G_OBJECT(button->widget()), "button-press-event",
+ G_CALLBACK(OnBackForwardPressEvent), this);
+ g_signal_connect(G_OBJECT(button->widget()), "clicked",
+ G_CALLBACK(OnButtonClick), this);
+ GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS);
+
+ gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0);
+ // Popup the menu as left-aligned relative to this widget rather than the
+ // default of right aligned.
+ g_object_set_data(G_OBJECT(button->widget()), "left-align-popup",
+ reinterpret_cast<void*>(true));
+ return button;
+}
+
+// static
+gboolean BrowserToolbarGtk::OnBackForwardPressEvent(GtkWidget* widget,
+ GdkEventButton* event,
+ BrowserToolbarGtk* toolbar) {
+ // TODO(port): only allow left clicks to open the menu.
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ toolbar->show_menu_factory_.NewRunnableMethod(
+ &BrowserToolbarGtk::ShowBackForwardMenu,
+ widget, event->button),
+ kMenuTimerDelay);
+ return FALSE;
+}
+
+void BrowserToolbarGtk::ShowBackForwardMenu(GtkWidget* widget,
+ gint button_type) {
+ if (widget == back_->widget()) {
+ back_forward_menu_.reset(new MenuGtk(back_menu_model_.get()));
+ } else {
+ back_forward_menu_.reset(new MenuGtk(forward_menu_model_.get()));
+ }
+
+ back_forward_menu_->Popup(widget, button_type, gtk_get_current_event_time());
+}
+
+void BrowserToolbarGtk::RunPageMenu(GdkEvent* button_press_event) {
+ if (page_menu_ == NULL) {
+ page_menu_.reset(new MenuGtk(this, GetStandardPageMenu()));
+ }
+
+ page_menu_->Popup(page_menu_button_->widget(), button_press_event);
+}
+
+void BrowserToolbarGtk::RunAppMenu(GdkEvent* button_press_event) {
+ if (app_menu_ == NULL) {
+ app_menu_.reset(new MenuGtk(this, GetStandardAppMenu()));
+ }
+
+ app_menu_->Popup(app_menu_button_->widget(), button_press_event);
+}
+
+CustomDrawButton* BrowserToolbarGtk::MakeHomeButton() {
+ return BuildToolbarButton(IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0,
+ l10n_util::GetString(IDS_TOOLTIP_HOME));
+}