diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 5 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/browser_window_gtk.cc | 6 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/bubble/bubble_gtk.cc | 72 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/bubble/bubble_gtk.h | 2 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/location_bar_view_gtk.cc | 306 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/location_bar_view_gtk.h | 29 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/zoom_bubble_gtk.cc | 153 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/zoom_bubble_gtk.h | 73 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 |
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 − </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"> &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', |