• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/gtk/infobars/infobar_container_gtk.h"
6 
7 #include <gtk/gtk.h>
8 
9 #include <utility>
10 
11 #include "base/command_line.h"
12 #include "chrome/browser/platform_util.h"
13 #include "chrome/browser/tab_contents/infobar_delegate.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
16 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
17 #include "chrome/browser/ui/gtk/gtk_util.h"
18 #include "chrome/browser/ui/gtk/infobars/infobar_gtk.h"
19 #include "content/browser/tab_contents/tab_contents.h"
20 #include "content/common/notification_details.h"
21 #include "content/common/notification_source.h"
22 #include "third_party/skia/include/core/SkPaint.h"
23 
24 namespace {
25 
26 static const char* kInfoBar = "info-bar";
27 
28 // If |infobar_widget| matches |info_bar_delegate|, then close the infobar.
AnimateClosingForDelegate(GtkWidget * infobar_widget,gpointer info_bar_delegate)29 void AnimateClosingForDelegate(GtkWidget* infobar_widget,
30                                gpointer info_bar_delegate) {
31   InfoBarDelegate* delegate =
32       static_cast<InfoBarDelegate*>(info_bar_delegate);
33   InfoBar* infobar = reinterpret_cast<InfoBar*>(
34       g_object_get_data(G_OBJECT(infobar_widget), kInfoBar));
35 
36   if (!infobar) {
37     NOTREACHED();
38     return;
39   }
40 
41   if (delegate == infobar->delegate())
42     infobar->AnimateClose();
43 }
44 
45 // If |infobar_widget| matches |info_bar_delegate|, then close the infobar w/o
46 // an animation.
ClosingForDelegate(GtkWidget * infobar_widget,gpointer info_bar_delegate)47 void ClosingForDelegate(GtkWidget* infobar_widget, gpointer info_bar_delegate) {
48   InfoBarDelegate* delegate =
49       static_cast<InfoBarDelegate*>(info_bar_delegate);
50   InfoBar* infobar = reinterpret_cast<InfoBar*>(
51       g_object_get_data(G_OBJECT(infobar_widget), kInfoBar));
52 
53   if (!infobar) {
54     NOTREACHED();
55     return;
56   }
57 
58   if (delegate == infobar->delegate())
59     infobar->Close();
60 }
61 
62 // Get the height of the widget and add it to |userdata|, but only if it is in
63 // the process of animating.
SumAnimatingBarHeight(GtkWidget * widget,gpointer userdata)64 void SumAnimatingBarHeight(GtkWidget* widget, gpointer userdata) {
65   int* height_sum = static_cast<int*>(userdata);
66   InfoBar* infobar = reinterpret_cast<InfoBar*>(
67       g_object_get_data(G_OBJECT(widget), kInfoBar));
68   if (infobar->IsAnimating())
69     *height_sum += widget->allocation.height;
70 }
71 
72 }  // namespace
73 
74 // InfoBarContainerGtk, public: ------------------------------------------------
75 
InfoBarContainerGtk(Profile * profile)76 InfoBarContainerGtk::InfoBarContainerGtk(Profile* profile)
77     : profile_(profile),
78       tab_contents_(NULL),
79       container_(gtk_vbox_new(FALSE, 0)) {
80   gtk_widget_show(widget());
81 }
82 
~InfoBarContainerGtk()83 InfoBarContainerGtk::~InfoBarContainerGtk() {
84   ChangeTabContents(NULL);
85 
86   container_.Destroy();
87 }
88 
ChangeTabContents(TabContents * contents)89 void InfoBarContainerGtk::ChangeTabContents(TabContents* contents) {
90   if (tab_contents_)
91     registrar_.RemoveAll();
92 
93   gtk_util::RemoveAllChildren(widget());
94   UpdateToolbarInfoBarState(NULL, false);
95 
96   tab_contents_ = contents;
97   if (tab_contents_) {
98     UpdateInfoBars();
99     Source<TabContents> source(tab_contents_);
100     registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
101     registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
102                    source);
103     registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REPLACED,
104                    source);
105   }
106 }
107 
RemoveDelegate(InfoBarDelegate * delegate)108 void InfoBarContainerGtk::RemoveDelegate(InfoBarDelegate* delegate) {
109   tab_contents_->RemoveInfoBar(delegate);
110 }
111 
TotalHeightOfAnimatingBars() const112 int InfoBarContainerGtk::TotalHeightOfAnimatingBars() const {
113   int sum = 0;
114   gtk_container_foreach(GTK_CONTAINER(widget()), SumAnimatingBarHeight, &sum);
115   return sum;
116 }
117 
118 // InfoBarContainerGtk, NotificationObserver implementation: -------------------
119 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)120 void InfoBarContainerGtk::Observe(NotificationType type,
121                                   const NotificationSource& source,
122                                   const NotificationDetails& details) {
123   if (type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED) {
124     AddInfoBar(Details<InfoBarDelegate>(details).ptr(), true);
125   } else if (type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED) {
126     RemoveInfoBar(Details<InfoBarDelegate>(details).ptr(), true);
127   } else if (type == NotificationType::TAB_CONTENTS_INFOBAR_REPLACED) {
128     std::pair<InfoBarDelegate*, InfoBarDelegate*>* delegates =
129         Details<std::pair<InfoBarDelegate*, InfoBarDelegate*> >(details).ptr();
130 
131     // By not animating the removal/addition, this appears to be a replace.
132     RemoveInfoBar(delegates->first, false);
133     AddInfoBar(delegates->second, false);
134   } else {
135     NOTREACHED();
136   }
137 }
138 
139 // InfoBarContainerGtk, private: -----------------------------------------------
140 
UpdateInfoBars()141 void InfoBarContainerGtk::UpdateInfoBars() {
142   for (size_t i = 0; i < tab_contents_->infobar_count(); ++i) {
143     InfoBarDelegate* delegate = tab_contents_->GetInfoBarDelegateAt(i);
144     AddInfoBar(delegate, false);
145   }
146 }
147 
ShowArrowForDelegate(InfoBarDelegate * delegate,bool animate)148 void InfoBarContainerGtk::ShowArrowForDelegate(InfoBarDelegate* delegate,
149                                                bool animate) {
150   GList* children = gtk_container_get_children(GTK_CONTAINER(widget()));
151   if (!children)
152     return;
153 
154   // Iterate through the infobars and find the last one that isn't closing.
155   InfoBar* last_bar = NULL;
156   InfoBar* this_bar = NULL;
157   for (GList* iter = children; iter != NULL; iter = iter->next) {
158     this_bar = reinterpret_cast<InfoBar*>(
159         g_object_get_data(G_OBJECT(iter->data), kInfoBar));
160 
161     if (this_bar->delegate() == delegate)
162       break;
163 
164     if (!this_bar->IsClosing())
165       last_bar = this_bar;
166 
167     this_bar = NULL;
168   }
169 
170   if (last_bar)
171     last_bar->ShowArrowFor(this_bar, animate);
172   else
173     UpdateToolbarInfoBarState(this_bar, animate);
174 
175   g_list_free(children);
176 }
177 
AddInfoBar(InfoBarDelegate * delegate,bool animate)178 void InfoBarContainerGtk::AddInfoBar(InfoBarDelegate* delegate, bool animate) {
179   InfoBar* infobar = delegate->CreateInfoBar();
180   infobar->set_container(this);
181   infobar->SetThemeProvider(GtkThemeService::GetFrom(profile_));
182   gtk_box_pack_start(GTK_BOX(widget()), infobar->widget(),
183                      FALSE, FALSE, 0);
184 
185   if (animate)
186     infobar->AnimateOpen();
187   else
188     infobar->Open();
189 
190   ShowArrowForDelegate(delegate, animate);
191 }
192 
RemoveInfoBar(InfoBarDelegate * delegate,bool animate)193 void InfoBarContainerGtk::RemoveInfoBar(InfoBarDelegate* delegate,
194                                         bool animate) {
195   if (animate) {
196     gtk_container_foreach(GTK_CONTAINER(widget()),
197                           AnimateClosingForDelegate, delegate);
198   } else {
199     gtk_container_foreach(GTK_CONTAINER(widget()), ClosingForDelegate,
200                           delegate);
201   }
202 
203   InfoBarDelegate* next_delegate = NULL;
204   for (size_t i = 1; i < tab_contents_->infobar_count(); ++i) {
205     if (tab_contents_->GetInfoBarDelegateAt(i - 1) == delegate) {
206       next_delegate = tab_contents_->GetInfoBarDelegateAt(i);
207       break;
208     }
209   }
210 
211   ShowArrowForDelegate(next_delegate, animate);
212 }
213 
UpdateToolbarInfoBarState(InfoBar * infobar,bool animate)214 void InfoBarContainerGtk::UpdateToolbarInfoBarState(InfoBar* infobar,
215                                                     bool animate) {
216   GtkWindow* parent = platform_util::GetTopLevel(widget());
217   BrowserWindowGtk* browser_window =
218       BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent);
219   if (browser_window)
220     browser_window->SetInfoBarShowing(infobar, animate);
221 }
222