diff options
Diffstat (limited to 'chrome/browser/ui/views/frame/contents_container.cc')
-rw-r--r-- | chrome/browser/ui/views/frame/contents_container.cc | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/chrome/browser/ui/views/frame/contents_container.cc b/chrome/browser/ui/views/frame/contents_container.cc new file mode 100644 index 0000000..fd80e3b --- /dev/null +++ b/chrome/browser/ui/views/frame/contents_container.cc @@ -0,0 +1,200 @@ +// Copyright (c) 2010 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/views/frame/contents_container.h" + +#include "app/resource_bundle.h" +#include "chrome/browser/location_bar.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "grit/theme_resources.h" +#include "views/controls/image_view.h" +#include "views/widget/root_view.h" + +#if defined(OS_WIN) +#include "views/widget/widget_win.h" +#elif defined(OS_LINUX) +#include "chrome/browser/gtk/gtk_util.h" +#include "views/window/window_gtk.h" +#endif + +#if defined(OS_WIN) + +class ContentsContainer::TearWindow : public views::WidgetWin { + public: + explicit TearWindow(ContentsContainer* contents_container) + : contents_container_(contents_container) { + set_window_style(WS_POPUP | WS_CLIPCHILDREN); + set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED); + } + + virtual ~TearWindow() { + // On windows it's possible for us to be deleted before the + // ContentsContainer. If this happens make sure contents_container_ doesn't + // attempt to delete us too. + if (contents_container_) + contents_container_->TearWindowDestroyed(); + } + + void set_contents_container(ContentsContainer* contents_container) { + contents_container_ = contents_container; + } + + virtual LRESULT OnMouseActivate(HWND window, + UINT hit_test, + UINT mouse_message) { + // Don't activate the window when the user clicks it. + contents_container_->browser_view_->GetLocationBar()->Revert(); + return MA_NOACTIVATE; + } + + private: + ContentsContainer* contents_container_; + + DISALLOW_COPY_AND_ASSIGN(TearWindow); +}; + +#endif + +ContentsContainer::ContentsContainer(BrowserView* browser_view, + views::View* active) + : browser_view_(browser_view), + active_(active), + preview_(NULL), + preview_tab_contents_(NULL), + tear_window_(NULL), + active_top_margin_(0) { + AddChildView(active_); +} + +ContentsContainer::~ContentsContainer() { + DeleteTearWindow(); +} + +void ContentsContainer::MakePreviewContentsActiveContents() { + active_ = preview_; + preview_ = NULL; + DeleteTearWindow(); + Layout(); +} + +void ContentsContainer::SetPreview(views::View* preview, + TabContents* preview_tab_contents) { + if (preview == preview_) + return; + + if (preview_) { + RemoveChildView(preview_); + DeleteTearWindow(); + } + preview_ = preview; + preview_tab_contents_ = preview_tab_contents; + if (preview_) { + AddChildView(preview_); + CreateTearWindow(); + } + + Layout(); + + if (preview_) + tear_window_->Show(); // Show after we'ved positioned it in Layout. +} + +void ContentsContainer::SetActiveTopMargin(int margin) { + if (active_top_margin_ == margin) + return; + + active_top_margin_ = margin; + // Make sure we layout next time around. We need this in case our bounds + // haven't changed. + InvalidateLayout(); +} + +gfx::Rect ContentsContainer::GetPreviewBounds() { + gfx::Point screen_loc; + ConvertPointToScreen(this, &screen_loc); + return gfx::Rect(screen_loc, size()); +} + +void ContentsContainer::Layout() { + // The active view always gets the full bounds. + active_->SetBounds(0, active_top_margin_, width(), + std::max(0, height() - active_top_margin_)); + + if (preview_) { + preview_->SetBounds(0, 0, width(), height()); + PositionTearWindow(); + } + + // Need to invoke views::View in case any views whose bounds didn't change + // still need a layout. + views::View::Layout(); +} + +void ContentsContainer::CreateTearWindow() { + DCHECK(preview_); + tear_window_ = CreateTearWindowImpl(); + + views::ImageView* image_view = new views::ImageView(); + image_view->SetImage(ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_MATCH_PREVIEW_TEAR)); + tear_window_->SetContentsView(image_view); +} + +#if defined(OS_WIN) + +ContentsContainer::TearWindow* ContentsContainer::CreateTearWindowImpl() { + TearWindow* widget = new TearWindow(this); + widget->Init(browser_view_->GetNativeHandle(), gfx::Rect()); + return widget; +} + +#elif defined(OS_LINUX) + +ContentsContainer::TearWindow* ContentsContainer::CreateTearWindowImpl() { + views::WidgetGtk* widget = new views::WidgetGtk(views::WidgetGtk::TYPE_POPUP); + widget->MakeTransparent(); + widget->Init(NULL, gfx::Rect()); + gtk_util::StackPopupWindow(widget->GetNativeView(), + GTK_WIDGET(browser_view_->GetNativeHandle())); + return widget; +} + +#endif + +void ContentsContainer::PositionTearWindow() { + if (!tear_window_) + return; + + gfx::Rect vis_bounds = GetVisibleBounds(); + + gfx::Size pref = tear_window_->GetRootView()->GetPreferredSize(); + // Constrain to the the visible bounds as we may be given a different size + // than is actually visible. + pref.SetSize(std::min(pref.width(), vis_bounds.width()), + std::min(pref.height(), vis_bounds.height())); + + gfx::Rect bounds(0, 0, pref.width(), pref.height()); + bounds.set_x(MirroredLeftPointForRect(bounds)); + + gfx::Point origin(bounds.origin()); + views::View::ConvertPointToScreen(this, &origin); + + tear_window_->SetBounds(gfx::Rect(origin, pref)); +} + +void ContentsContainer::DeleteTearWindow() { + if (!tear_window_) + return; + + tear_window_->Close(); +#if defined(OS_WIN) + tear_window_->set_contents_container(NULL); +#endif + // Close deletes the tear window. + tear_window_ = NULL; +} + +void ContentsContainer::TearWindowDestroyed() { + tear_window_ = NULL; +} |