| 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/browser_titlebar.h" | 5 #include "chrome/browser/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> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "app/gfx/skbitmap_operations.h" | 13 #include "app/gfx/skbitmap_operations.h" |
| 14 #include "app/l10n_util.h" | 14 #include "app/l10n_util.h" |
| 15 #include "app/resource_bundle.h" | 15 #include "app/resource_bundle.h" |
| 16 #include "base/gfx/gtk_util.h" | 16 #include "base/gfx/gtk_util.h" |
| 17 #include "chrome/app/chrome_dll_resource.h" | 17 #include "chrome/app/chrome_dll_resource.h" |
| 18 #include "chrome/browser/browser.h" | 18 #include "chrome/browser/browser.h" |
| 19 #include "chrome/browser/encoding_menu_controller.h" |
| 19 #include "chrome/browser/gtk/browser_window_gtk.h" | 20 #include "chrome/browser/gtk/browser_window_gtk.h" |
| 20 #include "chrome/browser/gtk/custom_button.h" | 21 #include "chrome/browser/gtk/custom_button.h" |
| 21 #include "chrome/browser/gtk/gtk_theme_provider.h" | 22 #include "chrome/browser/gtk/gtk_theme_provider.h" |
| 22 #include "chrome/browser/gtk/menu_gtk.h" | 23 #include "chrome/browser/gtk/menu_gtk.h" |
| 23 #include "chrome/browser/gtk/nine_box.h" | 24 #include "chrome/browser/gtk/nine_box.h" |
| 24 #include "chrome/browser/gtk/standard_menus.h" | 25 #include "chrome/browser/gtk/standard_menus.h" |
| 25 #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" | 26 #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" |
| 26 #include "chrome/browser/profile.h" | 27 #include "chrome/browser/profile.h" |
| 27 #include "chrome/browser/tab_contents/tab_contents.h" | 28 #include "chrome/browser/tab_contents/tab_contents.h" |
| 28 #include "chrome/common/gtk_util.h" | 29 #include "chrome/common/gtk_util.h" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 double one_difference = fabs(baseHSL.l - oneHSL.l); | 115 double one_difference = fabs(baseHSL.l - oneHSL.l); |
| 115 double two_difference = fabs(baseHSL.l - twoHSL.l); | 116 double two_difference = fabs(baseHSL.l - twoHSL.l); |
| 116 | 117 |
| 117 // Be biased towards the first color presented. | 118 // Be biased towards the first color presented. |
| 118 if (two_difference > one_difference + 0.1) | 119 if (two_difference > one_difference + 0.1) |
| 119 return *two; | 120 return *two; |
| 120 else | 121 else |
| 121 return *one; | 122 return *one; |
| 122 } | 123 } |
| 123 | 124 |
| 125 MenuCreateMaterial g_favicon_menu[] = { |
| 126 { MENU_NORMAL, IDC_BACK, IDS_CONTENT_CONTEXT_BACK, 0, NULL, |
| 127 GDK_Left, GDK_MOD1_MASK, true }, |
| 128 { MENU_NORMAL, IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD, 0, NULL, |
| 129 GDK_Right, GDK_MOD1_MASK, true }, |
| 130 { MENU_NORMAL, IDC_RELOAD, IDS_APP_MENU_RELOAD, 0, NULL, |
| 131 GDK_R, GDK_CONTROL_MASK, true }, |
| 132 { MENU_SEPARATOR }, |
| 133 { MENU_NORMAL, IDC_RESTORE_TAB, IDS_APP_MENU_RELOAD, 0, NULL, |
| 134 GDK_T, GDK_CONTROL_MASK | GDK_SHIFT_MASK, true }, |
| 135 { MENU_NORMAL, IDC_DUPLICATE_TAB, IDS_APP_MENU_DUPLICATE_APP_WINDOW }, |
| 136 { MENU_NORMAL, IDC_COPY_URL, IDS_APP_MENU_COPY_URL }, |
| 137 { MENU_NORMAL, IDC_SHOW_AS_TAB, IDS_SHOW_AS_TAB }, |
| 138 { MENU_NORMAL, IDC_NEW_TAB, IDS_APP_MENU_NEW_WEB_PAGE, 0, NULL, |
| 139 GDK_T, GDK_CONTROL_MASK }, |
| 140 }; |
| 141 |
| 142 const MenuCreateMaterial* GetFaviconMenu(Profile* profile, |
| 143 MenuGtk::Delegate* delegate) { |
| 144 static bool favicon_menu_built = false; |
| 145 static MenuCreateMaterial* favicon_menu; |
| 146 if (!favicon_menu_built) { |
| 147 const MenuCreateMaterial* standard_page = |
| 148 GetStandardPageMenu(profile, delegate); |
| 149 int standard_page_menu_length = 1; |
| 150 // Don't include the Create App Shortcut menu item. |
| 151 int start_offset = 0; |
| 152 for (int i = 0; standard_page[i].type != MENU_END; ++i) { |
| 153 if (standard_page[i].id == IDC_CREATE_SHORTCUTS) { |
| 154 // Pass the separator as well. |
| 155 start_offset = i + 2; |
| 156 ++i; |
| 157 continue; |
| 158 } else if (start_offset == 0) { |
| 159 // The Create App Shortcut menu item is the first menu item, and if that |
| 160 // ever changes we'll probably have to re-evaluate this code. |
| 161 NOTREACHED(); |
| 162 continue; |
| 163 } |
| 164 |
| 165 standard_page_menu_length++; |
| 166 } |
| 167 favicon_menu = new MenuCreateMaterial[arraysize(g_favicon_menu) + |
| 168 standard_page_menu_length]; |
| 169 memcpy(favicon_menu, g_favicon_menu, |
| 170 arraysize(g_favicon_menu) * sizeof(MenuCreateMaterial)); |
| 171 memcpy(favicon_menu + arraysize(g_favicon_menu), |
| 172 standard_page + start_offset, |
| 173 (standard_page_menu_length) * sizeof(MenuCreateMaterial)); |
| 174 } |
| 175 return favicon_menu; |
| 176 } |
| 177 |
| 124 } // namespace | 178 } // namespace |
| 125 | 179 |
| 126 BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window, | 180 BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window, |
| 127 GtkWindow* window) | 181 GtkWindow* window) |
| 128 : browser_window_(browser_window), window_(window), | 182 : browser_window_(browser_window), window_(window), |
| 129 app_mode_favicon_(NULL), | 183 app_mode_favicon_(NULL), |
| 130 app_mode_title_(NULL), | 184 app_mode_title_(NULL), |
| 131 using_custom_frame_(false), | 185 using_custom_frame_(false), |
| 132 window_has_focus_(false), | 186 window_has_focus_(false), |
| 133 theme_provider_(NULL) { | 187 theme_provider_(NULL) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 TRUE, 0); | 256 TRUE, 0); |
| 203 GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing); | 257 GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing); |
| 204 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox); | 258 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox); |
| 205 | 259 |
| 206 // Put the tab strip in the hbox even though we don't show it. Sometimes | 260 // Put the tab strip in the hbox even though we don't show it. Sometimes |
| 207 // we need the position of the tab strip so make sure it's in our widget | 261 // we need the position of the tab strip so make sure it's in our widget |
| 208 // hierarchy. | 262 // hierarchy. |
| 209 gtk_box_pack_start(GTK_BOX(app_mode_hbox), | 263 gtk_box_pack_start(GTK_BOX(app_mode_hbox), |
| 210 browser_window_->tabstrip()->widget(), FALSE, FALSE, 0); | 264 browser_window_->tabstrip()->widget(), FALSE, FALSE, 0); |
| 211 | 265 |
| 266 GtkWidget* favicon_event_box = gtk_event_box_new(); |
| 267 gtk_event_box_set_visible_window(GTK_EVENT_BOX(favicon_event_box), FALSE); |
| 268 g_signal_connect(favicon_event_box, "button-press-event", |
| 269 G_CALLBACK(OnButtonPressed), this); |
| 270 gtk_box_pack_start(GTK_BOX(app_mode_hbox), favicon_event_box, FALSE, |
| 271 FALSE, 0); |
| 212 // We use the app logo as a placeholder image so the title doesn't jump | 272 // We use the app logo as a placeholder image so the title doesn't jump |
| 213 // around. | 273 // around. |
| 214 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 274 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 215 // TODO(tc): Add a left click menu to this icon. | |
| 216 app_mode_favicon_ = gtk_image_new_from_pixbuf( | 275 app_mode_favicon_ = gtk_image_new_from_pixbuf( |
| 217 rb.GetRTLEnabledPixbufNamed(IDR_PRODUCT_LOGO_16)); | 276 rb.GetRTLEnabledPixbufNamed(IDR_PRODUCT_LOGO_16)); |
| 218 gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_favicon_, FALSE, | 277 g_object_set_data(G_OBJECT(app_mode_favicon_), "left-align-popup", |
| 219 FALSE, 0); | 278 reinterpret_cast<void*>(true)); |
| 279 gtk_container_add(GTK_CONTAINER(favicon_event_box), app_mode_favicon_); |
| 220 | 280 |
| 221 app_mode_title_ = gtk_label_new(NULL); | 281 app_mode_title_ = gtk_label_new(NULL); |
| 222 gtk_label_set_ellipsize(GTK_LABEL(app_mode_title_), PANGO_ELLIPSIZE_END); | 282 gtk_label_set_ellipsize(GTK_LABEL(app_mode_title_), PANGO_ELLIPSIZE_END); |
| 223 gtk_misc_set_alignment(GTK_MISC(app_mode_title_), 0.0, 0.5); | 283 gtk_misc_set_alignment(GTK_MISC(app_mode_title_), 0.0, 0.5); |
| 224 gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_title_, TRUE, TRUE, | 284 gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_title_, TRUE, TRUE, |
| 225 0); | 285 0); |
| 226 | 286 |
| 227 // Register with the theme provider to set the |app_mode_title_| label | 287 // Register with the theme provider to set the |app_mode_title_| label |
| 228 // color. | 288 // color. |
| 229 theme_provider_ = GtkThemeProvider::GetFrom( | 289 theme_provider_ = GtkThemeProvider::GetFrom( |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 &frame_color, &gfx::kGdkWhite, &gfx::kGdkBlack); | 487 &frame_color, &gfx::kGdkWhite, &gfx::kGdkBlack); |
| 428 gtk_util::SetLabelColor(app_mode_title_, &text_color); | 488 gtk_util::SetLabelColor(app_mode_title_, &text_color); |
| 429 } else { | 489 } else { |
| 430 // TODO(tc): Seems like this color should be themable, but it's hardcoded | 490 // TODO(tc): Seems like this color should be themable, but it's hardcoded |
| 431 // to white on Windows. http://crbug.com/18093 | 491 // to white on Windows. http://crbug.com/18093 |
| 432 gtk_util::SetLabelColor(app_mode_title_, &gfx::kGdkWhite); | 492 gtk_util::SetLabelColor(app_mode_title_, &gfx::kGdkWhite); |
| 433 } | 493 } |
| 434 } | 494 } |
| 435 } | 495 } |
| 436 | 496 |
| 497 void BrowserTitlebar::ShowFaviconMenu(GdkEventButton* event) { |
| 498 if (!favicon_menu_.get()) { |
| 499 favicon_menu_.reset(new MenuGtk(this, |
| 500 GetFaviconMenu(browser_window_->browser()->profile(), this), NULL)); |
| 501 } |
| 502 |
| 503 favicon_menu_->Popup(app_mode_favicon_, reinterpret_cast<GdkEvent*>(event)); |
| 504 } |
| 505 |
| 437 // static | 506 // static |
| 438 gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window, | 507 gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window, |
| 439 GdkEventWindowState* event, BrowserTitlebar* titlebar) { | 508 GdkEventWindowState* event, BrowserTitlebar* titlebar) { |
| 440 // Update the maximize/restore button. | 509 // Update the maximize/restore button. |
| 441 if (titlebar->browser_window_->IsMaximized()) { | 510 if (titlebar->browser_window_->IsMaximized()) { |
| 442 gtk_widget_hide(titlebar->maximize_button_->widget()); | 511 gtk_widget_hide(titlebar->maximize_button_->widget()); |
| 443 gtk_widget_show(titlebar->restore_button_->widget()); | 512 gtk_widget_show(titlebar->restore_button_->widget()); |
| 444 } else { | 513 } else { |
| 445 gtk_widget_hide(titlebar->restore_button_->widget()); | 514 gtk_widget_hide(titlebar->restore_button_->widget()); |
| 446 gtk_widget_show(titlebar->maximize_button_->widget()); | 515 gtk_widget_show(titlebar->maximize_button_->widget()); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 473 titlebar->browser_window_->Close(); | 542 titlebar->browser_window_->Close(); |
| 474 } else if (titlebar->restore_button_->widget() == button) { | 543 } else if (titlebar->restore_button_->widget() == button) { |
| 475 titlebar->browser_window_->UnMaximize(); | 544 titlebar->browser_window_->UnMaximize(); |
| 476 } else if (titlebar->maximize_button_->widget() == button) { | 545 } else if (titlebar->maximize_button_->widget() == button) { |
| 477 gtk_window_maximize(titlebar->window_); | 546 gtk_window_maximize(titlebar->window_); |
| 478 } else if (titlebar->minimize_button_->widget() == button) { | 547 } else if (titlebar->minimize_button_->widget() == button) { |
| 479 gtk_window_iconify(titlebar->window_); | 548 gtk_window_iconify(titlebar->window_); |
| 480 } | 549 } |
| 481 } | 550 } |
| 482 | 551 |
| 552 // static |
| 553 gboolean BrowserTitlebar::OnButtonPressed(GtkWidget* widget, |
| 554 GdkEventButton* event, |
| 555 BrowserTitlebar* titlebar) { |
| 556 if (event->button != 1) |
| 557 return FALSE; |
| 558 |
| 559 titlebar->ShowFaviconMenu(event); |
| 560 return TRUE; |
| 561 } |
| 562 |
| 483 void BrowserTitlebar::ShowContextMenu() { | 563 void BrowserTitlebar::ShowContextMenu() { |
| 484 if (!context_menu_.get()) { | 564 if (!context_menu_.get()) { |
| 485 static const MenuCreateMaterial context_menu_blueprint[] = { | 565 static const MenuCreateMaterial context_menu_blueprint[] = { |
| 486 { MENU_NORMAL, IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB, 0, NULL, | 566 { MENU_NORMAL, IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB, 0, NULL, |
| 487 GDK_t, GDK_CONTROL_MASK, true }, | 567 GDK_t, GDK_CONTROL_MASK, true }, |
| 488 { MENU_NORMAL, IDC_RESTORE_TAB, IDS_RESTORE_TAB, 0, NULL, | 568 { MENU_NORMAL, IDC_RESTORE_TAB, IDS_RESTORE_TAB, 0, NULL, |
| 489 GDK_t, GDK_CONTROL_MASK | GDK_SHIFT_MASK, true }, | 569 GDK_t, GDK_CONTROL_MASK | GDK_SHIFT_MASK, true }, |
| 490 { MENU_SEPARATOR }, | 570 { MENU_SEPARATOR }, |
| 491 { MENU_NORMAL, IDC_TASK_MANAGER, IDS_TASK_MANAGER, 0, NULL, | 571 { MENU_NORMAL, IDC_TASK_MANAGER, IDS_TASK_MANAGER, 0, NULL, |
| 492 GDK_Escape, GDK_SHIFT_MASK, true }, | 572 GDK_Escape, GDK_SHIFT_MASK, true }, |
| 493 #if !defined(OS_CHROMEOS) | 573 #if !defined(OS_CHROMEOS) |
| 494 { MENU_SEPARATOR }, | 574 { MENU_SEPARATOR }, |
| 495 { MENU_CHECKBOX, kShowWindowDecorationsCommand, | 575 { MENU_CHECKBOX, kShowWindowDecorationsCommand, |
| 496 IDS_SHOW_WINDOW_DECORATIONS }, | 576 IDS_SHOW_WINDOW_DECORATIONS }, |
| 497 #endif | 577 #endif |
| 498 { MENU_END }, | 578 { MENU_END }, |
| 499 }; | 579 }; |
| 500 | 580 |
| 501 context_menu_.reset(new MenuGtk(this, context_menu_blueprint, NULL)); | 581 context_menu_.reset(new MenuGtk(this, context_menu_blueprint, NULL)); |
| 502 } | 582 } |
| 503 | 583 |
| 504 context_menu_->PopupAsContext(gtk_get_current_event_time()); | 584 context_menu_->PopupAsContext(gtk_get_current_event_time()); |
| 505 } | 585 } |
| 506 | 586 |
| 507 bool BrowserTitlebar::IsCommandEnabled(int command_id) const { | 587 bool BrowserTitlebar::IsCommandEnabled(int command_id) const { |
| 508 switch (command_id) { | 588 if (command_id == kShowWindowDecorationsCommand) |
| 509 case IDC_NEW_TAB: | 589 return true; |
| 510 case kShowWindowDecorationsCommand: | |
| 511 return true; | |
| 512 | 590 |
| 513 case IDC_RESTORE_TAB: | 591 return browser_window_->browser()->command_updater()-> |
| 514 return browser_window_->browser()->CanRestoreTab(); | 592 IsCommandEnabled(command_id); |
| 593 } |
| 515 | 594 |
| 516 case IDC_TASK_MANAGER: | 595 bool BrowserTitlebar::IsItemChecked(int command_id) const { |
| 517 return true; | 596 if (command_id == kShowWindowDecorationsCommand) { |
| 597 PrefService* prefs = browser_window_->browser()->profile()->GetPrefs(); |
| 598 return !prefs->GetBoolean(prefs::kUseCustomChromeFrame); |
| 599 } |
| 518 | 600 |
| 519 default: | 601 EncodingMenuController controller; |
| 520 NOTREACHED(); | 602 if (controller.DoesCommandBelongToEncodingMenu(command_id)) { |
| 603 TabContents* tab_contents = |
| 604 browser_window_->browser()->GetSelectedTabContents(); |
| 605 if (tab_contents) { |
| 606 return controller.IsItemChecked(browser_window_->browser()->profile(), |
| 607 tab_contents->encoding(), |
| 608 command_id); |
| 609 } |
| 610 return false; |
| 521 } | 611 } |
| 612 |
| 613 NOTREACHED(); |
| 522 return false; | 614 return false; |
| 523 } | 615 } |
| 524 | 616 |
| 525 bool BrowserTitlebar::IsItemChecked(int command_id) const { | 617 void BrowserTitlebar::ExecuteCommand(int command_id) { |
| 526 DCHECK(command_id == kShowWindowDecorationsCommand); | 618 if (command_id == kShowWindowDecorationsCommand) { |
| 527 PrefService* prefs = browser_window_->browser()->profile()->GetPrefs(); | 619 PrefService* prefs = browser_window_->browser()->profile()->GetPrefs(); |
| 528 return !prefs->GetBoolean(prefs::kUseCustomChromeFrame); | 620 prefs->SetBoolean(prefs::kUseCustomChromeFrame, |
| 529 } | 621 !prefs->GetBoolean(prefs::kUseCustomChromeFrame)); |
| 622 return; |
| 623 } |
| 530 | 624 |
| 531 void BrowserTitlebar::ExecuteCommand(int command_id) { | 625 browser_window_->browser()->ExecuteCommand(command_id); |
| 532 switch (command_id) { | |
| 533 case IDC_NEW_TAB: | |
| 534 case IDC_RESTORE_TAB: | |
| 535 case IDC_TASK_MANAGER: | |
| 536 browser_window_->browser()->ExecuteCommand(command_id); | |
| 537 break; | |
| 538 | |
| 539 case kShowWindowDecorationsCommand: | |
| 540 { | |
| 541 PrefService* prefs = browser_window_->browser()->profile()->GetPrefs(); | |
| 542 prefs->SetBoolean(prefs::kUseCustomChromeFrame, | |
| 543 !prefs->GetBoolean(prefs::kUseCustomChromeFrame)); | |
| 544 break; | |
| 545 } | |
| 546 | |
| 547 default: | |
| 548 NOTREACHED(); | |
| 549 } | |
| 550 } | 626 } |
| 551 | 627 |
| 552 void BrowserTitlebar::Observe(NotificationType type, | 628 void BrowserTitlebar::Observe(NotificationType type, |
| 553 const NotificationSource& source, | 629 const NotificationSource& source, |
| 554 const NotificationDetails& details) { | 630 const NotificationDetails& details) { |
| 555 switch (type.value) { | 631 switch (type.value) { |
| 556 case NotificationType::BROWSER_THEME_CHANGED: | 632 case NotificationType::BROWSER_THEME_CHANGED: |
| 557 UpdateTextColor(); | 633 UpdateTextColor(); |
| 558 break; | 634 break; |
| 559 | 635 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 620 if (g_throbber_frames) | 696 if (g_throbber_frames) |
| 621 return; | 697 return; |
| 622 | 698 |
| 623 // We load the light version of the throbber since it'll be in the titlebar. | 699 // We load the light version of the throbber since it'll be in the titlebar. |
| 624 g_throbber_frames = new std::vector<GdkPixbuf*>; | 700 g_throbber_frames = new std::vector<GdkPixbuf*>; |
| 625 MakeThrobberFrames(IDR_THROBBER_LIGHT, g_throbber_frames); | 701 MakeThrobberFrames(IDR_THROBBER_LIGHT, g_throbber_frames); |
| 626 | 702 |
| 627 g_throbber_waiting_frames = new std::vector<GdkPixbuf*>; | 703 g_throbber_waiting_frames = new std::vector<GdkPixbuf*>; |
| 628 MakeThrobberFrames(IDR_THROBBER_WAITING_LIGHT, g_throbber_waiting_frames); | 704 MakeThrobberFrames(IDR_THROBBER_WAITING_LIGHT, g_throbber_waiting_frames); |
| 629 } | 705 } |
| OLD | NEW |