OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/notifications/balloon_view_gtk.h" | 5 #include "chrome/browser/gtk/notifications/balloon_view_gtk.h" |
6 | 6 |
| 7 #include <gtk/gtk.h> |
| 8 |
7 #include <string> | 9 #include <string> |
8 #include <vector> | 10 #include <vector> |
9 | 11 |
10 #include "app/l10n_util.h" | 12 #include "app/l10n_util.h" |
11 #include "app/resource_bundle.h" | 13 #include "app/resource_bundle.h" |
12 #include "app/slide_animation.h" | 14 #include "app/slide_animation.h" |
13 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
14 #include "base/string_util.h" | 16 #include "base/string_util.h" |
15 #include "chrome/browser/browser_list.h" | 17 #include "chrome/browser/browser_list.h" |
16 #include "chrome/browser/browser_theme_provider.h" | 18 #include "chrome/browser/browser_theme_provider.h" |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 html_contents_->Shutdown(); | 129 html_contents_->Shutdown(); |
128 if (frame_container_) { | 130 if (frame_container_) { |
129 // It's possible that |frame_container_| was destroyed before the | 131 // It's possible that |frame_container_| was destroyed before the |
130 // BalloonViewImpl if our related browser window was closed first. | 132 // BalloonViewImpl if our related browser window was closed first. |
131 gtk_widget_hide(frame_container_); | 133 gtk_widget_hide(frame_container_); |
132 } | 134 } |
133 balloon_->OnClose(by_user); | 135 balloon_->OnClose(by_user); |
134 } | 136 } |
135 | 137 |
136 void BalloonViewImpl::RepositionToBalloon() { | 138 void BalloonViewImpl::RepositionToBalloon() { |
137 DCHECK(frame_container_); | 139 if (!frame_container_) { |
| 140 // No need to create a slide animation when this balloon is fading out. |
| 141 return; |
| 142 } |
| 143 |
138 DCHECK(balloon_); | 144 DCHECK(balloon_); |
139 | 145 |
140 // Create an amination from the current position to the desired one. | 146 // Create an amination from the current position to the desired one. |
141 int start_x; | 147 int start_x; |
142 int start_y; | 148 int start_y; |
143 int start_w; | 149 int start_w; |
144 int start_h; | 150 int start_h; |
145 gtk_window_get_position(GTK_WINDOW(frame_container_), &start_x, &start_y); | 151 gtk_window_get_position(GTK_WINDOW(frame_container_), &start_x, &start_y); |
146 gtk_window_get_size(GTK_WINDOW(frame_container_), &start_w, &start_h); | 152 gtk_window_get_size(GTK_WINDOW(frame_container_), &start_w, &start_h); |
147 | 153 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 | 201 |
196 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 202 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
197 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 1, 1, 1, 1); | 203 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 1, 1, 1, 1); |
198 gtk_container_add(GTK_CONTAINER(alignment), box); | 204 gtk_container_add(GTK_CONTAINER(alignment), box); |
199 gtk_container_add(GTK_CONTAINER(button), alignment); | 205 gtk_container_add(GTK_CONTAINER(button), alignment); |
200 | 206 |
201 gtk_widget_show_all(alignment); | 207 gtk_widget_show_all(alignment); |
202 } | 208 } |
203 | 209 |
204 void BalloonViewImpl::Show(Balloon* balloon) { | 210 void BalloonViewImpl::Show(Balloon* balloon) { |
205 GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom( | 211 theme_provider_ = GtkThemeProvider::GetFrom(balloon->profile()); |
206 balloon->profile()); | |
207 | 212 |
208 const std::string source_label_text = l10n_util::GetStringFUTF8( | 213 const std::string source_label_text = l10n_util::GetStringFUTF8( |
209 IDS_NOTIFICATION_BALLOON_SOURCE_LABEL, | 214 IDS_NOTIFICATION_BALLOON_SOURCE_LABEL, |
210 WideToUTF16(balloon->notification().display_source())); | 215 WideToUTF16(balloon->notification().display_source())); |
211 const std::string options_text = | 216 const std::string options_text = |
212 l10n_util::GetStringUTF8(IDS_NOTIFICATION_OPTIONS_MENU_LABEL); | 217 l10n_util::GetStringUTF8(IDS_NOTIFICATION_OPTIONS_MENU_LABEL); |
213 const std::string dismiss_text = | 218 const std::string dismiss_text = |
214 l10n_util::GetStringUTF8(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL); | 219 l10n_util::GetStringUTF8(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL); |
215 | 220 |
216 balloon_ = balloon; | 221 balloon_ = balloon; |
(...skipping 18 matching lines...) Expand all Loading... |
235 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 240 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
236 gtk_alignment_set_padding( | 241 gtk_alignment_set_padding( |
237 GTK_ALIGNMENT(alignment), | 242 GTK_ALIGNMENT(alignment), |
238 kTopMargin, kBottomMargin, kLeftMargin, kRightMargin); | 243 kTopMargin, kBottomMargin, kLeftMargin, kRightMargin); |
239 gtk_widget_show_all(alignment); | 244 gtk_widget_show_all(alignment); |
240 gtk_container_add(GTK_CONTAINER(alignment), contents); | 245 gtk_container_add(GTK_CONTAINER(alignment), contents); |
241 gtk_container_add(GTK_CONTAINER(vbox), alignment); | 246 gtk_container_add(GTK_CONTAINER(vbox), alignment); |
242 | 247 |
243 shelf_ = gtk_hbox_new(0, 0); | 248 shelf_ = gtk_hbox_new(0, 0); |
244 GtkWidget* alignment2 = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 249 GtkWidget* alignment2 = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
245 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment2), 0, 0, 10, 0); | 250 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment2), 2, 2, 10, 0); |
246 gtk_container_add(GTK_CONTAINER(vbox), shelf_); | 251 gtk_container_add(GTK_CONTAINER(vbox), shelf_); |
247 | 252 |
248 // Create a toolbar and add it to the shelf. | 253 // Create a toolbar and add it to the shelf. |
249 hbox_ = gtk_hbox_new(FALSE, 0); | 254 hbox_ = gtk_hbox_new(FALSE, 0); |
250 // gtk_util::SuppressDefaultPainting(hbox_); | |
251 gtk_widget_set_size_request(GTK_WIDGET(hbox_), -1, GetShelfHeight()); | 255 gtk_widget_set_size_request(GTK_WIDGET(hbox_), -1, GetShelfHeight()); |
252 gtk_container_add(GTK_CONTAINER(alignment2), hbox_); | 256 gtk_container_add(GTK_CONTAINER(alignment2), hbox_); |
253 gtk_container_add(GTK_CONTAINER(shelf_), alignment2); | 257 gtk_container_add(GTK_CONTAINER(shelf_), alignment2); |
254 gtk_widget_show_all(vbox); | 258 gtk_widget_show_all(vbox); |
255 | 259 |
256 g_signal_connect(frame_container_, "expose-event", | 260 g_signal_connect(frame_container_, "expose-event", |
257 G_CALLBACK(OnExposeThunk), this); | 261 G_CALLBACK(OnExposeThunk), this); |
258 g_signal_connect(frame_container_, "destroy", | 262 g_signal_connect(frame_container_, "destroy", |
259 G_CALLBACK(OnDestroyThunk), this); | 263 G_CALLBACK(OnDestroyThunk), this); |
260 | 264 |
261 // Create a label for the source of the notification and add it to the | 265 // Create a label for the source of the notification and add it to the |
262 // toolbar. | 266 // toolbar. |
263 GtkWidget* source_label_ = gtk_label_new(NULL); | 267 GtkWidget* source_label_ = gtk_label_new(NULL); |
264 char* markup = g_markup_printf_escaped(kLabelMarkup, | 268 char* markup = g_markup_printf_escaped(kLabelMarkup, |
265 source_label_text.c_str()); | 269 source_label_text.c_str()); |
266 gtk_label_set_markup(GTK_LABEL(source_label_), markup); | 270 gtk_label_set_markup(GTK_LABEL(source_label_), markup); |
267 g_free(markup); | 271 g_free(markup); |
268 gtk_label_set_max_width_chars(GTK_LABEL(source_label_), | 272 gtk_label_set_max_width_chars(GTK_LABEL(source_label_), |
269 kOriginLabelCharacters); | 273 kOriginLabelCharacters); |
270 gtk_label_set_ellipsize(GTK_LABEL(source_label_), PANGO_ELLIPSIZE_END); | 274 gtk_label_set_ellipsize(GTK_LABEL(source_label_), PANGO_ELLIPSIZE_END); |
271 gtk_box_pack_start(GTK_BOX(hbox_), source_label_, FALSE, FALSE, 0); | 275 gtk_box_pack_start(GTK_BOX(hbox_), source_label_, FALSE, FALSE, 0); |
272 | 276 |
273 // Create a button for showing the options menu, and add it to the toolbar. | 277 // Create a button for showing the options menu, and add it to the toolbar. |
274 options_menu_button_ = theme_provider->BuildChromeButton(); | 278 options_menu_button_ = theme_provider_->BuildChromeButton(); |
275 g_signal_connect(options_menu_button_, "clicked", | 279 g_signal_connect(options_menu_button_, "clicked", |
276 G_CALLBACK(OnOptionsMenuButtonThunk), this); | 280 G_CALLBACK(OnOptionsMenuButtonThunk), this); |
277 PrepareButtonWithIcon(options_menu_button_, options_text, | 281 PrepareButtonWithIcon(options_menu_button_, options_text, |
278 IDR_BALLOON_OPTIONS_ARROW_HOVER); | 282 IDR_BALLOON_OPTIONS_ARROW_HOVER); |
279 gtk_box_pack_start(GTK_BOX(hbox_), options_menu_button_, FALSE, FALSE, 0); | 283 gtk_box_pack_start(GTK_BOX(hbox_), options_menu_button_, FALSE, FALSE, 0); |
280 | 284 |
281 // Create a button to dismiss the balloon and add it to the toolbar. | 285 // Create a button to dismiss the balloon and add it to the toolbar. |
282 close_button_ = theme_provider->BuildChromeButton(); | 286 close_button_ = theme_provider_->BuildChromeButton(); |
283 g_signal_connect(close_button_, "clicked", | 287 g_signal_connect(close_button_, "clicked", |
284 G_CALLBACK(OnCloseButtonThunk), this); | 288 G_CALLBACK(OnCloseButtonThunk), this); |
285 PrepareButtonWithIcon(close_button_, dismiss_text, IDR_BALLOON_CLOSE_HOVER); | 289 PrepareButtonWithIcon(close_button_, dismiss_text, IDR_BALLOON_CLOSE_HOVER); |
286 gtk_box_pack_start(GTK_BOX(hbox_), close_button_, FALSE, FALSE, 0); | 290 gtk_box_pack_start(GTK_BOX(hbox_), close_button_, FALSE, FALSE, 0); |
287 | 291 |
| 292 notification_registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
| 293 NotificationService::AllSources()); |
| 294 // We don't do InitThemesFor() because it just forces a redraw. |
| 295 |
288 // Position the view elements according to the balloon position and show. | 296 // Position the view elements according to the balloon position and show. |
289 RepositionToBalloon(); | 297 RepositionToBalloon(); |
290 gtk_widget_show_all(GTK_WIDGET(hbox_)); | 298 gtk_widget_show_all(GTK_WIDGET(hbox_)); |
291 gtk_widget_show(frame_container_); | 299 gtk_widget_show(frame_container_); |
292 | 300 |
293 gtk_util::ActAsRoundedWindow(frame_container_, gfx::kGdkBlack, 3, | 301 gtk_util::ActAsRoundedWindow(frame_container_, gfx::kGdkBlack, 3, |
294 gtk_util::ROUNDED_ALL, | 302 gtk_util::ROUNDED_ALL, |
295 gtk_util::BORDER_ALL); | 303 gtk_util::BORDER_ALL); |
296 | 304 |
297 notification_registrar_.Add(this, | 305 notification_registrar_.Add(this, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 gfx::Point offset = GetContentsOffset(); | 339 gfx::Point offset = GetContentsOffset(); |
332 int x = 0, y = 0; | 340 int x = 0, y = 0; |
333 gtk_window_get_position(GTK_WINDOW(frame_container_), &x, &y); | 341 gtk_window_get_position(GTK_WINDOW(frame_container_), &x, &y); |
334 return gfx::Rect(x + offset.x(), y + offset.y(), | 342 return gfx::Rect(x + offset.x(), y + offset.y(), |
335 content_size.width(), content_size.height()); | 343 content_size.width(), content_size.height()); |
336 } | 344 } |
337 | 345 |
338 void BalloonViewImpl::Observe(NotificationType type, | 346 void BalloonViewImpl::Observe(NotificationType type, |
339 const NotificationSource& source, | 347 const NotificationSource& source, |
340 const NotificationDetails& details) { | 348 const NotificationDetails& details) { |
341 if (type != NotificationType::NOTIFY_BALLOON_DISCONNECTED) { | 349 if (type == NotificationType::NOTIFY_BALLOON_DISCONNECTED) { |
| 350 // If the renderer process attached to this balloon is disconnected |
| 351 // (e.g., because of a crash), we want to close the balloon. |
| 352 notification_registrar_.Remove(this, |
| 353 NotificationType::NOTIFY_BALLOON_DISCONNECTED, |
| 354 Source<Balloon>(balloon_)); |
| 355 Close(false); |
| 356 } else if (type == NotificationType::BROWSER_THEME_CHANGED) { |
| 357 // Since all the buttons change their own properties, and our expose does |
| 358 // all the real differences, we'll need a redraw. |
| 359 gtk_widget_queue_draw(frame_container_); |
| 360 } else { |
342 NOTREACHED(); | 361 NOTREACHED(); |
343 return; | 362 } |
| 363 } |
| 364 |
| 365 gboolean BalloonViewImpl::OnExpose(GtkWidget* sender, GdkEventExpose* event) { |
| 366 if (theme_provider_->UseGtkTheme()) { |
| 367 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window)); |
| 368 gdk_cairo_rectangle(cr, &event->area); |
| 369 cairo_clip(cr); |
| 370 |
| 371 gfx::Size content_size = balloon_->content_size(); |
| 372 gfx::Point offset = GetContentsOffset(); |
| 373 |
| 374 // Draw lines of the content border color around the html content. |
| 375 GdkColor color = theme_provider_->GetBorderColor(); |
| 376 gdk_cairo_set_source_color(cr, &color); |
| 377 cairo_rectangle(cr, offset.x() - 1, offset.y() - 1, |
| 378 offset.x() + content_size.width() + 1, |
| 379 offset.y() + content_size.height()); |
| 380 cairo_fill(cr); |
| 381 |
| 382 // Now draw a one pixel black line under the separator stuff. |
| 383 cairo_move_to(cr, 0, offset.y() + content_size.height() + 1.5); |
| 384 cairo_line_to(cr, offset.x() + content_size.width() + 1, |
| 385 offset.y() + content_size.height() + 1.5); |
| 386 cairo_set_line_width(cr, 1.0); |
| 387 cairo_set_source_rgb(cr, 0, 0, 0); |
| 388 cairo_stroke(cr); |
| 389 |
| 390 cairo_destroy(cr); |
| 391 } else { |
| 392 // Draw the background images. |
| 393 balloon_background_->RenderToWidget(frame_container_); |
| 394 shelf_background_->RenderToWidget(shelf_); |
344 } | 395 } |
345 | 396 |
346 // If the renderer process attached to this balloon is disconnected | |
347 // (e.g., because of a crash), we want to close the balloon. | |
348 notification_registrar_.Remove(this, | |
349 NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon_)); | |
350 Close(false); | |
351 } | |
352 | |
353 gboolean BalloonViewImpl::OnExpose(GtkWidget* sender, GdkEventExpose* e) { | |
354 // Draw the background images. | |
355 balloon_background_->RenderToWidget(frame_container_); | |
356 shelf_background_->RenderToWidget(shelf_); | |
357 return FALSE; | 397 return FALSE; |
358 } | 398 } |
359 | 399 |
360 void BalloonViewImpl::OnOptionsMenuButton(GtkWidget* widget) { | 400 void BalloonViewImpl::OnOptionsMenuButton(GtkWidget* widget) { |
361 options_menu_->PopupAsContext(gtk_get_current_event_time()); | 401 options_menu_->PopupAsContext(gtk_get_current_event_time()); |
362 } | 402 } |
363 | 403 |
364 gboolean BalloonViewImpl::OnDestroy(GtkWidget* widget) { | 404 gboolean BalloonViewImpl::OnDestroy(GtkWidget* widget) { |
365 frame_container_ = NULL; | 405 frame_container_ = NULL; |
366 Close(false); | 406 Close(false); |
367 return FALSE; // Propagate. | 407 return FALSE; // Propagate. |
368 } | 408 } |
OLD | NEW |