OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui/gtk/browser_titlebar.h" | 5 #include "chrome/browser/ui/gtk/browser_titlebar.h" |
6 | 6 |
7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
8 #include <gtk/gtk.h> | 8 #include <gtk/gtk.h> |
9 | 9 |
10 #include <string> | 10 #include <string> |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 titlebar_right_avatar_frame_(NULL), | 234 titlebar_right_avatar_frame_(NULL), |
235 avatar_(NULL), | 235 avatar_(NULL), |
236 top_padding_left_(NULL), | 236 top_padding_left_(NULL), |
237 top_padding_right_(NULL), | 237 top_padding_right_(NULL), |
238 app_mode_favicon_(NULL), | 238 app_mode_favicon_(NULL), |
239 app_mode_title_(NULL), | 239 app_mode_title_(NULL), |
240 using_custom_frame_(false), | 240 using_custom_frame_(false), |
241 window_has_focus_(false), | 241 window_has_focus_(false), |
242 display_avatar_on_left_(false), | 242 display_avatar_on_left_(false), |
243 theme_service_(NULL) { | 243 theme_service_(NULL) { |
244 Init(); | |
245 } | 244 } |
246 | 245 |
247 void BrowserTitlebar::Init() { | 246 void BrowserTitlebar::Init() { |
248 // The widget hierarchy is shown below. | 247 // The widget hierarchy is shown below. |
249 // | 248 // |
250 // +- EventBox (container_) ------------------------------------------------+ | 249 // +- EventBox (container_) ------------------------------------------------+ |
251 // +- HBox (container_hbox_) -----------------------------------------------+ | 250 // +- HBox (container_hbox_) -----------------------------------------------+ |
252 // |+ VBox ---++- Algn. -++- Alignment --------------++- Algn. -++ VBox ---+| | 251 // |+ VBox ---++- Algn. -++- Alignment --------------++- Algn. -++ VBox ---+| |
253 // || titlebar||titlebar || (titlebar_alignment_) ||titlebar || titlebar|| | 252 // || titlebar||titlebar || (titlebar_alignment_) ||titlebar || titlebar|| |
254 // || left ||left || ||right || right || | 253 // || left ||left || ||right || right || |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 StringTokenizer tokenizer(button_string, ":,"); | 426 StringTokenizer tokenizer(button_string, ":,"); |
428 tokenizer.set_options(StringTokenizer::RETURN_DELIMS); | 427 tokenizer.set_options(StringTokenizer::RETURN_DELIMS); |
429 int left_count = 0; | 428 int left_count = 0; |
430 int right_count = 0; | 429 int right_count = 0; |
431 while (tokenizer.GetNext()) { | 430 while (tokenizer.GetNext()) { |
432 if (tokenizer.token_is_delim()) { | 431 if (tokenizer.token_is_delim()) { |
433 if (*tokenizer.token_begin() == ':') | 432 if (*tokenizer.token_begin() == ':') |
434 left_side = false; | 433 left_side = false; |
435 } else { | 434 } else { |
436 base::StringPiece token = tokenizer.token_piece(); | 435 base::StringPiece token = tokenizer.token_piece(); |
437 if (token == "minimize" && !IsTypePanel()) { | 436 if (BuildButton(token.as_string(), left_side)) |
438 (left_side ? left_count : right_count)++; | 437 (left_side ? left_count : right_count)++; |
439 GtkWidget* parent_box = GetButtonHBox(left_side); | |
440 minimize_button_.reset( | |
441 BuildTitlebarButton(IDR_MINIMIZE, IDR_MINIMIZE_P, | |
442 IDR_MINIMIZE_H, parent_box, true, | |
443 IDS_XPFRAME_MINIMIZE_TOOLTIP)); | |
444 | |
445 gtk_widget_size_request(minimize_button_->widget(), | |
446 &minimize_button_req_); | |
447 } else if (token == "maximize" && !IsTypePanel()) { | |
448 (left_side ? left_count : right_count)++; | |
449 GtkWidget* parent_box = GetButtonHBox(left_side); | |
450 restore_button_.reset( | |
451 BuildTitlebarButton(IDR_RESTORE, IDR_RESTORE_P, | |
452 IDR_RESTORE_H, parent_box, true, | |
453 IDS_XPFRAME_RESTORE_TOOLTIP)); | |
454 maximize_button_.reset( | |
455 BuildTitlebarButton(IDR_MAXIMIZE, IDR_MAXIMIZE_P, | |
456 IDR_MAXIMIZE_H, parent_box, true, | |
457 IDS_XPFRAME_MAXIMIZE_TOOLTIP)); | |
458 | |
459 gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(), | |
460 true, true, true); | |
461 gtk_widget_size_request(restore_button_->widget(), | |
462 &restore_button_req_); | |
463 } else if (token == "close") { | |
464 (left_side ? left_count : right_count)++; | |
465 GtkWidget* parent_box = GetButtonHBox(left_side); | |
466 close_button_.reset( | |
467 BuildTitlebarButton(IDR_CLOSE, IDR_CLOSE_P, | |
468 IDR_CLOSE_H, parent_box, true, | |
469 IDS_XPFRAME_CLOSE_TOOLTIP)); | |
470 close_button_->set_flipped(left_side); | |
471 | |
472 gtk_widget_size_request(close_button_->widget(), &close_button_req_); | |
473 } | |
474 // Ignore any other values like "pin" since we don't have images for | |
475 // those. | |
476 } | 438 } |
477 } | 439 } |
478 | 440 |
479 // If we are in incognito mode, add the spy guy to either the end of the left | 441 // If we are in incognito mode, add the spy guy to either the end of the left |
480 // or the beginning of the right depending on which side has fewer buttons. | 442 // or the beginning of the right depending on which side has fewer buttons. |
481 display_avatar_on_left_ = right_count > left_count; | 443 display_avatar_on_left_ = right_count > left_count; |
482 | 444 |
483 // Now show the correct widgets in the two hierarchies. | 445 // Now show the correct widgets in the two hierarchies. |
484 if (using_custom_frame_) { | 446 if (using_custom_frame_) { |
485 gtk_widget_show_all(titlebar_left_buttons_vbox_); | 447 gtk_widget_show_all(titlebar_left_buttons_vbox_); |
486 gtk_widget_show_all(titlebar_right_buttons_vbox_); | 448 gtk_widget_show_all(titlebar_right_buttons_vbox_); |
487 } | 449 } |
488 UpdateMaximizeRestoreVisibility(); | 450 UpdateMaximizeRestoreVisibility(); |
489 } | 451 } |
490 | 452 |
| 453 bool BrowserTitlebar::BuildButton(const std::string& button_token, |
| 454 bool left_side) { |
| 455 if (button_token == "minimize") { |
| 456 GtkWidget* parent_box = GetButtonHBox(left_side); |
| 457 minimize_button_.reset( |
| 458 CreateTitlebarButton(IDR_MINIMIZE, IDR_MINIMIZE_P, |
| 459 IDR_MINIMIZE_H, parent_box, |
| 460 IDS_XPFRAME_MINIMIZE_TOOLTIP)); |
| 461 |
| 462 gtk_widget_size_request(minimize_button_->widget(), |
| 463 &minimize_button_req_); |
| 464 return true; |
| 465 } else if (button_token == "maximize") { |
| 466 GtkWidget* parent_box = GetButtonHBox(left_side); |
| 467 restore_button_.reset( |
| 468 CreateTitlebarButton(IDR_RESTORE, IDR_RESTORE_P, |
| 469 IDR_RESTORE_H, parent_box, |
| 470 IDS_XPFRAME_RESTORE_TOOLTIP)); |
| 471 maximize_button_.reset( |
| 472 CreateTitlebarButton(IDR_MAXIMIZE, IDR_MAXIMIZE_P, |
| 473 IDR_MAXIMIZE_H, parent_box, |
| 474 IDS_XPFRAME_MAXIMIZE_TOOLTIP)); |
| 475 |
| 476 gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(), |
| 477 true, true, true); |
| 478 gtk_widget_size_request(restore_button_->widget(), |
| 479 &restore_button_req_); |
| 480 return true; |
| 481 } else if (button_token == "close") { |
| 482 GtkWidget* parent_box = GetButtonHBox(left_side); |
| 483 close_button_.reset( |
| 484 CreateTitlebarButton(IDR_CLOSE, IDR_CLOSE_P, |
| 485 IDR_CLOSE_H, parent_box, |
| 486 IDS_XPFRAME_CLOSE_TOOLTIP)); |
| 487 close_button_->set_flipped(left_side); |
| 488 |
| 489 gtk_widget_size_request(close_button_->widget(), &close_button_req_); |
| 490 return true; |
| 491 } |
| 492 // Ignore any other values like "pin" since we don't have images for |
| 493 // those. |
| 494 return false; |
| 495 } |
| 496 |
491 GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) { | 497 GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) { |
492 if (left_side && titlebar_left_buttons_hbox_) | 498 if (left_side && titlebar_left_buttons_hbox_) |
493 return titlebar_left_buttons_hbox_; | 499 return titlebar_left_buttons_hbox_; |
494 else if (!left_side && titlebar_right_buttons_hbox_) | 500 else if (!left_side && titlebar_right_buttons_hbox_) |
495 return titlebar_right_buttons_hbox_; | 501 return titlebar_right_buttons_hbox_; |
496 | 502 |
497 // We put the min/max/restore/close buttons in a vbox so they are top aligned | 503 // We put the min/max/restore/close buttons in a vbox so they are top aligned |
498 // (up to padding) and don't vertically stretch. | 504 // (up to padding) and don't vertically stretch. |
499 GtkWidget* vbox = left_side ? titlebar_left_buttons_vbox_ : | 505 GtkWidget* vbox = left_side ? titlebar_left_buttons_vbox_ : |
500 titlebar_right_buttons_vbox_; | 506 titlebar_right_buttons_vbox_; |
501 | 507 |
502 GtkWidget* top_padding = gtk_fixed_new(); | 508 GtkWidget* top_padding = gtk_fixed_new(); |
503 gtk_widget_set_size_request(top_padding, -1, kButtonOuterPadding); | 509 gtk_widget_set_size_request(top_padding, -1, kButtonOuterPadding); |
504 gtk_box_pack_start(GTK_BOX(vbox), top_padding, FALSE, FALSE, 0); | 510 gtk_box_pack_start(GTK_BOX(vbox), top_padding, FALSE, FALSE, 0); |
505 | 511 |
506 GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing); | 512 GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing); |
507 gtk_box_pack_start(GTK_BOX(vbox), buttons_hbox, FALSE, FALSE, 0); | 513 gtk_box_pack_start(GTK_BOX(vbox), buttons_hbox, FALSE, FALSE, 0); |
508 | 514 |
509 if (left_side) { | 515 if (left_side) { |
510 titlebar_left_buttons_hbox_ = buttons_hbox; | 516 titlebar_left_buttons_hbox_ = buttons_hbox; |
511 top_padding_left_ = top_padding; | 517 top_padding_left_ = top_padding; |
512 } else { | 518 } else { |
513 titlebar_right_buttons_hbox_ = buttons_hbox; | 519 titlebar_right_buttons_hbox_ = buttons_hbox; |
514 top_padding_right_ = top_padding; | 520 top_padding_right_ = top_padding; |
515 } | 521 } |
516 | 522 |
517 return buttons_hbox; | 523 return buttons_hbox; |
518 } | 524 } |
519 | 525 |
520 CustomDrawButton* BrowserTitlebar::BuildTitlebarButton(int image, | 526 CustomDrawButton* BrowserTitlebar::CreateTitlebarButton(int image, |
521 int image_pressed, int image_hot, GtkWidget* box, bool start, | 527 int image_pressed, int image_hot, GtkWidget* box, int tooltip) { |
522 int tooltip) { | |
523 CustomDrawButton* button = new CustomDrawButton(image, image_pressed, | 528 CustomDrawButton* button = new CustomDrawButton(image, image_pressed, |
524 image_hot, 0); | 529 image_hot, 0); |
525 gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); | 530 gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); |
526 g_signal_connect(button->widget(), "clicked", | 531 g_signal_connect(button->widget(), "clicked", |
527 G_CALLBACK(OnButtonClickedThunk), this); | 532 G_CALLBACK(OnButtonClickedThunk), this); |
528 g_signal_connect(button->widget(), "motion-notify-event", | 533 g_signal_connect(button->widget(), "motion-notify-event", |
529 G_CALLBACK(OnMouseMoveEvent), browser_window_); | 534 G_CALLBACK(OnMouseMoveEvent), browser_window_); |
530 std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip); | 535 std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip); |
531 gtk_widget_set_tooltip_text(button->widget(), | 536 gtk_widget_set_tooltip_text(button->widget(), |
532 localized_tooltip.c_str()); | 537 localized_tooltip.c_str()); |
533 if (start) | 538 gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); |
534 gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); | |
535 else | |
536 gtk_box_pack_end(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); | |
537 return button; | 539 return button; |
538 } | 540 } |
539 | 541 |
540 void BrowserTitlebar::UpdateButtonBackground(CustomDrawButton* button) { | 542 void BrowserTitlebar::UpdateButtonBackground(CustomDrawButton* button) { |
541 SkColor color = theme_service_->GetColor( | 543 SkColor color = theme_service_->GetColor( |
542 ThemeService::COLOR_BUTTON_BACKGROUND); | 544 ThemeService::COLOR_BUTTON_BACKGROUND); |
543 SkBitmap* background = | 545 SkBitmap* background = |
544 theme_service_->GetBitmapNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND); | 546 theme_service_->GetBitmapNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND); |
545 | 547 |
546 // TODO(erg): For now, we just use a completely black mask and we can get | 548 // TODO(erg): For now, we just use a completely black mask and we can get |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 void BrowserTitlebar::UpdateThrobber(WebContents* web_contents) { | 624 void BrowserTitlebar::UpdateThrobber(WebContents* web_contents) { |
623 DCHECK(app_mode_favicon_); | 625 DCHECK(app_mode_favicon_); |
624 | 626 |
625 if (web_contents && web_contents->IsLoading()) { | 627 if (web_contents && web_contents->IsLoading()) { |
626 GdkPixbuf* icon_pixbuf = | 628 GdkPixbuf* icon_pixbuf = |
627 throbber_.GetNextFrame(web_contents->IsWaitingForResponse()); | 629 throbber_.GetNextFrame(web_contents->IsWaitingForResponse()); |
628 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf); | 630 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf); |
629 } else { | 631 } else { |
630 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 632 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
631 | 633 |
632 // Note: we want to exclude the application popup window. | 634 // Note: we want to exclude the application popup/panel window. |
633 if ((browser_window_->browser()->is_app() && | 635 if ((browser_window_->browser()->is_app() && |
634 browser_window_->browser()->is_type_popup()) || | 636 !browser_window_->browser()->is_type_tabbed())) { |
635 IsTypePanel()) { | |
636 SkBitmap icon = browser_window_->browser()->GetCurrentPageIcon(); | 637 SkBitmap icon = browser_window_->browser()->GetCurrentPageIcon(); |
637 if (icon.empty()) { | 638 if (icon.empty()) { |
638 // Fallback to the Chromium icon if the page has no icon. | 639 // Fallback to the Chromium icon if the page has no icon. |
639 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), | 640 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), |
640 rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf()); | 641 rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf()); |
641 } else { | 642 } else { |
642 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&icon); | 643 GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&icon); |
643 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf); | 644 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf); |
644 g_object_unref(icon_pixbuf); | 645 g_object_unref(icon_pixbuf); |
645 } | 646 } |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 browser_window_->UnMaximize(); | 898 browser_window_->UnMaximize(); |
898 } else if (maximize_button_.get() && maximize_button_->widget() == button) { | 899 } else if (maximize_button_.get() && maximize_button_->widget() == button) { |
899 MaximizeButtonClicked(); | 900 MaximizeButtonClicked(); |
900 } else if (minimize_button_.get() && minimize_button_->widget() == button) { | 901 } else if (minimize_button_.get() && minimize_button_->widget() == button) { |
901 gtk_window_iconify(window_); | 902 gtk_window_iconify(window_); |
902 } | 903 } |
903 } | 904 } |
904 | 905 |
905 gboolean BrowserTitlebar::OnFaviconMenuButtonPressed(GtkWidget* widget, | 906 gboolean BrowserTitlebar::OnFaviconMenuButtonPressed(GtkWidget* widget, |
906 GdkEventButton* event) { | 907 GdkEventButton* event) { |
907 if (event->button != 1 || IsTypePanel()) | 908 if (event->button != 1) |
908 return FALSE; | 909 return FALSE; |
909 | 910 |
910 ShowFaviconMenu(event); | 911 ShowFaviconMenu(event); |
911 return TRUE; | 912 return TRUE; |
912 } | 913 } |
913 | 914 |
914 void BrowserTitlebar::ShowContextMenu(GdkEventButton* event) { | 915 void BrowserTitlebar::ShowContextMenu(GdkEventButton* event) { |
915 if (!context_menu_.get()) { | 916 if (!context_menu_.get()) { |
916 context_menu_model_.reset(new ContextMenuModel(this)); | 917 context_menu_model_.reset(new ContextMenuModel(this)); |
917 context_menu_.reset(new MenuGtk(NULL, context_menu_model_.get())); | 918 context_menu_.reset(new MenuGtk(NULL, context_menu_model_.get())); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 // Can be called during shutdown; BrowserWindowGtk will set our |window_| | 1049 // Can be called during shutdown; BrowserWindowGtk will set our |window_| |
1049 // to NULL during that time. | 1050 // to NULL during that time. |
1050 if (!window_) | 1051 if (!window_) |
1051 return; | 1052 return; |
1052 | 1053 |
1053 window_has_focus_ = | 1054 window_has_focus_ = |
1054 gtk_widget_get_window(GTK_WIDGET(window_)) == active_window; | 1055 gtk_widget_get_window(GTK_WIDGET(window_)) == active_window; |
1055 UpdateTextColor(); | 1056 UpdateTextColor(); |
1056 } | 1057 } |
1057 | 1058 |
1058 bool BrowserTitlebar::IsTypePanel() { | |
1059 return browser_window_->browser()->is_type_panel(); | |
1060 } | |
1061 | |
1062 bool BrowserTitlebar::ShouldDisplayAvatar() { | 1059 bool BrowserTitlebar::ShouldDisplayAvatar() { |
1063 return (IsOffTheRecord() || HasMultipleProfiles()) && | 1060 return (IsOffTheRecord() || HasMultipleProfiles()) && |
1064 browser_window_->browser()->is_type_tabbed(); | 1061 browser_window_->browser()->is_type_tabbed(); |
1065 } | 1062 } |
1066 | 1063 |
1067 bool BrowserTitlebar::IsOffTheRecord() { | 1064 bool BrowserTitlebar::IsOffTheRecord() { |
1068 return browser_window_->browser()->profile()->IsOffTheRecord(); | 1065 return browser_window_->browser()->profile()->IsOffTheRecord(); |
1069 } | 1066 } |
1070 | 1067 |
1071 /////////////////////////////////////////////////////////////////////////////// | 1068 /////////////////////////////////////////////////////////////////////////////// |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1128 ui::SimpleMenuModel::Delegate* delegate) | 1125 ui::SimpleMenuModel::Delegate* delegate) |
1129 : SimpleMenuModel(delegate) { | 1126 : SimpleMenuModel(delegate) { |
1130 AddItemWithStringId(IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB); | 1127 AddItemWithStringId(IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB); |
1131 AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB); | 1128 AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB); |
1132 AddSeparator(); | 1129 AddSeparator(); |
1133 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); | 1130 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER); |
1134 AddSeparator(); | 1131 AddSeparator(); |
1135 AddCheckItemWithStringId(kShowWindowDecorationsCommand, | 1132 AddCheckItemWithStringId(kShowWindowDecorationsCommand, |
1136 IDS_SHOW_WINDOW_DECORATIONS_MENU); | 1133 IDS_SHOW_WINDOW_DECORATIONS_MENU); |
1137 } | 1134 } |
OLD | NEW |