summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/infobar_container_gtk.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/gtk/infobar_container_gtk.cc')
-rw-r--r--chrome/browser/gtk/infobar_container_gtk.cc159
1 files changed, 159 insertions, 0 deletions
diff --git a/chrome/browser/gtk/infobar_container_gtk.cc b/chrome/browser/gtk/infobar_container_gtk.cc
new file mode 100644
index 0000000..88cf033
--- /dev/null
+++ b/chrome/browser/gtk/infobar_container_gtk.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gtk/infobar_container_gtk.h"
+
+#include <gtk/gtk.h>
+
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#include "chrome/browser/gtk/gtk_util.h"
+#include "chrome/browser/gtk/infobar_gtk.h"
+#include "chrome/browser/tab_contents/infobar_delegate.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/notification_service.h"
+
+namespace {
+
+// If |infobar_widget| matches |info_bar_delegate|, then close the infobar.
+void AnimateClosingForDelegate(GtkWidget* infobar_widget,
+ gpointer info_bar_delegate) {
+ InfoBarDelegate* delegate =
+ static_cast<InfoBarDelegate*>(info_bar_delegate);
+ InfoBar* infobar = reinterpret_cast<InfoBar*>(
+ g_object_get_data(G_OBJECT(infobar_widget), "info-bar"));
+
+ if (!infobar) {
+ NOTREACHED();
+ return;
+ }
+
+ if (delegate == infobar->delegate())
+ infobar->AnimateClose();
+}
+
+// If |infobar_widget| matches |info_bar_delegate|, then close the infobar w/o
+// an animation.
+void ClosingForDelegate(GtkWidget* infobar_widget, gpointer info_bar_delegate) {
+ InfoBarDelegate* delegate =
+ static_cast<InfoBarDelegate*>(info_bar_delegate);
+ InfoBar* infobar = reinterpret_cast<InfoBar*>(
+ g_object_get_data(G_OBJECT(infobar_widget), "info-bar"));
+
+ if (!infobar) {
+ NOTREACHED();
+ return;
+ }
+
+ if (delegate == infobar->delegate())
+ infobar->Close();
+}
+
+// Get the height of the widget and add it to |userdata|, but only if it is in
+// the process of animating.
+void SumAnimatingBarHeight(GtkWidget* widget, gpointer userdata) {
+ int* height_sum = static_cast<int*>(userdata);
+ InfoBar* infobar = reinterpret_cast<InfoBar*>(
+ g_object_get_data(G_OBJECT(widget), "info-bar"));
+ if (infobar->IsAnimating())
+ *height_sum += widget->allocation.height;
+}
+
+} // namespace
+
+// InfoBarContainerGtk, public: ------------------------------------------------
+
+InfoBarContainerGtk::InfoBarContainerGtk(Profile* profile)
+ : profile_(profile),
+ tab_contents_(NULL),
+ container_(gtk_vbox_new(FALSE, 0)) {
+ gtk_widget_show(widget());
+}
+
+InfoBarContainerGtk::~InfoBarContainerGtk() {
+ ChangeTabContents(NULL);
+
+ container_.Destroy();
+}
+
+void InfoBarContainerGtk::ChangeTabContents(TabContents* contents) {
+ if (tab_contents_)
+ registrar_.RemoveAll();
+
+ gtk_util::RemoveAllChildren(widget());
+
+ tab_contents_ = contents;
+ if (tab_contents_) {
+ UpdateInfoBars();
+ Source<TabContents> source(tab_contents_);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
+ source);
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REPLACED,
+ source);
+ }
+}
+
+void InfoBarContainerGtk::RemoveDelegate(InfoBarDelegate* delegate) {
+ tab_contents_->RemoveInfoBar(delegate);
+}
+
+int InfoBarContainerGtk::TotalHeightOfAnimatingBars() const {
+ int sum = 0;
+ gtk_container_foreach(GTK_CONTAINER(widget()), SumAnimatingBarHeight, &sum);
+ return sum;
+}
+
+// InfoBarContainerGtk, NotificationObserver implementation: -------------------
+
+void InfoBarContainerGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED) {
+ AddInfoBar(Details<InfoBarDelegate>(details).ptr(), true);
+ } else if (type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED) {
+ RemoveInfoBar(Details<InfoBarDelegate>(details).ptr(), true);
+ } else if (type == NotificationType::TAB_CONTENTS_INFOBAR_REPLACED) {
+ std::pair<InfoBarDelegate*, InfoBarDelegate*>* delegates =
+ Details<std::pair<InfoBarDelegate*, InfoBarDelegate*> >(details).ptr();
+
+ // By not animating the removal/addition, this appears to be a replace.
+ RemoveInfoBar(delegates->first, false);
+ AddInfoBar(delegates->second, false);
+ } else {
+ NOTREACHED();
+ }
+}
+
+// InfoBarContainerGtk, private: -----------------------------------------------
+
+void InfoBarContainerGtk::UpdateInfoBars() {
+ for (int i = 0; i < tab_contents_->infobar_delegate_count(); ++i) {
+ InfoBarDelegate* delegate = tab_contents_->GetInfoBarDelegateAt(i);
+ AddInfoBar(delegate, false);
+ }
+}
+
+void InfoBarContainerGtk::AddInfoBar(InfoBarDelegate* delegate, bool animate) {
+ InfoBar* infobar = delegate->CreateInfoBar();
+ infobar->set_container(this);
+ infobar->SetThemeProvider(GtkThemeProvider::GetFrom(profile_));
+ gtk_box_pack_end(GTK_BOX(widget()), infobar->widget(),
+ FALSE, FALSE, 0);
+ if (animate)
+ infobar->AnimateOpen();
+ else
+ infobar->Open();
+}
+
+void InfoBarContainerGtk::RemoveInfoBar(InfoBarDelegate* delegate,
+ bool animate) {
+ if (animate) {
+ gtk_container_foreach(GTK_CONTAINER(widget()),
+ AnimateClosingForDelegate, delegate);
+ } else {
+ gtk_container_foreach(GTK_CONTAINER(widget()), ClosingForDelegate,
+ delegate);
+ }
+}