Chromium Code Reviews

Side by Side Diff: chrome/browser/gtk/infobar_gtk.cc

Issue 6251001: Move chrome/browser/gtk/ to chrome/browser/ui/gtk/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
« no previous file with comments | « chrome/browser/gtk/infobar_gtk.h ('k') | chrome/browser/gtk/instant_confirm_dialog_gtk.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/gtk/infobar_gtk.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/gtk/browser_window_gtk.h"
11 #include "chrome/browser/gtk/custom_button.h"
12 #include "chrome/browser/gtk/gtk_chrome_link_button.h"
13 #include "chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h"
14 #include "chrome/browser/gtk/gtk_theme_provider.h"
15 #include "chrome/browser/gtk/gtk_util.h"
16 #include "chrome/browser/gtk/infobar_container_gtk.h"
17 #include "chrome/browser/platform_util.h"
18 #include "chrome/common/notification_service.h"
19 #include "gfx/gtk_util.h"
20
21 extern const int InfoBar::kInfoBarHeight = 37;
22
23 namespace {
24
25 // Spacing after message (and before buttons).
26 const int kEndOfLabelSpacing = 6;
27 // Spacing between buttons.
28 const int kButtonButtonSpacing = 3;
29
30 // Pixels between infobar elements.
31 const int kElementPadding = 5;
32
33 // Extra padding on either end of info bar.
34 const int kLeftPadding = 5;
35 const int kRightPadding = 5;
36
37 } // namespace
38
39 InfoBar::InfoBar(InfoBarDelegate* delegate)
40 : container_(NULL),
41 delegate_(delegate),
42 theme_provider_(NULL),
43 arrow_model_(this) {
44 // Create |hbox_| and pad the sides.
45 hbox_ = gtk_hbox_new(FALSE, kElementPadding);
46
47 // Make the whole infor bar horizontally shrinkable.
48 gtk_widget_set_size_request(hbox_, 0, -1);
49
50 GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1);
51 gtk_alignment_set_padding(GTK_ALIGNMENT(padding),
52 0, 0, kLeftPadding, kRightPadding);
53
54 bg_box_ = gtk_event_box_new();
55 gtk_widget_set_app_paintable(bg_box_, TRUE);
56 g_signal_connect(bg_box_, "expose-event",
57 G_CALLBACK(OnBackgroundExposeThunk), this);
58 gtk_container_add(GTK_CONTAINER(padding), hbox_);
59 gtk_container_add(GTK_CONTAINER(bg_box_), padding);
60 gtk_widget_set_size_request(bg_box_, -1, kInfoBarHeight);
61
62 // Add the icon on the left, if any.
63 SkBitmap* icon = delegate->GetIcon();
64 if (icon) {
65 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(icon);
66 GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
67 g_object_unref(pixbuf);
68 gtk_box_pack_start(GTK_BOX(hbox_), image, FALSE, FALSE, 0);
69 }
70
71 close_button_.reset(CustomDrawButton::CloseButton(NULL));
72 gtk_util::CenterWidgetInHBox(hbox_, close_button_->widget(), true, 0);
73 g_signal_connect(close_button_->widget(), "clicked",
74 G_CALLBACK(OnCloseButtonThunk), this);
75
76 slide_widget_.reset(new SlideAnimatorGtk(bg_box_,
77 SlideAnimatorGtk::DOWN,
78 0, true, true, this));
79 // We store a pointer back to |this| so we can refer to it from the infobar
80 // container.
81 g_object_set_data(G_OBJECT(slide_widget_->widget()), "info-bar", this);
82 }
83
84 InfoBar::~InfoBar() {
85 }
86
87 GtkWidget* InfoBar::widget() {
88 return slide_widget_->widget();
89 }
90
91 void InfoBar::AnimateOpen() {
92 slide_widget_->Open();
93
94 gtk_widget_show_all(bg_box_);
95 if (bg_box_->window)
96 gdk_window_lower(bg_box_->window);
97 }
98
99 void InfoBar::Open() {
100 slide_widget_->OpenWithoutAnimation();
101
102 gtk_widget_show_all(bg_box_);
103 if (bg_box_->window)
104 gdk_window_lower(bg_box_->window);
105 }
106
107 void InfoBar::AnimateClose() {
108 slide_widget_->Close();
109 }
110
111 void InfoBar::Close() {
112 if (delegate_) {
113 delegate_->InfoBarClosed();
114 delegate_ = NULL;
115 }
116 delete this;
117 }
118
119 bool InfoBar::IsAnimating() {
120 return slide_widget_->IsAnimating();
121 }
122
123 bool InfoBar::IsClosing() {
124 return slide_widget_->IsClosing();
125 }
126
127 void InfoBar::ShowArrowFor(InfoBar* other, bool animate) {
128 arrow_model_.ShowArrowFor(other, animate);
129 }
130
131 void InfoBar::PaintStateChanged() {
132 gtk_widget_queue_draw(widget());
133 }
134
135 void InfoBar::RemoveInfoBar() const {
136 container_->RemoveDelegate(delegate_);
137 }
138
139 void InfoBar::Closed() {
140 Close();
141 }
142
143 void InfoBar::SetThemeProvider(GtkThemeProvider* theme_provider) {
144 if (theme_provider_) {
145 NOTREACHED();
146 return;
147 }
148
149 theme_provider_ = theme_provider;
150 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
151 NotificationService::AllSources());
152 UpdateBorderColor();
153 }
154
155 void InfoBar::Observe(NotificationType type,
156 const NotificationSource& source,
157 const NotificationDetails& details) {
158 UpdateBorderColor();
159 }
160
161 void InfoBar::AddLabelWithInlineLink(const string16& display_text,
162 const string16& link_text,
163 size_t link_offset,
164 GCallback callback) {
165 GtkWidget* link_button = gtk_chrome_link_button_new(
166 UTF16ToUTF8(link_text).c_str());
167 gtk_chrome_link_button_set_use_gtk_theme(
168 GTK_CHROME_LINK_BUTTON(link_button), FALSE);
169 gtk_util::ForceFontSizePixels(
170 GTK_CHROME_LINK_BUTTON(link_button)->label, 13.4);
171 DCHECK(callback);
172 g_signal_connect(link_button, "clicked", callback, this);
173 gtk_util::SetButtonTriggersNavigation(link_button);
174
175 GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
176 // We want the link to be horizontally shrinkable, so that the Chrome
177 // window can be resized freely even with a very long link.
178 gtk_widget_set_size_request(hbox, 0, -1);
179 gtk_box_pack_start(GTK_BOX(hbox_), hbox, TRUE, TRUE, 0);
180
181 // Need to insert the link inside the display text.
182 GtkWidget* initial_label = gtk_label_new(
183 UTF16ToUTF8(display_text.substr(0, link_offset)).c_str());
184 GtkWidget* trailing_label = gtk_label_new(
185 UTF16ToUTF8(display_text.substr(link_offset)).c_str());
186
187 gtk_util::ForceFontSizePixels(initial_label, 13.4);
188 gtk_util::ForceFontSizePixels(trailing_label, 13.4);
189
190 // TODO(joth): Unlike the AddLabelAndLink below, none of the label widgets
191 // are set as shrinkable here, meaning the text will run under the close
192 // button etc. when the width is restricted, rather than eliding.
193 gtk_widget_modify_fg(initial_label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
194 gtk_widget_modify_fg(trailing_label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
195
196 // We don't want any spacing between the elements, so we pack them into
197 // this hbox that doesn't use kElementPadding.
198 gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0);
199 gtk_util::CenterWidgetInHBox(hbox, link_button, false, 0);
200 gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0);
201 }
202
203 // TODO(joth): This method factors out some common functionality between the
204 // various derived infobar classes, however the class hierarchy itself could
205 // use refactoring to reduce this duplication. http://crbug.com/38924
206 void InfoBar::AddLabelAndLink(const string16& display_text,
207 const string16& link_text,
208 GCallback callback) {
209 GtkWidget* link_button = NULL;
210 if (!link_text.empty()) {
211 // If we have some link text, create the link button.
212 link_button = gtk_chrome_link_button_new(UTF16ToUTF8(link_text).c_str());
213 gtk_chrome_link_button_set_use_gtk_theme(
214 GTK_CHROME_LINK_BUTTON(link_button), FALSE);
215 DCHECK(callback);
216 g_signal_connect(link_button, "clicked", callback, this);
217 gtk_util::SetButtonTriggersNavigation(link_button);
218 }
219
220 GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
221 // We want the link to be horizontally shrinkable, so that the Chrome
222 // window can be resized freely even with a very long link.
223 gtk_widget_set_size_request(hbox, 0, -1);
224 gtk_box_pack_start(GTK_BOX(hbox_), hbox, TRUE, TRUE, 0);
225
226 if (link_button)
227 gtk_box_pack_end(GTK_BOX(hbox), link_button, FALSE, FALSE, 0);
228 GtkWidget* label = gtk_label_new(UTF16ToUTF8(display_text).c_str());
229 gtk_util::ForceFontSizePixels(label, 13.4);
230 // In order to avoid the link_button and the label overlapping with each
231 // other, we make the label shrinkable.
232 gtk_widget_set_size_request(label, 0, -1);
233 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
234 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
235 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
236 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
237 }
238
239 void InfoBar::GetTopColor(InfoBarDelegate::Type type,
240 double* r, double* g, double *b) {
241 // These constants are copied from corresponding skia constants from
242 // browser/ui/views/infobars/infobars.cc, and then changed into 0-1 ranged
243 // values for cairo.
244 switch (type) {
245 case InfoBarDelegate::WARNING_TYPE:
246 *r = 255.0 / 255.0;
247 *g = 242.0 / 255.0;
248 *b = 183.0 / 255.0;
249 break;
250 case InfoBarDelegate::PAGE_ACTION_TYPE:
251 *r = 218.0 / 255.0;
252 *g = 231.0 / 255.0;
253 *b = 249.0 / 255.0;
254 break;
255 }
256 }
257
258 void InfoBar::GetBottomColor(InfoBarDelegate::Type type,
259 double* r, double* g, double *b) {
260 switch (type) {
261 case InfoBarDelegate::WARNING_TYPE:
262 *r = 250.0 / 255.0;
263 *g = 230.0 / 255.0;
264 *b = 145.0 / 255.0;
265 break;
266 case InfoBarDelegate::PAGE_ACTION_TYPE:
267 *r = 179.0 / 255.0;
268 *g = 202.0 / 255.0;
269 *b = 231.0 / 255.0;
270 break;
271 }
272 }
273
274 void InfoBar::UpdateBorderColor() {
275 gtk_widget_queue_draw(widget());
276 }
277
278 void InfoBar::OnCloseButton(GtkWidget* button) {
279 if (delegate_)
280 delegate_->InfoBarDismissed();
281 RemoveInfoBar();
282 }
283
284 gboolean InfoBar::OnBackgroundExpose(GtkWidget* sender,
285 GdkEventExpose* event) {
286 const int height = sender->allocation.height;
287
288 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window));
289 gdk_cairo_rectangle(cr, &event->area);
290 cairo_clip(cr);
291
292 cairo_pattern_t* pattern = cairo_pattern_create_linear(0, 0, 0, height);
293
294 double top_r, top_g, top_b;
295 GetTopColor(delegate_->GetInfoBarType(), &top_r, &top_g, &top_b);
296 cairo_pattern_add_color_stop_rgb(pattern, 0.0, top_r, top_g, top_b);
297
298 double bottom_r, bottom_g, bottom_b;
299 GetBottomColor(delegate_->GetInfoBarType(), &bottom_r, &bottom_g, &bottom_b);
300 cairo_pattern_add_color_stop_rgb(
301 pattern, 1.0, bottom_r, bottom_g, bottom_b);
302 cairo_set_source(cr, pattern);
303 cairo_paint(cr);
304 cairo_pattern_destroy(pattern);
305
306 // Draw the bottom border.
307 GdkColor border_color = theme_provider_->GetBorderColor();
308 cairo_set_source_rgb(cr, border_color.red / 65535.0,
309 border_color.green / 65535.0,
310 border_color.blue / 65535.0);
311 cairo_set_line_width(cr, 1.0);
312 int y = sender->allocation.height;
313 cairo_move_to(cr, 0, y - 0.5);
314 cairo_rel_line_to(cr, sender->allocation.width, 0);
315 cairo_stroke(cr);
316
317 cairo_destroy(cr);
318
319 if (!arrow_model_.NeedToDrawInfoBarArrow())
320 return FALSE;
321
322 GtkWindow* parent = platform_util::GetTopLevel(widget());
323 BrowserWindowGtk* browser_window =
324 BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent);
325 int x = browser_window ?
326 browser_window->GetXPositionOfLocationIcon(sender) : 0;
327
328 arrow_model_.Paint(sender, event, gfx::Point(x, y), border_color);
329
330 return FALSE;
331 }
332
333 // AlertInfoBar ----------------------------------------------------------------
334
335 class AlertInfoBar : public InfoBar {
336 public:
337 explicit AlertInfoBar(AlertInfoBarDelegate* delegate)
338 : InfoBar(delegate) {
339 AddLabelAndLink(delegate->GetMessageText(), string16(), NULL);
340 }
341 };
342
343 // LinkInfoBar -----------------------------------------------------------------
344
345 class LinkInfoBar : public InfoBar {
346 public:
347 explicit LinkInfoBar(LinkInfoBarDelegate* delegate)
348 : InfoBar(delegate) {
349 size_t link_offset;
350 string16 display_text = delegate->GetMessageTextWithOffset(&link_offset);
351 string16 link_text = delegate->GetLinkText();
352 AddLabelWithInlineLink(display_text, link_text, link_offset,
353 G_CALLBACK(OnLinkClick));
354 }
355
356 private:
357 static void OnLinkClick(GtkWidget* button, LinkInfoBar* link_info_bar) {
358 if (link_info_bar->delegate_->AsLinkInfoBarDelegate()->
359 LinkClicked(gtk_util::DispositionForCurrentButtonPressEvent())) {
360 link_info_bar->RemoveInfoBar();
361 }
362 }
363 };
364
365 // ConfirmInfoBar --------------------------------------------------------------
366
367 class ConfirmInfoBar : public InfoBar {
368 public:
369 explicit ConfirmInfoBar(ConfirmInfoBarDelegate* delegate);
370
371 private:
372 // Adds a button to the info bar by type. It will do nothing if the delegate
373 // doesn't specify a button of the given type.
374 void AddButton(ConfirmInfoBarDelegate::InfoBarButton type);
375
376 CHROMEGTK_CALLBACK_0(ConfirmInfoBar, void, OnOkButton);
377 CHROMEGTK_CALLBACK_0(ConfirmInfoBar, void, OnCancelButton);
378 CHROMEGTK_CALLBACK_0(ConfirmInfoBar, void, OnLinkClicked);
379
380 GtkWidget* confirm_hbox_;
381
382 DISALLOW_COPY_AND_ASSIGN(ConfirmInfoBar);
383 };
384
385 ConfirmInfoBar::ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
386 : InfoBar(delegate) {
387 confirm_hbox_ = gtk_chrome_shrinkable_hbox_new(FALSE, FALSE, 0);
388 gtk_box_pack_start(GTK_BOX(hbox_), confirm_hbox_, TRUE, TRUE, 0);
389 gtk_widget_set_size_request(confirm_hbox_, 0, -1);
390
391 std::string label_text = UTF16ToUTF8(delegate->GetMessageText());
392 GtkWidget* label = gtk_label_new(label_text.c_str());
393 gtk_util::ForceFontSizePixels(label, 13.4);
394 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
395 gtk_util::CenterWidgetInHBox(confirm_hbox_, label, false, kEndOfLabelSpacing);
396 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gtk_util::kGdkBlack);
397 g_signal_connect(label, "map",
398 G_CALLBACK(gtk_util::InitLabelSizeRequestAndEllipsizeMode),
399 NULL);
400
401 AddButton(ConfirmInfoBarDelegate::BUTTON_CANCEL);
402 AddButton(ConfirmInfoBarDelegate::BUTTON_OK);
403
404 std::string link_text = UTF16ToUTF8(delegate->GetLinkText());
405 GtkWidget* link = gtk_chrome_link_button_new(link_text.c_str());
406 gtk_misc_set_alignment(GTK_MISC(GTK_CHROME_LINK_BUTTON(link)->label), 0, 0.5);
407 g_signal_connect(link, "clicked", G_CALLBACK(OnLinkClickedThunk), this);
408 gtk_util::SetButtonTriggersNavigation(link);
409 // Until we switch to vector graphics, force the font size.
410 // 13.4px == 10pt @ 96dpi
411 gtk_util::ForceFontSizePixels(GTK_CHROME_LINK_BUTTON(link)->label, 13.4);
412 gtk_util::CenterWidgetInHBox(hbox_, link, true, kEndOfLabelSpacing);
413 }
414
415 void ConfirmInfoBar::AddButton(ConfirmInfoBarDelegate::InfoBarButton type) {
416 if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) {
417 GtkWidget* button = gtk_button_new_with_label(UTF16ToUTF8(
418 delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str());
419 gtk_util::CenterWidgetInHBox(confirm_hbox_, button, false,
420 kButtonButtonSpacing);
421 g_signal_connect(button, "clicked",
422 G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ?
423 OnOkButtonThunk : OnCancelButtonThunk),
424 this);
425 }
426 }
427
428 void ConfirmInfoBar::OnCancelButton(GtkWidget* widget) {
429 if (delegate_->AsConfirmInfoBarDelegate()->Cancel())
430 RemoveInfoBar();
431 }
432
433 void ConfirmInfoBar::OnOkButton(GtkWidget* widget) {
434 if (delegate_->AsConfirmInfoBarDelegate()->Accept())
435 RemoveInfoBar();
436 }
437
438 void ConfirmInfoBar::OnLinkClicked(GtkWidget* widget) {
439 if (delegate_->AsConfirmInfoBarDelegate()->LinkClicked(
440 gtk_util::DispositionForCurrentButtonPressEvent())) {
441 RemoveInfoBar();
442 }
443 }
444
445 InfoBar* AlertInfoBarDelegate::CreateInfoBar() {
446 return new AlertInfoBar(this);
447 }
448 InfoBar* LinkInfoBarDelegate::CreateInfoBar() {
449 return new LinkInfoBar(this);
450 }
451 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() {
452 return new ConfirmInfoBar(this);
453 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/infobar_gtk.h ('k') | chrome/browser/gtk/instant_confirm_dialog_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine