| 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 |