summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/constrained_window_impl.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/views/constrained_window_impl.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views/constrained_window_impl.cc')
-rw-r--r--chrome/browser/views/constrained_window_impl.cc1493
1 files changed, 1493 insertions, 0 deletions
diff --git a/chrome/browser/views/constrained_window_impl.cc b/chrome/browser/views/constrained_window_impl.cc
new file mode 100644
index 0000000..2e7f837
--- /dev/null
+++ b/chrome/browser/views/constrained_window_impl.cc
@@ -0,0 +1,1493 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/views/constrained_window_impl.h"
+
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/app/theme/theme_resources.h"
+#include "chrome/browser/tab_contents.h"
+#include "chrome/browser/views/constrained_window_animation.h"
+#include "chrome/browser/views/location_bar_view.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/toolbar_model.h"
+#include "chrome/browser/web_app.h"
+#include "chrome/browser/web_contents.h"
+#include "chrome/browser/window_sizer.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/gfx/chrome_canvas.h"
+#include "chrome/common/gfx/chrome_font.h"
+#include "chrome/common/gfx/path.h"
+#include "chrome/common/gfx/url_elider.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/win_util.h"
+#include "chrome/views/button.h"
+#include "chrome/views/focus_manager.h"
+#include "chrome/views/hwnd_view.h"
+#include "generated_resources.h"
+#include "net/base/net_util.h"
+
+namespace ChromeViews {
+class ClientView;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowResources
+
+// An enumeration of bitmap resources used by this window.
+enum FramePartBitmap {
+ FRAME_PART_BITMAP_FIRST = 0, // Must be first.
+
+ FRAME_BOTTOM_CENTER,
+ FRAME_BOTTOM_LEFT_CORNER,
+ FRAME_BOTTOM_RIGHT_CORNER,
+ FRAME_LEFT_SIDE,
+ FRAME_RIGHT_SIDE,
+ FRAME_TOP_CENTER,
+ FRAME_TOP_LEFT_CORNER,
+ FRAME_TOP_RIGHT_CORNER,
+
+ FRAME_CLOSE_BUTTON_ICON,
+ FRAME_CLOSE_BUTTON_ICON_H,
+ FRAME_CLOSE_BUTTON_ICON_P,
+
+ FRAME_PART_BITMAP_COUNT // Must be last.
+};
+
+static const int kXPFramePartIDs[] = {
+ 0, IDR_CONSTRAINED_BOTTOM_CENTER, IDR_CONSTRAINED_BOTTOM_LEFT_CORNER,
+ IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER, IDR_CONSTRAINED_LEFT_SIDE,
+ IDR_CONSTRAINED_RIGHT_SIDE, IDR_CONSTRAINED_TOP_CENTER,
+ IDR_CONSTRAINED_TOP_LEFT_CORNER, IDR_CONSTRAINED_TOP_RIGHT_CORNER,
+ IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, 0 };
+static const int kVistaFramePartIDs[] = {
+ 0, IDR_CONSTRAINED_BOTTOM_CENTER_V, IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V,
+ IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V, IDR_CONSTRAINED_LEFT_SIDE_V,
+ IDR_CONSTRAINED_RIGHT_SIDE_V, IDR_CONSTRAINED_TOP_CENTER_V,
+ IDR_CONSTRAINED_TOP_LEFT_CORNER_V, IDR_CONSTRAINED_TOP_RIGHT_CORNER_V,
+ IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, 0 };
+static const int kOTRFramePartIDs[] = {
+ 0, IDR_WINDOW_BOTTOM_CENTER_OTR, IDR_WINDOW_BOTTOM_LEFT_CORNER_OTR,
+ IDR_WINDOW_BOTTOM_RIGHT_CORNER_OTR, IDR_WINDOW_LEFT_SIDE_OTR,
+ IDR_WINDOW_RIGHT_SIDE_OTR, IDR_WINDOW_TOP_CENTER_OTR,
+ IDR_WINDOW_TOP_LEFT_CORNER_OTR, IDR_WINDOW_TOP_RIGHT_CORNER_OTR,
+ IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, 0 };
+
+class WindowResources {
+ public:
+ virtual ~WindowResources() {}
+ virtual SkBitmap* GetPartBitmap(FramePartBitmap part_id) const = 0;
+ virtual const ChromeFont& GetTitleFont() const = 0;
+ virtual SkColor GetTitleColor() const = 0;
+};
+
+class XPWindowResources : public WindowResources {
+ public:
+ XPWindowResources() {
+ InitClass();
+ }
+ virtual ~XPWindowResources() {}
+
+ virtual SkBitmap* GetPartBitmap(FramePartBitmap part_id) const {
+ return bitmaps_[part_id];
+ }
+ virtual const ChromeFont& GetTitleFont() const { return title_font_; }
+ virtual SkColor GetTitleColor() const { return SK_ColorWHITE; }
+
+ private:
+ static void InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) {
+ int id = kXPFramePartIDs[i];
+ if (id != 0)
+ bitmaps_[i] = rb.GetBitmapNamed(id);
+ }
+ title_font_ =
+ rb.GetFont(ResourceBundle::BaseFont).DeriveFont(1);
+ initialized = true;
+ }
+ }
+
+ static SkBitmap* bitmaps_[FRAME_PART_BITMAP_COUNT];
+ static ChromeFont title_font_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(XPWindowResources);
+};
+
+class VistaWindowResources : public WindowResources {
+ public:
+ VistaWindowResources() {
+ InitClass();
+ }
+ virtual ~VistaWindowResources() {}
+
+ virtual SkBitmap* GetPartBitmap(FramePartBitmap part_id) const {
+ return bitmaps_[part_id];
+ }
+ virtual const ChromeFont& GetTitleFont() const { return title_font_; }
+ virtual SkColor GetTitleColor() const { return SK_ColorBLACK; }
+
+ private:
+ static void InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) {
+ int id = kVistaFramePartIDs[i];
+ if (id != 0)
+ bitmaps_[i] = rb.GetBitmapNamed(id);
+ }
+ title_font_ =
+ rb.GetFont(ResourceBundle::BaseFont).DeriveFont(1);
+ initialized = true;
+ }
+ }
+
+ static SkBitmap* bitmaps_[FRAME_PART_BITMAP_COUNT];
+ static ChromeFont title_font_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(VistaWindowResources);
+};
+
+class OTRWindowResources : public WindowResources {
+ public:
+ OTRWindowResources() {
+ InitClass();
+ }
+ virtual ~OTRWindowResources() {}
+
+ virtual SkBitmap* GetPartBitmap(FramePartBitmap part_id) const {
+ return bitmaps_[part_id];
+ }
+ virtual const ChromeFont& GetTitleFont() const { return title_font_; }
+ virtual SkColor GetTitleColor() const { return SK_ColorWHITE; }
+
+ private:
+ static void InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) {
+ int id = kOTRFramePartIDs[i];
+ if (id != 0)
+ bitmaps_[i] = rb.GetBitmapNamed(id);
+ }
+ title_font_ =
+ rb.GetFont(ResourceBundle::BaseFont).DeriveFont(1);
+ initialized = true;
+ }
+ }
+
+ static SkBitmap* bitmaps_[FRAME_PART_BITMAP_COUNT];
+ static ChromeFont title_font_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(OTRWindowResources);
+};
+
+SkBitmap* XPWindowResources::bitmaps_[];
+ChromeFont XPWindowResources::title_font_;
+SkBitmap* VistaWindowResources::bitmaps_[];
+ChromeFont VistaWindowResources::title_font_;
+SkBitmap* OTRWindowResources::bitmaps_[];
+ChromeFont OTRWindowResources::title_font_;
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView
+
+class ConstrainedWindowNonClientView
+ : public ChromeViews::CustomFrameWindow::NonClientView,
+ public ChromeViews::BaseButton::ButtonListener,
+ public LocationBarView::Delegate,
+ public Task {
+ public:
+ ConstrainedWindowNonClientView(ConstrainedWindowImpl* container,
+ TabContents* owner);
+ virtual ~ConstrainedWindowNonClientView();
+
+ // Calculates the pixel height of the titlebar
+ int CalculateTitlebarHeight() const;
+
+ // Calculates the pixel height of all pieces of a window that are
+ // not part of the webcontent display area.
+ int CalculateNonClientHeight(bool with_url_field) const;
+ gfx::Rect CalculateWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds,
+ bool with_url_field) const;
+ void UpdateWindowIcon();
+ void UpdateWindowTitle();
+
+ void set_window_delegate(ChromeViews::WindowDelegate* window_delegate) {
+ window_delegate_ = window_delegate;
+ }
+
+ // Changes whether we display a throbber or the current favicon and
+ // forces a repaint of the titlebar.
+ void SetShowThrobber(bool show_throbber);
+
+ // Overridden from ChromeViews::CustomFrameWindow::NonClientView:
+ virtual void Init(ChromeViews::ClientView* client_view);
+ virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const;
+ virtual gfx::Size CalculateWindowSizeForClientSize(int width,
+ int height) const;
+ virtual CPoint GetSystemMenuPoint() const;
+ virtual int HitTest(const gfx::Point& point);
+ virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask);
+ virtual void EnableClose(bool enable);
+
+ // Overridden from ChromeViews::View:
+ virtual void Paint(ChromeCanvas* canvas);
+ virtual void Layout();
+ virtual void GetPreferredSize(CSize* out);
+ virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+ // Overridden from ChromeViews::BaseButton::ButtonListener:
+ virtual void ButtonPressed(ChromeViews::BaseButton* sender);
+
+ // Overridden from LocationBarView::Delegate:
+ virtual TabContents* GetTabContents();
+ virtual void OnInputInProgress(bool in_progress);
+
+ // Overridden from Task:
+ virtual void Run();
+
+ // Updates the current throbber animation frame; called from the
+ // overloaded Run() and from SetShowThrobber().
+ void UpdateThrobber();
+
+ // Whether we should display the throbber instead of the favicon.
+ bool should_show_throbber() const {
+ return show_throbber_ && current_throbber_frame_ != -1;
+ }
+
+ // Paints different parts of the window to the incoming canvas.
+ void PaintFrameBorder(ChromeCanvas* canvas);
+ void PaintTitleBar(ChromeCanvas* canvas);
+ void PaintThrobber(ChromeCanvas* canvas);
+ void PaintFavicon(ChromeCanvas* canvas);
+ void PaintWindowTitle(ChromeCanvas* canvas);
+
+ void UpdateLocationBar();
+ bool ShouldDisplayURLField() const;
+
+ // The View that provides the background for the window, and optionally
+ // dialog buttons. Note: the non-client view does _not_ own this view, the
+ // container does.
+ ChromeViews::ClientView* client_view_;
+
+ ConstrainedWindowImpl* container_;
+ ChromeViews::WindowDelegate* window_delegate_;
+
+ scoped_ptr<WindowResources> resources_;
+
+ gfx::Rect title_bounds_;
+ gfx::Rect icon_bounds_;
+ gfx::Rect client_bounds_;
+
+ ChromeViews::Button* close_button_;
+
+ LocationBarView* location_bar_;
+
+ // Specialization of ToolbarModel to obtain selected NavigationController for
+ // a constrained TabContents.
+ class ConstrainedWindowToolbarModel : public ToolbarModel {
+ public:
+ ConstrainedWindowToolbarModel(ConstrainedWindowImpl* constrained_window)
+ : constrained_window_(constrained_window) {
+ }
+ ~ConstrainedWindowToolbarModel() { }
+
+ protected:
+ virtual NavigationController* GetNavigationController() {
+ TabContents* tab = constrained_window_->constrained_contents();
+ return tab ? tab->controller() : NULL;
+ }
+
+ private:
+ ConstrainedWindowImpl* constrained_window_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowToolbarModel);
+ };
+
+ // The model used for the states of the location bar.
+ ConstrainedWindowToolbarModel toolbar_model_;
+
+ // Whether we should display the animated throbber instead of the
+ // favicon.
+ bool show_throbber_;
+
+ // The timer used to update frames for the throbber.
+ scoped_ptr<Timer> throbber_animation_timer_;
+
+ // The current index into the throbber image strip.
+ int current_throbber_frame_;
+
+ static void InitClass();
+
+ // The default favicon we render when the page has none.
+ static SkBitmap default_favicon_;
+
+ // The throbber to display while a constrained window is loading.
+ static SkBitmap throbber_frames_;
+
+ // The number of animation frames in throbber_frames_.
+ static int throbber_frame_count_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowNonClientView);
+};
+
+SkBitmap ConstrainedWindowNonClientView::default_favicon_;
+SkBitmap ConstrainedWindowNonClientView::throbber_frames_;
+int ConstrainedWindowNonClientView::throbber_frame_count_ = -1;
+static const int kWindowIconLeftOffset = 5;
+static const int kWindowIconTopOffset = 5;
+static const int kWindowControlsTopOffset = 1;
+static const int kWindowControlsRightOffset = 4;
+static const int kTitleTopOffset = 6;
+static const int kWindowIconTitleSpacing = 3;
+static const int kTitleBottomSpacing = 5;
+static const int kNoTitleTopSpacing = 8;
+static const int kResizeAreaSize = 5;
+static const int kResizeAreaNorthSize = 3;
+static const int kResizeAreaCornerSize = 16;
+static const int kWindowHorizontalBorderSize = 5;
+static const int kWindowVerticalBorderSize = 5;
+static const int kWindowIconSize = 16;
+
+// How much wider or shorter the location bar is relative to the client area.
+static const int kLocationBarOffset = 2;
+// Spacing between the location bar and the content area.
+static const int kLocationBarSpacing = 1;
+
+static const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0);
+static const SkColor kContentsBorderColor = SkColorSetRGB(219, 235, 255);
+
+static const int kThrobberFrameTimeMs = 30;
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView, public:
+
+ConstrainedWindowNonClientView::ConstrainedWindowNonClientView(
+ ConstrainedWindowImpl* container, TabContents* owner)
+ : container_(container),
+ window_delegate_(NULL),
+ close_button_(new ChromeViews::Button),
+ location_bar_(NULL),
+ show_throbber_(false),
+ current_throbber_frame_(-1),
+ toolbar_model_(container) {
+ InitClass();
+ if (owner->profile()->IsOffTheRecord()) {
+ resources_.reset(new OTRWindowResources);
+ } else {
+ if (win_util::ShouldUseVistaFrame()) {
+ resources_.reset(new VistaWindowResources);
+ } else {
+ resources_.reset(new XPWindowResources);
+ }
+ }
+
+ close_button_->SetImage(ChromeViews::Button::BS_NORMAL,
+ resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON));
+ close_button_->SetImage(ChromeViews::Button::BS_HOT,
+ resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_H));
+ close_button_->SetImage(ChromeViews::Button::BS_PUSHED,
+ resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_P));
+ close_button_->SetImageAlignment(ChromeViews::Button::ALIGN_CENTER,
+ ChromeViews::Button::ALIGN_MIDDLE);
+ close_button_->SetListener(this, 0);
+ AddChildView(close_button_);
+
+ throbber_animation_timer_.reset(
+ new Timer(kThrobberFrameTimeMs, this, true));
+
+ // Note: we don't need for a controller because no input event will be ever
+ // processed from a constrained window.
+ location_bar_ = new LocationBarView(owner->profile(),
+ NULL,
+ &toolbar_model_,
+ this,
+ true);
+ AddChildView(location_bar_);
+}
+
+ConstrainedWindowNonClientView::~ConstrainedWindowNonClientView() {
+ MessageLoop::current()->timer_manager()->StopTimer(
+ throbber_animation_timer_.get());
+}
+
+void ConstrainedWindowNonClientView::UpdateLocationBar() {
+ if (ShouldDisplayURLField()) {
+ std::wstring url_spec;
+ TabContents* tab = container_->constrained_contents();
+ url_spec = gfx::ElideUrl(tab->GetURL(),
+ ChromeFont(),
+ 0,
+ tab->profile()->GetPrefs()->GetString(prefs::kAcceptLanguages));
+ std::wstring ev_text, ev_tooltip_text;
+ tab->GetSSLEVText(&ev_text, &ev_tooltip_text),
+ location_bar_->Update(NULL);
+ }
+}
+
+bool ConstrainedWindowNonClientView::ShouldDisplayURLField() const {
+ // If the dialog is not fully initialized, default to showing the URL field.
+ if (!container_ || !container_->owner() || !container_->owner()->delegate())
+ return true;
+
+ return !container_->is_dialog() &&
+ container_->owner()->delegate()->ShouldDisplayURLField();
+}
+
+int ConstrainedWindowNonClientView::CalculateTitlebarHeight() const {
+ int height;
+ if (window_delegate_ && window_delegate_->ShouldShowWindowTitle()) {
+ height = kTitleTopOffset + resources_->GetTitleFont().height() +
+ kTitleBottomSpacing;
+ } else {
+ height = kNoTitleTopSpacing;
+ }
+
+ return height;
+}
+
+int ConstrainedWindowNonClientView::CalculateNonClientHeight(
+ bool with_url_field) const {
+ int r = CalculateTitlebarHeight();
+
+ if (with_url_field) {
+ CSize s;
+ location_bar_->GetPreferredSize(&s);
+ r += s.cy;
+ }
+ return r;
+}
+
+gfx::Rect ConstrainedWindowNonClientView::CalculateWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds,
+ bool with_url_field) const {
+ int non_client_height = CalculateNonClientHeight(with_url_field);
+ gfx::Rect window_bounds = client_bounds;
+ window_bounds.set_width(
+ window_bounds.width() + 2 * kWindowHorizontalBorderSize);
+ window_bounds.set_height(
+ window_bounds.height() + non_client_height + kWindowVerticalBorderSize);
+ window_bounds.set_x(
+ std::max(0, window_bounds.x() - kWindowHorizontalBorderSize));
+ window_bounds.set_y(std::max(0, window_bounds.y() - non_client_height));
+ return window_bounds;
+}
+
+void ConstrainedWindowNonClientView::UpdateWindowIcon() {
+ SchedulePaint(icon_bounds_.ToRECT(), false);
+}
+
+void ConstrainedWindowNonClientView::UpdateWindowTitle() {
+ SchedulePaint(title_bounds_.ToRECT(), false);
+ UpdateLocationBar();
+}
+
+void ConstrainedWindowNonClientView::SetShowThrobber(bool show_throbber) {
+ show_throbber_ = show_throbber;
+
+ TimerManager* tm = MessageLoop::current()->timer_manager();
+ Timer* timer = throbber_animation_timer_.get();
+ if (show_throbber) {
+ if (!tm->IsTimerRunning(timer))
+ tm->ResetTimer(timer);
+ } else {
+ if (tm->IsTimerRunning(timer)) {
+ UpdateThrobber();
+ tm->StopTimer(timer);
+ }
+ }
+}
+
+void ConstrainedWindowNonClientView::Run() {
+ UpdateThrobber();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView,
+// ChromeViews::CustomFrameWindow::NonClientView implementation:
+
+void ConstrainedWindowNonClientView::Init(
+ ChromeViews::ClientView* client_view) {
+ client_view_ = client_view;
+ AddChildView(client_view_);
+}
+
+gfx::Rect ConstrainedWindowNonClientView::CalculateClientAreaBounds(
+ int width,
+ int height) const {
+ int non_client_height = CalculateNonClientHeight(ShouldDisplayURLField());
+ return gfx::Rect(kWindowHorizontalBorderSize, non_client_height,
+ std::max(0, width - (2 * kWindowHorizontalBorderSize)),
+ std::max(0, height - non_client_height - kWindowVerticalBorderSize));
+}
+
+gfx::Size ConstrainedWindowNonClientView::CalculateWindowSizeForClientSize(
+ int width,
+ int height) const {
+ // This is only used for truly constrained windows, which does not include
+ // popups generated from a user gesture since those are detached immediately.
+ gfx::Rect window_bounds =
+ CalculateWindowBoundsForClientBounds(gfx::Rect(0, 0, width, height),
+ ShouldDisplayURLField());
+ return window_bounds.size();
+}
+
+CPoint ConstrainedWindowNonClientView::GetSystemMenuPoint() const {
+ CPoint system_menu_point(icon_bounds_.x(), icon_bounds_.bottom());
+ MapWindowPoints(container_->GetHWND(), HWND_DESKTOP, &system_menu_point, 1);
+ return system_menu_point;
+}
+
+int ConstrainedWindowNonClientView::HitTest(const gfx::Point& point) {
+ CRect bounds;
+ CPoint test_point = point.ToPOINT();
+
+ // First see if it's within the grow box area, since that overlaps the client
+ // bounds.
+ if (client_view_->PointIsInSizeBox(point))
+ return HTBOTTOMRIGHT;
+
+ // Then see if it's within the client area.
+ if (client_view_) {
+ client_view_->GetBounds(&bounds);
+ if (bounds.PtInRect(test_point))
+ return HTCLIENT;
+ }
+
+ // Then see if the point is within any of the window controls.
+ close_button_->GetBounds(&bounds);
+ if (bounds.PtInRect(test_point))
+ return HTCLOSE;
+ bounds = icon_bounds_.ToRECT();
+ if (bounds.PtInRect(test_point))
+ return HTSYSMENU;
+
+ // Then see if the point is within the resize boundaries.
+ int width = GetWidth();
+ int height = GetHeight();
+ int component = HTNOWHERE;
+ if (point.x() < kResizeAreaSize) {
+ if (point.y() < kResizeAreaCornerSize) {
+ component = HTTOPLEFT;
+ } else if (point.y() >= (height - kResizeAreaCornerSize)) {
+ component = HTBOTTOMLEFT;
+ } else {
+ component = HTLEFT;
+ }
+ } else if (point.x() < kResizeAreaCornerSize) {
+ if (point.y() < kResizeAreaNorthSize) {
+ component = HTTOPLEFT;
+ } else if (point.y() >= (height - kResizeAreaSize)) {
+ component = HTBOTTOMLEFT;
+ }
+ } else if (point.x() >= (width - kResizeAreaSize)) {
+ if (point.y() < kResizeAreaCornerSize) {
+ component = HTTOPRIGHT;
+ } else if (point.y() >= (height - kResizeAreaCornerSize)) {
+ component = HTBOTTOMRIGHT;
+ } else if (point.x() >= (width - kResizeAreaSize)) {
+ component = HTRIGHT;
+ }
+ } else if (point.x() >= (width - kResizeAreaCornerSize)) {
+ if (point.y() < kResizeAreaNorthSize) {
+ component = HTTOPRIGHT;
+ } else if (point.y() >= (height - kResizeAreaSize)) {
+ component = HTBOTTOMRIGHT;
+ }
+ } else if (point.y() < kResizeAreaNorthSize) {
+ component = HTTOP;
+ } else if (point.y() >= (height - kResizeAreaSize)) {
+ component = HTBOTTOM;
+ }
+
+ // If the window can't be resized, there are no resize boundaries, just
+ // window borders.
+ if (component != HTNOWHERE) {
+ if (window_delegate_ && !window_delegate_->CanResize()) {
+ return HTBORDER;
+ }
+ return component;
+ }
+
+ // Finally fall back to the caption.
+ GetBounds(&bounds);
+ if (bounds.PtInRect(test_point))
+ return HTCAPTION;
+ // The point is outside the window's bounds.
+ return HTNOWHERE;
+}
+
+void ConstrainedWindowNonClientView::GetWindowMask(const gfx::Size& size,
+ gfx::Path* window_mask) {
+ DCHECK(window_mask);
+
+ // Redefine the window visible region for the new size.
+ window_mask->moveTo(0, 3);
+ window_mask->lineTo(1, 2);
+ window_mask->lineTo(1, 1);
+ window_mask->lineTo(2, 1);
+ window_mask->lineTo(3, 0);
+
+ window_mask->lineTo(SkIntToScalar(size.width() - 3), 0);
+ window_mask->lineTo(SkIntToScalar(size.width() - 2), 1);
+ window_mask->lineTo(SkIntToScalar(size.width() - 1), 1);
+ window_mask->lineTo(SkIntToScalar(size.width() - 1), 2);
+ window_mask->lineTo(SkIntToScalar(size.width()), 3);
+
+ window_mask->lineTo(SkIntToScalar(size.width()),
+ SkIntToScalar(size.height()));
+ window_mask->lineTo(0, SkIntToScalar(size.height()));
+ window_mask->close();
+}
+
+void ConstrainedWindowNonClientView::EnableClose(bool enable) {
+ close_button_->SetEnabled(enable);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView, ChromeViews::View implementation:
+
+void ConstrainedWindowNonClientView::Paint(ChromeCanvas* canvas) {
+ PaintFrameBorder(canvas);
+ PaintTitleBar(canvas);
+}
+
+void ConstrainedWindowNonClientView::Layout() {
+ bool should_display_url_field = false;
+ if (location_bar_) {
+ should_display_url_field = ShouldDisplayURLField();
+ location_bar_->SetVisible(should_display_url_field);
+ }
+
+ int location_bar_height = 0;
+ CSize ps;
+ if (should_display_url_field) {
+ location_bar_->GetPreferredSize(&ps);
+ location_bar_height = ps.cy;
+ }
+
+ close_button_->GetPreferredSize(&ps);
+ close_button_->SetBounds(GetWidth() - ps.cx - kWindowControlsRightOffset,
+ kWindowControlsTopOffset, ps.cx, ps.cy);
+
+ int titlebar_height = CalculateTitlebarHeight();
+ if (window_delegate_) {
+ int icon_y = (titlebar_height - kWindowIconSize) / 2;
+ icon_bounds_.SetRect(kWindowIconLeftOffset, icon_y, 0, 0);
+ if (window_delegate_->ShouldShowWindowIcon()) {
+ icon_bounds_.set_width(kWindowIconSize);
+ icon_bounds_.set_height(kWindowIconSize);
+ }
+
+ if (window_delegate_->ShouldShowWindowTitle()) {
+ int spacing = window_delegate_->ShouldShowWindowIcon() ?
+ kWindowIconTitleSpacing : 0;
+ int title_right = close_button_->GetX() - spacing;
+ int title_left = icon_bounds_.right() + spacing;
+ title_bounds_.SetRect(title_left, kTitleTopOffset,
+ title_right - title_left,
+ resources_->GetTitleFont().height());
+ }
+ }
+
+ client_bounds_ = CalculateClientAreaBounds(GetWidth(), GetHeight());
+ if (should_display_url_field) {
+ location_bar_->SetBounds(client_bounds_.x() - kLocationBarOffset,
+ client_bounds_.y() - location_bar_height -
+ kLocationBarSpacing,
+ client_bounds_.width() + kLocationBarOffset * 2,
+ location_bar_height);
+ location_bar_->Layout();
+ }
+ if (client_view_)
+ client_view_->SetBounds(client_bounds_.ToRECT());
+}
+
+void ConstrainedWindowNonClientView::GetPreferredSize(CSize* out) {
+ DCHECK(out);
+ if (client_view_) {
+ client_view_->GetPreferredSize(out);
+ out->cx += 2 * kWindowHorizontalBorderSize;
+ out->cy += CalculateNonClientHeight(ShouldDisplayURLField()) +
+ kWindowVerticalBorderSize;
+ }
+}
+
+void ConstrainedWindowNonClientView::ViewHierarchyChanged(bool is_add,
+ View *parent,
+ View *child) {
+ if (is_add && location_bar_ && GetViewContainer() &&
+ !(location_bar_->IsInitialized())) {
+ location_bar_->Init();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView, ChromeViews::BaseButton::Button
+// implementation:
+
+void ConstrainedWindowNonClientView::ButtonPressed(
+ ChromeViews::BaseButton* sender) {
+ if (sender == close_button_)
+ container_->ExecuteSystemMenuCommand(SC_CLOSE);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView, LocationBarView::Delegate
+// implementation:
+TabContents* ConstrainedWindowNonClientView::GetTabContents() {
+ return container_->owner();
+}
+
+void ConstrainedWindowNonClientView::OnInputInProgress(bool in_progress) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowNonClientView, private:
+
+void ConstrainedWindowNonClientView::UpdateThrobber() {
+ if (show_throbber_)
+ current_throbber_frame_ = ++current_throbber_frame_ % throbber_frame_count_;
+ else
+ current_throbber_frame_ = -1;
+
+ SchedulePaint();
+}
+
+void ConstrainedWindowNonClientView::PaintFrameBorder(ChromeCanvas* canvas) {
+ int width = GetWidth();
+ int height = GetHeight();
+
+ SkBitmap* top_left_corner = resources_->GetPartBitmap(FRAME_TOP_LEFT_CORNER);
+ SkBitmap* top_right_corner =
+ resources_->GetPartBitmap(FRAME_TOP_RIGHT_CORNER);
+ SkBitmap* top_edge = resources_->GetPartBitmap(FRAME_TOP_CENTER);
+ SkBitmap* right_edge = resources_->GetPartBitmap(FRAME_RIGHT_SIDE);
+ SkBitmap* left_edge = resources_->GetPartBitmap(FRAME_LEFT_SIDE);
+ SkBitmap* bottom_left_corner =
+ resources_->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER);
+ SkBitmap* bottom_right_corner =
+ resources_->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER);
+ SkBitmap* bottom_edge = resources_->GetPartBitmap(FRAME_BOTTOM_CENTER);
+
+ // Top.
+ canvas->DrawBitmapInt(*top_left_corner, 0, 0);
+ canvas->TileImageInt(*top_edge, top_left_corner->width(), 0,
+ width - top_right_corner->width(), top_edge->height());
+ canvas->DrawBitmapInt(
+ *top_right_corner, width - top_right_corner->width(), 0);
+
+ // Right.
+ int top_stack_height = top_right_corner->height();
+ canvas->TileImageInt(*right_edge, width - right_edge->width(),
+ top_stack_height, right_edge->width(),
+ height - top_stack_height -
+ bottom_right_corner->height());
+
+ // Bottom.
+ canvas->DrawBitmapInt(*bottom_right_corner,
+ width - bottom_right_corner->width(),
+ height - bottom_right_corner->height());
+ canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(),
+ height - bottom_edge->height(),
+ width - bottom_left_corner->width() -
+ bottom_right_corner->width(),
+ bottom_edge->height());
+ canvas->DrawBitmapInt(*bottom_left_corner, 0,
+ height - bottom_left_corner->height());
+
+ // Left.
+ top_stack_height = top_left_corner->height();
+ canvas->TileImageInt(*left_edge, 0, top_stack_height, left_edge->width(),
+ height - top_stack_height -
+ bottom_left_corner->height());
+
+ // Contents Border.
+ gfx::Rect border_bounds = client_bounds_;
+ border_bounds.Inset(-2, -2);
+ canvas->FillRectInt(kContentsBorderShadow, border_bounds.x(),
+ border_bounds.y(), border_bounds.width(),
+ border_bounds.height());
+
+ border_bounds.Inset(1, 1);
+ canvas->FillRectInt(kContentsBorderColor, border_bounds.x(),
+ border_bounds.y(), border_bounds.width(),
+ border_bounds.height());
+}
+
+void ConstrainedWindowNonClientView::PaintTitleBar(ChromeCanvas* canvas) {
+ if (!window_delegate_)
+ return;
+
+ if (window_delegate_->ShouldShowWindowIcon()) {
+ if (should_show_throbber())
+ PaintThrobber(canvas);
+ else
+ PaintFavicon(canvas);
+ }
+ if (window_delegate_->ShouldShowWindowTitle()) {
+ PaintWindowTitle(canvas);
+ }
+}
+
+void ConstrainedWindowNonClientView::PaintThrobber(ChromeCanvas* canvas) {
+ int image_size = throbber_frames_.height();
+ int image_offset = current_throbber_frame_ * image_size;
+ canvas->DrawBitmapInt(throbber_frames_,
+ image_offset, 0, image_size, image_size,
+ icon_bounds_.x(), icon_bounds_.y(),
+ image_size, image_size,
+ false);
+}
+
+void ConstrainedWindowNonClientView::PaintFavicon(ChromeCanvas* canvas) {
+ SkBitmap window_icon = window_delegate_->GetWindowIcon();
+ if (window_icon.isNull())
+ window_icon = default_favicon_;
+ canvas->DrawBitmapInt(window_icon, 0, 0, window_icon.width(),
+ window_icon.height(), icon_bounds_.x(),
+ icon_bounds_.y(), icon_bounds_.width(),
+ icon_bounds_.height(), false);
+}
+
+void ConstrainedWindowNonClientView::PaintWindowTitle(ChromeCanvas* canvas) {
+ canvas->DrawStringInt(container_->GetWindowTitle(),
+ resources_->GetTitleFont(),
+ resources_->GetTitleColor(), title_bounds_.x(),
+ title_bounds_.y(), title_bounds_.width(),
+ title_bounds_.height());
+}
+
+// static
+void ConstrainedWindowNonClientView::InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ default_favicon_ = *rb.GetBitmapNamed(IDR_DEFAULT_FAVICON);
+
+ throbber_frames_ = *rb.GetBitmapNamed(IDR_THROBBER);
+ DCHECK(throbber_frames_.width() % throbber_frames_.height() == 0);
+ throbber_frame_count_ =
+ throbber_frames_.width() / throbber_frames_.height();
+
+ initialized = true;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedTabContentsWindowDelegate
+
+class ConstrainedTabContentsWindowDelegate
+ : public ChromeViews::WindowDelegate {
+ public:
+ explicit ConstrainedTabContentsWindowDelegate(
+ ConstrainedWindowImpl* window)
+ : window_(window) {
+ }
+
+ // ChromeViews::WindowDelegate implementation:
+ virtual bool CanResize() const {
+ return true;
+ }
+ virtual std::wstring GetWindowTitle() const {
+ TabContents* constrained_contents = window_->constrained_contents();
+ if (constrained_contents)
+ return constrained_contents->GetTitle();
+
+ return std::wstring();
+ }
+ virtual bool ShouldShowWindowIcon() const {
+ return true;
+ }
+ virtual SkBitmap GetWindowIcon() {
+ TabContents* constrained_contents = window_->constrained_contents();
+ if (constrained_contents)
+ return constrained_contents->GetFavIcon();
+
+ return SkBitmap();
+ }
+
+ private:
+ ConstrainedWindowImpl* window_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ConstrainedTabContentsWindowDelegate);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowImpl, public:
+
+// The space (in pixels) between minimized pop-ups stacked horizontally and
+// vertically.
+static const int kPopupRepositionOffset = 5;
+static const int kConstrainedWindowEdgePadding = 10;
+
+ConstrainedWindowImpl::ConstrainedWindowImpl(TabContents* owner)
+ : CustomFrameWindow(new ConstrainedWindowNonClientView(this, owner)),
+ owner_(owner),
+ constrained_contents_(NULL),
+ focus_restoration_disabled_(false),
+ is_dialog_(false),
+ titlebar_visibility_(0.0),
+ contents_container_(NULL) {
+ set_window_style(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION |
+ WS_THICKFRAME | WS_SYSMENU);
+ set_focus_on_creation(false);
+}
+
+ConstrainedWindowImpl::~ConstrainedWindowImpl() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowImpl, ConstrainedWindow implementation:
+
+ConstrainedWindowNonClientView* ConstrainedWindowImpl::non_client_view() {
+ return static_cast<ConstrainedWindowNonClientView*>(non_client_view_);
+}
+
+void ConstrainedWindowImpl::ActivateConstrainedWindow() {
+ if (CanDetach()) {
+ // Detachable pop-ups are torn out as soon as the window is activated.
+ Detach();
+ return;
+ }
+
+ // Other pop-ups are simply moved to the front of the z-order.
+ SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+
+ // Store the focus of our parent focus manager so we can restore it when we
+ // close.
+ ChromeViews::FocusManager* focus_manager =
+ ChromeViews::FocusManager::GetFocusManager(GetHWND());
+ DCHECK(focus_manager);
+ focus_manager = focus_manager->GetParentFocusManager();
+ if (focus_manager) {
+ // We could not have a parent focus manager if the ConstrainedWindow is
+ // displayed in a tab that is not currently selected.
+ // TODO(jcampan): we should store the ConstrainedWindow active events in
+ // that case and replay them when the WebContents becomes selected.
+ focus_manager->StoreFocusedView();
+
+ if (constrained_contents_) {
+ // We contain another window, let's assume it knows how to process the
+ // focus and let's focus it.
+ // TODO(jcampan): so far this case is the WebContents case. We need to
+ // better find whether the inner window should get focus.
+ ::SetFocus(constrained_contents_->GetContainerHWND());
+ } else {
+ // Give our window the focus so we get keyboard messages.
+ ::SetFocus(GetHWND());
+ }
+ }
+}
+
+void ConstrainedWindowImpl::CloseConstrainedWindow() {
+ // Broadcast to all observers of NOTIFY_CWINDOW_CLOSED.
+ // One example of such an observer is AutomationCWindowTracker in the
+ // automation component.
+ NotificationService::current()->Notify(NOTIFY_CWINDOW_CLOSED,
+ Source<ConstrainedWindow>(this),
+ NotificationService::NoDetails());
+
+ Close();
+}
+
+void ConstrainedWindowImpl::ResizeConstrainedWindow(int width, int height) {
+ gfx::Size window_size =
+ non_client_view_->CalculateWindowSizeForClientSize(width, height);
+ ::SetWindowPos(GetHWND(), NULL, 0, 0, window_size.width(),
+ window_size.height(),
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+}
+
+void ConstrainedWindowImpl::RepositionConstrainedWindowTo(
+ const gfx::Point& anchor_point) {
+ anchor_point_ = anchor_point;
+ ResizeConstrainedTitlebar();
+}
+
+bool ConstrainedWindowImpl::IsSuppressedConstrainedWindow() const {
+ return !is_dialog_;
+}
+
+void ConstrainedWindowImpl::WasHidden() {
+ if (constrained_contents_)
+ constrained_contents_->WasHidden();
+}
+
+void ConstrainedWindowImpl::DidBecomeSelected() {
+ if (constrained_contents_)
+ constrained_contents_->DidBecomeSelected();
+}
+
+std::wstring ConstrainedWindowImpl::GetWindowTitle() const {
+ // TODO(beng): (http://b/1085485) Need to decide if we want to append the app
+ // name to all constrained windows or just web renderers.
+ std::wstring page_title;
+ if (window_delegate())
+ page_title = window_delegate()->GetWindowTitle();
+
+ std::wstring display_title;
+ if (page_title.empty()) {
+ display_title = l10n_util::GetString(IDS_PRODUCT_NAME);
+ } else {
+ display_title = l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT,
+ page_title);
+ }
+ return display_title;
+}
+
+void ConstrainedWindowImpl::UpdateWindowTitle() {
+ UpdateUI(TabContents::INVALIDATE_TITLE);
+}
+
+const gfx::Rect& ConstrainedWindowImpl::GetCurrentBounds() const {
+ return current_bounds_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowImpl, TabContentsDelegate implementation:
+
+void ConstrainedWindowImpl::NavigationStateChanged(
+ const TabContents* source,
+ unsigned int changed_flags) {
+ UpdateUI(changed_flags);
+}
+
+void ConstrainedWindowImpl::ReplaceContents(TabContents* source,
+ TabContents* new_contents) {
+ source->set_delegate(NULL);
+
+ constrained_contents_ = new_contents;
+ constrained_contents_->set_delegate(this);
+ UpdateUI(TabContents::INVALIDATE_EVERYTHING);
+}
+
+void ConstrainedWindowImpl::AddNewContents(TabContents* source,
+ TabContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {
+ // Pass this to the delegate, since we can't open new tabs in the Constrained
+ // Window, they are sent up to the browser to open as new tabs.
+ owner_->AddNewContents(
+ this, new_contents, disposition, initial_pos, user_gesture);
+}
+
+void ConstrainedWindowImpl::ActivateContents(TabContents* contents) {
+ // Ask the delegate's (which is a TabContents) own TabContentsDelegate to
+ // activate itself...
+ owner_->delegate()->ActivateContents(owner_);
+
+ // Set as the foreground constrained window.
+ ActivateConstrainedWindow();
+}
+
+void ConstrainedWindowImpl::OpenURLFromTab(TabContents* source,
+ const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
+ owner_->OpenURL(this, url, disposition, transition);
+}
+
+void ConstrainedWindowImpl::LoadingStateChanged(TabContents* source) {
+ // TODO(beng): (http://b/1085543) Implement a throbber for the Constrained
+ // Window.
+ UpdateUI(TabContents::INVALIDATE_EVERYTHING);
+ non_client_view()->SetShowThrobber(source->is_loading());
+}
+
+void ConstrainedWindowImpl::NavigateToPage(TabContents* source,
+ const GURL& url,
+ PageTransition::Type transition) {
+ UpdateUI(TabContents::INVALIDATE_EVERYTHING);
+}
+
+void ConstrainedWindowImpl::SetTitlebarVisibilityPercentage(double percentage) {
+ titlebar_visibility_ = percentage;
+ ResizeConstrainedTitlebar();
+}
+
+void ConstrainedWindowImpl::StartSuppressedAnimation() {
+ animation_.reset(new ConstrainedWindowAnimation(this));
+ animation_->Start();
+}
+
+void ConstrainedWindowImpl::CloseContents(TabContents* source) {
+ Close();
+}
+
+void ConstrainedWindowImpl::MoveContents(TabContents* source,
+ const gfx::Rect& pos) {
+ if (!IsSuppressedConstrainedWindow())
+ SetWindowBounds(pos);
+}
+
+bool ConstrainedWindowImpl::IsPopup(TabContents* source) {
+ return true;
+}
+
+TabContents* ConstrainedWindowImpl::GetConstrainingContents(
+ TabContents* source) {
+ return owner_;
+}
+
+void ConstrainedWindowImpl::ToolbarSizeChanged(TabContents* source,
+ bool finished) {
+ // We don't control the layout of anything that could be animating,
+ // so do nothing.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowImpl, private:
+
+void ConstrainedWindowImpl::ResizeConstrainedTitlebar() {
+ DCHECK(constrained_contents_)
+ << "ResizeConstrainedTitlebar() is only valid for web popups";
+ // If we represent a web popup and we were not opened as the result of a
+ // user gesture, we override the position specified in |initial_bounds| to
+ // place ourselves at the bottom right of the parent HWND.
+ CRect this_bounds;
+ GetClientRect(&this_bounds);
+
+ // First determine the height of the title bar of a constrained window, so
+ // that we can offset by that much vertically if necessary...
+ int titlebar_height = non_client_view()->CalculateTitlebarHeight();
+
+ int visible_titlebar_pixels =
+ static_cast<int>(titlebar_height * titlebar_visibility_);
+
+ int x = anchor_point_.x() - this_bounds.Width();
+ int y = anchor_point_.y() - visible_titlebar_pixels;
+ SetWindowPos(NULL, x, y, this_bounds.Width(), visible_titlebar_pixels,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
+}
+
+void ConstrainedWindowImpl::InitAsDialog(
+ const gfx::Rect& initial_bounds,
+ ChromeViews::View* contents_view,
+ ChromeViews::WindowDelegate* window_delegate) {
+ is_dialog_ = true;
+ non_client_view()->set_window_delegate(window_delegate);
+ CustomFrameWindow::Init(owner_->GetContainerHWND(), initial_bounds,
+ contents_view, window_delegate);
+ ActivateConstrainedWindow();
+}
+
+void ConstrainedWindowImpl::InitWindowForContents(
+ TabContents* constrained_contents) {
+ constrained_contents_ = constrained_contents;
+ constrained_contents_->set_delegate(this);
+ contents_container_ = new ChromeViews::HWNDView;
+ contents_window_delegate_.reset(
+ new ConstrainedTabContentsWindowDelegate(this));
+
+ non_client_view()->set_window_delegate(contents_window_delegate_.get());
+}
+
+void ConstrainedWindowImpl::InitSizeForContents(
+ const gfx::Rect& initial_bounds) {
+ CustomFrameWindow::Init(owner_->GetContainerHWND(), initial_bounds,
+ contents_container_, contents_window_delegate_.get());
+ contents_container_->Attach(constrained_contents_->GetContainerHWND());
+
+ constrained_contents_->SizeContents(
+ gfx::Size(contents_container_->GetWidth(),
+ contents_container_->GetHeight()));
+ current_bounds_ = initial_bounds;
+
+ // Note that this is HWND_TOP, not HWND_TOPMOST... this is important
+ // because otherwise the window will not be visible on top of the
+ // RenderWidgetHostView!
+ win_util::SetChildBounds(GetHWND(), GetParent(), HWND_TOP, initial_bounds,
+ kConstrainedWindowEdgePadding, 0);
+}
+
+bool ConstrainedWindowImpl::CanDetach() const {
+ // Constrained TabContentses can be detached, dialog boxes can't.
+ return constrained_contents_ ? true : false;
+}
+
+void ConstrainedWindowImpl::Detach() {
+ DCHECK(CanDetach());
+ // Tell the container not to restore focus to whatever view was focused last,
+ // since this will interfere with the new window activation in the case where
+ // a constrained window is destroyed by being detached.
+ focus_restoration_disabled_ = true;
+
+ // Detach the HWND immediately.
+ contents_container_->Detach();
+ contents_container_ = NULL;
+
+ // To try and create as seamless as possible a popup experience, web pop-ups
+ // are automatically detached when the user interacts with them. We can
+ // dial this back if we feel this is too much.
+
+ // The detached contents "should" be re-parented by the delegate's
+ // DetachContents, but we clear the delegate pointing to us just in case.
+ constrained_contents_->set_delegate(NULL);
+
+ CRect bounds;
+ ::GetWindowRect(constrained_contents_->GetContainerHWND(), &bounds);
+ CPoint cursor_pos;
+ ::GetCursorPos(&cursor_pos);
+ gfx::Point screen_point(cursor_pos.x, cursor_pos.y);
+ int frame_component = static_cast<int>(OnNCHitTest(screen_point.ToPOINT()));
+ owner_->DetachContents(this, constrained_contents_, gfx::Rect(bounds),
+ screen_point, frame_component);
+ constrained_contents_ = NULL;
+ Close();
+}
+
+void ConstrainedWindowImpl::SetWindowBounds(const gfx::Rect& bounds) {
+ // Note: SetChildBounds ensures that the constrained window is constrained
+ // to the bounds of its parent, however there remains a bug where the
+ // window is positioned incorrectly when the outer window is opened on
+ // a monitor that has negative coords (e.g. secondary monitor to left
+ // of primary, see http://b/issue?id=967905.)
+ gfx::Size window_size = non_client_view()->CalculateWindowSizeForClientSize(
+ bounds.width(), bounds.height());
+
+ current_bounds_ = bounds;
+ current_bounds_.set_width(window_size.width());
+ current_bounds_.set_height(window_size.height());
+ win_util::SetChildBounds(GetHWND(), GetParent(), NULL, current_bounds_,
+ kConstrainedWindowEdgePadding, 0);
+}
+
+void ConstrainedWindowImpl::UpdateUI(unsigned int changed_flags) {
+ if (changed_flags & TabContents::INVALIDATE_FAVICON)
+ non_client_view()->UpdateWindowIcon();
+ if (changed_flags & TabContents::INVALIDATE_TITLE)
+ non_client_view()->UpdateWindowTitle();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindowImpl, ChromeViews::HWNDViewContainer overrides:
+
+void ConstrainedWindowImpl::OnDestroy() {
+ // We do this here, rather than |Close|, since the window may be destroyed in
+ // a way other than by some other component calling Close, e.g. by the native
+ // window hierarchy closing. We are guaranteed to receive a WM_DESTROY
+ // message regardless of how the window is closed.
+ // Note that when we get this message, the focus manager of the
+ // ConstrainedWindow has already been destroyed (by the processing of
+ // WM_DESTROY in FocusManager). So the FocusManager we retrieve here is the
+ // parent one (the one from the top window).
+ ChromeViews::FocusManager* focus_manager =
+ ChromeViews::FocusManager::GetFocusManager(GetHWND());
+ if (focus_manager) {
+ // We may not have a focus manager if:
+ // - we are hidden when closed (the TabContent would be detached).
+ // - the tab has been closed and we are closed as a result.
+ // TODO(jcampan): when hidden, we should modify the stored focus of the tab
+ // so when it becomes visible again we retrieve the focus appropriately.
+ if (!focus_restoration_disabled_)
+ focus_manager->RestoreFocusedView();
+ }
+
+ // If we have a child TabContents, we need to unhook it here so that it is
+ // not automatically WM_DESTROYed by virtue of the fact that it is part of
+ // our Window hierarchy. Rather, it needs to be destroyed just like top level
+ // TabContentses are: from OnMsgCloseACK in RenderWidgetHost. So we hide the
+ // TabContents and sever the parent relationship now. Note the GetParent
+ // check so that we don't hide and re-parent TabContentses that have been
+ // detached and re-attached into a new top level browser window via a user
+ // drag action.
+ if (constrained_contents_ &&
+ ::GetParent(constrained_contents_->GetContainerHWND()) == GetHWND()) {
+ ::ShowWindow(constrained_contents_->GetContainerHWND(), SW_HIDE);
+ ::SetParent(constrained_contents_->GetContainerHWND(), NULL);
+ }
+
+ // Make sure we call super so that it can do its cleanup.
+ Window::OnDestroy();
+}
+
+void ConstrainedWindowImpl::OnFinalMessage(HWND window) {
+ // Tell our constraining TabContents that we've gone so it can update its
+ // list.
+ owner_->WillClose(this);
+ if (constrained_contents_) {
+ constrained_contents_->CloseContents();
+ constrained_contents_ = NULL;
+ }
+
+ HWNDViewContainer::OnFinalMessage(window);
+}
+
+void ConstrainedWindowImpl::OnGetMinMaxInfo(LPMINMAXINFO mm_info) {
+ // Override this function to set the maximize area as the client area of the
+ // containing window.
+ CRect parent_rect;
+ ::GetClientRect(GetParent(), &parent_rect);
+
+ mm_info->ptMaxSize.x = parent_rect.Width();
+ mm_info->ptMaxSize.y = parent_rect.Height();
+ mm_info->ptMaxPosition.x = parent_rect.left;
+ mm_info->ptMaxPosition.y = parent_rect.top;
+}
+
+LRESULT ConstrainedWindowImpl::OnMouseActivate(HWND window,
+ UINT hittest_code,
+ UINT message) {
+ // We need to store this value before we call ActivateConstrainedWindow()
+ // since the window may be detached and so this function will return false
+ // afterwards.
+ bool can_detach = CanDetach();
+
+ // We only detach the window if the user clicked on the title bar. That
+ // way, users can click inside the contents of legitimate popups obtained
+ // with a mouse gesture.
+ if (hittest_code == HTCAPTION) {
+ ActivateConstrainedWindow();
+ } else {
+ // If the user did not click on the title bar, don't stop message
+ // propagation.
+ can_detach = false;
+ }
+
+ // If the popup can be detached, then we tell the parent window not to
+ // activate since we will already have adjusted activation ourselves. We also
+ // do _not_ eat the event otherwise the user will have to click again to
+ // interact with the popup.
+ return can_detach ? MA_NOACTIVATEANDEAT : MA_ACTIVATE;
+}
+
+void ConstrainedWindowImpl::OnWindowPosChanged(WINDOWPOS* window_pos) {
+ // If the window was moved or sized, tell the owner.
+ if (!(window_pos->flags & SWP_NOMOVE) || !(window_pos->flags & SWP_NOSIZE))
+ owner_->DidMoveOrResize(this);
+ SetMsgHandled(FALSE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ConstrainedWindow, public:
+
+// static
+void ConstrainedWindow::GenerateInitialBounds(
+ const gfx::Rect& initial_bounds, TabContents* parent,
+ gfx::Rect* window_bounds) {
+ // Calculate desired window bounds. Try to use the bounds of a
+ // non-maximized browser window; this matches other browsers' behavior.
+ //
+ // NOTE: The downside here is that, if we open multiple constrained popups,
+ // they'll all get the same window position, since WindowSizer uses the
+ // "last active browser window"'s bounds. Fixing this properly is hard,
+ // since we'd have to tell the WindowSizer about the window we're opening
+ // here, and figure out how the sizing memory and the clipping/offsetting
+ // behvaiors below interact.
+ std::wstring app_name;
+
+ if (parent->delegate() && parent->delegate()->IsApplication() &&
+ parent->AsWebContents() && parent->AsWebContents()->web_app()) {
+ app_name = parent->AsWebContents()->web_app()->name();
+ }
+ bool maximized = false;
+ gfx::Rect empty_bounds;
+ WindowSizer::GetBrowserWindowBounds(app_name, empty_bounds,
+ window_bounds, &maximized);
+ if (initial_bounds.width() > 0)
+ window_bounds->set_width(initial_bounds.width());
+ if (initial_bounds.height() > 0)
+ window_bounds->set_height(initial_bounds.height());
+
+ // Map desired window bounds from screen coordinates to our parent's
+ // coordinates.
+ CPoint window_origin(window_bounds->origin().ToPOINT());
+ MapWindowPoints(HWND_DESKTOP, parent->GetContainerHWND(), &window_origin,
+ 1);
+ window_bounds->set_origin(gfx::Point(window_origin));
+
+ // Ensure some amount of the page is visible above and to the left of the
+ // popup, so it doesn't cover the whole content area (we use 30 px).
+ if (window_bounds->x() < 30)
+ window_bounds->set_x(30);
+ if (window_bounds->y() < 30)
+ window_bounds->set_y(30);
+
+ // Clip the desired coordinates so they fit within the content area.
+ CRect parent_rect;
+ ::GetClientRect(parent->GetContainerHWND(), &parent_rect);
+ if (window_bounds->right() > parent_rect.right)
+ window_bounds->set_width(parent_rect.Width() - window_bounds->x());
+ if (window_bounds->bottom() > parent_rect.bottom)
+ window_bounds->set_height(parent_rect.Height() - window_bounds->y());
+
+ // Don't let the window become too small (we use a 60x30 minimum size).
+ if (window_bounds->width() < 60)
+ window_bounds->set_width(60);
+ if (window_bounds->height() < 30)
+ window_bounds->set_height(30);
+}
+
+// static
+ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog(
+ TabContents* parent,
+ const gfx::Rect& initial_bounds,
+ ChromeViews::View* contents_view,
+ ChromeViews::WindowDelegate* window_delegate) {
+ ConstrainedWindowImpl* window = new ConstrainedWindowImpl(parent);
+ window->InitAsDialog(initial_bounds, contents_view, window_delegate);
+ return window;
+}
+
+// static
+ConstrainedWindow* ConstrainedWindow::CreateConstrainedPopup(
+ TabContents* parent,
+ const gfx::Rect& initial_bounds,
+ TabContents* constrained_contents) {
+ ConstrainedWindowImpl* window =
+ new ConstrainedWindowImpl(parent);
+ window->InitWindowForContents(constrained_contents);
+
+ gfx::Rect window_bounds;
+ if (initial_bounds.width() == 0 || initial_bounds.height() == 0) {
+ GenerateInitialBounds(initial_bounds, parent, &window_bounds);
+ } else {
+ window_bounds = window->non_client_view()->
+ CalculateWindowBoundsForClientBounds(
+ initial_bounds,
+ parent->delegate()->ShouldDisplayURLField());
+ }
+
+ window->InitSizeForContents(window_bounds);
+
+ // This is a constrained popup window and thus we need to animate it in.
+ window->StartSuppressedAnimation();
+
+ return window;
+}