summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd5
-rw-r--r--chrome/browser/ui/gtk/browser_window_gtk.cc6
-rw-r--r--chrome/browser/ui/gtk/bubble/bubble_gtk.cc72
-rw-r--r--chrome/browser/ui/gtk/bubble/bubble_gtk.h2
-rw-r--r--chrome/browser/ui/gtk/location_bar_view_gtk.cc306
-rw-r--r--chrome/browser/ui/gtk/location_bar_view_gtk.h29
-rw-r--r--chrome/browser/ui/gtk/zoom_bubble_gtk.cc153
-rw-r--r--chrome/browser/ui/gtk/zoom_bubble_gtk.h73
-rw-r--r--chrome/chrome_browser.gypi2
9 files changed, 521 insertions, 127 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 48687b5..f990f4e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -970,7 +970,7 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
&#8722;
</message>
<message name="IDS_ZOOM_PERCENT" desc="Current pages zoom factor; shown in merged menu">
- <ph name="VALUE">$1<ex>100</ex></ph>%
+ <ph name="VALUE">$1<ex>100</ex></ph>%
</message>
<message name="IDS_ENCODING_MENU" desc="The text label of the Encoding submenu">
&amp;Encoding
@@ -6307,6 +6307,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_TOOLTIP_ACTION_BOX_BUTTON" desc="The tooltip for action box button">
Actions
</message>
+ <message name="IDS_TOOLTIP_ZOOM" desc="The tooltip for zoom icon">
+ Zoom: <ph name="VALUE">$1<ex>100</ex></ph>%
+ </message>
<!--Accessible name/action strings-->
<message name="IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT" desc="The format for the accessible title of an incognito window">
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index 017d062..6ea2b9c 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -889,15 +889,15 @@ void BrowserWindowGtk::SetStarredState(bool is_starred) {
}
void BrowserWindowGtk::SetZoomIconState(ZoomController::ZoomIconState state) {
- // TODO(khorimoto): Implement this.
+ toolbar_->GetLocationBarView()->SetZoomIconState(state);
}
void BrowserWindowGtk::SetZoomIconTooltipPercent(int zoom_percent) {
- // TODO(khorimoto): Implement this.
+ toolbar_->GetLocationBarView()->SetZoomIconTooltipPercent(zoom_percent);
}
void BrowserWindowGtk::ShowZoomBubble(int zoom_percent) {
- // TODO(khorimoto): Implement this.
+ toolbar_->GetLocationBarView()->ShowZoomBubble(zoom_percent);
}
gfx::Rect BrowserWindowGtk::GetRestoredBounds() const {
diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
index a06d398..ead2517 100644
--- a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
@@ -55,6 +55,11 @@ bool IsArrowLeft(BubbleGtk::ArrowLocationGtk location) {
location == BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT;
}
+bool IsArrowMiddle(BubbleGtk::ArrowLocationGtk location) {
+ return location == BubbleGtk::ARROW_LOCATION_TOP_MIDDLE ||
+ location == BubbleGtk::ARROW_LOCATION_BOTTOM_MIDDLE;
+}
+
bool IsArrowRight(BubbleGtk::ArrowLocationGtk location) {
return location == BubbleGtk::ARROW_LOCATION_TOP_RIGHT ||
location == BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT;
@@ -62,11 +67,13 @@ bool IsArrowRight(BubbleGtk::ArrowLocationGtk location) {
bool IsArrowTop(BubbleGtk::ArrowLocationGtk location) {
return location == BubbleGtk::ARROW_LOCATION_TOP_LEFT ||
+ location == BubbleGtk::ARROW_LOCATION_TOP_MIDDLE ||
location == BubbleGtk::ARROW_LOCATION_TOP_RIGHT;
}
bool IsArrowBottom(BubbleGtk::ArrowLocationGtk location) {
return location == BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT ||
+ location == BubbleGtk::ARROW_LOCATION_BOTTOM_MIDDLE ||
location == BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT;
}
@@ -198,10 +205,9 @@ void BubbleGtk::Init(GtkWidget* anchor_widget,
gtk_widget_show_all(window_);
- if (grab_input_) {
+ if (grab_input_)
gtk_grab_add(window_);
- GrabPointerAndKeyboard();
- }
+ GrabPointerAndKeyboard();
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
content::Source<ThemeService>(theme_service_));
@@ -244,14 +250,16 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints(
// The top arrow.
if (top_arrow_size) {
+ int arrow_x = arrow_location == ARROW_LOCATION_TOP_MIDDLE ?
+ width / 2 : kArrowX;
points.push_back(MakeBidiGdkPoint(
- kArrowX - top_arrow_size + x_off_r, top_arrow_size, width, on_left));
+ arrow_x - top_arrow_size + x_off_r, top_arrow_size, width, on_left));
points.push_back(MakeBidiGdkPoint(
- kArrowX + x_off_r, 0, width, on_left));
+ arrow_x + x_off_r, 0, width, on_left));
points.push_back(MakeBidiGdkPoint(
- kArrowX + 1 + x_off_l, 0, width, on_left));
+ arrow_x + 1 + x_off_l, 0, width, on_left));
points.push_back(MakeBidiGdkPoint(
- kArrowX + top_arrow_size + 1 + x_off_l, top_arrow_size,
+ arrow_x + top_arrow_size + 1 + x_off_l, top_arrow_size,
width, on_left));
}
@@ -271,17 +279,19 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints(
// The bottom arrow.
if (bottom_arrow_size) {
+ int arrow_x = arrow_location == ARROW_LOCATION_BOTTOM_MIDDLE ?
+ width / 2 : kArrowX;
points.push_back(MakeBidiGdkPoint(
- kArrowX + bottom_arrow_size + 1 + x_off_l,
+ arrow_x + bottom_arrow_size + 1 + x_off_l,
height - bottom_arrow_size + y_off,
width,
on_left));
points.push_back(MakeBidiGdkPoint(
- kArrowX + 1 + x_off_l, height + y_off, width, on_left));
+ arrow_x + 1 + x_off_l, height + y_off, width, on_left));
points.push_back(MakeBidiGdkPoint(
- kArrowX + x_off_r, height + y_off, width, on_left));
+ arrow_x + x_off_r, height + y_off, width, on_left));
points.push_back(MakeBidiGdkPoint(
- kArrowX - bottom_arrow_size + x_off_r,
+ arrow_x - bottom_arrow_size + x_off_r,
height - bottom_arrow_size + y_off,
width,
on_left));
@@ -315,20 +325,26 @@ BubbleGtk::ArrowLocationGtk BubbleGtk::GetArrowLocation(
ArrowLocationGtk arrow_location_none;
ArrowLocationGtk arrow_location_left;
+ ArrowLocationGtk arrow_location_middle;
ArrowLocationGtk arrow_location_right;
if (top_is_onscreen && (wants_top || !bottom_is_onscreen)) {
arrow_location_none = ARROW_LOCATION_NONE;
arrow_location_left = ARROW_LOCATION_TOP_LEFT;
+ arrow_location_middle = ARROW_LOCATION_TOP_MIDDLE;
arrow_location_right =ARROW_LOCATION_TOP_RIGHT;
} else {
arrow_location_none = ARROW_LOCATION_FLOAT;
arrow_location_left = ARROW_LOCATION_BOTTOM_LEFT;
+ arrow_location_middle = ARROW_LOCATION_BOTTOM_MIDDLE;
arrow_location_right =ARROW_LOCATION_BOTTOM_RIGHT;
}
if (!HasArrow(preferred_location))
return arrow_location_none;
+ if (IsArrowMiddle(preferred_location))
+ return arrow_location_middle;
+
bool wants_left = IsArrowLeft(preferred_location);
bool left_is_onscreen = (arrow_x - kArrowX + width < screen_width);
bool right_is_onscreen = (arrow_x + kArrowX - width >= 0);
@@ -408,7 +424,8 @@ void BubbleGtk::MoveWindow() {
gtk_widget_get_allocation(window_, &allocation);
gint screen_x = 0;
- if (!HasArrow(current_arrow_location_)) {
+ if (!HasArrow(current_arrow_location_) ||
+ IsArrowMiddle(current_arrow_location_)) {
screen_x =
toplevel_x + offset_x + (rect_.width() / 2) - allocation.width / 2;
} else if (IsArrowLeft(current_arrow_location_)) {
@@ -475,7 +492,10 @@ void BubbleGtk::GrabPointerAndKeyboard() {
GdkWindow* gdk_window = gtk_widget_get_window(window_);
// Install X pointer and keyboard grabs to make sure that we have the focus
- // and get all mouse and keyboard events until we're closed.
+ // and get all mouse and keyboard events until we're closed. As a hack, grab
+ // the pointer even if |grab_input_| is false to prevent a weird error
+ // rendering the bubble's frame. See
+ // https://code.google.com/p/chromium/issues/detail?id=130820.
GdkGrabStatus pointer_grab_status =
gdk_pointer_grab(gdk_window,
TRUE, // owner_events
@@ -489,13 +509,17 @@ void BubbleGtk::GrabPointerAndKeyboard() {
DLOG(ERROR) << "Unable to grab pointer (status="
<< pointer_grab_status << ")";
}
- GdkGrabStatus keyboard_grab_status =
- gdk_keyboard_grab(gdk_window,
- FALSE, // owner_events
- GDK_CURRENT_TIME);
- if (keyboard_grab_status != GDK_GRAB_SUCCESS) {
- DLOG(ERROR) << "Unable to grab keyboard (status="
- << keyboard_grab_status << ")";
+
+ // Only grab the keyboard input if |grab_input_| is true.
+ if (grab_input_) {
+ GdkGrabStatus keyboard_grab_status =
+ gdk_keyboard_grab(gdk_window,
+ FALSE, // owner_events
+ GDK_CURRENT_TIME);
+ if (keyboard_grab_status != GDK_GRAB_SUCCESS) {
+ DLOG(ERROR) << "Unable to grab keyboard (status="
+ << keyboard_grab_status << ")";
+ }
}
}
@@ -570,6 +594,14 @@ gboolean BubbleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) {
FRAME_STROKE);
gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size());
+ // If |grab_input_| is false, pointer input has been grabbed as a hack in
+ // |GrabPointerAndKeyboard()| to ensure that the polygon frame is drawn
+ // correctly. Since the intention is not actually to grab the pointer, release
+ // it now that the frame is drawn to prevent clicks from being missed. See
+ // https://code.google.com/p/chromium/issues/detail?id=130820.
+ if (!grab_input_)
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+
g_object_unref(gc);
return FALSE; // Propagate so our children paint, etc.
}
diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.h b/chrome/browser/ui/gtk/bubble/bubble_gtk.h
index b03e0be..fd85499 100644
--- a/chrome/browser/ui/gtk/bubble/bubble_gtk.h
+++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.h
@@ -52,8 +52,10 @@ class BubbleGtk : public content::NotificationObserver {
// Where should the arrow be placed relative to the bubble?
enum ArrowLocationGtk {
ARROW_LOCATION_TOP_LEFT,
+ ARROW_LOCATION_TOP_MIDDLE,
ARROW_LOCATION_TOP_RIGHT,
ARROW_LOCATION_BOTTOM_LEFT,
+ ARROW_LOCATION_BOTTOM_MIDDLE,
ARROW_LOCATION_BOTTOM_RIGHT,
ARROW_LOCATION_NONE, // No arrow. Positioned under the supplied rect.
ARROW_LOCATION_FLOAT, // No arrow. Centered over the supplied rect.
diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc
index e08e481..d0c7234 100644
--- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc
@@ -13,6 +13,7 @@
#include "base/debug/trace_event.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
@@ -55,8 +56,10 @@
#include "chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.h"
#include "chrome/browser/ui/gtk/rounded_window.h"
#include "chrome/browser/ui/gtk/view_id_util.h"
+#include "chrome/browser/ui/gtk/zoom_bubble_gtk.h"
#include "chrome/browser/ui/omnibox/location_bar_util.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
+#include "chrome/browser/ui/zoom/zoom_controller.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_action.h"
@@ -73,6 +76,7 @@
#include "ui/base/accelerators/accelerator_gtk.h"
#include "ui/base/dragdrop/gtk_dnd_util.h"
#include "ui/base/gtk/gtk_hig_constants.h"
+#include "ui/base/gtk/gtk_signal_registrar.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia_paint.h"
@@ -160,7 +164,8 @@ const GdkColor LocationBarViewGtk::kBackgroundColor =
GDK_COLOR_RGB(255, 255, 255);
LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
- : star_image_(NULL),
+ : zoom_image_(NULL),
+ star_image_(NULL),
starred_(false),
chrome_to_mobile_image_(NULL),
site_type_alignment_(NULL),
@@ -195,6 +200,7 @@ LocationBarViewGtk::LocationBarViewGtk(Browser* browser)
LocationBarViewGtk::~LocationBarViewGtk() {
// All of our widgets should be children of / owned by the alignment.
+ zoom_.Destroy();
star_.Destroy();
chrome_to_mobile_view_.Destroy();
hbox_.Destroy();
@@ -313,11 +319,14 @@ void LocationBarViewGtk::Init(bool popup_window_mode) {
// doesn't work, someone is probably calling show_all on our parent box.
gtk_box_pack_end(GTK_BOX(entry_box_), tab_to_search_hint_, FALSE, FALSE, 0);
- // Hide the star and Chrome To Mobile icons in popups, app windows, etc.
+ // Hide the zoom, star and Chrome To Mobile icons in popups, app windows, etc.
if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) {
CreateStarButton();
gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0);
+ CreateZoomButton();
+ gtk_box_pack_end(GTK_BOX(hbox_.get()), zoom_.get(), FALSE, FALSE, 0);
+
// Also disable Chrome To Mobile for off-the-record and non-synced profiles,
// or if the feature is disabled by a command line flag or chrome://flags.
if (!profile->IsOffTheRecord() && profile->IsSyncAccessible() &&
@@ -325,6 +334,9 @@ void LocationBarViewGtk::Init(bool popup_window_mode) {
CreateChromeToMobileButton();
gtk_box_pack_end(GTK_BOX(hbox_.get()), chrome_to_mobile_view_.get(),
FALSE, FALSE, 0);
+ command_updater_->AddCommandObserver(IDC_CHROME_TO_MOBILE_PAGE, this);
+ ChromeToMobileServiceFactory::GetForProfile(browser_->profile())->
+ RequestMobileListUpdate();
}
}
@@ -475,6 +487,7 @@ GtkWidget* LocationBarViewGtk::GetPageActionWidget(
}
void LocationBarViewGtk::Update(const WebContents* contents) {
+ UpdateZoomIcon();
UpdateStarIcon();
UpdateChromeToMobileIcon();
UpdateSiteTypeArea();
@@ -545,46 +558,65 @@ void LocationBarViewGtk::OnSelectionBoundsChanged() {
NOTIMPLEMENTED();
}
-void LocationBarViewGtk::CreateStarButton() {
- star_image_ = gtk_image_new();
+GtkWidget* LocationBarViewGtk::CreateIconButton(
+ GtkWidget** image,
+ int image_id,
+ ViewID debug_id,
+ int tooltip_id,
+ gboolean (click_callback)(GtkWidget*, GdkEventButton*, gpointer)) {
+ *image = image_id ?
+ gtk_image_new_from_pixbuf(
+ theme_service_->GetImageNamed(image_id)->ToGdkPixbuf()) :
+ gtk_image_new();
GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
- 0, kStarRightPadding);
- gtk_container_add(GTK_CONTAINER(alignment), star_image_);
+ 0, kInnerPadding);
+ gtk_container_add(GTK_CONTAINER(alignment), *image);
+
+ GtkWidget* result = gtk_event_box_new();
+ gtk_event_box_set_visible_window(GTK_EVENT_BOX(result), FALSE);
+ gtk_container_add(GTK_CONTAINER(result), alignment);
+ gtk_widget_show_all(result);
- star_.Own(gtk_event_box_new());
- gtk_event_box_set_visible_window(GTK_EVENT_BOX(star_.get()), FALSE);
- gtk_container_add(GTK_CONTAINER(star_.get()), alignment);
- gtk_widget_show_all(star_.get());
- ViewIDUtil::SetID(star_.get(), VIEW_ID_STAR_BUTTON);
+ if (debug_id != VIEW_ID_NONE)
+ ViewIDUtil::SetID(result, debug_id);
+
+ if (tooltip_id) {
+ gtk_widget_set_tooltip_text(result,
+ l10n_util::GetStringUTF8(tooltip_id).c_str());
+ }
- gtk_widget_set_tooltip_text(star_.get(),
- l10n_util::GetStringUTF8(IDS_TOOLTIP_STAR).c_str());
- g_signal_connect(star_.get(), "button-press-event",
- G_CALLBACK(OnStarButtonPressThunk), this);
+ g_signal_connect(result, "button-press-event",
+ G_CALLBACK(click_callback), this);
+
+ return result;
+}
+
+void LocationBarViewGtk::CreateZoomButton() {
+ // TODO(khorimoto): Add tests for zoom button.
+ zoom_.Own(CreateIconButton(&zoom_image_,
+ 0,
+ VIEW_ID_NONE,
+ 0,
+ OnZoomButtonPressThunk));
+}
+
+void LocationBarViewGtk::CreateStarButton() {
+ star_.Own(CreateIconButton(&star_image_,
+ 0,
+ VIEW_ID_STAR_BUTTON,
+ IDS_TOOLTIP_STAR,
+ OnStarButtonPressThunk));
}
void LocationBarViewGtk::CreateChromeToMobileButton() {
- chrome_to_mobile_image_ = gtk_image_new_from_pixbuf(
- theme_service_->GetImageNamed(IDR_MOBILE)->ToGdkPixbuf());
- chrome_to_mobile_view_.Own(gtk_event_box_new());
- gtk_event_box_set_visible_window(
- GTK_EVENT_BOX(chrome_to_mobile_view_.get()), FALSE);
- gtk_container_add(GTK_CONTAINER(chrome_to_mobile_view_.get()),
- chrome_to_mobile_image_);
- ViewIDUtil::SetID(chrome_to_mobile_view_.get(),
- VIEW_ID_CHROME_TO_MOBILE_BUTTON);
- gtk_widget_set_tooltip_text(chrome_to_mobile_view_.get(),
- l10n_util::GetStringUTF8(IDS_CHROME_TO_MOBILE_BUBBLE_TOOLTIP).c_str());
- gtk_widget_set_visible(chrome_to_mobile_view_.get(), FALSE);
- g_signal_connect(chrome_to_mobile_view_.get(), "button-press-event",
- G_CALLBACK(OnChromeToMobileButtonPressThunk), this);
-
- command_updater_->AddCommandObserver(IDC_CHROME_TO_MOBILE_PAGE, this);
-
- ChromeToMobileServiceFactory::GetForProfile(browser_->profile())->
- RequestMobileListUpdate();
+ chrome_to_mobile_view_.Own(
+ CreateIconButton(&chrome_to_mobile_image_,
+ IDR_MOBILE,
+ VIEW_ID_CHROME_TO_MOBILE_BUTTON,
+ IDS_CHROME_TO_MOBILE_BUBBLE_TOOLTIP,
+ OnChromeToMobileButtonPressThunk));
}
void LocationBarViewGtk::OnInputInProgress(bool in_progress) {
@@ -808,74 +840,89 @@ void LocationBarViewGtk::TestPageActionPressed(size_t index) {
void LocationBarViewGtk::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
- if (type == chrome::NOTIFICATION_PREF_CHANGED) {
- UpdateStarIcon();
- UpdateChromeToMobileIcon();
- return;
- }
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED: {
+ // Only update if the updated action box was for the active tab contents.
+ TabContents* target_tab =
+ content::Details<TabContents>(details).ptr();
+ if (target_tab == GetTabContents())
+ UpdatePageActions();
+ break;
+ }
- if (type == chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED) {
- // Only update if the updated action box was for the active tab contents.
- TabContents* target_tab = content::Details<TabContents>(details).ptr();
- if (target_tab == GetTabContents())
- UpdatePageActions();
- return;
- }
+ case chrome::NOTIFICATION_PREF_CHANGED: {
+ std::string* pref_name_in = content::Details<std::string>(details).ptr();
+ DCHECK(pref_name_in);
- DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
+ if (*pref_name_in == prefs::kEditBookmarksEnabled) {
+ UpdateStarIcon();
+ UpdateChromeToMobileIcon();
+ } else {
+ NOTREACHED();
+ }
+ break;
+ }
- if (theme_service_->UsingNativeTheme()) {
- gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, NULL);
-
- GdkColor border_color = theme_service_->GetGdkColor(
- ThemeService::COLOR_FRAME);
- gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color);
-
- gtk_util::UndoForceFontSize(security_info_label_);
- gtk_util::UndoForceFontSize(tab_to_search_full_label_);
- gtk_util::UndoForceFontSize(tab_to_search_partial_label_);
- gtk_util::UndoForceFontSize(tab_to_search_hint_leading_label_);
- gtk_util::UndoForceFontSize(tab_to_search_hint_trailing_label_);
-
- gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
- 0, 0, 0, 0);
- gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
- 1, 1, 1, 0);
- gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
- 1, 1, 1, 0);
- } else {
- gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL,
- &kKeywordBackgroundColor);
- gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_,
- kKeywordBorderColor);
-
- // Until we switch to vector graphics, force the font size of labels.
- // 12.1px = 9pt @ 96dpi
- gtk_util::ForceFontSizePixels(security_info_label_, 12.1);
- gtk_util::ForceFontSizePixels(tab_to_search_full_label_,
- browser_defaults::kAutocompleteEditFontPixelSize);
- gtk_util::ForceFontSizePixels(tab_to_search_partial_label_,
- browser_defaults::kAutocompleteEditFontPixelSize);
- gtk_util::ForceFontSizePixels(tab_to_search_hint_leading_label_,
- browser_defaults::kAutocompleteEditFontPixelSize);
- gtk_util::ForceFontSizePixels(tab_to_search_hint_trailing_label_,
- browser_defaults::kAutocompleteEditFontPixelSize);
-
- const int top_bottom = popup_window_mode_ ? kBorderThickness : 0;
- gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
- kTopMargin + kBorderThickness,
- kBottomMargin + kBorderThickness,
- top_bottom, top_bottom);
- gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
- 1, 1, 0, 0);
- gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
- 1, 1, 0, 0);
- }
+ case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
+ if (theme_service_->UsingNativeTheme()) {
+ gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, NULL);
+
+ GdkColor border_color = theme_service_->GetGdkColor(
+ ThemeService::COLOR_FRAME);
+ gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color);
+
+ gtk_util::UndoForceFontSize(security_info_label_);
+ gtk_util::UndoForceFontSize(tab_to_search_full_label_);
+ gtk_util::UndoForceFontSize(tab_to_search_partial_label_);
+ gtk_util::UndoForceFontSize(tab_to_search_hint_leading_label_);
+ gtk_util::UndoForceFontSize(tab_to_search_hint_trailing_label_);
+
+ gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
+ 0, 0, 0, 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
+ 1, 1, 1, 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
+ 1, 1, 1, 0);
+ } else {
+ gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL,
+ &kKeywordBackgroundColor);
+ gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_,
+ kKeywordBorderColor);
+
+ // Until we switch to vector graphics, force the font size of labels.
+ // 12.1px = 9pt @ 96dpi
+ gtk_util::ForceFontSizePixels(security_info_label_, 12.1);
+ gtk_util::ForceFontSizePixels(tab_to_search_full_label_,
+ browser_defaults::kAutocompleteEditFontPixelSize);
+ gtk_util::ForceFontSizePixels(tab_to_search_partial_label_,
+ browser_defaults::kAutocompleteEditFontPixelSize);
+ gtk_util::ForceFontSizePixels(tab_to_search_hint_leading_label_,
+ browser_defaults::kAutocompleteEditFontPixelSize);
+ gtk_util::ForceFontSizePixels(tab_to_search_hint_trailing_label_,
+ browser_defaults::kAutocompleteEditFontPixelSize);
+
+ const int top_bottom = popup_window_mode_ ? kBorderThickness : 0;
+ gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_),
+ kTopMargin + kBorderThickness,
+ kBottomMargin + kBorderThickness,
+ top_bottom, top_bottom);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(tab_to_search_alignment_),
+ 1, 1, 0, 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_),
+ 1, 1, 0, 0);
+ }
- UpdateStarIcon();
- UpdateChromeToMobileIcon();
- UpdateSiteTypeArea();
- UpdateContentSettingsIcons();
+ UpdateZoomIcon();
+ UpdateStarIcon();
+ UpdateChromeToMobileIcon();
+ UpdateSiteTypeArea();
+ UpdateContentSettingsIcons();
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
}
gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget,
@@ -1169,13 +1216,27 @@ void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender,
}
}
+gboolean LocationBarViewGtk::OnZoomButtonPress(GtkWidget* widget,
+ GdkEventButton* event) {
+ if (event->button == 1 && GetWebContents()) {
+ // If the zoom icon is clicked, show the zoom bubble and keep it open until
+ // it loses focus.
+ const ZoomController* zc = TabContents::FromWebContents(
+ GetWebContents())->zoom_controller();
+ ZoomBubbleGtk::Show(zoom_.get(), browser_->profile(),
+ zc->zoom_percent(), false);
+ return TRUE;
+ }
+ return FALSE;
+}
+
gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget,
GdkEventButton* event) {
if (event->button == 1) {
browser_->ExecuteCommand(IDC_BOOKMARK_PAGE);
- return FALSE;
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
gboolean LocationBarViewGtk::OnChromeToMobileButtonPress(
@@ -1183,9 +1244,16 @@ gboolean LocationBarViewGtk::OnChromeToMobileButtonPress(
GdkEventButton* event) {
if (event->button == 1) {
browser_->ExecuteCommand(IDC_CHROME_TO_MOBILE_PAGE);
- return FALSE;
+ return TRUE;
}
- return TRUE;
+ return FALSE;
+}
+
+void LocationBarViewGtk::ShowZoomBubble(int zoom_percent) {
+ if (!zoom_.get() || toolbar_model_->input_in_progress())
+ return;
+
+ ZoomBubbleGtk::Show(zoom_.get(), browser_->profile(), zoom_percent, true);
}
void LocationBarViewGtk::ShowStarBubble(const GURL& url,
@@ -1202,6 +1270,15 @@ void LocationBarViewGtk::ShowChromeToMobileBubble() {
browser_->profile());
}
+void LocationBarViewGtk::SetZoomIconTooltipPercent(int zoom_percent) {
+ UpdateZoomIcon();
+}
+
+void LocationBarViewGtk::SetZoomIconState(
+ ZoomController::ZoomIconState zoom_icon_state) {
+ UpdateZoomIcon();
+}
+
void LocationBarViewGtk::SetStarred(bool starred) {
if (starred == starred_)
return;
@@ -1210,6 +1287,31 @@ void LocationBarViewGtk::SetStarred(bool starred) {
UpdateStarIcon();
}
+void LocationBarViewGtk::UpdateZoomIcon() {
+ if (!zoom_.get() || !GetWebContents())
+ return;
+
+ const ZoomController* zc = TabContents::FromWebContents(
+ GetWebContents())->zoom_controller();
+
+ if (toolbar_model_->input_in_progress() ||
+ zc->zoom_icon_state() == ZoomController::NONE) {
+ gtk_widget_hide(zoom_.get());
+ ZoomBubbleGtk::Close();
+ return;
+ }
+
+ gtk_widget_show(zoom_.get());
+ int zoom_resource = zc->zoom_icon_state() == ZoomController::ZOOM_PLUS_ICON ?
+ IDR_ZOOM_PLUS : IDR_ZOOM_MINUS;
+ gtk_image_set_from_pixbuf(GTK_IMAGE(zoom_image_),
+ theme_service_->GetImageNamed(zoom_resource)->ToGdkPixbuf());
+
+ string16 tooltip = l10n_util::GetStringFUTF16Int(IDS_TOOLTIP_ZOOM,
+ zc->zoom_percent());
+ gtk_widget_set_tooltip_text(zoom_.get(), UTF16ToUTF8(tooltip).c_str());
+}
+
void LocationBarViewGtk::UpdateStarIcon() {
if (!star_.get())
return;
diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.h b/chrome/browser/ui/gtk/location_bar_view_gtk.h
index 67b79b4..f9aad7b 100644
--- a/chrome/browser/ui/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/ui/gtk/location_bar_view_gtk.h
@@ -24,6 +24,8 @@
#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
#include "chrome/browser/ui/gtk/menu_gtk.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
+#include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/zoom/zoom_controller.h"
#include "chrome/common/content_settings_types.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -95,12 +97,21 @@ class LocationBarViewGtk : public AutocompleteEditController,
// restore saved state that the tab holds.
void Update(const content::WebContents* tab_for_state_restoring);
+ // Show the zoom bubble.
+ void ShowZoomBubble(int zoom_percent);
+
// Show the bookmark bubble.
void ShowStarBubble(const GURL& url, bool newly_boomkarked);
// Shows the Chrome To Mobile bubble.
void ShowChromeToMobileBubble();
+ // Sets the tooltip for the zoom icon.
+ void SetZoomIconTooltipPercent(int zoom_percent);
+
+ // Sets the zoom icon state.
+ void SetZoomIconState(ZoomController::ZoomIconState zoom_icon_state);
+
// Set the starred state of the bookmark star.
void SetStarred(bool starred);
@@ -352,6 +363,8 @@ class LocationBarViewGtk : public AutocompleteEditController,
GtkAllocation*);
CHROMEGTK_CALLBACK_1(LocationBarViewGtk, void, OnEntryBoxSizeAllocate,
GtkAllocation*);
+ CHROMEGTK_CALLBACK_1(LocationBarViewGtk, gboolean, OnZoomButtonPress,
+ GdkEventButton*);
CHROMEGTK_CALLBACK_1(LocationBarViewGtk, gboolean, OnStarButtonPress,
GdkEventButton*);
CHROMEGTK_CALLBACK_1(LocationBarViewGtk, gboolean,
@@ -382,10 +395,20 @@ class LocationBarViewGtk : public AutocompleteEditController,
// available horizontal space in the location bar.
void AdjustChildrenVisibility();
- // Build the star and Chrome To Mobile icons.
+ // Build the zoom, star, and Chrome To Mobile icons.
+ GtkWidget* CreateIconButton(
+ GtkWidget** image,
+ int image_id,
+ ViewID debug_id,
+ int tooltip_id,
+ gboolean (click_callback)(GtkWidget*, GdkEventButton*, gpointer));
+ void CreateZoomButton();
void CreateStarButton();
void CreateChromeToMobileButton();
+ // Update the zoom icon after zoom changes.
+ void UpdateZoomIcon();
+
// Update the star icon after it is toggled or the theme changes.
void UpdateStarIcon();
@@ -399,6 +422,10 @@ class LocationBarViewGtk : public AutocompleteEditController,
// The outermost widget we want to be hosted.
ui::OwnedWidgetGtk hbox_;
+ // Zoom button.
+ ui::OwnedWidgetGtk zoom_;
+ GtkWidget* zoom_image_;
+
// Star button.
ui::OwnedWidgetGtk star_;
GtkWidget* star_image_;
diff --git a/chrome/browser/ui/gtk/zoom_bubble_gtk.cc b/chrome/browser/ui/gtk/zoom_bubble_gtk.cc
new file mode 100644
index 0000000..3e0f753
--- /dev/null
+++ b/chrome/browser/ui/gtk/zoom_bubble_gtk.cc
@@ -0,0 +1,153 @@
+// 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/gtk/zoom_bubble_gtk.h"
+
+#include "base/bind.h"
+#include "base/i18n/rtl.h"
+#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_source.h"
+#include "grit/generated_resources.h"
+#include "ui/base/gtk/gtk_hig_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/rect.h"
+
+namespace {
+
+// Pointer to singleton object (NULL if no bubble is open).
+ZoomBubbleGtk* g_bubble = NULL;
+
+// Padding on left and right of bubble.
+const int kContentBorder = 7;
+
+// Number of milliseconds the bubble should stay open for if it will auto-close.
+const int kBubbleCloseDelay = 400;
+
+// Need to manually set anchor width and height to ensure that the bubble shows
+// in the correct spot the first time it is displayed when no icon is present.
+const int kBubbleAnchorWidth = 20;
+const int kBubbleAnchorHeight = 25;
+
+} // namespace
+
+// static
+void ZoomBubbleGtk::Show(GtkWidget* anchor,
+ Profile* profile,
+ int zoom_percent,
+ bool auto_close) {
+ // If the bubble is already showing and its |auto_close_| value is equal to
+ // |auto_close|, the bubble can be reused and only the label text needs to
+ // be updated.
+ if (g_bubble && g_bubble->auto_close_ == auto_close) {
+ string16 text = l10n_util::GetStringFUTF16Int(
+ IDS_ZOOM_PERCENT, zoom_percent);
+ gtk_label_set_text(GTK_LABEL(g_bubble->label_), UTF16ToUTF8(text).c_str());
+
+ if (auto_close) {
+ // If the bubble should be closed automatically, reset the timer so that
+ // it will show for the full amount of time instead of only what remained
+ // from the previous time.
+ g_bubble->timer_.Reset();
+ }
+ } else {
+ // If the bubble is already showing but its |auto_close_| value is not equal
+ // to |auto_close|, the bubble's focus properties must change, so the
+ // current bubble must be closed and a new one created.
+ if (g_bubble)
+ g_bubble->Close();
+
+ g_bubble = new ZoomBubbleGtk(anchor, profile, zoom_percent, auto_close);
+ }
+}
+
+// static
+void ZoomBubbleGtk::Close() {
+ if (g_bubble)
+ g_bubble->CloseBubble();
+}
+
+void ZoomBubbleGtk::BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) {
+}
+
+void ZoomBubbleGtk::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
+
+ gtk_widget_modify_fg(label_,
+ GTK_STATE_NORMAL,
+ theme_service_->UsingNativeTheme() ?
+ NULL : &ui::kGdkBlack);
+}
+
+ZoomBubbleGtk::ZoomBubbleGtk(GtkWidget* anchor,
+ Profile* profile,
+ int zoom_percent,
+ bool auto_close)
+ : auto_close_(auto_close),
+ theme_service_(GtkThemeService::GetFrom(profile)) {
+ string16 text = l10n_util::GetStringFUTF16Int(
+ IDS_ZOOM_PERCENT, zoom_percent);
+ label_ = gtk_label_new(UTF16ToUTF8(text).c_str());
+
+ GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
+ kContentBorder, kContentBorder);
+ gtk_container_add(GTK_CONTAINER(alignment), label_);
+
+ GtkWidget* content = gtk_event_box_new();
+ gtk_event_box_set_visible_window(GTK_EVENT_BOX(content), TRUE);
+ gtk_container_add(GTK_CONTAINER(content), alignment);
+ gtk_widget_show_all(content);
+ gfx::Rect rect(kBubbleAnchorWidth, kBubbleAnchorHeight);
+ BubbleGtk::ArrowLocationGtk arrow_location =
+ BubbleGtk::ARROW_LOCATION_TOP_MIDDLE;
+ int attributeFlags = BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW;
+ bubble_ = BubbleGtk::Show(anchor,
+ &rect,
+ content,
+ arrow_location,
+ auto_close ? attributeFlags :
+ attributeFlags | BubbleGtk::GRAB_INPUT,
+ theme_service_,
+ this); // delegate
+
+ if (!bubble_) {
+ NOTREACHED();
+ return;
+ }
+
+ if (auto_close) {
+ timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kBubbleCloseDelay),
+ this,
+ &ZoomBubbleGtk::CloseBubble);
+ }
+
+ g_signal_connect(content, "destroy",
+ G_CALLBACK(&OnDestroyThunk), this);
+
+ registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+ content::Source<ThemeService>(theme_service_));
+ theme_service_->InitThemesFor(this);
+}
+
+ZoomBubbleGtk::~ZoomBubbleGtk() {
+ DCHECK_EQ(g_bubble, this);
+ // Set singleton pointer to NULL.
+ g_bubble = NULL;
+}
+
+void ZoomBubbleGtk::CloseBubble() {
+ bubble_->Close();
+}
+
+void ZoomBubbleGtk::OnDestroy(GtkWidget* widget) {
+ // Listen to the destroy signal and delete this instance when it is caught.
+ delete this;
+}
diff --git a/chrome/browser/ui/gtk/zoom_bubble_gtk.h b/chrome/browser/ui/gtk/zoom_bubble_gtk.h
new file mode 100644
index 0000000..baa7d60
--- /dev/null
+++ b/chrome/browser/ui/gtk/zoom_bubble_gtk.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_GTK_ZOOM_BUBBLE_GTK_H_
+#define CHROME_BROWSER_UI_GTK_ZOOM_BUBBLE_GTK_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer.h"
+#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
+#include "chrome/browser/ui/gtk/gtk_theme_service.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "ui/base/gtk/gtk_signal.h"
+
+class Profile;
+
+typedef struct _GtkWidget GtkWidget;
+
+class ZoomBubbleGtk : public BubbleDelegateGtk,
+ public content::NotificationObserver {
+ public:
+ // Shows the zoom bubble, pointing at |anchor_widget|.
+ static void Show(GtkWidget* anchor, Profile* profile,
+ int zoomPercent, bool auto_close);
+
+ // Closes the zoom bubble.
+ static void Close();
+
+ // BubbleDelegateGtk:
+ virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE;
+
+ // content::NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ private:
+ ZoomBubbleGtk(GtkWidget* anchor,
+ Profile* profile,
+ int zoom_percent,
+ bool auto_close);
+ virtual ~ZoomBubbleGtk();
+
+ // Closes the zoom bubble.
+ void CloseBubble();
+
+ // Notified when |content_| is destroyed so this instance can be deleted.
+ CHROMEGTK_CALLBACK_0(ZoomBubbleGtk, void, OnDestroy);
+
+ // Whether the currently displayed bubble will automatically close.
+ bool auto_close_;
+
+ // Timer used to close the bubble when |auto_close_| is true.
+ base::OneShotTimer<ZoomBubbleGtk> timer_;
+
+ // Provides colors.
+ GtkThemeService* theme_service_;
+
+ // Label showing zoom percentage.
+ GtkWidget* label_;
+
+ // The BubbleGtk object containing the zoom bubble's content.
+ BubbleGtk* bubble_;
+
+ content::NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoomBubbleGtk);
+};
+
+#endif // CHROME_BROWSER_UI_GTK_ZOOM_BUBBLE_GTK_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d9a66af..f2a358a 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3137,6 +3137,8 @@
'browser/ui/gtk/web_intent_picker_gtk.h',
'browser/ui/gtk/website_settings_popup_gtk.cc',
'browser/ui/gtk/website_settings_popup_gtk.h',
+ 'browser/ui/gtk/zoom_bubble_gtk.cc',
+ 'browser/ui/gtk/zoom_bubble_gtk.h',
'browser/ui/hung_plugin_tab_helper.cc',
'browser/ui/hung_plugin_tab_helper.h',
'browser/ui/intents/web_intent_inline_disposition_delegate.cc',