Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/gtk/status_bubble_gtk.h" | 5 #include "chrome/browser/gtk/status_bubble_gtk.h" |
| 6 | 6 |
| 7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
| 8 | 8 |
| 9 #include "app/gfx/text_elider.h" | 9 #include "app/gfx/text_elider.h" |
| 10 #include "app/l10n_util.h" | |
| 10 #include "base/gfx/gtk_util.h" | 11 #include "base/gfx/gtk_util.h" |
| 11 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 13 #include "chrome/browser/gtk/gtk_theme_provider.h" | 14 #include "chrome/browser/gtk/gtk_theme_provider.h" |
| 14 #include "chrome/browser/gtk/slide_animator_gtk.h" | 15 #include "chrome/browser/gtk/slide_animator_gtk.h" |
| 15 #include "chrome/common/gtk_util.h" | 16 #include "chrome/common/gtk_util.h" |
| 16 #include "chrome/common/notification_service.h" | 17 #include "chrome/common/notification_service.h" |
| 17 #include "googleurl/src/gurl.h" | 18 #include "googleurl/src/gurl.h" |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 const GdkColor kTextColor = GDK_COLOR_RGB(100, 100, 100); | |
| 22 const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xe6, 0xed, 0xf4); | |
| 23 const GdkColor kFrameBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4); | 22 const GdkColor kFrameBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4); |
| 24 | 23 |
| 25 // Inner padding between the border and the text label. | 24 // Inner padding between the border and the text label. |
| 26 const int kInternalTopBottomPadding = 1; | 25 const int kInternalTopBottomPadding = 1; |
| 27 const int kInternalLeftRightPadding = 2; | 26 const int kInternalLeftRightPadding = 2; |
| 28 | 27 |
| 29 // Border of color kFrameBorderColor around the status bubble. | 28 // The roundedness of the edges of our bubble. |
|
Evan Martin
2009/08/06 18:05:38
roundedness = radius, right?
| |
| 30 const int kBorderPadding = 1; | 29 const int kCornerSize = 4; |
| 31 | 30 |
| 32 // Milliseconds before we hide the status bubble widget when you mouseout. | 31 // Milliseconds before we hide the status bubble widget when you mouseout. |
| 33 static const int kHideDelay = 250; | 32 const int kHideDelay = 250; |
| 33 | |
| 34 // Number of times that the background color should be counted when trying to | |
| 35 // calculate the border color in GTK theme mode. | |
| 36 const int kBgWeight = 3; | |
| 37 | |
| 38 GdkPoint MakeBidiGdkPoint(gint x, gint y, gint width, bool ltr) { | |
|
Evan Martin
2009/08/06 18:05:38
docs on all functions
| |
| 39 GdkPoint point = {ltr ? x : width - x, y}; | |
| 40 return point; | |
| 41 } | |
| 42 | |
| 43 enum FrameType { | |
| 44 FRAME_MASK, | |
| 45 FRAME_STROKE, | |
| 46 }; | |
| 47 | |
| 48 std::vector<GdkPoint> MakeFramePolygonPoints(int width, | |
| 49 int height, | |
| 50 FrameType type) { | |
| 51 std::vector<GdkPoint> points; | |
| 52 | |
| 53 bool ltr = l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT; | |
| 54 // If we have a stroke, we have to offset some of our points by 1 pixel. | |
| 55 // We have to inset by 1 pixel when we draw horizontal lines that are on the | |
| 56 // bottom or when we draw vertical lines that are closer to the end (end is | |
| 57 // right for ltr). | |
| 58 int y_off = (type == FRAME_MASK) ? 0 : -1; | |
| 59 // We use this one for LTR. | |
| 60 int x_off_l = ltr ? y_off : 0; | |
| 61 | |
| 62 // Top left corner. | |
| 63 points.push_back(MakeBidiGdkPoint(0, 0, width, ltr)); | |
| 64 | |
| 65 // Top right (rounded) corner. | |
| 66 points.push_back(MakeBidiGdkPoint( | |
| 67 width - kCornerSize + 1 + x_off_l, 0, width, ltr)); | |
| 68 points.push_back(MakeBidiGdkPoint( | |
| 69 width + x_off_l, kCornerSize - 1, width, ltr)); | |
| 70 | |
| 71 // Bottom right corner. | |
| 72 points.push_back(MakeBidiGdkPoint( | |
| 73 width + x_off_l, height + y_off, width, ltr)); | |
| 74 | |
| 75 if (type == FRAME_MASK) { | |
| 76 // Bottom left corner. | |
| 77 points.push_back(MakeBidiGdkPoint(0, height + y_off, width, ltr)); | |
| 78 } | |
| 79 | |
| 80 return points; | |
| 81 } | |
| 34 | 82 |
| 35 } // namespace | 83 } // namespace |
| 36 | 84 |
| 37 StatusBubbleGtk::StatusBubbleGtk(Profile* profile) | 85 StatusBubbleGtk::StatusBubbleGtk(Profile* profile) |
| 38 : theme_provider_(GtkThemeProvider::GetFrom(profile)), | 86 : theme_provider_(GtkThemeProvider::GetFrom(profile)), |
| 39 timer_factory_(this) { | 87 timer_factory_(this) { |
| 40 InitWidgets(); | 88 InitWidgets(); |
| 41 | 89 |
| 42 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, | 90 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
| 43 NotificationService::AllSources()); | 91 NotificationService::AllSources()); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 UserChangedTheme(); | 179 UserChangedTheme(); |
| 132 } | 180 } |
| 133 } | 181 } |
| 134 | 182 |
| 135 void StatusBubbleGtk::InitWidgets() { | 183 void StatusBubbleGtk::InitWidgets() { |
| 136 label_ = gtk_label_new(NULL); | 184 label_ = gtk_label_new(NULL); |
| 137 | 185 |
| 138 GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1); | 186 GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1); |
| 139 gtk_alignment_set_padding(GTK_ALIGNMENT(padding), | 187 gtk_alignment_set_padding(GTK_ALIGNMENT(padding), |
| 140 kInternalTopBottomPadding, kInternalTopBottomPadding, | 188 kInternalTopBottomPadding, kInternalTopBottomPadding, |
| 141 kInternalLeftRightPadding, kInternalLeftRightPadding); | 189 kInternalLeftRightPadding, |
| 190 kInternalLeftRightPadding + kCornerSize); | |
| 142 gtk_container_add(GTK_CONTAINER(padding), label_); | 191 gtk_container_add(GTK_CONTAINER(padding), label_); |
| 143 | 192 |
| 144 bg_box_ = gtk_event_box_new(); | 193 container_.Own(gtk_event_box_new()); |
| 145 gtk_container_add(GTK_CONTAINER(bg_box_), padding); | |
| 146 | |
| 147 container_.Own(gtk_util::CreateGtkBorderBin(bg_box_, &kFrameBorderColor, | |
| 148 kBorderPadding, kBorderPadding, kBorderPadding, kBorderPadding)); | |
| 149 gtk_widget_set_name(container_.get(), "status-bubble"); | 194 gtk_widget_set_name(container_.get(), "status-bubble"); |
| 195 gtk_container_add(GTK_CONTAINER(container_.get()), padding); | |
| 150 gtk_widget_set_app_paintable(container_.get(), TRUE); | 196 gtk_widget_set_app_paintable(container_.get(), TRUE); |
| 197 g_signal_connect(G_OBJECT(container_.get()), "expose-event", | |
| 198 G_CALLBACK(OnExpose), this); | |
| 199 g_signal_connect(G_OBJECT(container_.get()), "size-allocate", | |
| 200 G_CALLBACK(OnSizeAllocate), this); | |
| 151 | 201 |
| 152 UserChangedTheme(); | 202 UserChangedTheme(); |
| 153 } | 203 } |
| 154 | 204 |
| 155 void StatusBubbleGtk::UserChangedTheme() { | 205 void StatusBubbleGtk::UserChangedTheme() { |
| 156 if (theme_provider_->UseGtkTheme()) { | 206 if (theme_provider_->UseGtkTheme()) { |
| 157 gtk_widget_modify_fg(label_, GTK_STATE_NORMAL, NULL); | 207 gtk_widget_modify_fg(label_, GTK_STATE_NORMAL, NULL); |
| 158 gtk_widget_modify_bg(bg_box_, GTK_STATE_NORMAL, NULL); | 208 gtk_widget_modify_bg(container_.get(), GTK_STATE_NORMAL, NULL); |
| 209 | |
| 210 // Creates a weighted average between the text and base color where | |
| 211 // the base color counts twice. | |
|
Evan Martin
2009/08/06 18:05:38
clever!
| |
| 212 GtkStyle* style = gtk_rc_get_style(container_.get()); | |
| 213 border_color_.pixel = 0; | |
| 214 border_color_.red = (style->text[GTK_STATE_NORMAL].red + | |
| 215 (style->bg[GTK_STATE_NORMAL].red * kBgWeight)) / | |
| 216 (1 + kBgWeight); | |
| 217 border_color_.green = (style->text[GTK_STATE_NORMAL].green + | |
| 218 (style->bg[GTK_STATE_NORMAL].green * kBgWeight)) / | |
| 219 (1 + kBgWeight); | |
| 220 border_color_.blue = (style->text[GTK_STATE_NORMAL].blue + | |
| 221 (style->bg[GTK_STATE_NORMAL].blue * kBgWeight)) / | |
| 222 (1 + kBgWeight); | |
| 159 } else { | 223 } else { |
| 160 // TODO(erg): This is the closest to "text that will look good on a | 224 // TODO(erg): This is the closest to "text that will look good on a |
| 161 // toolbar" that I can find. Maybe in later iterations of the theme system, | 225 // toolbar" that I can find. Maybe in later iterations of the theme system, |
| 162 // there will be a better color to pick. | 226 // there will be a better color to pick. |
| 163 GdkColor bookmark_text = | 227 GdkColor bookmark_text = |
| 164 theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT); | 228 theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT); |
| 165 gtk_widget_modify_fg(label_, GTK_STATE_NORMAL, &bookmark_text); | 229 gtk_widget_modify_fg(label_, GTK_STATE_NORMAL, &bookmark_text); |
| 166 | 230 |
| 167 GdkColor toolbar_color = | 231 GdkColor toolbar_color = |
| 168 theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_TOOLBAR); | 232 theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_TOOLBAR); |
| 169 gtk_widget_modify_bg(bg_box_, GTK_STATE_NORMAL, &toolbar_color); | 233 gtk_widget_modify_bg(container_.get(), GTK_STATE_NORMAL, &toolbar_color); |
| 234 | |
| 235 border_color_ = kFrameBorderColor; | |
| 170 } | 236 } |
| 237 } | |
| 171 | 238 |
| 172 // TODO(erg): I don't know what to do with the status bubble border | 239 // static |
| 173 // (|container_|). There needs to be a border in GTK mode, and I'm not sure | 240 gboolean StatusBubbleGtk::OnExpose(GtkWidget* widget, |
| 174 // which BrowserThemeProvider::COLOR I'm supposed to use here since the Views | 241 GdkEventExpose* event, |
| 175 // implementation still uses constants in the equivalent, and it's used for | 242 StatusBubbleGtk* bubble) { |
| 176 // alpha blending instead of drawing a real border. | 243 GdkDrawable* drawable = GDK_DRAWABLE(event->window); |
| 177 // | 244 GdkGC* gc = gdk_gc_new(drawable); |
| 178 // This doesn't really matter because this part of the UI needs to be | 245 gdk_gc_set_rgb_fg_color(gc, &bubble->border_color_); |
| 179 // rewritten per the UI review anyway; we should be matching windows with a | 246 |
| 180 // semi-transparent, rounded border instead of our constantly | 247 // Stroke the frame border. |
| 181 // CreateGtkBorderBin() usage. | 248 std::vector<GdkPoint> points = MakeFramePolygonPoints( |
| 249 widget->allocation.width, widget->allocation.height, FRAME_STROKE); | |
| 250 gdk_draw_lines(drawable, gc, &points[0], points.size()); | |
| 251 | |
| 252 g_object_unref(gc); | |
| 253 return FALSE; // Propagate so our children paint, etc. | |
| 182 } | 254 } |
| 255 | |
| 256 // static | |
| 257 void StatusBubbleGtk::OnSizeAllocate(GtkWidget* widget, | |
| 258 GtkAllocation* allocation, | |
| 259 StatusBubbleGtk* bubble) { | |
|
Evan Martin
2009/08/06 18:05:38
Does this get called only when the allocation chan
| |
| 260 std::vector<GdkPoint> points = MakeFramePolygonPoints( | |
| 261 widget->allocation.width, widget->allocation.height, FRAME_MASK); | |
| 262 GdkRegion* mask_region = gdk_region_polygon(&points[0], | |
| 263 points.size(), | |
| 264 GDK_EVEN_ODD_RULE); | |
| 265 gdk_window_shape_combine_region(widget->window, mask_region, 0, 0); | |
| 266 gdk_region_destroy(mask_region); | |
| 267 } | |
| OLD | NEW |