Index: chrome/browser/ui/panels/panel_titlebar_gtk.cc |
diff --git a/chrome/browser/ui/panels/panel_titlebar_gtk.cc b/chrome/browser/ui/panels/panel_titlebar_gtk.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e15f9c6762887393d3177e36efa99b278157996c |
--- /dev/null |
+++ b/chrome/browser/ui/panels/panel_titlebar_gtk.cc |
@@ -0,0 +1,311 @@ |
+// Copyright (c) 2012 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/panels/panel_titlebar_gtk.h" |
+ |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/ui/gtk/custom_button.h" |
+#include "chrome/browser/ui/gtk/gtk_theme_service.h" |
+#include "chrome/browser/ui/gtk/gtk_util.h" |
+#include "chrome/browser/ui/panels/panel.h" |
+#include "chrome/browser/ui/panels/panel_gtk.h" |
+#include "content/public/browser/web_contents.h" |
+#include "grit/generated_resources.h" |
+#include "grit/theme_resources.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "ui/base/gtk/gtk_compat.h" |
+#include "ui/base/l10n/l10n_util.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/skia_utils_gtk.h" |
+ |
+namespace { |
+ |
+// Padding around the titlebar. |
+const int kPanelTitlebarPaddingTop = 7; |
+const int kPanelTitlebarPaddingBottom = 7; |
+const int kPanelTitlebarPaddingLeft = 4; |
+const int kPanelTitlebarPaddingRight = 8; |
+ |
+// Spacing between buttons of panel's titlebar. |
+const int kPanelButtonSpacing = 5; |
+ |
+// Spacing between the icon and the title text. |
+const int kPanelIconTitleSpacing = 9; |
+ |
+// Color used to draw title text under default theme. |
+const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9); |
+ |
+// Markup used to paint the title with the desired font. |
+const char* const kTitleMarkupPrefix = "<span face='Arial' size='11264'>"; |
+const char* const kTitleMarkupSuffix = "</span>"; |
+ |
+} // namespace |
+ |
+PanelTitlebarGtk::PanelTitlebarGtk(PanelGtk* panel_gtk) |
+ : panel_gtk_(panel_gtk), |
+ container_(NULL), |
+ titlebar_right_buttons_vbox_(NULL), |
+ titlebar_right_buttons_hbox_(NULL), |
+ icon_(NULL), |
+ title_(NULL), |
+ theme_service_(GtkThemeService::GetFrom(panel_gtk_->panel()->profile())) { |
+} |
+ |
+PanelTitlebarGtk::~PanelTitlebarGtk() { |
+} |
+ |
+void PanelTitlebarGtk::Init() { |
+ container_ = gtk_event_box_new(); |
+ gtk_widget_set_name(container_, "chrome-panel-titlebar"); |
+ gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE); |
+ |
+ // We use an alignment to control the titlebar paddings. |
+ GtkWidget* container_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
+ gtk_container_add(GTK_CONTAINER(container_), container_alignment); |
+ gtk_alignment_set_padding(GTK_ALIGNMENT(container_alignment), |
+ kPanelTitlebarPaddingTop, |
+ kPanelTitlebarPaddingBottom, |
+ kPanelTitlebarPaddingLeft, |
+ kPanelTitlebarPaddingRight); |
+ |
+ // Add a container box. |
+ GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0); |
+ gtk_container_add(GTK_CONTAINER(container_alignment), container_hbox); |
+ |
+ // Add minimize/restore and close buttons. Panel buttons are always placed |
+ // on the right part of the titlebar. |
+ titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0); |
+ gtk_box_pack_end(GTK_BOX(container_hbox), titlebar_right_buttons_vbox_, |
+ FALSE, FALSE, 0); |
+ BuildButtons(); |
+ |
+ // Add hbox for holding icon and title. |
+ GtkWidget* icon_title_hbox = gtk_hbox_new(FALSE, kPanelIconTitleSpacing); |
+ gtk_box_pack_start(GTK_BOX(container_hbox), icon_title_hbox, TRUE, TRUE, 0); |
+ |
+ // Add icon. We use the app logo as a placeholder image so the title doesn't |
+ // jump around. |
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
+ icon_ = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed( |
+ IDR_PRODUCT_LOGO_16, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf()); |
+ g_object_set_data(G_OBJECT(icon_), "left-align-popup", |
+ reinterpret_cast<void*>(true)); |
+ gtk_box_pack_start(GTK_BOX(icon_title_hbox), icon_, FALSE, FALSE, 0); |
+ |
+ // Add title. |
+ title_ = gtk_label_new(NULL); |
+ gtk_label_set_ellipsize(GTK_LABEL(title_), PANGO_ELLIPSIZE_END); |
+ gtk_misc_set_alignment(GTK_MISC(title_), 0.0, 0.5); |
+ gtk_box_pack_start(GTK_BOX(icon_title_hbox), title_, TRUE, TRUE, 0); |
+ UpdateTitleAndIcon(); |
+ UpdateTextColor(); |
+ |
+ gtk_widget_show_all(container_); |
+} |
+ |
+SkColor PanelTitlebarGtk::GetTextColor() const { |
+ if (panel_gtk_->UsingDefaultTheme()) |
+ return kTitleTextDefaultColor; |
+ return theme_service_->GetColor(panel_gtk_->paint_state() == |
+ PanelGtk::PAINT_AS_ACTIVE ? |
+ ThemeService::COLOR_TAB_TEXT : |
+ ThemeService::COLOR_BACKGROUND_TAB_TEXT); |
+} |
+ |
+void PanelTitlebarGtk::BuildButtons() { |
+ minimize_button_.reset(CreateButton(panel::MINIMIZE_BUTTON)); |
+ restore_button_.reset(CreateButton(panel::RESTORE_BUTTON)); |
+ close_button_.reset(CreateButton(panel::CLOSE_BUTTON)); |
+ |
+ // We control visibility of minimize and restore buttons. |
+ gtk_widget_set_no_show_all(minimize_button_->widget(), TRUE); |
+ gtk_widget_set_no_show_all(restore_button_->widget(), TRUE); |
+ |
+ // Now show the correct widgets in the two hierarchies. |
+ UpdateMinimizeRestoreButtonVisibility(); |
+} |
+ |
+CustomDrawButton* PanelTitlebarGtk::CreateButton( |
+ panel::TitlebarButtonType button_type) { |
+ int normal_image_id = -1; |
+ int pressed_image_id = -1; |
+ int hover_image_id = -1; |
+ int tooltip_id = -1; |
+ GetButtonResources(button_type, &normal_image_id, &pressed_image_id, |
+ &hover_image_id, &tooltip_id); |
+ |
+ CustomDrawButton* button = new CustomDrawButton(normal_image_id, |
+ pressed_image_id, |
+ hover_image_id, |
+ 0); |
+ gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); |
+ g_signal_connect(button->widget(), "clicked", |
+ G_CALLBACK(OnButtonClickedThunk), this); |
+ |
+ std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip_id); |
+ gtk_widget_set_tooltip_text(button->widget(), |
+ localized_tooltip.c_str()); |
+ |
+ GtkWidget* box = GetButtonHBox(); |
+ gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); |
+ return button; |
+} |
+ |
+void PanelTitlebarGtk::GetButtonResources( |
+ panel::TitlebarButtonType button_type, |
+ int* normal_image_id, |
+ int* pressed_image_id, |
+ int* hover_image_id, |
+ int* tooltip_id) const { |
+ switch (button_type) { |
+ case panel::CLOSE_BUTTON: |
+ *normal_image_id = IDR_PANEL_CLOSE; |
+ *pressed_image_id = IDR_PANEL_CLOSE_C; |
+ *hover_image_id = IDR_PANEL_CLOSE_H; |
+ *tooltip_id = IDS_PANEL_CLOSE_TOOLTIP; |
+ break; |
+ case panel::MINIMIZE_BUTTON: |
+ *normal_image_id = IDR_PANEL_MINIMIZE; |
+ *pressed_image_id = IDR_PANEL_MINIMIZE_C; |
+ *hover_image_id = IDR_PANEL_MINIMIZE_H; |
+ *tooltip_id = IDS_PANEL_MINIMIZE_TOOLTIP; |
+ break; |
+ case panel::RESTORE_BUTTON: |
+ *normal_image_id = IDR_PANEL_RESTORE; |
+ *pressed_image_id = IDR_PANEL_RESTORE_C; |
+ *hover_image_id = IDR_PANEL_RESTORE_H; |
+ *tooltip_id = IDS_PANEL_RESTORE_TOOLTIP; |
+ break; |
+ } |
+} |
+ |
+GtkWidget* PanelTitlebarGtk::GetButtonHBox() { |
+ if (!titlebar_right_buttons_hbox_) { |
+ // We put the minimize/restore/close buttons in a vbox so they are top |
+ // aligned (up to padding) and don't vertically stretch. |
+ titlebar_right_buttons_hbox_ = gtk_hbox_new(FALSE, kPanelButtonSpacing); |
+ gtk_box_pack_start(GTK_BOX(titlebar_right_buttons_vbox_), |
+ titlebar_right_buttons_hbox_, FALSE, FALSE, 0); |
+ } |
+ |
+ return titlebar_right_buttons_hbox_; |
+} |
+ |
+void PanelTitlebarGtk::UpdateTitleAndIcon() { |
+ std::string title_text = |
+ UTF16ToUTF8(panel_gtk_->panel()->GetWindowTitle()); |
+ |
+ // Add the markup to show the title in the desired font. |
+ gchar* escaped_title_text = g_markup_escape_text(title_text.c_str(), -1); |
+ gchar* title_text_with_markup = g_strconcat(kTitleMarkupPrefix, |
+ escaped_title_text, |
+ kTitleMarkupSuffix, |
+ NULL); |
+ gtk_label_set_markup(GTK_LABEL(title_), title_text_with_markup); |
+ g_free(escaped_title_text); |
+ g_free(title_text_with_markup); |
+} |
+ |
+void PanelTitlebarGtk::UpdateThrobber( |
+ content::WebContents* web_contents) { |
+ if (web_contents && web_contents->IsLoading()) { |
+ GdkPixbuf* icon_pixbuf = |
+ throbber_.GetNextFrame(web_contents->IsWaitingForResponse()); |
+ gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf); |
+ } else { |
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
+ |
+ SkBitmap icon = panel_gtk_->panel()->GetCurrentPageIcon(); |
+ if (icon.empty()) { |
+ // Fallback to the Chromium icon if the page has no icon. |
+ gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), |
+ rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf()); |
+ } else { |
+ GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(icon); |
+ gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf); |
+ g_object_unref(icon_pixbuf); |
+ } |
+ |
+ throbber_.Reset(); |
+ } |
+} |
+ |
+void PanelTitlebarGtk::UpdateTextColor() { |
+ GdkColor text_color = gfx::SkColorToGdkColor(GetTextColor()); |
+ gtk_util::SetLabelColor(title_, &text_color); |
+} |
+ |
+void PanelTitlebarGtk::UpdateMinimizeRestoreButtonVisibility() { |
+ Panel* panel = panel_gtk_->panel(); |
+ gtk_widget_set_visible(minimize_button_->widget(), panel->CanMinimize()); |
+ gtk_widget_set_visible(restore_button_->widget(), panel->CanRestore()); |
+} |
+ |
+void PanelTitlebarGtk::OnButtonClicked(GtkWidget* button) { |
+ Panel* panel = panel_gtk_->panel(); |
+ if (close_button_->widget() == button) { |
+ panel->Close(); |
+ return; |
+ } |
+ |
+ GdkEvent* event = gtk_get_current_event(); |
+ DCHECK(event && event->type == GDK_BUTTON_RELEASE); |
+ |
+ if (minimize_button_->widget() == button) { |
+ panel->OnMinimizeButtonClicked( |
+ (event->button.state & GDK_CONTROL_MASK) ? |
+ panel::APPLY_TO_ALL : panel::NO_MODIFIER); |
+ } else if (restore_button_->widget() == button) { |
+ panel->OnRestoreButtonClicked( |
+ (event->button.state & GDK_CONTROL_MASK) ? |
+ panel::APPLY_TO_ALL : panel::NO_MODIFIER); |
+ } |
+ |
+ gdk_event_free(event); |
+} |
+ |
+void PanelTitlebarGtk::SendEnterNotifyToCloseButtonIfUnderMouse() { |
+ if (!close_button()) |
+ return; |
+ |
+ gint x; |
+ gint y; |
+ GtkAllocation widget_allocation = close_button()->WidgetAllocation(); |
+ gtk_widget_get_pointer(GTK_WIDGET(close_button()->widget()), &x, &y); |
+ |
+ gfx::Rect button_rect(0, 0, widget_allocation.width, |
+ widget_allocation.height); |
+ if (!button_rect.Contains(x, y)) { |
+ // Mouse is not over the close button. |
+ return; |
+ } |
+ |
+ // Create and emit an enter-notify-event on close button. |
+ GValue return_value; |
+ return_value.g_type = G_TYPE_BOOLEAN; |
+ g_value_set_boolean(&return_value, false); |
+ |
+ GdkEvent* event = gdk_event_new(GDK_ENTER_NOTIFY); |
+ event->crossing.window = |
+ gtk_button_get_event_window(GTK_BUTTON(close_button()->widget())); |
+ event->crossing.send_event = FALSE; |
+ event->crossing.subwindow = gtk_widget_get_window(close_button()->widget()); |
+ event->crossing.time = gtk_util::XTimeNow(); |
+ event->crossing.x = x; |
+ event->crossing.y = y; |
+ event->crossing.x_root = widget_allocation.x; |
+ event->crossing.y_root = widget_allocation.y; |
+ event->crossing.mode = GDK_CROSSING_NORMAL; |
+ event->crossing.detail = GDK_NOTIFY_ANCESTOR; |
+ event->crossing.focus = true; |
+ event->crossing.state = 0; |
+ |
+ g_signal_emit_by_name(GTK_OBJECT(close_button()->widget()), |
+ "enter-notify-event", event, |
+ &return_value); |
+} |
+ |
+GtkWidget* PanelTitlebarGtk::widget() const { |
+ return container_; |
+} |