| 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/tabs/tab_strip_gtk.h" | 5 #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "app/gfx/canvas_paint.h" | 9 #include "app/gfx/canvas_paint.h" |
| 10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
| 11 #include "app/resource_bundle.h" | 11 #include "app/resource_bundle.h" |
| 12 #include "app/slide_animation.h" | 12 #include "app/slide_animation.h" |
| 13 #include "base/gfx/gtk_util.h" | 13 #include "base/gfx/gtk_util.h" |
| 14 #include "base/gfx/point.h" | 14 #include "base/gfx/point.h" |
| 15 #include "chrome/browser/browser_theme_provider.h" | 15 #include "chrome/browser/browser_theme_provider.h" |
| 16 #include "chrome/browser/gtk/custom_button.h" | 16 #include "chrome/browser/gtk/custom_button.h" |
| 17 #include "chrome/browser/gtk/gtk_dnd_util.h" | 17 #include "chrome/browser/gtk/gtk_dnd_util.h" |
| 18 #include "chrome/browser/gtk/gtk_theme_provider.h" | 18 #include "chrome/browser/gtk/gtk_theme_provider.h" |
| 19 #include "chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h" | 19 #include "chrome/browser/gtk/tabs/dragged_tab_controller_gtk.h" |
| 20 #include "chrome/browser/profile.h" | 20 #include "chrome/browser/profile.h" |
| 21 #include "chrome/browser/tab_contents/tab_contents.h" | 21 #include "chrome/browser/tab_contents/tab_contents.h" |
| 22 #include "chrome/common/gtk_util.h" | 22 #include "chrome/common/gtk_util.h" |
| 23 #include "chrome/common/notification_service.h" | 23 #include "chrome/common/notification_service.h" |
| 24 #include "chrome/common/notification_type.h" | 24 #include "chrome/common/notification_type.h" |
| 25 #include "grit/app_resources.h" | 25 #include "grit/app_resources.h" |
| 26 #include "grit/theme_resources.h" | 26 #include "grit/theme_resources.h" |
| 27 | 27 |
| 28 #if defined(OS_CHROMEOS) | |
| 29 #include "chrome/browser/browser.h" | |
| 30 #include "chrome/browser/browser_list.h" | |
| 31 #include "chrome/browser/gtk/browser_window_gtk.h" | |
| 32 #include "chrome/browser/metrics/user_metrics.h" | |
| 33 #include "chrome/browser/views/tabs/tab_overview_types.h" | |
| 34 #include "chrome/common/x11_util.h" | |
| 35 #endif | |
| 36 | |
| 37 namespace { | 28 namespace { |
| 38 | 29 |
| 39 const int kDefaultAnimationDurationMs = 100; | 30 const int kDefaultAnimationDurationMs = 100; |
| 40 const int kResizeLayoutAnimationDurationMs = 166; | 31 const int kResizeLayoutAnimationDurationMs = 166; |
| 41 const int kReorderAnimationDurationMs = 166; | 32 const int kReorderAnimationDurationMs = 166; |
| 42 const int kAnimateToBoundsDurationMs = 150; | 33 const int kAnimateToBoundsDurationMs = 150; |
| 43 const int kPinnedTabAnimationDurationMs = 166; | 34 const int kPinnedTabAnimationDurationMs = 166; |
| 44 | 35 |
| 45 const int kNewTabButtonHOffset = -5; | 36 const int kNewTabButtonHOffset = -5; |
| 46 const int kNewTabButtonVOffset = 5; | 37 const int kNewTabButtonVOffset = 5; |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 G_CALLBACK(OnDragMotion), this); | 703 G_CALLBACK(OnDragMotion), this); |
| 713 g_signal_connect(G_OBJECT(tabstrip_.get()), "drag-drop", | 704 g_signal_connect(G_OBJECT(tabstrip_.get()), "drag-drop", |
| 714 G_CALLBACK(OnDragDrop), this); | 705 G_CALLBACK(OnDragDrop), this); |
| 715 g_signal_connect(G_OBJECT(tabstrip_.get()), "drag-leave", | 706 g_signal_connect(G_OBJECT(tabstrip_.get()), "drag-leave", |
| 716 G_CALLBACK(OnDragLeave), this); | 707 G_CALLBACK(OnDragLeave), this); |
| 717 g_signal_connect(G_OBJECT(tabstrip_.get()), "drag-data-received", | 708 g_signal_connect(G_OBJECT(tabstrip_.get()), "drag-data-received", |
| 718 G_CALLBACK(OnDragDataReceived), this); | 709 G_CALLBACK(OnDragDataReceived), this); |
| 719 | 710 |
| 720 newtab_button_.reset(MakeNewTabButton()); | 711 newtab_button_.reset(MakeNewTabButton()); |
| 721 | 712 |
| 722 #if defined(OS_CHROMEOS) | |
| 723 tab_overview_button_.reset(MakeTabOverviewButton()); | |
| 724 #endif | |
| 725 | |
| 726 gtk_widget_show_all(tabstrip_.get()); | 713 gtk_widget_show_all(tabstrip_.get()); |
| 727 | 714 |
| 728 bounds_ = GetInitialWidgetBounds(tabstrip_.get()); | 715 bounds_ = GetInitialWidgetBounds(tabstrip_.get()); |
| 729 | 716 |
| 730 if (drop_indicator_width == 0) { | 717 if (drop_indicator_width == 0) { |
| 731 // Direction doesn't matter, both images are the same size. | 718 // Direction doesn't matter, both images are the same size. |
| 732 GdkPixbuf* drop_image = GetDropArrowImage(true); | 719 GdkPixbuf* drop_image = GetDropArrowImage(true); |
| 733 drop_indicator_width = gdk_pixbuf_get_width(drop_image); | 720 drop_indicator_width = gdk_pixbuf_get_width(drop_image); |
| 734 drop_indicator_height = gdk_pixbuf_get_height(drop_image); | 721 drop_indicator_height = gdk_pixbuf_get_height(drop_image); |
| 735 } | 722 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 755 int tab_right = 0; | 742 int tab_right = 0; |
| 756 for (int i = 0; i < tab_count; ++i) { | 743 for (int i = 0; i < tab_count; ++i) { |
| 757 const gfx::Rect& bounds = tab_data_.at(i).ideal_bounds; | 744 const gfx::Rect& bounds = tab_data_.at(i).ideal_bounds; |
| 758 TabGtk* tab = GetTabAt(i); | 745 TabGtk* tab = GetTabAt(i); |
| 759 SetTabBounds(tab, bounds); | 746 SetTabBounds(tab, bounds); |
| 760 tab_right = bounds.right(); | 747 tab_right = bounds.right(); |
| 761 tab_right += GetTabHOffset(i + 1); | 748 tab_right += GetTabHOffset(i + 1); |
| 762 } | 749 } |
| 763 | 750 |
| 764 LayoutNewTabButton(static_cast<double>(tab_right), current_unselected_width_); | 751 LayoutNewTabButton(static_cast<double>(tab_right), current_unselected_width_); |
| 765 #if defined(OS_CHROMEOS) | |
| 766 LayoutTabOverviewButton(); | |
| 767 #endif | |
| 768 gtk_widget_queue_draw(tabstrip_.get()); | 752 gtk_widget_queue_draw(tabstrip_.get()); |
| 769 } | 753 } |
| 770 | 754 |
| 771 void TabStripGtk::SchedulePaint() { | 755 void TabStripGtk::SchedulePaint() { |
| 772 gtk_widget_queue_draw(tabstrip_.get()); | 756 gtk_widget_queue_draw(tabstrip_.get()); |
| 773 } | 757 } |
| 774 | 758 |
| 775 void TabStripGtk::SetBounds(const gfx::Rect& bounds) { | 759 void TabStripGtk::SetBounds(const gfx::Rect& bounds) { |
| 776 bounds_ = bounds; | 760 bounds_ = bounds; |
| 777 } | 761 } |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1234 | 1218 |
| 1235 void TabStripGtk::LayoutNewTabButton(double last_tab_right, | 1219 void TabStripGtk::LayoutNewTabButton(double last_tab_right, |
| 1236 double unselected_width) { | 1220 double unselected_width) { |
| 1237 gfx::Rect bounds(0, kNewTabButtonVOffset, | 1221 gfx::Rect bounds(0, kNewTabButtonVOffset, |
| 1238 newtab_button_->width(), newtab_button_->height()); | 1222 newtab_button_->width(), newtab_button_->height()); |
| 1239 int delta = abs(Round(unselected_width) - TabGtk::GetStandardSize().width()); | 1223 int delta = abs(Round(unselected_width) - TabGtk::GetStandardSize().width()); |
| 1240 if (delta > 1 && !resize_layout_scheduled_) { | 1224 if (delta > 1 && !resize_layout_scheduled_) { |
| 1241 // We're shrinking tabs, so we need to anchor the New Tab button to the | 1225 // We're shrinking tabs, so we need to anchor the New Tab button to the |
| 1242 // right edge of the TabStrip's bounds, rather than the right edge of the | 1226 // right edge of the TabStrip's bounds, rather than the right edge of the |
| 1243 // right-most Tab, otherwise it'll bounce when animating. | 1227 // right-most Tab, otherwise it'll bounce when animating. |
| 1244 #if defined(OS_CHROMEOS) | |
| 1245 bounds.set_x(bounds_.width() - newtab_button_->width() - | |
| 1246 tab_overview_button_->width()); | |
| 1247 #else | |
| 1248 bounds.set_x(bounds_.width() - newtab_button_->width()); | 1228 bounds.set_x(bounds_.width() - newtab_button_->width()); |
| 1249 #endif | |
| 1250 } else { | 1229 } else { |
| 1251 bounds.set_x(Round(last_tab_right - kTabHOffset) + kNewTabButtonHOffset); | 1230 bounds.set_x(Round(last_tab_right - kTabHOffset) + kNewTabButtonHOffset); |
| 1252 } | 1231 } |
| 1253 bounds.set_x(gtk_util::MirroredLeftPointForRect(tabstrip_.get(), bounds)); | 1232 bounds.set_x(gtk_util::MirroredLeftPointForRect(tabstrip_.get(), bounds)); |
| 1254 | 1233 |
| 1255 gtk_fixed_move(GTK_FIXED(tabstrip_.get()), newtab_button_->widget(), | 1234 gtk_fixed_move(GTK_FIXED(tabstrip_.get()), newtab_button_->widget(), |
| 1256 bounds.x(), bounds.y()); | 1235 bounds.x(), bounds.y()); |
| 1257 } | 1236 } |
| 1258 | 1237 |
| 1259 #if defined OS_CHROMEOS | |
| 1260 void TabStripGtk::LayoutTabOverviewButton() { | |
| 1261 gtk_fixed_move(GTK_FIXED(tabstrip_.get()), tab_overview_button_->widget(), | |
| 1262 bounds_.width() - tab_overview_button_->width(), 0); | |
| 1263 } | |
| 1264 #endif | |
| 1265 | |
| 1266 void TabStripGtk::GetDesiredTabWidths(int tab_count, | 1238 void TabStripGtk::GetDesiredTabWidths(int tab_count, |
| 1267 int pinned_tab_count, | 1239 int pinned_tab_count, |
| 1268 double* unselected_width, | 1240 double* unselected_width, |
| 1269 double* selected_width) const { | 1241 double* selected_width) const { |
| 1270 DCHECK(tab_count >= 0 && pinned_tab_count >= 0 && | 1242 DCHECK(tab_count >= 0 && pinned_tab_count >= 0 && |
| 1271 pinned_tab_count <= tab_count); | 1243 pinned_tab_count <= tab_count); |
| 1272 const double min_unselected_width = | 1244 const double min_unselected_width = |
| 1273 TabGtk::GetMinimumUnselectedSize().width(); | 1245 TabGtk::GetMinimumUnselectedSize().width(); |
| 1274 const double min_selected_width = | 1246 const double min_selected_width = |
| 1275 TabGtk::GetMinimumSelectedSize().width(); | 1247 TabGtk::GetMinimumSelectedSize().width(); |
| 1276 | 1248 |
| 1277 *unselected_width = min_unselected_width; | 1249 *unselected_width = min_unselected_width; |
| 1278 *selected_width = min_selected_width; | 1250 *selected_width = min_selected_width; |
| 1279 | 1251 |
| 1280 if (tab_count == 0) { | 1252 if (tab_count == 0) { |
| 1281 // Return immediately to avoid divide-by-zero below. | 1253 // Return immediately to avoid divide-by-zero below. |
| 1282 return; | 1254 return; |
| 1283 } | 1255 } |
| 1284 | 1256 |
| 1285 // Determine how much space we can actually allocate to tabs. | 1257 // Determine how much space we can actually allocate to tabs. |
| 1286 int available_width = tabstrip_->allocation.width; | 1258 int available_width = tabstrip_->allocation.width; |
| 1287 if (available_width_for_tabs_ < 0) { | 1259 if (available_width_for_tabs_ < 0) { |
| 1288 available_width = bounds_.width(); | 1260 available_width = bounds_.width(); |
| 1289 available_width -= | 1261 available_width -= |
| 1290 (kNewTabButtonHOffset + newtab_button_->width()); | 1262 (kNewTabButtonHOffset + newtab_button_->width()); |
| 1291 #if defined(OS_CHROMEOS) | |
| 1292 available_width -= tab_overview_button_->width(); | |
| 1293 #endif | |
| 1294 } else { | 1263 } else { |
| 1295 // Interesting corner case: if |available_width_for_tabs_| > the result | 1264 // Interesting corner case: if |available_width_for_tabs_| > the result |
| 1296 // of the calculation in the conditional arm above, the strip is in | 1265 // of the calculation in the conditional arm above, the strip is in |
| 1297 // overflow. We can either use the specified width or the true available | 1266 // overflow. We can either use the specified width or the true available |
| 1298 // width here; the first preserves the consistent "leave the last tab under | 1267 // width here; the first preserves the consistent "leave the last tab under |
| 1299 // the user's mouse so they can close many tabs" behavior at the cost of | 1268 // the user's mouse so they can close many tabs" behavior at the cost of |
| 1300 // prolonging the glitchy appearance of the overflow state, while the second | 1269 // prolonging the glitchy appearance of the overflow state, while the second |
| 1301 // gets us out of overflow as soon as possible but forces the user to move | 1270 // gets us out of overflow as soon as possible but forces the user to move |
| 1302 // their mouse for a few tabs' worth of closing. We choose visual | 1271 // their mouse for a few tabs' worth of closing. We choose visual |
| 1303 // imperfection over behavioral imperfection and select the first option. | 1272 // imperfection over behavioral imperfection and select the first option. |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1670 double tab_width = TabAnimation::GetCurrentTabWidth(this, animation, i); | 1639 double tab_width = TabAnimation::GetCurrentTabWidth(this, animation, i); |
| 1671 double end_of_tab = tab_x + tab_width; | 1640 double end_of_tab = tab_x + tab_width; |
| 1672 int rounded_tab_x = Round(tab_x); | 1641 int rounded_tab_x = Round(tab_x); |
| 1673 TabGtk* tab = GetTabAt(i); | 1642 TabGtk* tab = GetTabAt(i); |
| 1674 gfx::Rect bounds(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, | 1643 gfx::Rect bounds(rounded_tab_x, 0, Round(end_of_tab) - rounded_tab_x, |
| 1675 tab_height); | 1644 tab_height); |
| 1676 SetTabBounds(tab, bounds); | 1645 SetTabBounds(tab, bounds); |
| 1677 tab_x = end_of_tab + GetTabHOffset(i + 1); | 1646 tab_x = end_of_tab + GetTabHOffset(i + 1); |
| 1678 } | 1647 } |
| 1679 LayoutNewTabButton(tab_x, unselected_width); | 1648 LayoutNewTabButton(tab_x, unselected_width); |
| 1680 #if defined(OS_CHROMEOS) | |
| 1681 LayoutTabOverviewButton(); | |
| 1682 #endif | |
| 1683 gtk_widget_queue_draw(tabstrip_.get()); | 1649 gtk_widget_queue_draw(tabstrip_.get()); |
| 1684 } | 1650 } |
| 1685 | 1651 |
| 1686 void TabStripGtk::StartInsertTabAnimation(int index) { | 1652 void TabStripGtk::StartInsertTabAnimation(int index) { |
| 1687 // The TabStrip can now use its entire width to lay out Tabs. | 1653 // The TabStrip can now use its entire width to lay out Tabs. |
| 1688 available_width_for_tabs_ = -1; | 1654 available_width_for_tabs_ = -1; |
| 1689 if (active_animation_.get()) | 1655 if (active_animation_.get()) |
| 1690 active_animation_->Stop(); | 1656 active_animation_->Stop(); |
| 1691 active_animation_.reset(new InsertTabAnimation(this, index)); | 1657 active_animation_.reset(new InsertTabAnimation(this, index)); |
| 1692 active_animation_->Start(); | 1658 active_animation_->Start(); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1771 event->area.x = 0; | 1737 event->area.x = 0; |
| 1772 event->area.y = 0; | 1738 event->area.y = 0; |
| 1773 event->area.width = tabstrip->bounds_.width(); | 1739 event->area.width = tabstrip->bounds_.width(); |
| 1774 event->area.height = tabstrip->bounds_.height(); | 1740 event->area.height = tabstrip->bounds_.height(); |
| 1775 gdk_region_union_with_rect(event->region, &event->area); | 1741 gdk_region_union_with_rect(event->region, &event->area); |
| 1776 | 1742 |
| 1777 // Paint the New Tab button. | 1743 // Paint the New Tab button. |
| 1778 gtk_container_propagate_expose(GTK_CONTAINER(tabstrip->tabstrip_.get()), | 1744 gtk_container_propagate_expose(GTK_CONTAINER(tabstrip->tabstrip_.get()), |
| 1779 tabstrip->newtab_button_->widget(), event); | 1745 tabstrip->newtab_button_->widget(), event); |
| 1780 | 1746 |
| 1781 #if defined(OS_CHROMEOS) | |
| 1782 // Paint the tab overview button. | |
| 1783 gtk_container_propagate_expose(GTK_CONTAINER(tabstrip->tabstrip_.get()), | |
| 1784 tabstrip->tab_overview_button_->widget(), event); | |
| 1785 #endif | |
| 1786 | |
| 1787 // Paint the tabs in reverse order, so they stack to the left. | 1747 // Paint the tabs in reverse order, so they stack to the left. |
| 1788 TabGtk* selected_tab = NULL; | 1748 TabGtk* selected_tab = NULL; |
| 1789 int tab_count = tabstrip->GetTabCount(); | 1749 int tab_count = tabstrip->GetTabCount(); |
| 1790 for (int i = tab_count - 1; i >= 0; --i) { | 1750 for (int i = tab_count - 1; i >= 0; --i) { |
| 1791 TabGtk* tab = tabstrip->GetTabAt(i); | 1751 TabGtk* tab = tabstrip->GetTabAt(i); |
| 1792 // We must ask the _Tab's_ model, not ourselves, because in some situations | 1752 // We must ask the _Tab's_ model, not ourselves, because in some situations |
| 1793 // the model will be different to this object, e.g. when a Tab is being | 1753 // the model will be different to this object, e.g. when a Tab is being |
| 1794 // removed after its TabContents has been destroyed. | 1754 // removed after its TabContents has been destroyed. |
| 1795 if (!tab->IsSelected()) { | 1755 if (!tab->IsSelected()) { |
| 1796 gtk_container_propagate_expose(GTK_CONTAINER(tabstrip->tabstrip_.get()), | 1756 gtk_container_propagate_expose(GTK_CONTAINER(tabstrip->tabstrip_.get()), |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1904 CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON, | 1864 CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON, |
| 1905 IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0); | 1865 IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0); |
| 1906 | 1866 |
| 1907 g_signal_connect(G_OBJECT(button->widget()), "clicked", | 1867 g_signal_connect(G_OBJECT(button->widget()), "clicked", |
| 1908 G_CALLBACK(OnNewTabClicked), this); | 1868 G_CALLBACK(OnNewTabClicked), this); |
| 1909 GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS); | 1869 GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS); |
| 1910 gtk_fixed_put(GTK_FIXED(tabstrip_.get()), button->widget(), 0, 0); | 1870 gtk_fixed_put(GTK_FIXED(tabstrip_.get()), button->widget(), 0, 0); |
| 1911 | 1871 |
| 1912 return button; | 1872 return button; |
| 1913 } | 1873 } |
| 1914 | |
| 1915 #if defined(OS_CHROMEOS) | |
| 1916 CustomDrawButton* TabStripGtk::MakeTabOverviewButton() { | |
| 1917 CustomDrawButton* button = | |
| 1918 new CustomDrawButton(IDR_TAB_OVERVIEW_BUTTON_ICON, 0, 0, 0); | |
| 1919 | |
| 1920 g_signal_connect(G_OBJECT(button->widget()), "clicked", | |
| 1921 G_CALLBACK(OnTabOverviewButtonClicked), this); | |
| 1922 GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS); | |
| 1923 gtk_fixed_put(GTK_FIXED(tabstrip_.get()), button->widget(), 0, 0); | |
| 1924 | |
| 1925 return button; | |
| 1926 } | |
| 1927 | |
| 1928 // static | |
| 1929 void TabStripGtk::OnTabOverviewButtonClicked(GtkWidget* widget, | |
| 1930 TabStripGtk* tabstrip) { | |
| 1931 Browser* browser = BrowserList::GetLastActive(); | |
| 1932 DCHECK(browser); // In order for the user to click on the tab there should | |
| 1933 // be an active browser. | |
| 1934 TabOverviewTypes::Message message; | |
| 1935 message.set_type(TabOverviewTypes::Message::WM_SWITCH_TO_OVERVIEW_MODE); | |
| 1936 GtkWidget* browser_widget = GTK_WIDGET( | |
| 1937 static_cast<BrowserWindowGtk*>(browser->window())->GetNativeHandle()); | |
| 1938 message.set_param(0, x11_util::GetX11WindowFromGtkWidget(browser_widget)); | |
| 1939 TabOverviewTypes::instance()->SendMessage(message); | |
| 1940 | |
| 1941 UserMetrics::RecordAction(L"TabOverview_PressedTabOverviewButton", | |
| 1942 tabstrip->model_->profile()); | |
| 1943 } | |
| 1944 #endif | |
| OLD | NEW |