| 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/gtk_dnd_util.h" | 9 #include "app/gtk_dnd_util.h" |
| 10 #include "app/gfx/canvas_paint.h" | 10 #include "app/gfx/canvas_paint.h" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 } | 64 } |
| 65 | 65 |
| 66 // widget->allocation is not guaranteed to be set. After window creation, | 66 // widget->allocation is not guaranteed to be set. After window creation, |
| 67 // we pick up the normal bounds by connecting to the configure-event signal. | 67 // we pick up the normal bounds by connecting to the configure-event signal. |
| 68 gfx::Rect GetInitialWidgetBounds(GtkWidget* widget) { | 68 gfx::Rect GetInitialWidgetBounds(GtkWidget* widget) { |
| 69 GtkRequisition request; | 69 GtkRequisition request; |
| 70 gtk_widget_size_request(widget, &request); | 70 gtk_widget_size_request(widget, &request); |
| 71 return gfx::Rect(0, 0, request.width, request.height); | 71 return gfx::Rect(0, 0, request.width, request.height); |
| 72 } | 72 } |
| 73 | 73 |
| 74 // Sort rectangles based on their x position. We don't care about y position |
| 75 // so we don't bother breaking ties. |
| 76 int CompareGdkRectangles(const void* p1, const void* p2) { |
| 77 int p1_x = static_cast<const GdkRectangle*>(p1)->x; |
| 78 int p2_x = static_cast<const GdkRectangle*>(p2)->x; |
| 79 if (p1_x < p2_x) |
| 80 return -1; |
| 81 else if (p1_x == p2_x) |
| 82 return 0; |
| 83 return 1; |
| 84 } |
| 85 |
| 86 bool GdkRectMatchesTabFavIconBounds(const GdkRectangle& gdk_rect, TabGtk* tab) { |
| 87 gfx::Rect favicon_bounds = tab->favicon_bounds(); |
| 88 return gdk_rect.x == favicon_bounds.x() + tab->x() && |
| 89 gdk_rect.y == favicon_bounds.y() + tab->y() && |
| 90 gdk_rect.width == favicon_bounds.width() && |
| 91 gdk_rect.height == favicon_bounds.height(); |
| 92 } |
| 93 |
| 74 } // namespace | 94 } // namespace |
| 75 | 95 |
| 76 //////////////////////////////////////////////////////////////////////////////// | 96 //////////////////////////////////////////////////////////////////////////////// |
| 77 // | 97 // |
| 78 // TabAnimation | 98 // TabAnimation |
| 79 // | 99 // |
| 80 // A base class for all TabStrip animations. | 100 // A base class for all TabStrip animations. |
| 81 // | 101 // |
| 82 class TabStripGtk::TabAnimation : public AnimationDelegate { | 102 class TabStripGtk::TabAnimation : public AnimationDelegate { |
| 83 public: | 103 public: |
| (...skipping 903 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 987 } | 1007 } |
| 988 } | 1008 } |
| 989 | 1009 |
| 990 void TabStripGtk::TabChangedAt(TabContents* contents, int index, | 1010 void TabStripGtk::TabChangedAt(TabContents* contents, int index, |
| 991 bool loading_only) { | 1011 bool loading_only) { |
| 992 // Index is in terms of the model. Need to make sure we adjust that index in | 1012 // Index is in terms of the model. Need to make sure we adjust that index in |
| 993 // case we have an animation going. | 1013 // case we have an animation going. |
| 994 TabGtk* tab = GetTabAt(index); | 1014 TabGtk* tab = GetTabAt(index); |
| 995 tab->UpdateData(contents, loading_only); | 1015 tab->UpdateData(contents, loading_only); |
| 996 tab->UpdateFromModel(); | 1016 tab->UpdateFromModel(); |
| 997 gtk_widget_queue_draw(tabstrip_.get()); | |
| 998 } | 1017 } |
| 999 | 1018 |
| 1000 void TabStripGtk::TabPinnedStateChanged(TabContents* contents, int index) { | 1019 void TabStripGtk::TabPinnedStateChanged(TabContents* contents, int index) { |
| 1001 GetTabAt(index)->set_pinned(model_->IsTabPinned(index)); | 1020 GetTabAt(index)->set_pinned(model_->IsTabPinned(index)); |
| 1002 StartPinnedTabAnimation(index); | 1021 StartPinnedTabAnimation(index); |
| 1003 } | 1022 } |
| 1004 | 1023 |
| 1005 //////////////////////////////////////////////////////////////////////////////// | 1024 //////////////////////////////////////////////////////////////////////////////// |
| 1006 // TabStripGtk, TabGtk::TabDelegate implementation: | 1025 // TabStripGtk, TabGtk::TabDelegate implementation: |
| 1007 | 1026 |
| (...skipping 745 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1753 if (layout) | 1772 if (layout) |
| 1754 Layout(); | 1773 Layout(); |
| 1755 } | 1774 } |
| 1756 | 1775 |
| 1757 // static | 1776 // static |
| 1758 gboolean TabStripGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event, | 1777 gboolean TabStripGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event, |
| 1759 TabStripGtk* tabstrip) { | 1778 TabStripGtk* tabstrip) { |
| 1760 if (gdk_region_empty(event->region)) | 1779 if (gdk_region_empty(event->region)) |
| 1761 return TRUE; | 1780 return TRUE; |
| 1762 | 1781 |
| 1782 // If we're only repainting favicons, optimize the paint path and only draw |
| 1783 // the favicons. |
| 1784 GdkRectangle* rects; |
| 1785 gint num_rects; |
| 1786 gdk_region_get_rectangles(event->region, &rects, &num_rects); |
| 1787 qsort(rects, num_rects, sizeof(GdkRectangle), CompareGdkRectangles); |
| 1788 std::vector<int> tabs_to_repaint; |
| 1789 if (tabstrip->CanPaintOnlyFavIcons(rects, num_rects, &tabs_to_repaint)) { |
| 1790 tabstrip->PaintOnlyFavIcons(event, tabs_to_repaint); |
| 1791 g_free(rects); |
| 1792 return TRUE; |
| 1793 } |
| 1794 g_free(rects); |
| 1795 |
| 1763 // TODO(jhawkins): Ideally we'd like to only draw what's needed in the damage | 1796 // TODO(jhawkins): Ideally we'd like to only draw what's needed in the damage |
| 1764 // rect, but the tab widgets overlap each other, and painting on one widget | 1797 // rect, but the tab widgets overlap each other, and painting on one widget |
| 1765 // will cause an expose-event to be sent to the widgets underneath. The | 1798 // will cause an expose-event to be sent to the widgets underneath. The |
| 1766 // underlying widget does not need to be redrawn as we control the order of | 1799 // underlying widget does not need to be redrawn as we control the order of |
| 1767 // expose-events. Currently we hack it to redraw the entire tabstrip. We | 1800 // expose-events. Currently we hack it to redraw the entire tabstrip. We |
| 1768 // could change the damage rect to just contain the tabs + the new tab button. | 1801 // could change the damage rect to just contain the tabs + the new tab button. |
| 1769 event->area.x = 0; | 1802 event->area.x = 0; |
| 1770 event->area.y = 0; | 1803 event->area.y = 0; |
| 1771 event->area.width = tabstrip->bounds_.width(); | 1804 event->area.width = tabstrip->bounds_.width(); |
| 1772 event->area.height = tabstrip->bounds_.height(); | 1805 event->area.height = tabstrip->bounds_.height(); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1940 } | 1973 } |
| 1941 | 1974 |
| 1942 void TabStripGtk::SetTabBounds(TabGtk* tab, const gfx::Rect& bounds) { | 1975 void TabStripGtk::SetTabBounds(TabGtk* tab, const gfx::Rect& bounds) { |
| 1943 gfx::Rect bds = bounds; | 1976 gfx::Rect bds = bounds; |
| 1944 bds.set_x(gtk_util::MirroredLeftPointForRect(tabstrip_.get(), bounds)); | 1977 bds.set_x(gtk_util::MirroredLeftPointForRect(tabstrip_.get(), bounds)); |
| 1945 tab->SetBounds(bds); | 1978 tab->SetBounds(bds); |
| 1946 gtk_fixed_move(GTK_FIXED(tabstrip_.get()), tab->widget(), | 1979 gtk_fixed_move(GTK_FIXED(tabstrip_.get()), tab->widget(), |
| 1947 bds.x(), bds.y()); | 1980 bds.x(), bds.y()); |
| 1948 } | 1981 } |
| 1949 | 1982 |
| 1983 bool TabStripGtk::CanPaintOnlyFavIcons(const GdkRectangle* rects, |
| 1984 int num_rects, std::vector<int>* tabs_to_paint) { |
| 1985 // |rects| are sorted so we just need to scan from left to right and compare |
| 1986 // it to the tab favicon positions from left to right. |
| 1987 int t = 0; |
| 1988 for (int r = 0; r < num_rects; ++r) { |
| 1989 while (t < GetTabCount()) { |
| 1990 TabGtk* tab = GetTabAt(t); |
| 1991 if (GdkRectMatchesTabFavIconBounds(rects[r], tab)) { |
| 1992 tabs_to_paint->push_back(t); |
| 1993 ++t; |
| 1994 break; |
| 1995 } |
| 1996 ++t; |
| 1997 } |
| 1998 } |
| 1999 return static_cast<int>(tabs_to_paint->size()) == num_rects; |
| 2000 } |
| 2001 |
| 2002 void TabStripGtk::PaintOnlyFavIcons(GdkEventExpose* event, |
| 2003 const std::vector<int>& tabs_to_paint) { |
| 2004 for (size_t i = 0; i < tabs_to_paint.size(); ++i) |
| 2005 GetTabAt(tabs_to_paint[i])->PaintFavIconArea(event); |
| 2006 } |
| 2007 |
| 1950 CustomDrawButton* TabStripGtk::MakeNewTabButton() { | 2008 CustomDrawButton* TabStripGtk::MakeNewTabButton() { |
| 1951 CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON, | 2009 CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON, |
| 1952 IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0); | 2010 IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0); |
| 1953 | 2011 |
| 1954 // Let the middle mouse button initiate clicks as well. | 2012 // Let the middle mouse button initiate clicks as well. |
| 1955 gtk_util::SetButtonTriggersNavigation(button->widget()); | 2013 gtk_util::SetButtonTriggersNavigation(button->widget()); |
| 1956 g_signal_connect(G_OBJECT(button->widget()), "clicked", | 2014 g_signal_connect(G_OBJECT(button->widget()), "clicked", |
| 1957 G_CALLBACK(OnNewTabClicked), this); | 2015 G_CALLBACK(OnNewTabClicked), this); |
| 1958 GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS); | 2016 GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS); |
| 1959 gtk_fixed_put(GTK_FIXED(tabstrip_.get()), button->widget(), 0, 0); | 2017 gtk_fixed_put(GTK_FIXED(tabstrip_.get()), button->widget(), 0, 0); |
| 1960 | 2018 |
| 1961 return button; | 2019 return button; |
| 1962 } | 2020 } |
| OLD | NEW |