diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-28 23:05:33 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-28 23:05:33 +0000 |
commit | fda418552b5a32755b4414c172f4b5c52615e502 (patch) | |
tree | 3f7eedbde68c5feafe3da104e4ef9a7e3a09c0d6 /chrome/browser/gtk | |
parent | a0c878693f22701d83e90ffdd610747ffc8b7111 (diff) | |
download | chromium_src-fda418552b5a32755b4414c172f4b5c52615e502.zip chromium_src-fda418552b5a32755b4414c172f4b5c52615e502.tar.gz chromium_src-fda418552b5a32755b4414c172f4b5c52615e502.tar.bz2 |
GTK: Refactoring and rounds the "Search site for:" hint.
Factor out common window rounding code from two places where it was used,
generalize it, and use it to round the "Search site for:" hint in the location
bar. Theoretically, people should be able to use this anywhere they need a
window to have rounded corners.
http://crbug.com/18310
Review URL: http://codereview.chromium.org/179026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24828 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/blocked_popup_container_view_gtk.cc | 102 | ||||
-rw-r--r-- | chrome/browser/gtk/blocked_popup_container_view_gtk.h | 12 | ||||
-rw-r--r-- | chrome/browser/gtk/location_bar_view_gtk.cc | 18 | ||||
-rw-r--r-- | chrome/browser/gtk/location_bar_view_gtk.h | 1 | ||||
-rw-r--r-- | chrome/browser/gtk/rounded_window.cc | 213 | ||||
-rw-r--r-- | chrome/browser/gtk/rounded_window.h | 46 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.cc | 92 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.h | 12 |
8 files changed, 298 insertions, 198 deletions
diff --git a/chrome/browser/gtk/blocked_popup_container_view_gtk.cc b/chrome/browser/gtk/blocked_popup_container_view_gtk.cc index b48b93e..925c390 100644 --- a/chrome/browser/gtk/blocked_popup_container_view_gtk.cc +++ b/chrome/browser/gtk/blocked_popup_container_view_gtk.cc @@ -10,6 +10,7 @@ #include "chrome/browser/gtk/custom_button.h" #include "chrome/browser/gtk/gtk_chrome_button.h" #include "chrome/browser/gtk/gtk_theme_provider.h" +#include "chrome/browser/gtk/rounded_window.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view_gtk.h" @@ -32,48 +33,6 @@ const double kBackgroundColorBottom[] = { 219.0 / 255, 235.0 / 255, 1.0 }; // Rounded corner radius (in pixels). const int kCornerSize = 4; -enum FrameType { - FRAME_MASK, - FRAME_STROKE, -}; - -std::vector<GdkPoint> MakeFramePolygonPoints(int width, - int height, - FrameType type) { - using gtk_util::MakeBidiGdkPoint; - std::vector<GdkPoint> points; - - bool ltr = l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT; - // If we have a stroke, we have to offset some of our points by 1 pixel. - // We have to inset by 1 pixel when we draw horizontal lines that are on the - // bottom or when we draw vertical lines that are closer to the end (end is - // right for ltr). - int y_off = (type == FRAME_MASK) ? 0 : -1; - // We use this one for LTR. - int x_off_l = ltr ? y_off : 0; - // We use this one for RTL. - int x_off_r = !ltr ? -y_off : 0; - - // Bottom left corner. - points.push_back(MakeBidiGdkPoint(0, height + y_off, width, ltr)); - - // Top left (rounded) corner. - points.push_back(MakeBidiGdkPoint(x_off_r, kCornerSize - 1, width, ltr)); - points.push_back(MakeBidiGdkPoint(kCornerSize + x_off_r - 1, 0, width, ltr)); - - // Top right (rounded) corner. - points.push_back(MakeBidiGdkPoint( - width - kCornerSize + 1 + x_off_l, 0, width, ltr)); - points.push_back(MakeBidiGdkPoint( - width + x_off_l, kCornerSize - 1, width, ltr)); - - // Bottom right corner. - points.push_back(MakeBidiGdkPoint( - width + x_off_l, height + y_off, width, ltr)); - - return points; -} - } // namespace // static @@ -150,10 +109,13 @@ void BlockedPopupContainerViewGtk::Observe(NotificationType type, GtkWidget* label = gtk_bin_get_child(GTK_BIN(menu_button_)); if (theme_provider_->UseGtkTheme()) { gtk_util::SetLabelColor(label, NULL); + GdkColor color = theme_provider_->GetBorderColor(); + gtk_util::SetRoundedWindowBorderColor(container_.get(), color); } else { GdkColor color = theme_provider_->GetGdkColor( BrowserThemeProvider::COLOR_BOOKMARK_TEXT); gtk_util::SetLabelColor(label, &color); + gtk_util::SetRoundedWindowBorderColor(container_.get(), kBorderColor); } } @@ -189,9 +151,7 @@ BlockedPopupContainerViewGtk::BlockedPopupContainerViewGtk( BlockedPopupContainer* container) : model_(container), theme_provider_(GtkThemeProvider::GetFrom(container->profile())), - close_button_(CustomDrawButton::CloseButton(theme_provider_)), - notification_width_(-1), - notification_height_(-1) { + close_button_(CustomDrawButton::CloseButton(theme_provider_)) { Init(); registrar_.Add(this, @@ -214,10 +174,14 @@ void BlockedPopupContainerViewGtk::Init() { container_.Own(gtk_util::CreateGtkBorderBin(hbox, NULL, kSmallPadding, kSmallPadding, kSmallPadding, kSmallPadding)); - // Manually paint the event box. - gtk_widget_set_app_paintable(container_.get(), TRUE); + // Connect an expose signal that draws the background. Most connect before + // the ActAsRoundedWindow one. g_signal_connect(container_.get(), "expose-event", - G_CALLBACK(OnContainerExpose), this); + G_CALLBACK(OnRoundedExposeCallback), this); + gtk_util::ActAsRoundedWindow( + container_.get(), kBorderColor, kCornerSize, + gtk_util::ROUNDED_TOP_LEFT | gtk_util::ROUNDED_TOP_RIGHT, + gtk_util::BORDER_LEFT | gtk_util::BORDER_TOP | gtk_util::BORDER_RIGHT); ContainingView()->AttachBlockedPopupView(this); } @@ -258,30 +222,13 @@ void BlockedPopupContainerViewGtk::OnCloseButtonClicked( container->model_->CloseAll(); } -gboolean BlockedPopupContainerViewGtk::OnContainerExpose( +gboolean BlockedPopupContainerViewGtk::OnRoundedExposeCallback( GtkWidget* widget, GdkEventExpose* event, BlockedPopupContainerViewGtk* container) { - int width = widget->allocation.width; - int height = widget->allocation.height; - - // Update our window shape if we need to. - if (container->notification_width_ != widget->allocation.width || - container->notification_height_ != widget->allocation.height) { - // We need to update the shape of the status bubble whenever our GDK - // window changes shape. - std::vector<GdkPoint> mask_points = MakeFramePolygonPoints( - widget->allocation.width, widget->allocation.height, FRAME_MASK); - GdkRegion* mask_region = gdk_region_polygon(&mask_points[0], - mask_points.size(), - GDK_EVEN_ODD_RULE); - gdk_window_shape_combine_region(widget->window, mask_region, 0, 0); - gdk_region_destroy(mask_region); - - container->notification_width_ = widget->allocation.width; - container->notification_height_ = widget->allocation.height; - } - if (!container->theme_provider_->UseGtkTheme()) { + int width = widget->allocation.width; + int height = widget->allocation.height; + // Clip to our damage rect. cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(event->window)); cairo_rectangle(cr, event->area.x, event->area.y, @@ -309,20 +256,5 @@ gboolean BlockedPopupContainerViewGtk::OnContainerExpose( cairo_destroy(cr); } - GdkDrawable* drawable = GDK_DRAWABLE(event->window); - GdkGC* gc = gdk_gc_new(drawable); - if (container->theme_provider_->UseGtkTheme()) { - GdkColor color = container->theme_provider_->GetBorderColor(); - gdk_gc_set_rgb_fg_color(gc, &color); - } else { - gdk_gc_set_rgb_fg_color(gc, &kBorderColor); - } - - // Stroke the frame border. - std::vector<GdkPoint> points = MakeFramePolygonPoints( - widget->allocation.width, widget->allocation.height, FRAME_STROKE); - gdk_draw_lines(drawable, gc, &points[0], points.size()); - - g_object_unref(gc); - return FALSE; // Allow subwidgets to paint. + return FALSE; } diff --git a/chrome/browser/gtk/blocked_popup_container_view_gtk.h b/chrome/browser/gtk/blocked_popup_container_view_gtk.h index f8de623..50a256b3 100644 --- a/chrome/browser/gtk/blocked_popup_container_view_gtk.h +++ b/chrome/browser/gtk/blocked_popup_container_view_gtk.h @@ -81,9 +81,10 @@ class BlockedPopupContainerViewGtk : public BlockedPopupContainerView, static void OnCloseButtonClicked(GtkButton *button, BlockedPopupContainerViewGtk* container); - // Draws |container_| with a custom background. - static gboolean OnContainerExpose(GtkWidget* widget, GdkEventExpose* event, - BlockedPopupContainerViewGtk* container); + // Draw the custom background to our rounded widget. + static gboolean OnRoundedExposeCallback( + GtkWidget* widget, GdkEventExpose* event, + BlockedPopupContainerViewGtk* container); NotificationRegistrar registrar_; @@ -105,11 +106,6 @@ class BlockedPopupContainerViewGtk : public BlockedPopupContainerView, // The popup menu with options to launch blocked popups. scoped_ptr<MenuGtk> launch_menu_; - // Cached allocation of |container_|. We keep this on hand so that we can - // reset the widget's shape when the width/height change. - int notification_width_; - int notification_height_; - DISALLOW_COPY_AND_ASSIGN(BlockedPopupContainerViewGtk); }; diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index 60e9ea8..d99b27a 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -19,6 +19,7 @@ #include "chrome/browser/command_updater.h" #include "chrome/browser/gtk/first_run_bubble.h" #include "chrome/browser/gtk/gtk_theme_provider.h" +#include "chrome/browser/gtk/rounded_window.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url.h" #include "chrome/browser/search_engines/template_url_model.h" @@ -74,6 +75,9 @@ const GdkColor kEvTextColor = GDK_COLOR_RGB(0x00, 0x96, 0x14); // Green. const GdkColor kKeywordBackgroundColor = GDK_COLOR_RGB(0xf0, 0xf4, 0xfa); const GdkColor kKeywordBorderColor = GDK_COLOR_RGB(0xcb, 0xde, 0xf7); +// Size of the rounding of the "Search site for:" box. +const int kCornerSize = 3; + // Returns the short name for a keyword. std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword) { @@ -104,7 +108,6 @@ LocationBarViewGtk::LocationBarViewGtk(CommandUpdater* command_updater, info_label_align_(NULL), info_label_(NULL), tab_to_search_(NULL), - tab_to_search_border_(NULL), tab_to_search_box_(NULL), tab_to_search_label_(NULL), tab_to_search_hint_(NULL), @@ -174,9 +177,9 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { // keyword text with a border, background color, and padding around the text. tab_to_search_box_ = gtk_util::CreateGtkBorderBin( tab_to_search_label_, NULL, 1, 1, 2, 2); - tab_to_search_border_ = gtk_util::CreateGtkBorderBin( - tab_to_search_box_, NULL, 1, 1, 1, 1); - gtk_container_add(GTK_CONTAINER(tab_to_search_), tab_to_search_border_); + gtk_util::ActAsRoundedWindow(tab_to_search_box_, kBorderColor, kCornerSize, + gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL); + gtk_container_add(GTK_CONTAINER(tab_to_search_), tab_to_search_box_); gtk_box_pack_start(GTK_BOX(hbox_.get()), tab_to_search_, FALSE, FALSE, 0); GtkWidget* align = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); @@ -418,8 +421,7 @@ void LocationBarViewGtk::Observe(NotificationType type, GdkColor border_color = theme_provider_->GetGdkColor( BrowserThemeProvider::COLOR_FRAME); - gtk_widget_modify_bg(tab_to_search_border_, GTK_STATE_NORMAL, - &border_color); + gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color); gtk_util::SetLabelColor(tab_to_search_label_, NULL); gtk_util::SetLabelColor(tab_to_search_hint_leading_label_, NULL); @@ -427,8 +429,8 @@ void LocationBarViewGtk::Observe(NotificationType type, } else { gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, &kKeywordBackgroundColor); - gtk_widget_modify_bg(tab_to_search_border_, GTK_STATE_NORMAL, - &kKeywordBorderColor); + gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, + kKeywordBorderColor); gtk_util::SetLabelColor(tab_to_search_label_, &gfx::kGdkBlack); gtk_util::SetLabelColor(tab_to_search_hint_leading_label_, diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h index 8105302..ebf7035 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.h +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -131,7 +131,6 @@ class LocationBarViewGtk : public AutocompleteEditController, // Area on the left shown when in tab to search mode. GtkWidget* tab_to_search_; - GtkWidget* tab_to_search_border_; GtkWidget* tab_to_search_box_; GtkWidget* tab_to_search_label_; diff --git a/chrome/browser/gtk/rounded_window.cc b/chrome/browser/gtk/rounded_window.cc new file mode 100644 index 0000000..b549a3f --- /dev/null +++ b/chrome/browser/gtk/rounded_window.cc @@ -0,0 +1,213 @@ +// 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/rounded_window.h" + +#include <gtk/gtk.h> + +#include "app/l10n_util.h" +#include "chrome/common/gtk_util.h" + +namespace gtk_util { + +namespace { + +const char* kRoundedData = "rounded-window-data"; + +struct RoundedWindowData { + // Expected window size. Used to detect when we need to reshape the window. + int expected_width; + int expected_height; + + // Color of the border. + GdkColor border_color; + + // Radius of the edges in pixels. + int corner_size; + + // Which corners should be rounded? + int rounded_edges; + + // Which sides of the window should have an internal border? + int drawn_borders; +}; + +// Callback from GTK to release allocated memory. +void FreeRoundedWindowData(gpointer data) { + delete static_cast<RoundedWindowData*>(data); +} + +enum FrameType { + FRAME_MASK, + FRAME_STROKE, +}; + +// Returns a list of points that either form the outline of the status bubble +// (|type| == FRAME_MASK) or form the inner border around the inner edge +// (|type| == FRAME_STROKE). +std::vector<GdkPoint> MakeFramePolygonPoints(RoundedWindowData* data, + FrameType type) { + using gtk_util::MakeBidiGdkPoint; + int width = data->expected_width; + int height = data->expected_height; + int corner_size = data->corner_size; + + std::vector<GdkPoint> points; + + bool ltr = l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT; + // If we have a stroke, we have to offset some of our points by 1 pixel. + // We have to inset by 1 pixel when we draw horizontal lines that are on the + // bottom or when we draw vertical lines that are closer to the end (end is + // right for ltr). + int y_off = (type == FRAME_MASK) ? 0 : -1; + // We use this one for LTR. + int x_off_l = ltr ? y_off : 0; + // We use this one for RTL. + int x_off_r = !ltr ? -y_off : 0; + + // Bottom left corner. + if (type == FRAME_MASK || + (data->drawn_borders & (BORDER_LEFT | BORDER_BOTTOM))) { + if (data->rounded_edges & ROUNDED_BOTTOM_LEFT) { + points.push_back(MakeBidiGdkPoint( + corner_size + x_off_l, height + y_off, width, ltr)); + points.push_back(MakeBidiGdkPoint( + x_off_r, height - corner_size, width, ltr)); + } else { + points.push_back(MakeBidiGdkPoint(x_off_r, height + y_off, width, ltr)); + } + } + + // Top left corner. + if (type == FRAME_MASK || + (data->drawn_borders & (BORDER_LEFT | BORDER_TOP))) { + if (data->rounded_edges & ROUNDED_TOP_LEFT) { + points.push_back(MakeBidiGdkPoint( + x_off_r, corner_size - 1, width, ltr)); + points.push_back(MakeBidiGdkPoint( + corner_size + x_off_r - 1, 0, width, ltr)); + } else { + points.push_back(MakeBidiGdkPoint(x_off_r, 0, width, ltr)); + } + } + + // Top right corner. + if (type == FRAME_MASK || + (data->drawn_borders & (BORDER_TOP | BORDER_RIGHT))) { + if (data->rounded_edges & ROUNDED_TOP_RIGHT) { + points.push_back(MakeBidiGdkPoint( + width - corner_size + 1 + x_off_l, 0, width, ltr)); + points.push_back(MakeBidiGdkPoint( + width + x_off_l, corner_size - 1, width, ltr)); + } else { + points.push_back(MakeBidiGdkPoint( + width + x_off_l, 0, width, ltr)); + } + } + + // Bottom right corner. + if (type == FRAME_MASK || + (data->drawn_borders & (BORDER_RIGHT | BORDER_BOTTOM))) { + if (data->rounded_edges & ROUNDED_BOTTOM_RIGHT) { + points.push_back(MakeBidiGdkPoint( + width + x_off_l, height - corner_size, width, ltr)); + points.push_back(MakeBidiGdkPoint( + width - corner_size + x_off_r, height + y_off, width, ltr)); + } else { + points.push_back(MakeBidiGdkPoint( + width + x_off_l, height + y_off, width, ltr)); + } + } + + return points; +} + +// Set the window shape in needed, lets our owner do some drawing (if it wants +// to), and finally draw the border. +gboolean OnRoundedWindowExpose(GtkWidget* widget, + GdkEventExpose* event) { + RoundedWindowData* data = static_cast<RoundedWindowData*>( + g_object_get_data(G_OBJECT(widget), kRoundedData)); + + if (data->expected_width != widget->allocation.width || + data->expected_height != widget->allocation.height) { + data->expected_width = widget->allocation.width; + data->expected_height = widget->allocation.height; + + // We need to update the shape of the status bubble whenever our GDK + // window changes shape. + std::vector<GdkPoint> mask_points = MakeFramePolygonPoints( + data, FRAME_MASK); + GdkRegion* mask_region = gdk_region_polygon(&mask_points[0], + mask_points.size(), + GDK_EVEN_ODD_RULE); + gdk_window_shape_combine_region(widget->window, mask_region, 0, 0); + gdk_region_destroy(mask_region); + } + + GdkDrawable* drawable = GDK_DRAWABLE(event->window); + GdkGC* gc = gdk_gc_new(drawable); + gdk_gc_set_rgb_fg_color(gc, &data->border_color); + + // Stroke the frame border. + std::vector<GdkPoint> points = MakeFramePolygonPoints( + data, FRAME_STROKE); + if (data->drawn_borders == BORDER_ALL) { + // If we want to have borders everywhere, we need to draw a polygon instead + // of a set of lines. + gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); + } else { + gdk_draw_lines(drawable, gc, &points[0], points.size()); + } + + g_object_unref(gc); + return FALSE; // Propagate so our children paint, etc. +} + +// On theme changes, window shapes are reset, but we detect whether we need to +// reshape a window by whether its allocation has changed so force it to reset +// the window shape on next expose. +void OnStyleSet(GtkWidget* widget, GtkStyle* previous_style) { + DCHECK(widget); + RoundedWindowData* data = static_cast<RoundedWindowData*>( + g_object_get_data(G_OBJECT(widget), kRoundedData)); + DCHECK(data); + data->expected_width = -1; + data->expected_height = -1; +} + +} // namespace + +void ActAsRoundedWindow( + GtkWidget* widget, GdkColor color, int corner_size, + int rounded_edges, int drawn_borders) { + DCHECK(widget); + gtk_widget_set_app_paintable(widget, TRUE); + g_signal_connect(G_OBJECT(widget), "expose-event", + G_CALLBACK(OnRoundedWindowExpose), NULL); + g_signal_connect(G_OBJECT(widget), "style-set", G_CALLBACK(OnStyleSet), NULL); + + RoundedWindowData* data = new RoundedWindowData; + data->expected_width = -1; + data->expected_height = -1; + + data->border_color = color; + data->corner_size = corner_size; + + data->rounded_edges = rounded_edges; + data->drawn_borders = drawn_borders; + + g_object_set_data_full(G_OBJECT(widget), kRoundedData, + data, FreeRoundedWindowData); +} + +void SetRoundedWindowBorderColor(GtkWidget* widget, GdkColor color) { + DCHECK(widget); + RoundedWindowData* data = static_cast<RoundedWindowData*>( + g_object_get_data(G_OBJECT(widget), kRoundedData)); + DCHECK(data); + data->border_color = color; +} + +} // namespace gtk_util diff --git a/chrome/browser/gtk/rounded_window.h b/chrome/browser/gtk/rounded_window.h new file mode 100644 index 0000000..d72991a --- /dev/null +++ b/chrome/browser/gtk/rounded_window.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef CHROME_BROWSER_GTK_ROUNDED_WINDOW_H_ +#define CHROME_BROWSER_GTK_ROUNDED_WINDOW_H_ + +#include <gtk/gtk.h> + +namespace gtk_util { + +// Symbolic names for arguments to |rounded_edges| in ActAsRoundedWindow(). +enum RoundedBorders { + ROUNDED_BOTTOM_LEFT = 1 << 0, + ROUNDED_TOP_LEFT = 1 << 1, + ROUNDED_TOP_RIGHT = 1 << 2, + ROUNDED_BOTTOM_RIGHT = 1 << 3, + ROUNDED_ALL = 0xF +}; + +// Symbolic names for arguments to |drawn_borders| in ActAsRoundedWindow(). +enum BorderEdge { + BORDER_LEFT = 1 << 0, + BORDER_TOP = 1 << 1, + BORDER_RIGHT = 1 << 2, + BORDER_BOTTOM = 1 << 3, + BORDER_ALL = 0xF +}; + +// Sets up the passed in widget that has its own GdkWindow with an expose +// handler that forces the window shape into roundness. Caller should not set +// an "expose-event" handler on |widget|; if caller needs to do custom +// rendering, use SetRoundedWindowExposeFunction() instead. |rounded_edges| +// control which corners are rounded. |drawn_borders| border control which +// sides have a visible border drawn in |color|. +void ActAsRoundedWindow( + GtkWidget* widget, GdkColor color, int corner_size, + int rounded_edges, int drawn_borders); + +// Sets the color of the border on a widget that was returned from +// ActAsRoundedWindow(). +void SetRoundedWindowBorderColor(GtkWidget* widget, GdkColor color); + +} // namespace gtk_util + +#endif // CHROME_BROWSER_GTK_ROUNDED_WINDOW_H_ diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc index e21f581..155edeb 100644 --- a/chrome/browser/gtk/status_bubble_gtk.cc +++ b/chrome/browser/gtk/status_bubble_gtk.cc @@ -12,6 +12,7 @@ #include "base/message_loop.h" #include "base/string_util.h" #include "chrome/browser/gtk/gtk_theme_provider.h" +#include "chrome/browser/gtk/rounded_window.h" #include "chrome/browser/gtk/slide_animator_gtk.h" #include "chrome/common/gtk_util.h" #include "chrome/common/notification_service.h" @@ -31,56 +32,10 @@ const int kCornerSize = 3; // Milliseconds before we hide the status bubble widget when you mouseout. const int kHideDelay = 250; -enum FrameType { - FRAME_MASK, - FRAME_STROKE, -}; - -// Returns a list of points that either form the outline of the status bubble -// (|type| == FRAME_MASK) or form the inner border around the inner edge -// (|type| == FRAME_STROKE). -std::vector<GdkPoint> MakeFramePolygonPoints(int width, - int height, - FrameType type) { - using gtk_util::MakeBidiGdkPoint; - std::vector<GdkPoint> points; - - bool ltr = l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT; - // If we have a stroke, we have to offset some of our points by 1 pixel. - // We have to inset by 1 pixel when we draw horizontal lines that are on the - // bottom or when we draw vertical lines that are closer to the end (end is - // right for ltr). - int y_off = (type == FRAME_MASK) ? 0 : -1; - // We use this one for LTR. - int x_off_l = ltr ? y_off : 0; - - // Top left corner. - points.push_back(MakeBidiGdkPoint(0, 0, width, ltr)); - - // Top right (rounded) corner. - points.push_back(MakeBidiGdkPoint( - width - kCornerSize + 1 + x_off_l, 0, width, ltr)); - points.push_back(MakeBidiGdkPoint( - width + x_off_l, kCornerSize - 1, width, ltr)); - - // Bottom right corner. - points.push_back(MakeBidiGdkPoint( - width + x_off_l, height + y_off, width, ltr)); - - if (type == FRAME_MASK) { - // Bottom left corner. - points.push_back(MakeBidiGdkPoint(0, height + y_off, width, ltr)); - } - - return points; -} - } // namespace StatusBubbleGtk::StatusBubbleGtk(Profile* profile) : theme_provider_(GtkThemeProvider::GetFrom(profile)), - bubble_width_(-1), - bubble_height_(-1), timer_factory_(this) { InitWidgets(); @@ -188,11 +143,12 @@ void StatusBubbleGtk::InitWidgets() { gtk_container_add(GTK_CONTAINER(padding), label_); container_.Own(gtk_event_box_new()); + gtk_util::ActAsRoundedWindow( + container_.get(), kFrameBorderColor, kCornerSize, + gtk_util::ROUNDED_TOP_RIGHT, + gtk_util::BORDER_TOP | gtk_util::BORDER_RIGHT); gtk_widget_set_name(container_.get(), "status-bubble"); gtk_container_add(GTK_CONTAINER(container_.get()), padding); - gtk_widget_set_app_paintable(container_.get(), TRUE); - g_signal_connect(G_OBJECT(container_.get()), "expose-event", - G_CALLBACK(OnExpose), this); UserChangedTheme(); } @@ -202,7 +158,8 @@ void StatusBubbleGtk::UserChangedTheme() { gtk_widget_modify_fg(label_, GTK_STATE_NORMAL, NULL); gtk_widget_modify_bg(container_.get(), GTK_STATE_NORMAL, NULL); - border_color_ = theme_provider_->GetBorderColor(); + gtk_util::SetRoundedWindowBorderColor(container_.get(), + theme_provider_->GetBorderColor()); } else { // TODO(erg): This is the closest to "text that will look good on a // toolbar" that I can find. Maybe in later iterations of the theme system, @@ -215,39 +172,6 @@ void StatusBubbleGtk::UserChangedTheme() { theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_TOOLBAR); gtk_widget_modify_bg(container_.get(), GTK_STATE_NORMAL, &toolbar_color); - border_color_ = kFrameBorderColor; - } -} - -// static -gboolean StatusBubbleGtk::OnExpose(GtkWidget* widget, - GdkEventExpose* event, - StatusBubbleGtk* bubble) { - if (bubble->bubble_width_ != widget->allocation.width || - bubble->bubble_height_ != widget->allocation.height) { - // We need to update the shape of the status bubble whenever our GDK - // window changes shape. - std::vector<GdkPoint> mask_points = MakeFramePolygonPoints( - widget->allocation.width, widget->allocation.height, FRAME_MASK); - GdkRegion* mask_region = gdk_region_polygon(&mask_points[0], - mask_points.size(), - GDK_EVEN_ODD_RULE); - gdk_window_shape_combine_region(widget->window, mask_region, 0, 0); - gdk_region_destroy(mask_region); - - bubble->bubble_width_ = widget->allocation.width; - bubble->bubble_height_ = widget->allocation.height; + gtk_util::SetRoundedWindowBorderColor(container_.get(), kFrameBorderColor); } - - GdkDrawable* drawable = GDK_DRAWABLE(event->window); - GdkGC* gc = gdk_gc_new(drawable); - gdk_gc_set_rgb_fg_color(gc, &bubble->border_color_); - - // Stroke the frame border. - std::vector<GdkPoint> points = MakeFramePolygonPoints( - widget->allocation.width, widget->allocation.height, FRAME_STROKE); - gdk_draw_lines(drawable, gc, &points[0], points.size()); - - g_object_unref(gc); - return FALSE; // Propagate so our children paint, etc. } diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h index c1a8ede..87b43d3 100644 --- a/chrome/browser/gtk/status_bubble_gtk.h +++ b/chrome/browser/gtk/status_bubble_gtk.h @@ -69,10 +69,6 @@ class StatusBubbleGtk : public StatusBubble, // Notification from the window that we should retheme ourself. void UserChangedTheme(); - // Draws the inside border. - static gboolean OnExpose(GtkWidget* widget, GdkEventExpose* event, - StatusBubbleGtk* bubble); - NotificationRegistrar registrar_; // Provides colors. @@ -90,14 +86,6 @@ class StatusBubbleGtk : public StatusBubble, // The url we want to display when there is no status text to display. std::string url_text_; - // Color of the lighter border around the edge of the status bubble. - GdkColor border_color_; - - // Cached allocation of |container_|. We keep this on hand so that we can - // reset the widget's shape when the width/height change. - int bubble_width_; - int bubble_height_; - // A timer that hides our window after a delay. ScopedRunnableMethodFactory<StatusBubbleGtk> timer_factory_; }; |