diff options
Diffstat (limited to 'chrome/browser/gtk/infobar_container_gtk.cc')
-rw-r--r-- | chrome/browser/gtk/infobar_container_gtk.cc | 159 |
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); + } +} |