diff options
author | beng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-13 01:30:05 +0000 |
---|---|---|
committer | beng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-13 01:30:05 +0000 |
commit | 012d2fb0a5e0ae21a9970ff553e92101a2268ae0 (patch) | |
tree | cfc9dc311cc0509393dcddaa152a2bce7ccd1c39 /chrome/browser/views | |
parent | 1ee1d8c401cf3018e993252a0df59d7e513ad23e (diff) | |
download | chromium_src-012d2fb0a5e0ae21a9970ff553e92101a2268ae0.zip chromium_src-012d2fb0a5e0ae21a9970ff553e92101a2268ae0.tar.gz chromium_src-012d2fb0a5e0ae21a9970ff553e92101a2268ae0.tar.bz2 |
Move XPFrame, VistaFrame to views/old_frames
Also remove WindowClippingInfo, since it's not used by anyone.
And fix a couple of header include issues.
B=2205
Review URL: http://codereview.chromium.org/2820
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2158 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views')
-rw-r--r-- | chrome/browser/views/browser_views.vcproj | 52 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/frame_view.cc | 109 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/frame_view.h | 70 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/point_buffer.cc | 60 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/point_buffer.h | 61 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/simple_vista_frame.cc | 240 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/simple_vista_frame.h | 85 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/simple_xp_frame.cc | 403 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/simple_xp_frame.h | 177 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/vista_frame.cc | 1636 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/vista_frame.h | 414 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/xp_frame.cc | 2523 | ||||
-rw-r--r-- | chrome/browser/views/old_frames/xp_frame.h | 528 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab_strip.cc | 1 |
14 files changed, 6358 insertions, 1 deletions
diff --git a/chrome/browser/views/browser_views.vcproj b/chrome/browser/views/browser_views.vcproj index d7072d7..15054b5 100644 --- a/chrome/browser/views/browser_views.vcproj +++ b/chrome/browser/views/browser_views.vcproj @@ -381,6 +381,58 @@ > </File> </Filter> + <Filter + Name="Frame (Old)" + > + <File + RelativePath=".\old_frames\frame_view.cc" + > + </File> + <File + RelativePath=".\old_frames\frame_view.h" + > + </File> + <File + RelativePath=".\old_frames\point_buffer.cc" + > + </File> + <File + RelativePath=".\old_frames\point_buffer.h" + > + </File> + <File + RelativePath=".\old_frames\simple_vista_frame.cc" + > + </File> + <File + RelativePath=".\old_frames\simple_vista_frame.h" + > + </File> + <File + RelativePath=".\old_frames\simple_xp_frame.cc" + > + </File> + <File + RelativePath=".\old_frames\simple_xp_frame.h" + > + </File> + <File + RelativePath=".\old_frames\vista_frame.cc" + > + </File> + <File + RelativePath=".\old_frames\vista_frame.h" + > + </File> + <File + RelativePath=".\old_frames\xp_frame.cc" + > + </File> + <File + RelativePath=".\old_frames\xp_frame.h" + > + </File> + </Filter> <File RelativePath=".\about_chrome_view.cc" > diff --git a/chrome/browser/views/old_frames/frame_view.cc b/chrome/browser/views/old_frames/frame_view.cc new file mode 100644 index 0000000..3375d07 --- /dev/null +++ b/chrome/browser/views/old_frames/frame_view.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2006-2008 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/old_frames/frame_view.h" + +#include "chrome/browser/browser_window.h" +#include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/common/drag_drop_types.h" +#include "chrome/common/os_exchange_data.h" + +FrameView::FrameView(BrowserWindow* window) + : window_(window), + can_drop_(false), + forwarding_to_tab_strip_(false) { +} + +void FrameView::AddViewToDropList(ChromeViews::View* view) { + dropable_views_.insert(view); +} + +bool FrameView::CanDrop(const OSExchangeData& data) { + can_drop_ = (window_->GetTabStrip()->IsVisible() && + !window_->GetTabStrip()->IsAnimating() && + data.HasURL()); + return can_drop_; +} + +void FrameView::OnDragEntered(const ChromeViews::DropTargetEvent& event) { + if (can_drop_ && ShouldForwardToTabStrip(event)) { + forwarding_to_tab_strip_ = true; + scoped_ptr<ChromeViews::DropTargetEvent> mapped_event( + MapEventToTabStrip(event)); + window_->GetTabStrip()->OnDragEntered(*mapped_event.get()); + } +} + +int FrameView::OnDragUpdated(const ChromeViews::DropTargetEvent& event) { + if (can_drop_) { + if (ShouldForwardToTabStrip(event)) { + scoped_ptr<ChromeViews::DropTargetEvent> mapped_event( + MapEventToTabStrip(event)); + if (!forwarding_to_tab_strip_) { + window_->GetTabStrip()->OnDragEntered(*mapped_event.get()); + forwarding_to_tab_strip_ = true; + } + return window_->GetTabStrip()->OnDragUpdated(*mapped_event.get()); + } else if (forwarding_to_tab_strip_) { + forwarding_to_tab_strip_ = false; + window_->GetTabStrip()->OnDragExited(); + } + } + return DragDropTypes::DRAG_NONE; +} + +void FrameView::OnDragExited() { + if (forwarding_to_tab_strip_) { + forwarding_to_tab_strip_ = false; + window_->GetTabStrip()->OnDragExited(); + } +} + +int FrameView::OnPerformDrop(const ChromeViews::DropTargetEvent& event) { + if (forwarding_to_tab_strip_) { + forwarding_to_tab_strip_ = false; + scoped_ptr<ChromeViews::DropTargetEvent> mapped_event( + MapEventToTabStrip(event)); + return window_->GetTabStrip()->OnPerformDrop(*mapped_event.get()); + } + return DragDropTypes::DRAG_NONE; +} + +bool FrameView::ShouldForwardToTabStrip( + const ChromeViews::DropTargetEvent& event) { + if (!window_->GetTabStrip()->IsVisible()) + return false; + + const int tab_y = window_->GetTabStrip()->GetY(); + const int tab_height = window_->GetTabStrip()->GetHeight(); + if (event.GetY() >= tab_y + tab_height) + return false; + + if (event.GetY() >= tab_y) + return true; + + // Mouse isn't over the tab strip. Only forward if the mouse isn't over + // another view on the tab strip or is over a view we were told the user can + // drop on. + ChromeViews::View* view_over_mouse = + GetViewForPoint(CPoint(event.GetX(), event.GetY())); + return (view_over_mouse == this || + view_over_mouse == window_->GetTabStrip() || + dropable_views_.find(view_over_mouse) != dropable_views_.end()); +} + +void FrameView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { + if (!is_add) + dropable_views_.erase(child); +} + +ChromeViews::DropTargetEvent* FrameView::MapEventToTabStrip( + const ChromeViews::DropTargetEvent& event) { + gfx::Point tab_strip_loc(event.location()); + ConvertPointToView(this, window_->GetTabStrip(), &tab_strip_loc); + return new ChromeViews::DropTargetEvent(event.GetData(), tab_strip_loc.x(), + tab_strip_loc.y(), + event.GetSourceOperations()); +} + diff --git a/chrome/browser/views/old_frames/frame_view.h b/chrome/browser/views/old_frames/frame_view.h new file mode 100644 index 0000000..81e3010 --- /dev/null +++ b/chrome/browser/views/old_frames/frame_view.h @@ -0,0 +1,70 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_FRAME_VIEW_H__ +#define CHROME_BROWSER_FRAME_VIEW_H__ + +#include <set> + +#include "chrome/views/view.h" + +class BrowserWindow; +class OSExchangeData; + +// FrameView is the View that contains all the views of the BrowserWindow +// (XPFrame or VistaFrame). FrameView forwards all drag and drop messages to +// the TabStrip. +class FrameView : public ChromeViews::View { + public: + explicit FrameView(BrowserWindow* frame); + virtual ~FrameView() {} + + // Adds view to the set of views that drops are allowed to occur on. You only + // need invoke this for views whose y-coordinate extends above the tab strip + // and you want to allow drops on. + void AddViewToDropList(ChromeViews::View* view); + + protected: + // As long as ShouldForwardToTabStrip returns true, drag and drop methods + // are forwarded to the tab strip. + virtual bool CanDrop(const OSExchangeData& data); + virtual void OnDragEntered(const ChromeViews::DropTargetEvent& event); + virtual int OnDragUpdated(const ChromeViews::DropTargetEvent& event); + virtual void OnDragExited(); + virtual int OnPerformDrop(const ChromeViews::DropTargetEvent& event); + + // Returns true if the event should be forwarded to the TabStrip. This returns + // true if y coordinate is less than the bottom of the tab strip, and is not + // over another child view. + virtual bool ShouldForwardToTabStrip( + const ChromeViews::DropTargetEvent& event); + + // Overriden to remove views from dropable_views_. + virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); + + private: + // Creates and returns a new DropTargetEvent in the coordinates of the + // TabStrip. + ChromeViews::DropTargetEvent* MapEventToTabStrip( + const ChromeViews::DropTargetEvent& event); + + // The BrowserWindow we're the child of. + BrowserWindow* window_; + + // Initially set in CanDrop by invoking the same method on the TabStrip. + bool can_drop_; + + // If true, drag and drop events are being forwarded to the tab strip. + // This is used to determine when to send OnDragExited and OnDragExited + // to the tab strip. + bool forwarding_to_tab_strip_; + + // Set of additional views drops are allowed on. We do NOT own these. + std::set<ChromeViews::View*> dropable_views_; + + DISALLOW_EVIL_CONSTRUCTORS(FrameView); +}; + +#endif // CHROME_BROWSER_FRAME_VIEW_H__ + diff --git a/chrome/browser/views/old_frames/point_buffer.cc b/chrome/browser/views/old_frames/point_buffer.cc new file mode 100644 index 0000000..e9ff263 --- /dev/null +++ b/chrome/browser/views/old_frames/point_buffer.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2006-2008 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/old_frames/point_buffer.h" + +#include "base/logging.h" + +PointBuffer::PointBuffer() : points_(NULL), + next_(0), + max_count_(0) { +} + +PointBuffer::~PointBuffer() { + if (points_) { + delete []points_; + } +} + +void PointBuffer::AddPoint(int x, int y) { + POINT t; + t.x = x; + t.y = y; + AddPoint(t); +} + +void PointBuffer::AddPoint(const POINT &p) { + GrowPointBufferIfNeeded(); + points_[next_++] = p; +} + +HRGN PointBuffer::GetCurrentPolygonRegion() const { + return ::CreatePolygonRgn(points_, next_, ALTERNATE); +} + +void PointBuffer::GrowPointBufferIfNeeded() { + if (next_ == max_count_) { + int nmc = 32 + (max_count_ * 2); + POINT *new_buffer = new POINT[nmc]; + + if (next_ > 0) { + memcpy(new_buffer, points_, sizeof(POINT) * next_); + delete []points_; + } + + points_ = new_buffer; + max_count_ = nmc; + } +} + +#if 0 +void PointBuffer::Log() { + LOG(INFO) << "PointBuffer {"; + int i; + for (i=0 ; i < next_ ; i++) { + LOG(INFO) << "\t" << points_[i].x << ", " << points_[i].y; + } +} +#endif + diff --git a/chrome/browser/views/old_frames/point_buffer.h b/chrome/browser/views/old_frames/point_buffer.h new file mode 100644 index 0000000..94a0808 --- /dev/null +++ b/chrome/browser/views/old_frames/point_buffer.h @@ -0,0 +1,61 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_OLD_FRAMES_POINT_BUFFER_H__ +#define CHROME_BROWSER_VIEWS_OLD_FRAMES_POINT_BUFFER_H__ + +#include <windows.h> + +#include "base/basictypes.h" + +//////////////////////////////////////////////////////////////////////////////// +// +// PointBuffer class +// +// A facility to accumulate 2d points and produce polygon regions. +// +//////////////////////////////////////////////////////////////////////////////// +class PointBuffer { + public: + + // + // Create an empty path buffer + // + PointBuffer(); + + ~PointBuffer(); + + // + // Add a point in the buffer + // + void AddPoint(const POINT &p); + void AddPoint(int x, int y); + + // + // Return new polygon region matching the current points. + // It is the caller's responsability to delete the returned region by using + // ::DeleteObject() + // + HRGN GetCurrentPolygonRegion() const; + +#if 0 + void Log(); +#endif + + private: + + // + // Grow the point buffer if we are out of space + // + void GrowPointBufferIfNeeded(); + + POINT *points_; + int next_; + int max_count_; + + DISALLOW_EVIL_CONSTRUCTORS(PointBuffer); +}; + +#endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_POINT_BUFFER_H__ + diff --git a/chrome/browser/views/old_frames/simple_vista_frame.cc b/chrome/browser/views/old_frames/simple_vista_frame.cc new file mode 100644 index 0000000..fc25e6a --- /dev/null +++ b/chrome/browser/views/old_frames/simple_vista_frame.cc @@ -0,0 +1,240 @@ +// Copyright (c) 2006-2008 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/old_frames/simple_vista_frame.h" + +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/tab_contents_container_view.h" +#include "chrome/browser/web_app.h" +#include "chrome/browser/web_app_icon_manager.h" +#include "chrome/browser/web_contents.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/gfx/icon_util.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/resource_bundle.h" +#include "net/base/net_util.h" + +#include "chromium_strings.h" +#include "generated_resources.h" + +// Number of frames for our throbber. +static const int kThrobberIconCount = 24; + +// How outdented the location bar should be (so that the DWM client area +// border masks the location bar frame). +static const int kLocationBarOutdent = 2; +// Spacing between the location bar and the content area. +static const int kLocationBarSpacing = 1; + +// Each throbber frame. +static HICON g_throbber_icons[kThrobberIconCount]; + +static bool g_throbber_initialized = false; + +static void InitThrobberIcons() { + if (!g_throbber_initialized) { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < kThrobberIconCount; ++i) { + g_throbber_icons[i] = rb.LoadThemeIcon(IDR_THROBBER_01 + i); + DCHECK(g_throbber_icons[i]); + } + g_throbber_initialized = true; + } +} + +// static +SimpleVistaFrame* SimpleVistaFrame::CreateFrame(const gfx::Rect& bounds, + Browser* browser) { + SimpleVistaFrame* instance = new SimpleVistaFrame(browser); + instance->Create(NULL, bounds.ToRECT(), + l10n_util::GetString(IDS_PRODUCT_NAME).c_str()); + instance->InitAfterHWNDCreated(); + instance->SetIsOffTheRecord(browser->profile()->IsOffTheRecord()); + ChromeViews::FocusManager::CreateFocusManager(instance->m_hWnd, + instance->GetRootView()); + return instance; +} + +SimpleVistaFrame::SimpleVistaFrame(Browser* browser) + : VistaFrame(browser), + throbber_running_(false), + throbber_frame_(0), + location_bar_(NULL) { +} + +SimpleVistaFrame::~SimpleVistaFrame() { +} + +void SimpleVistaFrame::Init() { + VistaFrame::Init(); + location_bar_ = new LocationBarView(browser_->profile(), + browser_->controller(), + browser_->toolbar_model(), + this, true); + frame_view_->AddChildView(location_bar_); + location_bar_->Init(); + + // Constrained popups that were unconstrained will need to set up a + // throbber. + UpdateTitleBar(); +} + +void SimpleVistaFrame::SetWindowTitle(const std::wstring& title) { + std::wstring t; + if (browser_->IsApplication()) { + t = title; + } else { + t = Browser::ComputePopupTitle(browser_->GetSelectedTabContents()->GetURL(), + title); + } + + VistaFrame::SetWindowTitle(t); + SetWindowText(t.c_str()); + UpdateLocationBar(); +} + +void SimpleVistaFrame::ShowTabContents(TabContents* selected_contents) { + VistaFrame::ShowTabContents(selected_contents); + icon_manager_->SetContents(selected_contents); + UpdateLocationBar(); +} + +void SimpleVistaFrame::SizeToContents(const gfx::Rect& contents_bounds) { + // First we need to ensure everything has an initial size. Currently, the + // window has the wrong size, but that's OK, doing this will allow us to + // figure out how big all the UI bits are. + Layout(); + + // These calculations are a copy from VistaFrame and we used to just use + // that implementation. The problem is that we overload Layout() which + // then references our location_bar_, which doesn't get compensated for + // in VistaFrame::SizeToContents(). + CRect window_bounds, client_bounds; + GetBounds(&window_bounds, true); + GetBounds(&client_bounds, false); + int left_edge_width = client_bounds.left - window_bounds.left; + int top_edge_height = client_bounds.top - window_bounds.top + + location_bar_->GetHeight(); + int right_edge_width = window_bounds.right - client_bounds.right; + int bottom_edge_height = window_bounds.bottom - client_bounds.bottom; + + // Now resize the window. This will result in Layout() getting called again + // and the contents getting sized to the value specified in |contents_bounds| + SetWindowPos(NULL, contents_bounds.x() - left_edge_width, + contents_bounds.y() - top_edge_height, + contents_bounds.width() + left_edge_width + right_edge_width, + contents_bounds.height() + top_edge_height + bottom_edge_height, + SWP_NOZORDER | SWP_NOACTIVATE); +} + +LRESULT SimpleVistaFrame::OnNCHitTest(const CPoint& pt) { + SetMsgHandled(false); + return 0; +} + +LRESULT SimpleVistaFrame::OnNCCalcSize(BOOL w_param, LPARAM l_param) { + SetMsgHandled(false); + return 0; +} + +void SimpleVistaFrame::OnNCLButtonDown(UINT flags, const CPoint& pt) { + if (flags == HTSYSMENU) { + POINT p = {0, 0}; + ::ClientToScreen(*this, &p); + browser_->RunSimpleFrameMenu(p, *this); + SetMsgHandled(true); + } else { + SetMsgHandled(false); + } +} + +void SimpleVistaFrame::StartThrobber() { + if (!throbber_running_) { + icon_manager_->SetUpdatesEnabled(false); + throbber_running_ = true; + throbber_frame_ = 0; + InitThrobberIcons(); + ::SendMessage(*this, WM_SETICON, static_cast<WPARAM>(ICON_SMALL), + reinterpret_cast<LPARAM>(g_throbber_icons[throbber_frame_])); + } +} + +void SimpleVistaFrame::DisplayNextThrobberFrame() { + throbber_frame_ = (throbber_frame_ + 1) % kThrobberIconCount; + ::SendMessage(*this, WM_SETICON, static_cast<WPARAM>(ICON_SMALL), + reinterpret_cast<LPARAM>(g_throbber_icons[throbber_frame_])); +} + +bool SimpleVistaFrame::IsThrobberRunning() { + return throbber_running_; +} + +void SimpleVistaFrame::StopThrobber() { + if (throbber_running_) { + throbber_running_ = false; + icon_manager_->SetUpdatesEnabled(true); + } +} + +void SimpleVistaFrame::ValidateThrobber() { + if (!browser_) + return; + TabContents* tc = browser_->GetSelectedTabContents(); + if (IsThrobberRunning()) { + if (!tc || !tc->is_loading()) + StopThrobber(); + else + DisplayNextThrobberFrame(); + } else if (tc && tc->is_loading()) { + StartThrobber(); + } +} + +void SimpleVistaFrame::Layout() { + VistaFrame::Layout(); + + // This happens while executing Init(). + if (!location_bar_) + return; + + if (browser_->ShouldDisplayURLField()) { + TabContentsContainerView* container = GetTabContentsContainer(); + CSize s; + location_bar_->GetPreferredSize(&s); + location_bar_->SetBounds(container->GetX() - kLocationBarOutdent, + container->GetY() - kLocationBarOutdent, + container->GetWidth() + kLocationBarOutdent * 2, + s.cy); + container->SetBounds(container->GetX(), + location_bar_->GetY() + location_bar_->GetHeight() - + kLocationBarSpacing, container->GetWidth(), + container->GetHeight() - location_bar_->GetHeight() + + 3); + location_bar_->SetVisible(true); + location_bar_->Layout(); + } else { + location_bar_->SetVisible(false); + } +} + +void SimpleVistaFrame::InitAfterHWNDCreated() { + icon_manager_.reset(new WebAppIconManager(*this)); + VistaFrame::InitAfterHWNDCreated(); +} + +TabContents* SimpleVistaFrame::GetTabContents() { + return browser_->GetSelectedTabContents(); +} + +void SimpleVistaFrame::OnInputInProgress(bool in_progress) { +} + +void SimpleVistaFrame::UpdateLocationBar() { + if (location_bar_ && location_bar_->IsVisible()) + location_bar_->Update(NULL); +} + diff --git a/chrome/browser/views/old_frames/simple_vista_frame.h b/chrome/browser/views/old_frames/simple_vista_frame.h new file mode 100644 index 0000000..c267f7d --- /dev/null +++ b/chrome/browser/views/old_frames/simple_vista_frame.h @@ -0,0 +1,85 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_OLD_FRAMES_SIMPLE_VISTA_FRAME_H__ +#define CHROME_BROWSER_VIEWS_OLD_FRAMES_SIMPLE_VISTA_FRAME_H__ + +#include "chrome/browser/views/location_bar_view.h" +#include "chrome/browser/views/old_frames/vista_frame.h" + +class WebAppIconManager; + +//////////////////////////////////////////////////////////////////////////////// +// +// A simple vista frame that contains a browser object. This frame doesn't show +// any tab. It is used for web applications. It will likely be used in the +// future for detached popups. +// +// This window simply uses the traditional Vista look and feel. +// +//////////////////////////////////////////////////////////////////////////////// +class SimpleVistaFrame : public VistaFrame, + public LocationBarView::Delegate { + public: + // Invoked by ChromeFrame::CreateChromeFrame to create a new SimpleVistaFrame. + // An empty |bounds| means that Windows should decide where to place the + // window. + static SimpleVistaFrame* CreateFrame(const gfx::Rect& bounds, + Browser* browser); + + virtual ~SimpleVistaFrame(); + + virtual void Init(); + + // LocationBarView delegate. + virtual TabContents* GetTabContents(); + virtual void OnInputInProgress(bool in_progress); + + protected: + // Overridden from VistaFrame. + virtual bool IsTabStripVisible() const { return false; } + virtual bool IsToolBarVisible() const { return false; } + virtual bool SupportsBookmarkBar() const { return false; } + virtual void SetWindowTitle(const std::wstring& title); + virtual void ShowTabContents(TabContents* selected_contents); + virtual void SizeToContents(const gfx::Rect& contents_bounds); + virtual LRESULT OnNCHitTest(const CPoint& pt); + virtual LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param); + virtual void OnNCLButtonDown(UINT flags, const CPoint& pt); + virtual void ValidateThrobber(); + + virtual void Layout(); + + // Overriden to create the WebAppIconManager, then invoke super. + virtual void InitAfterHWNDCreated(); + + private: + explicit SimpleVistaFrame(Browser* browser); + + void StartThrobber(); + bool IsThrobberRunning(); + void DisplayNextThrobberFrame(); + void StopThrobber(); + + // Update the location bar if it is visible. + void UpdateLocationBar(); + + // Set the current window icon. Use NULL for a default icon. + void SetCurrentIcon(HICON icon); + + // We change the window icon for the throbber. + bool throbber_running_; + + // Current throbber frame. + int throbber_frame_; + + // The optional location bar for popup windows. + LocationBarView* location_bar_; + + scoped_ptr<WebAppIconManager> icon_manager_; + + DISALLOW_EVIL_CONSTRUCTORS(SimpleVistaFrame); +}; +#endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_SIMPLE_VISTA_FRAME_H__ + diff --git a/chrome/browser/views/old_frames/simple_xp_frame.cc b/chrome/browser/views/old_frames/simple_xp_frame.cc new file mode 100644 index 0000000..4c4d506 --- /dev/null +++ b/chrome/browser/views/old_frames/simple_xp_frame.cc @@ -0,0 +1,403 @@ +// Copyright (c) 2006-2008 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/old_frames/simple_xp_frame.h" + +#include "chrome/app/theme/theme_resources.h" +#include "base/string_util.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/tab_contents_container_view.h" +#include "chrome/browser/views/location_bar_view.h" +#include "chrome/browser/views/tabs/tab.h" +#include "chrome/browser/web_app.h" +#include "chrome/browser/web_app_icon_manager.h" +#include "chrome/browser/web_contents.h" +#include "chrome/common/win_util.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/l10n_util.h" +#include "chrome/views/focus_manager.h" +#include "chrome/views/label.h" +#include "chrome/views/text_field.h" +#include "net/base/net_util.h" +#include "SkBitmap.h" + +#include "chromium_strings.h" +#include "generated_resources.h" + +// The title bar text color. +static const SkColor kTitleBarTextColor = SkColorSetRGB(255, 255, 255); + +// How thick is the top resize bar. +static const int kTopResizeBarHeight = 3; + +// Left margin on the left side of the favicon. +static const int kFavIconMargin = 1; + +// Label offset. +static const int kLabelVerticalOffset = -1; + +// Padding between the favicon and the text. +static const int kFavIconPadding = 4; + +// Background color for the button hot state. +static const SkColor kHotColor = SkColorSetRGB(49, 106, 197); + +// distance between contents and drop arrow. +static const int kHorizMargin = 4; + +// Border all around the menu. +static const int kHorizBorderSize = 2; +static const int kVertBorderSize = 1; + +// 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; + +//////////////////////////////////////////////////////////////////////////////// +// +// TitleBarMenuButton implementation. +// +//////////////////////////////////////////////////////////////////////////////// +TitleBarMenuButton::TitleBarMenuButton(SimpleXPFrameTitleBar* title_bar) + : ChromeViews::MenuButton(L"", title_bar, false), + contents_(NULL), + title_bar_(title_bar) { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + drop_arrow_ = rb.GetBitmapNamed(IDR_APP_DROPARROW); +} + +TitleBarMenuButton::~TitleBarMenuButton() { +} + +void TitleBarMenuButton::SetContents(ChromeViews::View* contents) { + contents_ = contents; +} + +void TitleBarMenuButton::GetPreferredSize(CSize *out) { + if (contents_) + contents_->GetPreferredSize(out); + else + out->cx = out->cy = 0; + + out->cx += drop_arrow_->width() + kHorizMargin + (2 * kHorizBorderSize); + out->cy = std::max(drop_arrow_->height(), static_cast<int>(out->cy)); + out->cy += (2 * kVertBorderSize); +} + +void TitleBarMenuButton::Paint(ChromeCanvas* canvas) { + if (GetState() == TextButton::BS_HOT || + GetState() == TextButton::BS_PUSHED || menu_visible_) { + canvas->FillRectInt(kHotColor, 0, 0, GetWidth(), GetHeight()); + } + + if (contents_) { + CSize s; + contents_->GetPreferredSize(&s); + // Note: we use a floating view in this case because we never want the + // contents to process any event. + PaintFloatingView(canvas, + contents_, + kVertBorderSize, + (GetHeight() - s.cy) / 2, + GetWidth() - kHorizMargin - drop_arrow_->width() - + (2 * kHorizBorderSize), + s.cy); + } + + // We can not use the mirroring infrastructure in ChromeViews in order to + // mirror the drop down arrow because is is drawn directly on the canvas + // (instead of using a child View). Thus, we should mirror its position + // manually. + gfx::Rect arrow_bounds(GetWidth() - drop_arrow_->width() - kHorizBorderSize, + (GetHeight() - drop_arrow_->height()) / 2, + drop_arrow_->width(), + drop_arrow_->height()); + arrow_bounds.set_x(MirroredLeftPointForRect(arrow_bounds)); + canvas->DrawBitmapInt(*drop_arrow_, arrow_bounds.x(), arrow_bounds.y()); +} + +bool TitleBarMenuButton::OnMousePressed(const ChromeViews::MouseEvent& e) { + if (e.GetFlags() & ChromeViews::MouseEvent::EF_IS_DOUBLE_CLICK) { + if (!HitTest(WTL::CPoint(e.GetX(), e.GetY()))) + return true; + title_bar_->CloseWindow(); + return true; + } else { + return MenuButton::OnMousePressed(e); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// SimpleXPFrameTitleBar implementation. +// +//////////////////////////////////////////////////////////////////////////////// + +SimpleXPFrameTitleBar::SimpleXPFrameTitleBar(SimpleXPFrame* parent) + : parent_(parent) { + DCHECK(parent); + tab_icon_.reset(new TabIconView(this)); + tab_icon_->set_is_light(true); + menu_button_ = new TitleBarMenuButton(this); + menu_button_->SetContents(tab_icon_view()); + AddChildView(menu_button_); + + tab_icon_->Update(); + + label_ = new ChromeViews::Label(); + label_->SetColor(kTitleBarTextColor); + label_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); + AddChildView(label_); +} + +SimpleXPFrameTitleBar::~SimpleXPFrameTitleBar() { +} + +TabContents* SimpleXPFrameTitleBar::GetCurrentTabContents() { + return parent_->GetCurrentContents(); +} + +SkBitmap SimpleXPFrameTitleBar::GetFavIcon() { + // Only use the favicon if we're a web application. + TabContents* contents = GetCurrentTabContents(); + if (parent_->IsApplication()) { + TabContents* contents = GetCurrentTabContents(); + WebContents* web_contents = contents->AsWebContents(); + if (web_contents) { + // If it's a web contents, pull the favicon from the WebApp, and fallback + // to the icon. + WebApp* web_app = web_contents->web_app(); + if (web_app && !web_app->GetFavIcon().isNull()) + return web_app->GetFavIcon(); + } + if (contents) { + SkBitmap favicon = contents->GetFavIcon(); + if (!favicon.isNull()) + return favicon; + } + } + + // Otherwise, use the default icon. + return SkBitmap(); +} + +void SimpleXPFrameTitleBar::RunMenu(ChromeViews::View* source, + const CPoint& pt, HWND hwnd) { + // Make sure we calculate the menu position based on the display bounds of + // the menu button. The display bounds are different than the actual bounds + // when the UI layout is RTL and hence we use the mirroring transformation + // flag. We also adjust the menu position because RTL menus use a different + // anchor point. + CPoint p(menu_button_->GetX(APPLY_MIRRORING_TRANSFORMATION), + menu_button_->GetY() + menu_button_->GetHeight()); + + if (UILayoutIsRightToLeft()) + p.x += menu_button_->GetWidth(); + View::ConvertPointToScreen(this, &p); + parent_->RunMenu(p, hwnd); +} + +void SimpleXPFrameTitleBar::Layout() { + CSize s; + menu_button_->GetPreferredSize(&s); + menu_button_->SetBounds(kFavIconMargin, (GetHeight() - s.cy) / 2, + s.cx, s.cy); + menu_button_->Layout(); + label_->SetBounds(menu_button_->GetX() + menu_button_->GetWidth() + + kFavIconPadding, kLabelVerticalOffset, + GetWidth() - (menu_button_->GetX() + + menu_button_->GetWidth() + kFavIconPadding), + GetHeight()); +} + +bool SimpleXPFrameTitleBar::WillHandleMouseEvent(int x, int y) { + // If the locale is RTL, we must query for the bounds of the menu button in + // a way that returns the mirrored position and not the position set using + // SetX()/SetBounds(). + CPoint p(x - menu_button_->GetX(APPLY_MIRRORING_TRANSFORMATION), + y - menu_button_->GetY()); + return menu_button_->HitTest(p); +} + +void SimpleXPFrameTitleBar::SetWindowTitle(std::wstring s) { + if (parent_->IsApplication()) { + std::wstring t(s); + Browser::FormatTitleForDisplay(&t); + label_->SetText(t); + } else { + label_->SetText(Browser::ComputePopupTitle( + GetCurrentTabContents()->GetURL(), s)); + } +} + +void SimpleXPFrameTitleBar::ValidateThrobber() { + tab_icon_->Update(); + menu_button_->SchedulePaint(); +} + +void SimpleXPFrameTitleBar::CloseWindow() { + parent_->Close(); +} + +void SimpleXPFrameTitleBar::Update() { + tab_icon_->Update(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// SimpleXPFrame implementation. +// +//////////////////////////////////////////////////////////////////////////////// + +// static +SimpleXPFrame* SimpleXPFrame::CreateFrame(const gfx::Rect& bounds, + Browser* browser) { + SimpleXPFrame* instance = new SimpleXPFrame(browser); + instance->Create(NULL, bounds.ToRECT(), + l10n_util::GetString(IDS_PRODUCT_NAME).c_str()); + instance->InitAfterHWNDCreated(); + instance->SetIsOffTheRecord(browser->profile()->IsOffTheRecord()); + ChromeViews::FocusManager::CreateFocusManager(instance->m_hWnd, + instance->GetRootView()); + return instance; +} + +SimpleXPFrame::SimpleXPFrame(Browser* browser) + : XPFrame(browser), + title_bar_(NULL), + location_bar_(NULL) { +} + +void SimpleXPFrame::InitAfterHWNDCreated() { + icon_manager_.reset(new WebAppIconManager(*this)); + XPFrame::InitAfterHWNDCreated(); +} + +SimpleXPFrame::~SimpleXPFrame() { +} + +void SimpleXPFrame::Init() { + XPFrame::Init(); + if (IsTitleBarVisible()) { + title_bar_ = new SimpleXPFrameTitleBar(this); + GetFrameView()->AddChildView(title_bar_); + } + + location_bar_ = new LocationBarView(browser_->profile(), + browser_->controller(), + browser_->toolbar_model(), + this, true); + GetFrameView()->AddChildView(location_bar_); + location_bar_->Init(); + + // Constrained popups that were unconstrained will need to set up a + // throbber. + UpdateTitleBar(); +} + +TabContents* SimpleXPFrame::GetCurrentContents() { + if (browser_) + return browser_->GetSelectedTabContents(); + else + return NULL; +} + +void SimpleXPFrame::Layout() { + XPFrame::Layout(); + if (IsTitleBarVisible()) { + TabContentsContainerView* tccv = GetTabContentsContainer(); + DCHECK(tccv); + title_bar_->SetBounds(tccv->GetX(), 0, + GetButtonXOrigin() - tccv->GetX(), + GetContentsYOrigin()); + title_bar_->Layout(); + } + + if (browser_->ShouldDisplayURLField()) { + TabContentsContainerView* container = GetTabContentsContainer(); + CSize s; + location_bar_->GetPreferredSize(&s); + location_bar_->SetBounds(container->GetX() - kLocationBarOffset, + container->GetY(), + container->GetWidth() + kLocationBarOffset * 2, + s.cy); + container->SetBounds(container->GetX(), + location_bar_->GetY() + location_bar_->GetHeight() + + kLocationBarSpacing, container->GetWidth(), + container->GetHeight() - location_bar_->GetHeight() - + 1); + location_bar_->SetVisible(true); + location_bar_->Layout(); + } else { + location_bar_->SetVisible(false); + } +} + +LRESULT SimpleXPFrame::OnNCHitTest(const CPoint& pt) { + if (IsTitleBarVisible()) { + CPoint p(pt); + ChromeViews::View::ConvertPointToView(NULL, title_bar_, &p); + if (!title_bar_->WillHandleMouseEvent(p.x, p.y) && + p.x >= 0 && p.y >= kTopResizeBarHeight && + p.x < title_bar_->GetWidth() && + p.y < title_bar_->GetHeight()) { + return HTCAPTION; + } + } + return XPFrame::OnNCHitTest(pt); +} + +void SimpleXPFrame::SetWindowTitle(const std::wstring& title) { + if (IsTitleBarVisible()) + title_bar_->SetWindowTitle(title); + XPFrame::SetWindowTitle(title); +} + +void SimpleXPFrame::UpdateTitleBar() { + if (IsTitleBarVisible()) { + title_bar_->Update(); + title_bar_->SchedulePaint(); + } + UpdateLocationBar(); +} + +void SimpleXPFrame::ValidateThrobber() { + if (IsTitleBarVisible()) + title_bar_->ValidateThrobber(); +} + +void SimpleXPFrame::RunMenu(const CPoint& pt, HWND hwnd) { + browser_->RunSimpleFrameMenu(pt, hwnd); +} + +void SimpleXPFrame::ShowTabContents(TabContents* selected_contents) { + XPFrame::ShowTabContents(selected_contents); + + icon_manager_->SetContents(selected_contents); + + UpdateLocationBar(); +} + +bool SimpleXPFrame::IsApplication() const { + return browser_->IsApplication(); +} + +void SimpleXPFrame::UpdateLocationBar() { + if (location_bar_ && location_bar_->IsVisible()) + location_bar_->Update(NULL); +} + +TabContents* SimpleXPFrame::GetTabContents() { + return GetCurrentContents(); +} + +void SimpleXPFrame::OnInputInProgress(bool in_progress) { +} + diff --git a/chrome/browser/views/old_frames/simple_xp_frame.h b/chrome/browser/views/old_frames/simple_xp_frame.h new file mode 100644 index 0000000..24a8a25 --- /dev/null +++ b/chrome/browser/views/old_frames/simple_xp_frame.h @@ -0,0 +1,177 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_OLD_FRAMES_SIMPLE_XP_FRAME_H__ +#define CHROME_BROWSER_VIEWS_OLD_FRAMES_SIMPLE_XP_FRAME_H__ + +#include "chrome/browser/views/location_bar_view.h" +#include "chrome/browser/views/old_frames/xp_frame.h" +#include "chrome/browser/views/tab_icon_view.h" +#include "chrome/views/menu_button.h" +#include "chrome/views/view_menu_delegate.h" + +class SimpleXPFrameTitleBar; +class WebAppIconManager; + +namespace ChromeViews { +class Label; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// A simple frame that contains a browser object. This frame doesn't show any +// tab. It is used for web applications. It will likely be used in the future +// for detached popups. +// +//////////////////////////////////////////////////////////////////////////////// +class SimpleXPFrame : public XPFrame, + public LocationBarView::Delegate { + public: + // Invoked by ChromeFrame::CreateChromeFrame to create a new SimpleXPFrame. + // An empty |bounds| means that Windows should decide where to place the + // window. + static SimpleXPFrame* CreateFrame(const gfx::Rect& bounds, Browser* browser); + + virtual ~SimpleXPFrame(); + + // Overridden from XPFrame. + virtual void Init(); + virtual void Layout(); + virtual bool IsTabStripVisible() const { return false; } + virtual bool IsToolBarVisible() const { return false; } + virtual bool SupportsBookmarkBar() const { return false; } +#ifdef CHROME_PERSONALIZATION + virtual bool PersonalizationEnabled() const { return false; } +#endif + virtual LRESULT OnNCHitTest(const CPoint& pt); + virtual void SetWindowTitle(const std::wstring& title); + virtual void ValidateThrobber(); + virtual void ShowTabContents(TabContents* selected_contents); + virtual void UpdateTitleBar(); + + // Return the currently visible contents. + TabContents* GetCurrentContents(); + + void RunMenu(const CPoint& pt, HWND hwnd); + + // Returns true if this popup contains a popup which has been created + // by a browser with a minimal chrome. + bool IsApplication() const; + + // LocationBarView delegate. + virtual TabContents* GetTabContents(); + virtual void OnInputInProgress(bool in_progress); + + protected: + explicit SimpleXPFrame(Browser* browser); + + // The default implementation has a title bar. Override if not needed. + virtual bool IsTitleBarVisible() { return true; } + + // Overriden to create the WebAppIconManager, then invoke super. + virtual void InitAfterHWNDCreated(); + + private: + // Set the current window icon. Use NULL for a default icon. + void SetCurrentIcon(HICON icon); + + // Update the location bar if it is visible. + void UpdateLocationBar(); + + // The simple frame title bar including favicon, menu and title. + SimpleXPFrameTitleBar* title_bar_; + + // The optional URL field. + //SimplifiedURLField* url_field_; + LocationBarView* location_bar_; + + // Handles the icon for web apps. + scoped_ptr<WebAppIconManager> icon_manager_; + + DISALLOW_EVIL_CONSTRUCTORS(SimpleXPFrame); +}; + +class SimpleXPFrameTitleBar; + +//////////////////////////////////////////////////////////////////////////////// +// +// A custom menu button for the custom title bar. +// +//////////////////////////////////////////////////////////////////////////////// +class TitleBarMenuButton : public ChromeViews::MenuButton { + public: + explicit TitleBarMenuButton(SimpleXPFrameTitleBar* title_bar); + virtual ~TitleBarMenuButton(); + + // Set the contents view which is the view presenting the menu icon. + void SetContents(ChromeViews::View* contents); + + // overridden from View + virtual void GetPreferredSize(CSize *out); + virtual void Paint(ChromeCanvas* canvas); + virtual bool OnMousePressed(const ChromeViews::MouseEvent& e); + + private: + // The drop arrow icon. + SkBitmap* drop_arrow_; + + // The contents is an additional view positioned before the drop down. + ChromeViews::View* contents_; + + // The title bar that created this instance. + SimpleXPFrameTitleBar* title_bar_; + + DISALLOW_EVIL_CONSTRUCTORS(TitleBarMenuButton); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Custom title bar. +// +//////////////////////////////////////////////////////////////////////////////// +class SimpleXPFrameTitleBar : public ChromeViews::View, + public TabIconView::TabContentsProvider, + public ChromeViews::ViewMenuDelegate { + public: + explicit SimpleXPFrameTitleBar(SimpleXPFrame* parent); + virtual ~SimpleXPFrameTitleBar(); + + // Overriden from TabIconView::TabContentsProvider: + virtual TabContents* GetCurrentTabContents(); + virtual SkBitmap GetFavIcon(); + + virtual void RunMenu(ChromeViews::View* source, const CPoint& pt, HWND hwnd); + virtual void Layout(); + bool WillHandleMouseEvent(int x, int y); + void SetWindowTitle(std::wstring s); + void ValidateThrobber(); + void CloseWindow(); + + // Updates the state of the tab icon. + void Update(); + + TabIconView* tab_icon_view() const { return tab_icon_.get(); } + + private: + // The menu button. + TitleBarMenuButton* menu_button_; + + // The tab icon. + scoped_ptr<TabIconView> tab_icon_; + + // The corresponding SimpleXPFrame. + SimpleXPFrame* parent_; + + // The window title. + ChromeViews::Label* label_; + + // Lazily created chrome icon. Created and used as the icon in the + // TabIconView for all non-Application windows. + SkBitmap* chrome_icon_; + + DISALLOW_EVIL_CONSTRUCTORS(SimpleXPFrameTitleBar); +}; + +#endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_SIMPLE_XP_FRAME_H__ + diff --git a/chrome/browser/views/old_frames/vista_frame.cc b/chrome/browser/views/old_frames/vista_frame.cc new file mode 100644 index 0000000..faa1213 --- /dev/null +++ b/chrome/browser/views/old_frames/vista_frame.cc @@ -0,0 +1,1636 @@ +// Copyright (c) 2006-2008 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/old_frames/vista_frame.h" + +#include <windows.h> +#include <atlbase.h> +#include <atlapp.h> +#include <atltheme.h> +#include <commctrl.h> +#include <dwmapi.h> +#include <limits> + +#include "base/gfx/native_theme.h" +#include "base/logging.h" +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/frame_util.h" +#include "chrome/browser/suspend_controller.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/tab_contents_container_view.h" +#include "chrome/browser/view_ids.h" +#include "chrome/browser/views/bookmark_bar_view.h" +#include "chrome/browser/views/download_shelf_view.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/win_util.h" +#include "chrome/views/accessibility/view_accessibility.h" +#include "chrome/views/aero_tooltip_manager.h" +#include "chrome/views/background.h" +#include "chrome/views/event.h" +#include "chrome/views/hwnd_view_container.h" +#include "chrome/views/hwnd_notification_source.h" + +#include "chromium_strings.h" +#include "generated_resources.h" + +// By how much the toolbar overlaps with the tab strip. +static const int kToolbarOverlapVertOffset = 3; + +// How much space on the right is not used for the tab strip (to provide +// separation between the tabs and the window controls). +static const int kTabStripRightHorizOffset = 30; + +static const int kResizeCornerSize = 12; +static const int kResizeBorder = 5; +static const int kTitlebarHeight = 14; +static const int kTabShadowSize = 2; + +// The line drawn to separate tab end contents. +static const int kSeparationLineHeight = 1; + +// OTR image offsets. +static const int kOTRImageHorizMargin = 2; +static const int kOTRImageVertMargin = 2; + +// Distributor logo offsets. +static const int kDistributorLogoVerticalOffset = 3; + +// The DWM puts a light border around the client area - we need to +// take this border size into account when we reduce its size so that +// we don't draw our content border dropshadow images over the top. +static const int kDwmBorderSize = 1; + +// When laying out the tabstrip, we size it such that it fits to the left of +// the window controls. We get the bounds of the window controls by sending a +// message to the window, but Windows answers the question assuming 96 dpi and +// a fairly conventional screen layout (i.e. not rotated etc). So we need to +// hack around this by making sure the tabstrip is at least this amount inset +// from the right side of the window. +static const int kWindowControlsMinOffset = 100; + +//static +bool VistaFrame::g_initialized = FALSE; + +//static +SkBitmap** VistaFrame::g_bitmaps; + +static const int kImageNames[] = { IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, + IDR_CONTENT_LEFT_SIDE, + IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_LEFT_CORNER, + IDR_CONTENT_TOP_RIGHT_CORNER, +}; + +typedef enum { CT_BOTTOM_CENTER = 0, CT_BOTTOM_LEFT_CORNER, + CT_BOTTOM_RIGHT_CORNER, CT_LEFT_SIDE, CT_RIGHT_SIDE, + CT_TOP_CENTER, CT_TOP_LEFT_CORNER, CT_TOP_RIGHT_CORNER }; + +using ChromeViews::Accelerator; +using ChromeViews::FocusManager; + +//static +VistaFrame* VistaFrame::CreateFrame(const gfx::Rect& bounds, + Browser* browser, + bool is_off_the_record) { + VistaFrame* instance = new VistaFrame(browser); + instance->Create(NULL, bounds.ToRECT(), + l10n_util::GetString(IDS_PRODUCT_NAME).c_str()); + instance->InitAfterHWNDCreated(); + instance->SetIsOffTheRecord(is_off_the_record); + FocusManager::CreateFocusManager(instance->m_hWnd, instance->GetRootView()); + return instance; +} + +VistaFrame::VistaFrame(Browser* browser) + : browser_(browser), + root_view_(this), + tabstrip_(NULL), + active_bookmark_bar_(NULL), + tab_contents_container_(NULL), + custom_window_enabled_(false), + saved_window_placement_(false), + on_mouse_leave_armed_(false), + in_drag_session_(false), + shelf_view_(NULL), + bookmark_bar_view_(NULL), + info_bar_view_(NULL), + is_off_the_record_(false), + off_the_record_image_(NULL), + distributor_logo_(NULL), + ignore_ncactivate_(false), + should_save_window_placement_(browser->GetType() != BrowserType::BROWSER), + browser_view_(NULL) { + InitializeIfNeeded(); +} + +void VistaFrame::InitializeIfNeeded() { + if (!g_initialized) { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + g_bitmaps = new SkBitmap*[arraysize(kImageNames)]; + for (int i = 0; i < arraysize(kImageNames); i++) + g_bitmaps[i] = rb.GetBitmapNamed(kImageNames[i]); + g_initialized = TRUE; + } +} + +VistaFrame::~VistaFrame() { + DestroyBrowser(); +} + +// On Vista (unlike on XP), we let the OS render the Windows decor (close +// button, maximize button, etc.). Since the mirroring infrastructure in +// ChromeViews does not rely on HWND flipping, the Windows decor on Vista are +// not mirrored for RTL locales; that is, they appear on the upper right +// instead of on the upper left (see bug http://b/issue?id=1128173). +// +// Due to the above, we need to be careful when positioning the tabstrip and +// the OTR image. The OTR image and the tabstrip are automatically mirrored for +// RTL locales by the mirroring infrastructure. In order to make sure they are +// not mirrored, we flip them manually so make sure they don't overlap the +// Windows decor. Unfortunately, there is no cleaner way to do this because the +// current ChromeViews mirroring API does not allow mirroring the position of +// a subset of child Views; in other words, once a View is mirrored (in our +// case frame_view_), then the positions of all its child Views (including, in +// our case, the OTR image and the tabstrip) are mirrored. Once bug mentioned +// above is fixed, we won't need to perform any manual mirroring. +void VistaFrame::Layout() { + CRect client_rect; + GetClientRect(&client_rect); + int width = client_rect.Width(); + int height = client_rect.Height(); + + root_view_.SetBounds(0, 0, width, height); + frame_view_->SetBounds(0, 0, width, height); + + if (IsTabStripVisible()) { + tabstrip_->SetVisible(true); + int tabstrip_x = g_bitmaps[CT_LEFT_SIDE]->width(); + if (is_off_the_record_) { + off_the_record_image_->SetVisible(true); + CSize otr_image_size; + off_the_record_image_->GetPreferredSize(&otr_image_size); + tabstrip_x += otr_image_size.cx + (2 * kOTRImageHorizMargin); + gfx::Rect off_the_record_bounds; + if (IsZoomed()) { + off_the_record_bounds.SetRect(g_bitmaps[CT_LEFT_SIDE]->width(), + kResizeBorder, + otr_image_size.cx, + tabstrip_->GetPreferredHeight() - + kToolbarOverlapVertOffset + 1); + } else { + off_the_record_bounds.SetRect(g_bitmaps[CT_LEFT_SIDE]->width(), + kResizeBorder + kTitlebarHeight + + tabstrip_->GetPreferredHeight() - + otr_image_size.cy - + kToolbarOverlapVertOffset + 1, + otr_image_size.cx, + otr_image_size.cy); + } + + if (frame_view_->UILayoutIsRightToLeft()) + off_the_record_bounds.set_x(frame_view_->MirroredLeftPointForRect( + off_the_record_bounds)); + off_the_record_image_->SetBounds(off_the_record_bounds.x(), + off_the_record_bounds.y(), + off_the_record_bounds.width(), + off_the_record_bounds.height()); + + } + + // Figure out where the minimize button is for layout purposes. + TITLEBARINFOEX titlebar_info; + titlebar_info.cbSize = sizeof(TITLEBARINFOEX); + SendMessage(WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info); + + // rgrect[2] refers to the minimize button. min_offset will + // be the distance between the right side of the window + // and the minimize button. + CRect window_rect; + GetWindowRect(&window_rect); + int min_offset = window_rect.right - titlebar_info.rgrect[2].left; + + // If we are maxmized, the tab strip will be in line with the window + // controls, so we need to make sure they don't overlap. + int zoomed_offset = 0; + if (distributor_logo_) { + if(IsZoomed()) { + zoomed_offset = std::max(min_offset, kWindowControlsMinOffset); + + // Hide the distributor logo if we're zoomed. + distributor_logo_->SetVisible(false); + } else { + CSize distributor_logo_size; + distributor_logo_->GetPreferredSize(&distributor_logo_size); + + int logo_x; + // Because of Bug 1128173, our Window controls aren't actually flipped + // on Vista, yet all our math and layout presumes that they are. + if (frame_view_->UILayoutIsRightToLeft()) + logo_x = width - distributor_logo_size.cx; + else + logo_x = width - min_offset - distributor_logo_size.cx; + + distributor_logo_->SetVisible(true); + distributor_logo_->SetBounds(logo_x, + kDistributorLogoVerticalOffset, + distributor_logo_size.cx, + distributor_logo_size.cy); + } + } + + gfx::Rect tabstrip_bounds(tabstrip_x, + kResizeBorder + (IsZoomed() ? + kDwmBorderSize : kTitlebarHeight), + width - tabstrip_x - kTabStripRightHorizOffset - + zoomed_offset, + tabstrip_->GetPreferredHeight()); + if (frame_view_->UILayoutIsRightToLeft() && + (IsZoomed() || is_off_the_record_)) + tabstrip_bounds.set_x( + frame_view_->MirroredLeftPointForRect(tabstrip_bounds)); + tabstrip_->SetBounds(tabstrip_bounds.x(), + tabstrip_bounds.y(), + tabstrip_bounds.width(), + tabstrip_bounds.height()); + + frame_view_->SetContentsOffset(tabstrip_->GetY() + + tabstrip_->GetHeight() - + kToolbarOverlapVertOffset); + } else { + tabstrip_->SetBounds(0, 0, 0, 0); + tabstrip_->SetVisible(false); + if (is_off_the_record_) + off_the_record_image_->SetVisible(false); + } + + int toolbar_bottom; + if (IsToolBarVisible()) { + browser_view_->SetVisible(true); + browser_view_->SetBounds(g_bitmaps[CT_LEFT_SIDE]->width(), + tabstrip_->GetY() + tabstrip_->GetHeight() - + kToolbarOverlapVertOffset, + width - g_bitmaps[CT_LEFT_SIDE]->width() - + g_bitmaps[CT_RIGHT_SIDE]->width(), + g_bitmaps[CT_TOP_CENTER]->height()); + browser_view_->Layout(); + toolbar_bottom = browser_view_->GetY() + browser_view_->GetHeight(); + } else { + browser_view_->SetBounds(0, 0, 0, 0); + browser_view_->SetVisible(false); + toolbar_bottom = tabstrip_->GetY() + tabstrip_->GetHeight(); + } + int browser_x, browser_y; + int browser_w, browser_h; + + if (IsTabStripVisible()) { + browser_x = g_bitmaps[CT_LEFT_SIDE]->width(); + browser_y = toolbar_bottom; + browser_w = width - g_bitmaps[CT_LEFT_SIDE]->width() - + g_bitmaps[CT_RIGHT_SIDE]->width(); + browser_h = height - browser_y - g_bitmaps[CT_BOTTOM_CENTER]->height(); + } else { + browser_x = 0; + browser_y = toolbar_bottom; + browser_w = width; + browser_h = height; + } + + CSize preferred_size; + if (shelf_view_) { + shelf_view_->GetPreferredSize(&preferred_size); + shelf_view_->SetBounds(browser_x, + height - g_bitmaps[CT_BOTTOM_CENTER]->height() - + preferred_size.cy, + browser_w, + preferred_size.cy); + browser_h -= preferred_size.cy; + } + + CSize bookmark_bar_size; + CSize info_bar_size; + + if (bookmark_bar_view_.get()) + bookmark_bar_view_->GetPreferredSize(&bookmark_bar_size); + + if (info_bar_view_) + info_bar_view_->GetPreferredSize(&info_bar_size); + + // If we're showing a bookmarks bar in the new tab page style and we + // have an infobar showing, we need to flip them. + if (info_bar_view_ && + bookmark_bar_view_.get() && + bookmark_bar_view_->IsNewTabPage() && + !bookmark_bar_view_->IsAlwaysShown()) { + info_bar_view_->SetBounds(browser_x, + browser_y, + browser_w, + info_bar_size.cy); + browser_h -= info_bar_size.cy; + + browser_y += info_bar_size.cy - kSeparationLineHeight; + + bookmark_bar_view_->SetBounds(browser_x, + browser_y, + browser_w, + bookmark_bar_size.cy); + browser_h -= bookmark_bar_size.cy - kSeparationLineHeight; + browser_y += bookmark_bar_size.cy; + } else { + if (bookmark_bar_view_.get()) { + // We want our bookmarks bar to be responsible for drawing its own + // separator, so we let it overlap ours. + browser_y -= kSeparationLineHeight; + + bookmark_bar_view_->SetBounds(browser_x, + browser_y, + browser_w, + bookmark_bar_size.cy); + browser_h -= bookmark_bar_size.cy - kSeparationLineHeight; + browser_y += bookmark_bar_size.cy; + } + + if (info_bar_view_) { + info_bar_view_->SetBounds(browser_x, + browser_y, + browser_w, + info_bar_size.cy); + browser_h -= info_bar_size.cy; + browser_y += info_bar_size.cy; + } + } + + // While our OnNCCalcSize handler does a good job of covering most of the + // cases where we need to do this, it unfortunately doesn't cover the + // case where we're returning from maximized mode. + ResetDWMFrame(); + + tab_contents_container_->SetBounds(browser_x, + browser_y, + browser_w, + browser_h); + + browser_view_->LayoutStatusBubble(browser_y + browser_h); + + frame_view_->SchedulePaint(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// BrowserWindow implementation +// +//////////////////////////////////////////////////////////////////////////////// + +void VistaFrame::Init() { + FrameUtil::RegisterBrowserWindow(this); + + // Link the HWND with its root view so we can retrieve the RootView from the + // HWND for automation purposes. + ChromeViews::SetRootViewForHWND(m_hWnd, &root_view_); + + frame_view_ = new VistaFrameView(this); + root_view_.AddChildView(frame_view_); + root_view_.SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); + frame_view_->SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); + + browser_view_ = new BrowserView(this, browser_, NULL, NULL); + frame_view_->AddChildView(browser_view_); + + tabstrip_ = CreateTabStrip(browser_); + tabstrip_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_TABSTRIP)); + frame_view_->AddChildView(tabstrip_); + + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + + if (is_off_the_record_) { + off_the_record_image_ = new ChromeViews::ImageView(); + frame_view_->AddViewToDropList(off_the_record_image_); + SkBitmap* otr_icon = rb.GetBitmapNamed(IDR_OTR_ICON); + off_the_record_image_->SetImage(*otr_icon); + off_the_record_image_->SetTooltipText( + l10n_util::GetString(IDS_OFF_THE_RECORD_TOOLTIP)); + off_the_record_image_->SetVerticalAlignment( + ChromeViews::ImageView::LEADING); + frame_view_->AddChildView(off_the_record_image_); + } + + SkBitmap* image = rb.GetBitmapNamed(IDR_DISTRIBUTOR_LOGO); + if (!image->isNull()) { + distributor_logo_ = new ChromeViews::ImageView(); + frame_view_->AddViewToDropList(distributor_logo_); + distributor_logo_->SetImage(image); + frame_view_->AddChildView(distributor_logo_); + } + + tab_contents_container_ = new TabContentsContainerView(); + frame_view_->AddChildView(tab_contents_container_); + + // Add the task manager item to the system menu before the last entry. + task_manager_label_text_ = l10n_util::GetString(IDS_TASKMANAGER); + HMENU system_menu = ::GetSystemMenu(m_hWnd, FALSE); + int index = ::GetMenuItemCount(system_menu) - 1; + if (index < 0) { + NOTREACHED(); + // Paranoia check. + index = 0; + } + + // First we add the separator. + MENUITEMINFO menu_info; + memset(&menu_info, 0, sizeof(MENUITEMINFO)); + menu_info.cbSize = sizeof(MENUITEMINFO); + menu_info.fMask = MIIM_FTYPE; + menu_info.fType = MFT_SEPARATOR; + ::InsertMenuItem(system_menu, index, TRUE, &menu_info); + // Then the actual menu. + menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; + menu_info.fType = MFT_STRING; + menu_info.fState = MFS_ENABLED; + menu_info.wID = IDC_TASKMANAGER; + menu_info.dwTypeData = const_cast<wchar_t*>(task_manager_label_text_.c_str()); + ::InsertMenuItem(system_menu, index, TRUE, &menu_info); + + // Register accelerators. + HACCEL accelerators_table = AtlLoadAccelerators(IDR_MAINFRAME); + DCHECK(accelerators_table); + FrameUtil::LoadAccelerators(this, accelerators_table, this); + + ShelfVisibilityChanged(); + root_view_.OnViewContainerCreated(); + Layout(); +} + +TabStrip* VistaFrame::CreateTabStrip(Browser* browser) { + return new TabStrip(browser->tabstrip_model()); +} + +void VistaFrame::Show(int command, bool adjust_to_fit) { + if (adjust_to_fit) + win_util::AdjustWindowToFit(*this); + ::ShowWindow(*this, command); +} + +// This is called when we receive WM_ENDSESSION. In Vista the we have 5 seconds +// or will be forcefully terminated if we get stuck servicing this message and +// not pump the final messages. +void VistaFrame::OnEndSession(BOOL ending, UINT logoff) { + tabstrip_->AbortActiveDragSession(); + FrameUtil::EndSession(); +} + +// Note: called directly by the handler macros to handle WM_CLOSE messages. +void VistaFrame::Close() { + // You cannot close a frame for which there is an active originating drag + // session. + if (tabstrip_->IsDragSessionActive()) + return; + + // Give beforeunload handlers the chance to cancel the close before we hide + // the window below. + if (!browser_->ShouldCloseWindow()) + return; + + // We call this here so that the window position gets saved before moving + // the window into hyperspace. + if (!saved_window_placement_ && should_save_window_placement_ && browser_) { + browser_->SaveWindowPlacement(); + browser_->SaveWindowPlacementToDatabase(); + saved_window_placement_ = true; + } + + if (browser_ && !browser_->tabstrip_model()->empty()) { + // Tab strip isn't empty. Hide the window (so it appears to have closed + // immediately) and close all the tabs, allowing the renderers to shut + // down. When the tab strip is empty we'll be called back recursively. + // NOTE: Don't use ShowWindow(SW_HIDE) here, otherwise end session blocks + // here. + SetWindowPos(NULL, 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); + browser_->OnWindowClosing(); + } else { + // Empty tab strip, it's now safe to clean-up. + root_view_.OnViewContainerDestroyed(); + + NotificationService::current()->Notify( + NOTIFY_WINDOW_CLOSED, Source<HWND>(m_hWnd), + NotificationService::NoDetails()); + + DestroyWindow(); + } +} + +void* VistaFrame::GetPlatformID() { + return reinterpret_cast<void*>(m_hWnd); +} + +void VistaFrame::SetAcceleratorTable( + std::map<Accelerator, int>* accelerator_table) { + accelerator_table_.reset(accelerator_table); +} + +bool VistaFrame::GetAccelerator(int cmd_id, + ChromeViews::Accelerator* accelerator) { + std::map<ChromeViews::Accelerator, int>::iterator it = + accelerator_table_->begin(); + for (; it != accelerator_table_->end(); ++it) { + if(it->second == cmd_id) { + *accelerator = it->first; + return true; + } + } + return false; +} + +bool VistaFrame::AcceleratorPressed(const Accelerator& accelerator) { + DCHECK(accelerator_table_.get()); + std::map<Accelerator, int>::const_iterator iter = + accelerator_table_->find(accelerator); + DCHECK(iter != accelerator_table_->end()); + + int command_id = iter->second; + if (browser_->SupportsCommand(command_id) && + browser_->IsCommandEnabled(command_id)) { + browser_->ExecuteCommand(command_id); + return true; + } + return false; +} + +gfx::Rect VistaFrame::GetNormalBounds() { + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + const bool ret = !!GetWindowPlacement(&wp); + DCHECK(ret); + return gfx::Rect(wp.rcNormalPosition); +} + +bool VistaFrame::IsMaximized() { + return !!IsZoomed(); +} + +gfx::Rect VistaFrame::GetBoundsForContentBounds(const gfx::Rect content_rect) { + if (tab_contents_container_->GetX() == 0 && + tab_contents_container_->GetWidth() == 0) { + Layout(); + } + + CPoint p(0, 0); + ChromeViews::View::ConvertPointToViewContainer(tab_contents_container_, &p); + CRect bounds; + GetBounds(&bounds, true); + + gfx::Rect r; + r.set_x(content_rect.x() - p.x); + r.set_y(content_rect.y() - p.y); + r.set_width(p.x + content_rect.width() + + (bounds.Width() - (p.x + tab_contents_container_->GetWidth()))); + r.set_height(p.y + content_rect.height() + + (bounds.Height() - (p.y + + tab_contents_container_->GetHeight()))); + return r; +} + +void VistaFrame::InfoBubbleShowing() { + ignore_ncactivate_ = true; +} + +ToolbarStarToggle* VistaFrame::GetStarButton() const { + return NULL; +} + +LocationBarView* VistaFrame::GetLocationBarView() const { + return NULL; +} + +GoButton* VistaFrame::GetGoButton() const { + return NULL; +} + +BookmarkBarView* VistaFrame::GetBookmarkBarView() { + TabContents* current_tab = browser_->GetSelectedTabContents(); + if (!current_tab || !current_tab->profile()) + return NULL; + + if (!bookmark_bar_view_.get()) { + bookmark_bar_view_.reset(new BookmarkBarView(current_tab->profile(), + browser_)); + bookmark_bar_view_->SetParentOwned(false); + } else { + bookmark_bar_view_->SetProfile(current_tab->profile()); + } + bookmark_bar_view_->SetPageNavigator(current_tab); + return bookmark_bar_view_.get(); +} + +BrowserView* VistaFrame::GetBrowserView() const { + return browser_view_; +} + +void VistaFrame::UpdateToolbar(TabContents* contents, + bool should_restore_state) { +} + +void VistaFrame::ProfileChanged(Profile* profile) { +} + +void VistaFrame::FocusToolbar() { +} + +bool VistaFrame::IsBookmarkBarVisible() const { + if (!bookmark_bar_view_.get()) + return false; + + if (bookmark_bar_view_->IsNewTabPage() || bookmark_bar_view_->IsAnimating()) + return true; + + CSize sz; + bookmark_bar_view_->GetPreferredSize(&sz); + // 1 is the minimum in GetPreferredSize for the bookmark bar. + return sz.cy > 1; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Events +// +//////////////////////////////////////////////////////////////////////////////// + +LRESULT VistaFrame::OnSettingChange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled) { + // Set this to false, if we actually handle the message, we'll set it to + // true below. + handled = FALSE; + if (w_param != SPI_SETWORKAREA) + return 0; // Return value is effectively ignored in atlwin.h. + + win_util::AdjustWindowToFit(m_hWnd); + handled = TRUE; + return 0; // Return value is effectively ignored in atlwin.h. +} + +LRESULT VistaFrame::OnNCActivate(BOOL param) { + if (ignore_ncactivate_) { + ignore_ncactivate_ = false; + return DefWindowProc(WM_NCACTIVATE, TRUE, 0); + } + SetMsgHandled(false); + return 0; +} + +BOOL VistaFrame::OnPowerBroadcast(DWORD power_event, DWORD data) { + if (PBT_APMSUSPEND == power_event) { + SuspendController::OnSuspend(browser_->profile()); + return TRUE; + } else if (PBT_APMRESUMEAUTOMATIC == power_event) { + SuspendController::OnResume(browser_->profile()); + return TRUE; + } + + SetMsgHandled(FALSE); + return FALSE; +} + +void VistaFrame::OnThemeChanged() { + // Notify NativeTheme. + gfx::NativeTheme::instance()->CloseHandles(); +} + +void VistaFrame::OnMouseButtonDown(UINT flags, const CPoint& pt) { + if (m_hWnd == NULL) { + return; + } + + if (ProcessMousePressed(pt, flags, FALSE)) { + SetMsgHandled(TRUE); + } else { + SetMsgHandled(FALSE); + } +} + +void VistaFrame::OnMouseButtonUp(UINT flags, const CPoint& pt) { + if (m_hWnd == NULL) { + return; + } + + if (in_drag_session_) { + ProcessMouseReleased(pt, flags); + } +} + +void VistaFrame::OnMouseButtonDblClk(UINT flags, const CPoint& pt) { + if (ProcessMousePressed(pt, flags, TRUE)) { + SetMsgHandled(TRUE); + } else { + SetMsgHandled(FALSE); + } +} + +void VistaFrame::OnLButtonUp(UINT flags, const CPoint& pt) { + OnMouseButtonUp(flags | MK_LBUTTON, pt); +} + +void VistaFrame::OnMButtonUp(UINT flags, const CPoint& pt) { + OnMouseButtonUp(flags | MK_MBUTTON, pt); +} + +void VistaFrame::OnRButtonUp(UINT flags, const CPoint& pt) { + OnMouseButtonUp(flags | MK_RBUTTON, pt); +} + +void VistaFrame::OnNCMButtonDown(UINT flags, const CPoint& pt) { + // The point is in screen coordinate system so we need to convert + CRect window_rect; + GetWindowRect(&window_rect); + CPoint point(pt); + point.x -= window_rect.left; + point.y -= window_rect.top; + + // Yes we need to add MK_MBUTTON. Windows doesn't include it + OnMouseButtonDown(flags | MK_MBUTTON, point); +} + +void VistaFrame::OnNCRButtonDown(UINT flags, const CPoint& pt) { + if (flags == HTCAPTION) { + HMENU system_menu = ::GetSystemMenu(*this, FALSE); + int id = ::TrackPopupMenu(system_menu, + TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, + pt.x, + pt.y, + 0, + *this, + NULL); + if (id) + ::SendMessage(*this, + WM_SYSCOMMAND, + id, + 0); + } else { + SetMsgHandled(FALSE); + } +} + +void VistaFrame::OnMouseMove(UINT flags, const CPoint& pt) { + if (m_hWnd == NULL) { + return; + } + + if (in_drag_session_) { + ProcessMouseDragged(pt, flags); + } else { + ArmOnMouseLeave(); + ProcessMouseMoved(pt, flags); + } +} + +void VistaFrame::OnMouseLeave() { + if (m_hWnd == NULL) { + return; + } + + ProcessMouseExited(); + on_mouse_leave_armed_ = false; +} + +LRESULT VistaFrame::OnGetObject(UINT uMsg, WPARAM w_param, LPARAM object_id) { + LRESULT reference_result = static_cast<LRESULT>(0L); + + // Accessibility readers will send an OBJID_CLIENT message + if (OBJID_CLIENT == object_id) { + // If our MSAA root is already created, reuse that pointer. Otherwise, + // create a new one. + if (!accessibility_root_) { + CComObject<ViewAccessibility>* instance = NULL; + + HRESULT hr = CComObject<ViewAccessibility>::CreateInstance(&instance); + DCHECK(SUCCEEDED(hr)); + + if (!instance) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + CComPtr<IAccessible> accessibility_instance(instance); + + if (!SUCCEEDED(instance->Initialize(&root_view_))) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + // All is well, assign the temp instance to the class smart pointer + accessibility_root_.Attach(accessibility_instance.Detach()); + + if (!accessibility_root_) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + // Notify that an instance of IAccessible was allocated for m_hWnd + ::NotifyWinEvent(EVENT_OBJECT_CREATE, m_hWnd, OBJID_CLIENT, + CHILDID_SELF); + } + + // Create a reference to ViewAccessibility that MSAA will marshall + // to the client. + reference_result = LresultFromObject(IID_IAccessible, w_param, + static_cast<IAccessible*>(accessibility_root_)); + } + return reference_result; +} + +void VistaFrame::OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags) { + ChromeViews::KeyEvent event(ChromeViews::Event::ET_KEY_PRESSED, c, + rep_cnt, flags); + root_view_.ProcessKeyEvent(event); +} + +void VistaFrame::OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags) { + ChromeViews::KeyEvent event(ChromeViews::Event::ET_KEY_RELEASED, c, + rep_cnt, flags); + root_view_.ProcessKeyEvent(event); +} + +LRESULT VistaFrame::OnAppCommand( + HWND w_param, short app_command, WORD device, int keystate) { + if (browser_ && !browser_->ExecuteWindowsAppCommand(app_command)) + SetMsgHandled(FALSE); + return 0; +} + +void VistaFrame::OnCommand(UINT notification_code, + int command_id, + HWND window) { + if (browser_ && browser_->SupportsCommand(command_id)) { + browser_->ExecuteCommand(command_id); + } else { + SetMsgHandled(FALSE); + } +} + +void VistaFrame::OnSysCommand(UINT notification_code, CPoint click) { + switch (notification_code) { + case IDC_TASKMANAGER: + if (browser_) + browser_->ExecuteCommand(IDC_TASKMANAGER); + break; + default: + // Use the default implementation for any other command. + SetMsgHandled(FALSE); + break; + } +} + +void VistaFrame::OnMove(const CSize& size) { + if (!saved_window_placement_ && should_save_window_placement_ ) + browser_->SaveWindowPlacementToDatabase(); + + browser_->WindowMoved(); +} + +void VistaFrame::OnMoving(UINT param, LPRECT new_bounds) { + // We want to let the browser know that the window moved so that it can + // update the positions of any dependent WS_POPUPs + browser_->WindowMoved(); +} + +void VistaFrame::OnSize(UINT param, const CSize& size) { + Layout(); + + if (root_view_.NeedsPainting(false)) { + PaintNow(root_view_.GetScheduledPaintRect()); + } + + if (!saved_window_placement_ && should_save_window_placement_) + browser_->SaveWindowPlacementToDatabase(); +} + +void VistaFrame::OnFinalMessage(HWND hwnd) { + delete this; +} + +void VistaFrame::OnNCLButtonDown(UINT flags, const CPoint& pt) { + SetMsgHandled(false); +} + +LRESULT VistaFrame::OnNCCalcSize(BOOL w_param, LPARAM l_param) { + // By default the client side is set to the window size which is what + // we want. + if (w_param == TRUE) { + // Calculate new NCCALCSIZE_PARAMS based on custom NCA inset. + NCCALCSIZE_PARAMS *pncsp = reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param); + + // Hack necessary to stop black background flicker, we cut out + // resizeborder here to save us from having to do too much + // addition and subtraction in Layout(). We don't cut off the + // top + titlebar as that prevents the window controls from + // highlighting. + pncsp->rgrc[0].left = pncsp->rgrc[0].left + kResizeBorder; + pncsp->rgrc[0].right = pncsp->rgrc[0].right - kResizeBorder; + pncsp->rgrc[0].bottom = pncsp->rgrc[0].bottom - kResizeBorder; + + // We need to reset the frame, as Vista resets it whenever it changes + // composition modes (and NCCALCSIZE is the closest thing we get to + // a reliable message about the change). + ResetDWMFrame(); + + SetMsgHandled(TRUE); + return 0; + } + + SetMsgHandled(FALSE); + return 0; +} + +LRESULT VistaFrame::OnNCHitTest(const CPoint& pt) { + SetMsgHandled(TRUE); + + // Test the caption buttons + LRESULT l_res; + BOOL dwm_processed = DwmDefWindowProc(m_hWnd, + WM_NCHITTEST, + 0, + (LPARAM)MAKELONG(pt.x, pt.y), + &l_res); + + if (dwm_processed) { + return l_res; + } + + CRect cr; + GetBounds(&cr, false); + + CPoint tab_pt(pt); + ChromeViews::View::ConvertPointToView(NULL, tabstrip_, &tab_pt); + + // If we are over the tabstrip + if (tab_pt.x > 0 && tab_pt.y >= kTabShadowSize && + tab_pt.x < tabstrip_->GetWidth() && + tab_pt.y < tabstrip_->GetHeight()) { + ChromeViews::View* v = tabstrip_->GetViewForPoint(tab_pt); + if (v == tabstrip_) + return HTCAPTION; + + // If the view under mouse is a tab, check if the tab strip allows tab + // dragging or not. If not, return caption to get window dragging. + if (v->GetClassName() == Tab::kTabClassName && + !tabstrip_->HasAvailableDragActions()) + return HTCAPTION; + + return HTCLIENT; + } + + CPoint p(pt); + CRect r; + GetWindowRect(&r); + + // Convert from screen to window coordinates + p.x -= r.left; + p.y -= r.top; + + if (p.x < kResizeBorder + g_bitmaps[CT_LEFT_SIDE]->width()) { + if (p.y < kResizeCornerSize) { + return HTTOPLEFT; + } else if (p.y >= (r.Height() - kResizeCornerSize)) { + return HTBOTTOMLEFT; + } else { + return HTLEFT; + } + // BOTTOM_LEFT / TOP_LEFT horizontal extensions + } else if (p.x < kResizeCornerSize) { + if (p.y < kResizeBorder) { + return HTTOPLEFT; + } else if (p.y >= (r.Height() - kResizeBorder)) { + return HTBOTTOMLEFT; + } + // EAST / BOTTOMRIGHT / TOPRIGHT edge + } else if (p.x >= (r.Width() - kResizeBorder - + g_bitmaps[CT_RIGHT_SIDE]->width())) { + if (p.y < kResizeCornerSize) { + return HTTOPRIGHT; + } else if (p.y >= (r.Height() - kResizeCornerSize)) { + return HTBOTTOMRIGHT; + } else { + return HTRIGHT; + } + // EAST / BOTTOMRIGHT / TOPRIGHT horizontal extensions + } else if (p.x >= (r.Width() - kResizeCornerSize)) { + if (p.y < kResizeBorder) { + return HTTOPRIGHT; + } else if (p.y >= (r.Height() - kResizeBorder)) { + return HTBOTTOMRIGHT; + } + // TOP edge + } else if (p.y < kResizeBorder) { + return HTTOP; + // BOTTOM edge + } else if (p.y >= (r.Height() - kResizeBorder - + g_bitmaps[CT_BOTTOM_CENTER]->height())) { + return HTBOTTOM; + } + + if (p.y <= tabstrip_->GetY() + tabstrip_->GetHeight()) { + return HTCAPTION; + } + + SetMsgHandled(FALSE); + return 0; +} + +void VistaFrame::OnActivate(UINT n_state, BOOL is_minimized, HWND other) { + if (FrameUtil::ActivateAppModalDialog(browser_)) + return; + + // Enable our custom window if we haven't already (this works in combination + // with our NCCALCSIZE handler). + if (!custom_window_enabled_) { + RECT rcClient; + ::GetWindowRect(m_hWnd, &rcClient); + ::SetWindowPos( + m_hWnd, + NULL, + rcClient.left, rcClient.top, + rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, + SWP_FRAMECHANGED); + custom_window_enabled_ = true; + + // We need to fire this here as well as in OnNCCalcSize, as that function + // does not fire at the right time for this to work when opening the + // window. + ResetDWMFrame(); + } + + SetMsgHandled(FALSE); + if (!is_minimized) + browser_->WindowActivationChanged(n_state != WA_INACTIVE); +} + +int VistaFrame::OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, + UINT message) { + return FrameUtil::ActivateAppModalDialog(browser_) ? MA_NOACTIVATEANDEAT + : MA_ACTIVATE; +} + +void VistaFrame::OnPaint(HDC dc) { + // Warning: on Vista the ChromeCanvasPaint *must* use an opaque flag of true + // so that ChromeCanvasPaint performs a BitBlt and not an alpha blend. + // + root_view_.OnPaint(*this); +} + +LRESULT VistaFrame::OnEraseBkgnd(HDC dc) { + SetMsgHandled(TRUE); + return 0; +} + +void VistaFrame::ArmOnMouseLeave() { + if (!on_mouse_leave_armed_) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = *this; + tme.dwHoverTime = 0; + TrackMouseEvent(&tme); + on_mouse_leave_armed_ = TRUE; + } +} + +void VistaFrame::OnCaptureChanged(HWND hwnd) { + if (in_drag_session_) + root_view_.ProcessMouseDragCanceled(); + in_drag_session_ = false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// View events propagation +// +//////////////////////////////////////////////////////////////////////////////// + +bool VistaFrame::ProcessMousePressed(const CPoint& pt, UINT flags, + bool dbl_click) { + using namespace ChromeViews; + MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, + pt.x, + pt.y, + (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) | + Event::ConvertWindowsFlags(flags)); + if (root_view_.OnMousePressed(mouse_pressed)) { + // If an additional button is pressed during a drag session we don't want + // to call SetCapture() again as it will result in no more events. + if (!in_drag_session_) { + in_drag_session_ = true; + SetCapture(); + } + return TRUE; + } + return FALSE; +} + +void VistaFrame::ProcessMouseDragged(const CPoint& pt, UINT flags) { + using namespace ChromeViews; + MouseEvent drag_event(Event::ET_MOUSE_DRAGGED, + pt.x, + pt.y, + Event::ConvertWindowsFlags(flags)); + root_view_.OnMouseDragged(drag_event); +} + +void VistaFrame::ProcessMouseReleased(const CPoint& pt, UINT flags) { + using namespace ChromeViews; + if (in_drag_session_) { + in_drag_session_ = false; + ReleaseCapture(); + } + MouseEvent mouse_released(Event::ET_MOUSE_RELEASED, + pt.x, + pt.y, + Event::ConvertWindowsFlags(flags)); + root_view_.OnMouseReleased(mouse_released, false); +} + +void VistaFrame::ProcessMouseMoved(const CPoint &pt, UINT flags) { + using namespace ChromeViews; + MouseEvent mouse_move(Event::ET_MOUSE_MOVED, + pt.x, + pt.y, + Event::ConvertWindowsFlags(flags)); + root_view_.OnMouseMoved(mouse_move); +} + +void VistaFrame::ProcessMouseExited() { + root_view_.ProcessOnMouseExited(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// ChromeViews::ViewContainer +// +//////////////////////////////////////////////////////////////////////////////// + +void VistaFrame::GetBounds(CRect *out, bool including_frame) const { + if (including_frame) { + GetWindowRect(out); + } else { + GetClientRect(out); + + POINT p = {0, 0}; + ::ClientToScreen(*this, &p); + + out->left += p.x; + out->top += p.y; + out->right += p.x; + out->bottom += p.y; + } +} + +void VistaFrame::MoveToFront(bool should_activate) { + int flags = SWP_NOMOVE | SWP_NOSIZE; + if (!should_activate) { + flags |= SWP_NOACTIVATE; + } + SetWindowPos(HWND_TOP, 0, 0, 0, 0, flags); + SetForegroundWindow(*this); +} + +HWND VistaFrame::GetHWND() const { + return m_hWnd; +} + +void VistaFrame::PaintNow(const CRect& update_rect) { + if (!update_rect.IsRectNull() && IsVisible()) { + RedrawWindow(update_rect, + NULL, + RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_NOERASE); + } +} + +ChromeViews::RootView* VistaFrame::GetRootView() { + return const_cast<ChromeViews::RootView*>(&root_view_); +} + +bool VistaFrame::IsVisible() { + return !!::IsWindowVisible(*this); +} + +bool VistaFrame::IsActive() { + return win_util::IsWindowActive(*this); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// VistaFrameView +// +//////////////////////////////////////////////////////////////////////////////// +void VistaFrame::VistaFrameView::PaintContentsBorder(ChromeCanvas* canvas, + int x, + int y, + int w, + int h) { + if (!parent_->IsTabStripVisible()) + return; + int ro, bo; + canvas->DrawBitmapInt(*g_bitmaps[CT_TOP_LEFT_CORNER], x, y); + canvas->TileImageInt(*g_bitmaps[CT_TOP_CENTER], + x + g_bitmaps[CT_TOP_LEFT_CORNER]->width(), + y, + w - g_bitmaps[CT_TOP_LEFT_CORNER]->width() - + g_bitmaps[CT_TOP_RIGHT_CORNER]->width(), + g_bitmaps[CT_TOP_CENTER]->height()); + ro = x + w - g_bitmaps[CT_TOP_RIGHT_CORNER]->width(); + canvas->DrawBitmapInt(*g_bitmaps[CT_TOP_RIGHT_CORNER], ro, y); + canvas->TileImageInt(*g_bitmaps[CT_RIGHT_SIDE], + ro, + y + g_bitmaps[CT_TOP_RIGHT_CORNER]->height(), + g_bitmaps[CT_RIGHT_SIDE]->width(), + h - (g_bitmaps[CT_TOP_RIGHT_CORNER]->height() + + g_bitmaps[CT_BOTTOM_RIGHT_CORNER]->height())); + bo = y + h - g_bitmaps[CT_BOTTOM_RIGHT_CORNER]->height(); + canvas->DrawBitmapInt(*g_bitmaps[CT_BOTTOM_RIGHT_CORNER], + x + w - g_bitmaps[CT_BOTTOM_RIGHT_CORNER]->width(), + bo); + + canvas->TileImageInt(*g_bitmaps[CT_BOTTOM_CENTER], + x + g_bitmaps[CT_BOTTOM_LEFT_CORNER]->width(), + bo, + w - (g_bitmaps[CT_BOTTOM_LEFT_CORNER]->width() + + g_bitmaps[CT_BOTTOM_RIGHT_CORNER]->width()), + g_bitmaps[CT_BOTTOM_CENTER]->height()); + canvas->DrawBitmapInt(*g_bitmaps[CT_BOTTOM_LEFT_CORNER], x, bo); + canvas->TileImageInt(*g_bitmaps[CT_LEFT_SIDE], + x, + y + g_bitmaps[CT_TOP_LEFT_CORNER]->height(), + g_bitmaps[CT_LEFT_SIDE]->width(), + h - (g_bitmaps[CT_TOP_LEFT_CORNER]->height() + + g_bitmaps[CT_BOTTOM_LEFT_CORNER]->height())); +} + +void VistaFrame::VistaFrameView::Paint(ChromeCanvas* canvas) { + canvas->save(); + + // When painting the border, exclude the contents area. This will prevent the + // border bitmaps (which might be larger than the visible area) from coming + // into the content area when there is no tab painted yet. + int x = parent_->tab_contents_container_->GetX(); + int y = parent_->tab_contents_container_->GetY(); + SkRect clip; + clip.set(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(x + parent_->tab_contents_container_->GetWidth()), + SkIntToScalar(y + parent_->tab_contents_container_->GetHeight())); + canvas->clipRect(clip, SkRegion::kDifference_Op); + + PaintContentsBorder(canvas, + 0, + contents_offset_, + GetWidth(), + GetHeight() - contents_offset_); + + canvas->restore(); +} + +void VistaFrame::VistaFrameView::SetContentsOffset(int o) { + contents_offset_ = o; +} + +bool VistaFrame::VistaFrameView::GetAccessibleRole(VARIANT* role) { + DCHECK(role); + + role->vt = VT_I4; + role->lVal = ROLE_SYSTEM_CLIENT; + return true; +} + +bool VistaFrame::VistaFrameView::GetAccessibleName(std::wstring* name) { + if (!accessible_name_.empty()) { + name->assign(accessible_name_); + return true; + } + return false; +} + +void VistaFrame::VistaFrameView::SetAccessibleName(const std::wstring& name) { + accessible_name_.assign(name); +} + +// Helper function to extract the min/max x-coordinate as well as the max +// y coordinate from the TITLEBARINFOEX struct at the specified index. +static void UpdatePosition(const TITLEBARINFOEX& info, + int element, + int* min_x, + int* max_x, + int* max_y) { + if ((info.rgstate[element] & (STATE_SYSTEM_INVISIBLE | + STATE_SYSTEM_OFFSCREEN | + STATE_SYSTEM_UNAVAILABLE)) == 0) { + *min_x = std::min(*min_x, static_cast<int>(info.rgrect[element].left)); + *max_x = std::max(*max_x, static_cast<int>(info.rgrect[element].right)); + *max_y = std::max(*max_y, static_cast<int>(info.rgrect[element].bottom)); + } +} + +bool VistaFrame::VistaFrameView::ShouldForwardToTabStrip( + const ChromeViews::DropTargetEvent& event) { + if (!FrameView::ShouldForwardToTabStrip(event)) + return false; + + TITLEBARINFOEX titlebar_info; + titlebar_info.cbSize = sizeof(TITLEBARINFOEX); + SendMessage(parent_->m_hWnd, WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info); + + int min_x = std::numeric_limits<int>::max(); + int max_x = std::numeric_limits<int>::min(); + int max_y = std::numeric_limits<int>::min(); + + // 2 is the minimize button. + UpdatePosition(titlebar_info, 2, &min_x, &max_x, &max_y); + // 3 is the maximize button. + UpdatePosition(titlebar_info, 3, &min_x, &max_x, &max_y); + // 5 is the close button. + UpdatePosition(titlebar_info, 5, &min_x, &max_x, &max_y); + + if (min_x != std::numeric_limits<int>::max() && + max_x != std::numeric_limits<int>::min() && + max_y != std::numeric_limits<int>::min()) { + CPoint screen_drag_point(event.GetX(), event.GetY()); + ConvertPointToScreen(this, &screen_drag_point); + if (screen_drag_point.x >= min_x && screen_drag_point.x <= max_x && + screen_drag_point.y <= max_y) { + return false; + } + } + return true; +} + +LRESULT VistaFrame::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled) { + // Tooltip handling is broken in Vista when using custom frames, so + // we have to implement a lot of this ourselves. + tooltip_manager_->OnMouse(u_msg, w_param, l_param); + handled = FALSE; + + return 0; +} + +LRESULT VistaFrame::OnNotify(int w_param, NMHDR* l_param) { + bool handled; + LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled); + SetMsgHandled(handled); + return result; +} + +ChromeViews::TooltipManager* VistaFrame::GetTooltipManager() { + return tooltip_manager_.get(); +} + +StatusBubble* VistaFrame::GetStatusBubble() { + return NULL; +} + +void VistaFrame::InitAfterHWNDCreated() { + tooltip_manager_.reset(new ChromeViews::AeroTooltipManager(this, m_hWnd)); +} + +void VistaFrame::ResetDWMFrame() { + if (IsTabStripVisible()) { + // Note: we don't use DwmEnableBlurBehindWindow because any region not + // included in the glass region is composited source over. This means + // that anything drawn directly with GDI appears fully transparent. + // + // We want this region to extend past our content border images, as they + // may be partially-transparent. + MARGINS margins = {kDwmBorderSize + + g_bitmaps[CT_TOP_LEFT_CORNER]->width(), + kDwmBorderSize + + g_bitmaps[CT_TOP_RIGHT_CORNER]->width(), + kDwmBorderSize + + IsToolBarVisible() ? + browser_view_->GetY() + kToolbarOverlapVertOffset : + tabstrip_->GetHeight(), + kDwmBorderSize + + g_bitmaps[CT_BOTTOM_CENTER]->height()}; + + DwmExtendFrameIntoClientArea(*this, &margins); + } +} + +void VistaFrame::ShelfVisibilityChanged() { + ShelfVisibilityChangedImpl(browser_->GetSelectedTabContents()); +} + +void VistaFrame::SelectedTabToolbarSizeChanged(bool is_animating) { + if (is_animating) { + tab_contents_container_->set_fast_resize(true); + ShelfVisibilityChanged(); + tab_contents_container_->set_fast_resize(false); + } else { + ShelfVisibilityChanged(); + tab_contents_container_->UpdateHWNDBounds(); + } +} + +bool VistaFrame::UpdateChildViewAndLayout(ChromeViews::View* new_view, + ChromeViews::View** view) { + DCHECK(view); + if (*view == new_view) { + // The views haven't changed, if the views pref changed schedule a layout. + if (new_view) { + CSize pref_size; + new_view->GetPreferredSize(&pref_size); + if (pref_size.cy != new_view->GetHeight()) + return true; + } + return false; + } + + // The views differ, and one may be null (but not both). Remove the old + // view (if it non-null), and add the new one (if it is non-null). If the + // height has changed, schedule a layout, otherwise reuse the existing + // bounds to avoid scheduling a layout. + + int current_height = 0; + if (*view) { + current_height = (*view)->GetHeight(); + root_view_.RemoveChildView(*view); + } + + int new_height = 0; + if (new_view) { + CSize preferred_size; + new_view->GetPreferredSize(&preferred_size); + new_height = preferred_size.cy; + root_view_.AddChildView(new_view); + } + + bool changed = false; + if (new_height != current_height) { + changed = true; + } else if (new_view && *view) { + // The view changed, but the new view wants the same size, give it the + // bounds of the last view and have it repaint. + CRect last_bounds; + (*view)->GetBounds(&last_bounds); + new_view->SetBounds(last_bounds.left, last_bounds.top, + last_bounds.Width(), last_bounds.Height()); + new_view->SchedulePaint(); + } else if (new_view) { + DCHECK(new_height == 0); + // The heights are the same, but the old view is null. This only happens + // when the height is zero. Zero out the bounds. + new_view->SetBounds(0, 0, 0, 0); + } + *view = new_view; + return changed; +} + +void VistaFrame::SetWindowTitle(const std::wstring& title) { + SetWindowText(title.c_str()); +} + +void VistaFrame::Activate() { + if (IsIconic()) + ShowWindow(SW_RESTORE); + MoveToFront(true); +} + +void VistaFrame::FlashFrame() { + FLASHWINFO flash_window_info; + flash_window_info.cbSize = sizeof(FLASHWINFO); + flash_window_info.hwnd = GetHWND(); + flash_window_info.dwFlags = FLASHW_ALL; + flash_window_info.uCount = 4; + flash_window_info.dwTimeout = 0; + ::FlashWindowEx(&flash_window_info); +} + +void VistaFrame::ShowTabContents(TabContents* selected_contents) { + tab_contents_container_->SetTabContents(selected_contents); + + // Force a LoadingStateChanged notification because the TabContents + // could be loading (such as when the user unconstrains a tab. + if (selected_contents && selected_contents->delegate()) + selected_contents->delegate()->LoadingStateChanged(selected_contents); + + ShelfVisibilityChangedImpl(selected_contents); +} + +TabStrip* VistaFrame::GetTabStrip() const { + return tabstrip_; +} + +void VistaFrame::ContinueDetachConstrainedWindowDrag(const gfx::Point& mouse_pt, + int frame_component) { + // Need to force a paint at this point so that the newly created window looks + // correct. (Otherwise parts of the tabstrip are clipped). + CRect cr; + GetClientRect(&cr); + PaintNow(cr); + + // The user's mouse is already moving, and the left button is down, but we + // need to start moving this frame, so we _post_ it a NCLBUTTONDOWN message + // with the HTCAPTION flag to trick windows into believing the user just + // started dragging on the title bar. All the frame moving is then handled + // automatically by windows. Note that we use PostMessage here since we need + // to return to the message loop first otherwise Windows' built in move code + // will not be able to be triggered. + POINTS pts; + pts.x = mouse_pt.x(); + pts.y = mouse_pt.y(); + PostMessage(WM_NCLBUTTONDOWN, frame_component, + reinterpret_cast<LPARAM>(&pts)); +} + +void VistaFrame::SizeToContents(const gfx::Rect& contents_bounds) { + // First we need to ensure everything has an initial size. Currently, the + // window has the wrong size, but that's OK, doing this will allow us to + // figure out how big all the UI bits are. + Layout(); + + // Now figure out the height of the non-client area (the Native windows + // chrome) by comparing the window bounds to the client bounds. + CRect window_bounds, client_bounds; + GetBounds(&window_bounds, true); + GetBounds(&client_bounds, false); + int left_edge_width = client_bounds.left - window_bounds.left; + int top_edge_height = client_bounds.top - window_bounds.top; + int right_edge_width = window_bounds.right - client_bounds.right; + int bottom_edge_height = window_bounds.bottom - client_bounds.bottom; + + // Now resize the window. This will result in Layout() getting called again + // and the contents getting sized to the value specified in |contents_bounds| + SetWindowPos(NULL, contents_bounds.x() - left_edge_width, + contents_bounds.y() - top_edge_height, + contents_bounds.width() + left_edge_width + right_edge_width, + contents_bounds.height() + top_edge_height + bottom_edge_height, + SWP_NOZORDER | SWP_NOACTIVATE); +} + +void VistaFrame::SetIsOffTheRecord(bool value) { + is_off_the_record_ = value; +} + +TabContentsContainerView* VistaFrame::GetTabContentsContainer() { + return tab_contents_container_; +} + +void VistaFrame::DestroyBrowser() { + // TODO(beng): (Cleanup) tidy this up, just fixing the build red for now. + // Need to do this first, before the browser_ is deleted and we can't remove + // the tabstrip from the model's observer list because the model was + // destroyed with browser_. + if (browser_) { + if (bookmark_bar_view_.get() && bookmark_bar_view_->GetParent()) { + // The bookmark bar should not be parented by the time we get here. + // If you hit this NOTREACHED file a bug with the trace. + NOTREACHED(); + bookmark_bar_view_->GetParent()->RemoveChildView(bookmark_bar_view_.get()); + } + + // Explicitly delete the BookmarkBarView now. That way we don't have to + // worry about the BookmarkBarView potentially outliving the Browser & + // Profile. + bookmark_bar_view_.reset(NULL); + + browser_->tabstrip_model()->RemoveObserver(tabstrip_); + delete browser_; + browser_ = NULL; + } +} + +void VistaFrame::ShelfVisibilityChangedImpl(TabContents* current_tab) { + // Coalesce layouts. + bool changed = false; + + ChromeViews::View* new_shelf = NULL; + if (current_tab && current_tab->IsDownloadShelfVisible()) + new_shelf = current_tab->GetDownloadShelfView(); + changed |= UpdateChildViewAndLayout(new_shelf, &shelf_view_); + + ChromeViews::View* new_info_bar = NULL; + if (current_tab && current_tab->IsInfoBarVisible()) + new_info_bar = current_tab->GetInfoBarView(); + changed |= UpdateChildViewAndLayout(new_info_bar, &info_bar_view_); + + ChromeViews::View* new_bookmark_bar_view = NULL; + if (SupportsBookmarkBar()) + new_bookmark_bar_view = GetBookmarkBarView(); + changed |= UpdateChildViewAndLayout(new_bookmark_bar_view, + &active_bookmark_bar_); + + // Only do a layout if the current contents is non-null. We assume that if the + // contents is NULL, we're either being destroyed, or ShowTabContents is going + // to be invoked with a non-null TabContents again so that there is no need + // in doing a layout now (and would result in extra work/invalidation on + // tab switches). + if (changed && current_tab) + Layout(); +} diff --git a/chrome/browser/views/old_frames/vista_frame.h b/chrome/browser/views/old_frames/vista_frame.h new file mode 100644 index 0000000..b812db1 --- /dev/null +++ b/chrome/browser/views/old_frames/vista_frame.h @@ -0,0 +1,414 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_OLD_FRAMES_VISTA_FRAME_H__ +#define CHROME_BROWSER_VIEWS_OLD_FRAMES_VISTA_FRAME_H__ + +#include <windows.h> +#include <atlbase.h> +#include <atlcrack.h> +#include <atlapp.h> +#include <atlframe.h> + +#include "base/message_loop.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/views/old_frames/frame_view.h" +#include "chrome/browser/views/status_bubble.h" +#include "chrome/views/view_container.h" +#include "chrome/views/root_view.h" +#include "chrome/views/hwnd_view.h" +#include "chrome/views/image_view.h" +#include "chrome/views/tooltip_manager.h" + +#define VISTA_FRAME_CLASSNAME L"Chrome_VistaFrame" + +class BookmarkBarView; +class Browser; +class BrowserView; +class TabContentsContainerView; +class ChromeViews::FocusManager; +class SkBitmap; +class TabStrip; + +//////////////////////////////////////////////////////////////////////////////// +// +// VistaFrame class +// +// A CWindowImpl subclass that implements our main frame on Windows Vista +// +//////////////////////////////////////////////////////////////////////////////// +class VistaFrame : public BrowserWindow, + public CWindowImpl<VistaFrame, + CWindow, + CWinTraits<WS_OVERLAPPEDWINDOW | + WS_CLIPCHILDREN>>, + public ChromeViews::ViewContainer, + public ChromeViews::AcceleratorTarget { + public: + // Create a new VistaFrame given the bounds and provided browser. + // |bounds| may be empty to let Windows decide where to place the window. + // The browser_window object acts both as a container for the actual + // browser contents as well as a source for the tab strip and the toolbar. + // |is_off_the_record| defines whether this window should represent an off the + // record session. + // + // Note: this method creates an HWND for the frame but doesn't initialize + // the view hierarchy. The browser creates its HWND from the frame HWND + // and then calls Init() on the frame to finalize the initialization + static VistaFrame* CreateFrame(const gfx::Rect& bounds, + Browser* browser, + bool is_off_the_record); + + virtual ~VistaFrame(); + + //////////////////////////////////////////////////////////////////////////////// + // Events + //////////////////////////////////////////////////////////////////////////////// + + DECLARE_FRAME_WND_CLASS_EX(VISTA_FRAME_CLASSNAME, + IDR_MAINFRAME, + CS_DBLCLKS, + NULL) + + BEGIN_MSG_MAP(VistaFrame) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) + MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseRange) + MESSAGE_HANDLER(WM_NCMOUSELEAVE, OnMouseRange) + MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseRange) + MESSAGE_RANGE_HANDLER(WM_SETTINGCHANGE, WM_SETTINGCHANGE, OnSettingChange) + MSG_WM_LBUTTONDOWN(OnMouseButtonDown) + MSG_WM_LBUTTONUP(OnLButtonUp); + MSG_WM_LBUTTONDBLCLK(OnMouseButtonDblClk) + MSG_WM_MBUTTONDOWN(OnMouseButtonDown) + MSG_WM_MBUTTONUP(OnMButtonUp); + MSG_WM_MBUTTONDBLCLK(OnMouseButtonDblClk); + MSG_WM_RBUTTONDOWN(OnMouseButtonDown) + MSG_WM_RBUTTONUP(OnRButtonUp); + MSG_WM_NCMBUTTONDOWN(OnNCMButtonDown) + MSG_WM_NCRBUTTONDOWN(OnNCRButtonDown) + MSG_WM_RBUTTONDBLCLK(OnMouseButtonDblClk); + MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject); // To avoid edit atlcrack.h. + MSG_WM_KEYDOWN(OnKeyDown); + MSG_WM_KEYUP(OnKeyUp); + MSG_WM_MOUSEMOVE(OnMouseMove) + MSG_WM_MOUSELEAVE(OnMouseLeave) + MSG_WM_CLOSE(Close) // Note: Calls Close() directly, there is no OnClose() + MSG_WM_ENDSESSION(OnEndSession) + MSG_WM_APPCOMMAND(OnAppCommand) + MSG_WM_COMMAND(OnCommand) + MSG_WM_SYSCOMMAND(OnSysCommand) + MSG_WM_SIZE(OnSize) + MSG_WM_MOVE(OnMove) + MSG_WM_MOVING(OnMoving) + MSG_WM_ACTIVATE(OnActivate) + MSG_WM_PAINT(OnPaint) + MSG_WM_ERASEBKGND(OnEraseBkgnd) + MSG_WM_NCHITTEST(OnNCHitTest) + MSG_WM_NCCALCSIZE(OnNCCalcSize) + MSG_WM_CAPTURECHANGED(OnCaptureChanged) + MSG_WM_NOTIFY(OnNotify) + MSG_WM_NCLBUTTONDOWN(OnNCLButtonDown) + MSG_WM_NCACTIVATE(OnNCActivate) + MSG_WM_MOUSEACTIVATE(OnMouseActivate) + MSG_WM_POWERBROADCAST(OnPowerBroadcast) + MSG_WM_THEMECHANGED(OnThemeChanged) + REFLECT_NOTIFICATIONS() + END_MSG_MAP() + + void OnEndSession(BOOL ending, UINT logoff); + void OnActivate(UINT n_state, BOOL is_minimized, HWND other); + int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message); + void OnMouseButtonDown(UINT flags, const CPoint& pt); + void OnMouseButtonUp(UINT flags, const CPoint& pt); + void OnLButtonUp(UINT flags, const CPoint& pt); + void OnMouseButtonDblClk(UINT flags, const CPoint& pt); + void OnMButtonUp(UINT flags, const CPoint& pt); + void OnRButtonUp(UINT flags, const CPoint& pt); + void OnNCMButtonDown(UINT flags, const CPoint& pt); + void OnNCRButtonDown(UINT flags, const CPoint& pt); + void OnMouseMove(UINT flags, const CPoint& pt); + void OnMouseLeave(); + void OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags); + void OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags); + LRESULT OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param); + LRESULT OnAppCommand( + HWND w_param, short app_command, WORD device, int keystate); + void OnCommand(UINT notification_code, int command_id, HWND window); + void OnSysCommand(UINT notification_code, CPoint click); + void OnMove(const CSize& size); + void OnMoving(UINT param, const LPRECT new_bounds); + void OnSize(UINT param, const CSize& size); + void OnFinalMessage(HWND hwnd); + void OnPaint(HDC dc); + LRESULT OnEraseBkgnd(HDC dc); + + void ArmOnMouseLeave(); + void OnCaptureChanged(HWND hwnd); + LRESULT OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled); + LRESULT OnNotify(int w_param, NMHDR* hdr); + LRESULT OnSettingChange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled); + LRESULT OnNCActivate(BOOL param); + BOOL OnPowerBroadcast(DWORD power_event, DWORD data); + void OnThemeChanged(); + + //////////////////////////////////////////////////////////////////////////////// + // BrowserWindow implementation + //////////////////////////////////////////////////////////////////////////////// + + virtual void Init(); + virtual void Show(int command, bool adjust_to_fit); + virtual void Close(); + virtual void* GetPlatformID(); + virtual void ShowTabContents(TabContents* contents); + virtual TabStrip* GetTabStrip() const; + virtual void ContinueDetachConstrainedWindowDrag( + const gfx::Point& mouse_pt, + int frame_component); + virtual void SizeToContents(const gfx::Rect& contents_bounds); + virtual void SetAcceleratorTable( + std::map<ChromeViews::Accelerator, int>* accelerator_table); + virtual bool AcceleratorPressed(const ChromeViews::Accelerator& accelerator); + virtual gfx::Rect GetNormalBounds(); + virtual bool IsMaximized(); + virtual gfx::Rect GetBoundsForContentBounds(const gfx::Rect content_rect); + virtual void InfoBubbleShowing(); + virtual ToolbarStarToggle* GetStarButton() const; + virtual LocationBarView* GetLocationBarView() const; + virtual GoButton* GetGoButton() const; + virtual BookmarkBarView* GetBookmarkBarView(); + virtual BrowserView* GetBrowserView() const; + virtual void UpdateToolbar(TabContents* contents, bool should_restore_state); + virtual void ProfileChanged(Profile* profile); + virtual void FocusToolbar(); + virtual bool IsBookmarkBarVisible() const; + + //////////////////////////////////////////////////////////////////////////////// + // ChromeViews::ViewContainer + //////////////////////////////////////////////////////////////////////////////// + + virtual void GetBounds(CRect *out, bool including_frame) const; + virtual void MoveToFront(bool should_activate); + virtual HWND GetHWND() const; + virtual void PaintNow(const CRect& update_rect); + virtual ChromeViews::RootView* GetRootView(); + virtual bool IsVisible(); + virtual bool IsActive(); + virtual ChromeViews::TooltipManager* GetTooltipManager(); + virtual StatusBubble* GetStatusBubble(); + virtual bool GetAccelerator(int cmd_id, + ChromeViews::Accelerator* accelerator); + + virtual void ShelfVisibilityChanged(); + virtual void SelectedTabToolbarSizeChanged(bool is_animating); + virtual void SetWindowTitle(const std::wstring& title); + virtual void Activate(); + virtual void FlashFrame(); + + protected: + explicit VistaFrame(Browser* browser); + + // For subclassers. + virtual bool IsTabStripVisible() const { return true; } + virtual bool IsToolBarVisible() const { return true; } + virtual bool SupportsBookmarkBar() const { return true; } + + // Invoked after the HWND has been created but before the window is showing. + // This registers tooltips. If you override, be sure and invoke this + // implementation. + virtual void InitAfterHWNDCreated(); + + // Override as needed. + virtual LRESULT OnNCHitTest(const CPoint& pt); + virtual LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param); + virtual void OnNCLButtonDown(UINT flags, const CPoint& pt); + + // Create a default tab strip. Override as needed. + virtual TabStrip* CreateTabStrip(Browser* browser); + + // Set whether this frame represents an off the record session. This is + // currently only called during initialization. + void SetIsOffTheRecord(bool value); + + // Layout the various views + virtual void Layout(); + + // Return the tab contents container. + TabContentsContainerView* GetTabContentsContainer(); + + virtual void DestroyBrowser(); + + // The Browser that created this frame + Browser* browser_; + + // Top level frame view + class VistaFrameView; + VistaFrameView* frame_view_; + + friend class VistaFrameView; + + // The view we use to display the background under tab / toolbar area + class VistaFrameView : public FrameView { + public: + explicit VistaFrameView(VistaFrame* parent) + : FrameView(parent), + contents_offset_(0), + parent_(parent) { + } + + virtual void Paint(ChromeCanvas* canvas); + + void SetContentsOffset(int o); + + // Accessibility information + bool GetAccessibleRole(VARIANT* role); + + // Returns a brief, identifying string, containing a unique, readable name. + bool GetAccessibleName(std::wstring* name); + + // Assigns an accessible string name. + void SetAccessibleName(const std::wstring& name); + + protected: + // Overriden to return false if over the min/max/close buttons of the frame. + virtual bool ShouldForwardToTabStrip( + const ChromeViews::DropTargetEvent& event); + + private: + void PaintContentsBorder(ChromeCanvas* canvas, + int x, + int y, + int w, + int h); + + int contents_offset_; + + VistaFrame* parent_; + + // Storage of strings needed for accessibility. + std::wstring accessible_name_; + + DISALLOW_EVIL_CONSTRUCTORS(VistaFrameView); + }; + + private: + // + // View events propagation + // + bool ProcessMousePressed(const CPoint& pt, UINT flags, bool dbl_click); + void ProcessMouseDragged(const CPoint& pt, UINT flags); + void ProcessMouseReleased(const CPoint& pt, UINT flags); + void ProcessMouseMoved(const CPoint &pt, UINT flags); + void ProcessMouseExited(); + + // Reset the black DWM frame (the black non-glass area with lightly-colored + // border that sits behind our content). Generally there's no single place + // to call this, as Vista likes to reset the frame in different situations + // (return from maximize, non-composited > composited, app launch), and + // the notifications we receive and the timing of those notifications + // varies so wildly that we end up having to call this in many different + // message handlers. + void ResetDWMFrame(); + + // Initialize static members the first time this is invoked + static void InitializeIfNeeded(); + + // Updates a single view. If *view differs from new_view the old view is + // removed and the new view is added. + // + // This is intended to be used when swapping in/out child views that are + // referenced via a field. + // + // This function returns true if anything was changed. The caller should + // ensure that Layout() is eventually called in this case. + bool UpdateChildViewAndLayout(ChromeViews::View* new_view, + ChromeViews::View** view); + + // Implementation for ShelfVisibilityChanged(). Updates the various shelf + // fields. If one of the shelves has changed (or it's size has changed) and + // current_tab is non-NULL layout occurs. + void ShelfVisibilityChangedImpl(TabContents* current_tab); + + // Root view + ChromeViews::RootView root_view_; + + // Tooltip Manager + scoped_ptr<ChromeViews::TooltipManager> tooltip_manager_; + + // The optional container for the off the record icon. + ChromeViews::ImageView* off_the_record_image_; + + // The container for the distributor logo. + ChromeViews::ImageView* distributor_logo_; + + // The view that contains the tabs and any associated controls. + TabStrip* tabstrip_; + + // The bookmark bar. This is lazily created. + scoped_ptr<BookmarkBarView> bookmark_bar_view_; + + // The visible bookmark bar. NULL if none is visible. + ChromeViews::View* active_bookmark_bar_; + + // Browser contents + TabContentsContainerView* tab_contents_container_; + + // Whether we enabled our custom window yet. + bool custom_window_enabled_; + + // Whether we saved the window placement yet. + bool saved_window_placement_; + + // whether we are expecting a mouse leave event + bool on_mouse_leave_armed_; + + // whether we are currently processing a view level drag session + bool in_drag_session_; + + // A view positioned at the bottom of the frame. + ChromeViews::View* shelf_view_; + + // A view positioned beneath the bookmark bar view. + // Implementation mirrors shelf_view_ + ChromeViews::View* info_bar_view_; + + // We need to own the text of the menu, the Windows API does not copy it. + std::wstring task_manager_label_text_; + + // A mapping between accelerators and commands. + scoped_ptr<std::map<ChromeViews::Accelerator, int>> accelerator_table_; + + // Whether this frame represents an off the record session. + bool is_off_the_record_; + + // Static resources + static bool g_initialized; + static SkBitmap** g_bitmaps; + + // Instance of accessibility information and handling for MSAA root + CComPtr<IAccessible> accessibility_root_; + + // This is used to make sure we visually look active when the bubble is shown + // even though we aren't active. When the info bubble is shown it takes + // activation. Visually we still want the frame to look active. To make the + // frame look active when we get WM_NCACTIVATE and ignore_ncactivate_ is + // true, we tell the frame it is still active. When the info bubble closes we + // tell the window it is no longer active. This results in painting the + // active frame even though we aren't active. + bool ignore_ncactivate_; + + // Whether we should save the bounds of the window. We don't want to + // save the default size of windows for certain classes of windows + // like unconstrained popups. Defaults to true. + bool should_save_window_placement_; + + // A view that holds the client-area contents of the browser window. + BrowserView* browser_view_; + + DISALLOW_EVIL_CONSTRUCTORS(VistaFrame); +}; +#endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_VISTA_FRAME_H__ + diff --git a/chrome/browser/views/old_frames/xp_frame.cc b/chrome/browser/views/old_frames/xp_frame.cc new file mode 100644 index 0000000..6a33d77 --- /dev/null +++ b/chrome/browser/views/old_frames/xp_frame.cc @@ -0,0 +1,2523 @@ +// Copyright (c) 2006-2008 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/old_frames/xp_frame.h" + +#include <windows.h> + +#include "base/command_line.h" +#include "base/gfx/native_theme.h" +#include "base/gfx/rect.h" +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/frame_util.h" +#include "chrome/browser/suspend_controller.h" +#include "chrome/browser/tab_contents.h" +#include "chrome/browser/tab_contents_container_view.h" +#include "chrome/browser/tabs/tab_strip_model.h" +#include "chrome/browser/view_ids.h" +#include "chrome/browser/views/bookmark_bar_view.h" +#include "chrome/browser/views/download_shelf_view.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/old_frames/point_buffer.h" +#include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/win_util.h" +#include "chrome/views/accessibility/view_accessibility.h" +#include "chrome/views/accelerator.h" +#include "chrome/views/background.h" +#include "chrome/views/event.h" +#include "chrome/views/focus_manager.h" +#include "chrome/views/hwnd_view_container.h" +#include "chrome/views/hwnd_notification_source.h" +#include "chrome/views/tooltip_manager.h" +#include "chrome/views/view.h" + +#include "chromium_strings.h" +#include "generated_resources.h" + +// Needed for accessibility support. +// NOTE(klink): To comply with a directive from Darin, I have added +// this #pragma directive instead of adding "oleacc.lib" to a project file. +#pragma comment(lib, "oleacc.lib") + +// Layout constants and image size dependent values +static const int kZoomedTopMargin = 1; +static const int kZoomedBottomMargin = 1; + +static const int kTopMargin = 16; +static const int kContentBorderHorizOffset = 2; +static const int kContentBorderVertTopOffset = 37; +static const int kContentBorderVertBottomOffset = 2; +static const int kToolbarOverlapVertOffset = 3; +static const int kTabShadowSize = 2; + +static const int kDistributorLogoHorizontalOffset = 7; +static const int kDistributorLogoVerticalOffset = 3; + +// Size of a corner. We use this when drawing a black background in maximized +// mode +static const int kCornerSize = 4; + +// The visual size of the curved window corners - used when masking out the +// corners when resizing. This should vary as the shape of the curve varies +// in OnSize. +static const int kCurvedCornerSize = 3; + +static int g_title_bar_height; +static int g_bottom_margin; +static int g_left_margin; +static int g_right_margin; + +static const int kResizeAreaSize = 5; +static const int kResizeAreaNorthSize = 3; +static const int kResizeAreaCornerSize = 16; +static const int kWindowControlsTopOffset = 1; +static const int kWindowControlsRightOffset = 4; +static const int kWindowControlsTopZoomedOffset = 1; +static const int kWindowControlsRightZoomedOffset = 3; + +// Number of pixels still visible when the toolbar is invisible. +static const int kCollapsedToolbarHeight = 4; + +// Minimum title bar height used when the tab strip is not visible. +static const int kMinTitleBarHeight = 25; + +// OTR image offsets. +static const int kOTRImageHorizMargin = 2; +static const int kOTRImageVertMargin = 2; + +// The line drawn to separate tab end contents. +static const int kSeparationLineHeight = 1; +static const SkColor kSeparationLineColor = SkColorSetRGB(178, 178, 178); + +// Padding between the tab strip and the window controls in maximized mode. +static const int kZoomedStripPadding = 16; + +using ChromeViews::Accelerator; +using ChromeViews::FocusManager; + +//////////////////////////////////////////////////////////////////////////////// +// +// RegionsUnderInfo class +// +// A facility to enumerate the windows obscured by a window. For each window, +// a region is provided. +// +//////////////////////////////////////////////////////////////////////////////// +class RegionsUnderInfo { + public: + explicit RegionsUnderInfo(HWND hwnd) : hwnd_(hwnd), + found_hwnd_(false) { + CRect window_rect; + ::GetWindowRect(hwnd, &window_rect); + hwnd_rgn_ = ::CreateRectRgn(window_rect.left, window_rect.top, + window_rect.right, window_rect.bottom); + Init(); + } + + ~RegionsUnderInfo() { + int i, region_count; + region_count = static_cast<int>(regions_.size()); + for (i = 0; i < region_count; i++) { + ::DeleteObject(regions_[i]); + } + + ::DeleteObject(hwnd_rgn_); + } + + int GetWindowCount() { + return static_cast<int>(windows_.size()); + } + + HWND GetWindowAt(int index) { + return windows_[index]; + } + + HRGN GetRegionAt(int index) { + return regions_[index]; + } + + private: + static BOOL CALLBACK WindowEnumProc(HWND hwnd, LPARAM lParam) { + RegionsUnderInfo* rui = + reinterpret_cast<RegionsUnderInfo*>(lParam); + + if (hwnd == rui->hwnd_) { + rui->found_hwnd_ = true; + return TRUE; + } + + int status = ERROR; + bool should_delete_rgn = true; + if (rui->found_hwnd_) { + if (::IsWindowVisible(hwnd)) { + RECT r; + ::GetWindowRect(hwnd, &r); + HRGN tmp = ::CreateRectRgn(r.left, r.top, r.right, r.bottom); + if (::CombineRgn(tmp, + rui->hwnd_rgn_, + tmp, + RGN_AND) != NULLREGION) { + // Remove that intersection to exclude any window below + int status = ::CombineRgn(rui->hwnd_rgn_, + rui->hwnd_rgn_, + tmp, + RGN_DIFF); + + // We have an interesction, add it with the region in hwnd + // coordinate system + ::OffsetRgn(tmp, -r.left, -r.top); + rui->windows_.push_back(hwnd); + rui->regions_.push_back(tmp); + should_delete_rgn = false; + } + if (should_delete_rgn) { + ::DeleteObject(tmp); + } + } + } + + // If hwnd_rgn_ is NULL, we are done + if (status == NULLREGION) { + return FALSE; + } else { + return TRUE; + } + } + + void Init() { + ::EnumWindows(WindowEnumProc, reinterpret_cast<LPARAM>(this)); + } + + + HWND hwnd_; + HRGN hwnd_rgn_; + bool found_hwnd_; + std::vector<HWND> windows_; + std::vector<HRGN> regions_; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// XPFrame implementation +// +//////////////////////////////////////////////////////////////////////////////// + +// static +bool XPFrame::g_initialized = FALSE; + +// static +HCURSOR XPFrame::g_resize_cursors[4]; + +// static +SkBitmap** XPFrame::g_bitmaps; + +// static +SkBitmap** XPFrame::g_otr_bitmaps; + +// Possible frame action. +enum FrameActionTag { + MINIATURIZE_TAG = 0, + MAXIMIZE_TAG, + RESTORE_TAG, + CLOSE_TAG, +}; + +static const int kImageNames[] = { IDR_WINDOW_BOTTOM_CENTER, + IDR_WINDOW_BOTTOM_LEFT_CORNER, + IDR_WINDOW_BOTTOM_RIGHT_CORNER, + IDR_WINDOW_LEFT_SIDE, + IDR_WINDOW_RIGHT_SIDE, + IDR_WINDOW_TOP_CENTER, + IDR_WINDOW_TOP_LEFT_CORNER, + IDR_WINDOW_TOP_RIGHT_CORNER, + IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, + IDR_CONTENT_LEFT_SIDE, + IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_LEFT_CORNER, + IDR_CONTENT_TOP_RIGHT_CORNER, + IDR_DEWINDOW_BOTTOM_CENTER, + IDR_DEWINDOW_BOTTOM_LEFT_CORNER, + IDR_DEWINDOW_BOTTOM_RIGHT_CORNER, + IDR_DEWINDOW_LEFT_SIDE, + IDR_DEWINDOW_RIGHT_SIDE, + IDR_DEWINDOW_TOP_CENTER, + IDR_DEWINDOW_TOP_LEFT_CORNER, + IDR_DEWINDOW_TOP_RIGHT_CORNER, + IDR_APP_TOP_LEFT, + IDR_APP_TOP_CENTER, + IDR_APP_TOP_RIGHT +}; + +static const int kOTRImageNames[] = { 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_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, + IDR_CONTENT_LEFT_SIDE, + IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_LEFT_CORNER, + IDR_CONTENT_TOP_RIGHT_CORNER, + IDR_DEWINDOW_BOTTOM_CENTER_OTR, + IDR_DEWINDOW_BOTTOM_LEFT_CORNER_OTR, + IDR_DEWINDOW_BOTTOM_RIGHT_CORNER_OTR, + IDR_DEWINDOW_LEFT_SIDE_OTR, + IDR_DEWINDOW_RIGHT_SIDE_OTR, + IDR_DEWINDOW_TOP_CENTER_OTR, + IDR_DEWINDOW_TOP_LEFT_CORNER_OTR, + IDR_DEWINDOW_TOP_RIGHT_CORNER_OTR, + IDR_APP_TOP_LEFT, + IDR_APP_TOP_CENTER, + IDR_APP_TOP_RIGHT +}; + +typedef enum { BOTTOM_CENTER = 0, BOTTOM_LEFT_CORNER, BOTTOM_RIGHT_CORNER, + LEFT_SIDE, RIGHT_SIDE, TOP_CENTER, TOP_LEFT_CORNER, + TOP_RIGHT_CORNER, CT_BOTTOM_CENTER, + CT_BOTTOM_LEFT_CORNER, CT_BOTTOM_RIGHT_CORNER, CT_LEFT_SIDE, + CT_RIGHT_SIDE, CT_TOP_CENTER, CT_TOP_LEFT_CORNER, + CT_TOP_RIGHT_CORNER, DE_BOTTOM_CENTER, + DE_BOTTOM_LEFT_CORNER, DE_BOTTOM_RIGHT_CORNER, DE_LEFT_SIDE, + DE_RIGHT_SIDE, DE_TOP_CENTER, DE_TOP_LEFT_CORNER, + DE_TOP_RIGHT_CORNER, + APP_TOP_LEFT, APP_TOP_CENTER, APP_TOP_RIGHT +}; + +// static +XPFrame* XPFrame::CreateFrame(const gfx::Rect& bounds, + Browser* browser, + bool is_otr) { + XPFrame* instance = new XPFrame(browser); + instance->Create(NULL, bounds.ToRECT(), + l10n_util::GetString(IDS_PRODUCT_NAME).c_str()); + instance->InitAfterHWNDCreated(); + instance->SetIsOffTheRecord(is_otr); +#ifdef CHROME_PERSONALIZATION + instance->EnablePersonalization(CommandLine().HasSwitch( + switches::kEnableP13n)); +#endif + FocusManager::CreateFocusManager(instance->m_hWnd, &(instance->root_view_)); + return instance; +} + +XPFrame::XPFrame(Browser* browser) + : browser_(browser), + root_view_(this), + frame_view_(NULL), + tabstrip_(NULL), + active_bookmark_bar_(NULL), + tab_contents_container_(NULL), + min_button_(NULL), + max_button_(NULL), + restore_button_(NULL), + close_button_(NULL), + should_save_window_placement_(browser->GetType() != BrowserType::BROWSER), + saved_window_placement_(false), + current_action_(FA_NONE), + on_mouse_leave_armed_(false), + previous_cursor_(NULL), + minimum_size_(100, 100), + shelf_view_(NULL), + bookmark_bar_view_(NULL), + info_bar_view_(NULL), + is_active_(false), + is_off_the_record_(false), + title_bar_height_(0), + off_the_record_image_(NULL), + distributor_logo_(NULL), + ignore_ncactivate_(false), +#ifdef CHROME_PERSONALIZATION + personalization_enabled_(false), + personalization_(NULL), +#endif + paint_as_active_(false), + browser_view_(NULL) { + InitializeIfNeeded(); +} + +XPFrame::~XPFrame() { + DestroyBrowser(); +} + +void XPFrame::InitAfterHWNDCreated() { + tooltip_manager_.reset(new ChromeViews::TooltipManager(this, m_hWnd)); +} + +ChromeViews::TooltipManager* XPFrame::GetTooltipManager() { + return tooltip_manager_.get(); +} + +StatusBubble* XPFrame::GetStatusBubble() { + return NULL; +} + +void XPFrame::InitializeIfNeeded() { + if (!g_initialized) { + g_resize_cursors[RC_VERTICAL] = LoadCursor(NULL, IDC_SIZENS); + g_resize_cursors[RC_HORIZONTAL] = LoadCursor(NULL, IDC_SIZEWE); + g_resize_cursors[RC_NESW] = LoadCursor(NULL, IDC_SIZENESW); + g_resize_cursors[RC_NWSE] = LoadCursor(NULL, IDC_SIZENWSE); + + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + g_bitmaps = new SkBitmap*[arraysize(kImageNames)]; + g_otr_bitmaps = new SkBitmap*[arraysize(kOTRImageNames)]; + for (int i = 0; i < arraysize(kImageNames); i++) { + g_bitmaps[i] = rb.GetBitmapNamed(kImageNames[i]); + g_otr_bitmaps[i] = rb.GetBitmapNamed(kOTRImageNames[i]); + } + + g_bottom_margin = (int) kContentBorderVertBottomOffset + + g_bitmaps[CT_BOTTOM_CENTER]->height(); + g_left_margin = (int) kContentBorderHorizOffset + + g_bitmaps[CT_LEFT_SIDE]->width(); + g_right_margin = g_left_margin; + g_title_bar_height = (int) kContentBorderVertTopOffset + + g_bitmaps[CT_TOP_CENTER]->height(); + + g_initialized = TRUE; + } +} + +void XPFrame::Init() { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + + FrameUtil::RegisterBrowserWindow(this); + + // Link the HWND with its root view so we can retrieve the RootView from the + // HWND for automation purposes. + ChromeViews::SetRootViewForHWND(m_hWnd, &root_view_); + + // Remove the WS_CAPTION explicitely because we don't want a window style + // title bar + SetWindowLongPtr(GWL_STYLE, + (GetWindowLongPtr(GWL_STYLE) & ~WS_CAPTION) | WS_BORDER); + + frame_view_ = new XPFrameView(this); + root_view_.AddChildView(frame_view_); + root_view_.SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); + frame_view_->SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); + + // Use a white background. This will be the color of the content area until + // the first tab has started, so we want it to look minimally jarring when + // it is replaced by web content. + // + // TODO(brettw) if we have a preference for default page background, this + // color should be the same. + root_view_.SetBackground( + ChromeViews::Background::CreateSolidBackground(SK_ColorWHITE)); + + browser_view_ = new BrowserView(this, browser_, NULL, NULL); + frame_view_->AddChildView(browser_view_); + + tabstrip_ = CreateTabStrip(browser_); + tabstrip_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_TABSTRIP)); + frame_view_->AddChildView(tabstrip_); + + tab_contents_container_ = new TabContentsContainerView(); + frame_view_->AddChildView(tab_contents_container_); + +#ifdef CHROME_PERSONALIZATION + if (PersonalizationEnabled()) { + personalization_ = Personalization::CreateFramePersonalization( + browser_->profile(), frame_view_); + } +#endif + + if (is_off_the_record_) { + off_the_record_image_ = new ChromeViews::ImageView(); + SkBitmap* otr_icon = rb.GetBitmapNamed(IDR_OTR_ICON); + off_the_record_image_->SetImage(*otr_icon); + off_the_record_image_->SetTooltipText( + l10n_util::GetString(IDS_OFF_THE_RECORD_TOOLTIP)); + frame_view_->AddChildView(off_the_record_image_); + frame_view_->AddViewToDropList(off_the_record_image_); + } + + SkBitmap* image = rb.GetBitmapNamed(IDR_DISTRIBUTOR_LOGO_LIGHT); + if (!image->isNull()) { + distributor_logo_ = new ChromeViews::ImageView(); + frame_view_->AddViewToDropList(distributor_logo_); + distributor_logo_->SetImage(image); + frame_view_->AddChildView(distributor_logo_); + } + + min_button_ = new ChromeViews::Button(); + min_button_->SetListener(this, MINIATURIZE_TAG); + min_button_->SetImage(ChromeViews::Button::BS_NORMAL, + rb.GetBitmapNamed(IDR_MINIMIZE)); + min_button_->SetImage(ChromeViews::Button::BS_HOT, + rb.GetBitmapNamed(IDR_MINIMIZE_H)); + min_button_->SetImage(ChromeViews::Button::BS_PUSHED, + rb.GetBitmapNamed(IDR_MINIMIZE_P)); + min_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_MINIMIZE)); + min_button_->SetTooltipText( + l10n_util::GetString(IDS_XPFRAME_MINIMIZE_TOOLTIP)); + frame_view_->AddChildView(min_button_); + + max_button_ = new ChromeViews::Button(); + max_button_->SetListener(this, MAXIMIZE_TAG); + max_button_->SetImage(ChromeViews::Button::BS_NORMAL, + rb.GetBitmapNamed(IDR_MAXIMIZE)); + max_button_->SetImage(ChromeViews::Button::BS_HOT, + rb.GetBitmapNamed(IDR_MAXIMIZE_H)); + max_button_->SetImage(ChromeViews::Button::BS_PUSHED, + rb.GetBitmapNamed(IDR_MAXIMIZE_P)); + max_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_MAXIMIZE)); + max_button_->SetTooltipText( + l10n_util::GetString(IDS_XPFRAME_MAXIMIZE_TOOLTIP)); + frame_view_->AddChildView(max_button_); + + restore_button_ = new ChromeViews::Button(); + restore_button_->SetListener(this, RESTORE_TAG); + restore_button_->SetImage(ChromeViews::Button::BS_NORMAL, + rb.GetBitmapNamed(IDR_RESTORE)); + restore_button_->SetImage(ChromeViews::Button::BS_HOT, + rb.GetBitmapNamed(IDR_RESTORE_H)); + restore_button_->SetImage(ChromeViews::Button::BS_PUSHED, + rb.GetBitmapNamed(IDR_RESTORE_P)); + restore_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_RESTORE)); + restore_button_->SetTooltipText( + l10n_util::GetString(IDS_XPFRAME_RESTORE_TOOLTIP)); + frame_view_->AddChildView(restore_button_); + + close_button_ = new ChromeViews::Button(); + close_button_->SetListener(this, CLOSE_TAG); + close_button_->SetImage(ChromeViews::Button::BS_NORMAL, + rb.GetBitmapNamed(IDR_CLOSE)); + close_button_->SetImage(ChromeViews::Button::BS_HOT, + rb.GetBitmapNamed(IDR_CLOSE_H)); + close_button_->SetImage(ChromeViews::Button::BS_PUSHED, + rb.GetBitmapNamed(IDR_CLOSE_P)); + close_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); + close_button_->SetTooltipText( + l10n_util::GetString(IDS_XPFRAME_CLOSE_TOOLTIP)); + frame_view_->AddChildView(close_button_); + + // Add the task manager item to the system menu before the last entry. + task_manager_label_text_ = l10n_util::GetString(IDS_TASKMANAGER); + HMENU system_menu = ::GetSystemMenu(m_hWnd, FALSE); + int index = ::GetMenuItemCount(system_menu) - 1; + if (index < 0) { + // Paranoia check. + index = 0; + } + + // First we add the separator. + MENUITEMINFO menu_info; + memset(&menu_info, 0, sizeof(MENUITEMINFO)); + menu_info.cbSize = sizeof(MENUITEMINFO); + menu_info.fMask = MIIM_FTYPE; + menu_info.fType = MFT_SEPARATOR; + ::InsertMenuItem(system_menu, index, TRUE, &menu_info); + // Then the actual menu. + menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; + menu_info.fType = MFT_STRING; + menu_info.fState = MFS_ENABLED; + menu_info.wID = IDC_TASKMANAGER; + menu_info.dwTypeData = const_cast<wchar_t*>(task_manager_label_text_.c_str()); + ::InsertMenuItem(system_menu, index, TRUE, &menu_info); + + // Register accelerators. + HACCEL accelerators_table = AtlLoadAccelerators(IDR_MAINFRAME); + DCHECK(accelerators_table); + FrameUtil::LoadAccelerators(this, accelerators_table, this); + + ShelfVisibilityChanged(); + root_view_.OnViewContainerCreated(); +} + +TabStrip* XPFrame::CreateTabStrip(Browser* browser) { + return new TabStrip(browser->tabstrip_model()); +} + +void XPFrame::Show(int command, bool adjust_to_fit) { + if (adjust_to_fit) + win_util::AdjustWindowToFit(*this); + ::ShowWindow(*this, command); +} + +void* XPFrame::GetPlatformID() { + return reinterpret_cast<void*>(m_hWnd); +} + +int XPFrame::GetContentsYOrigin() { + int min_y = tab_contents_container_->GetY(); + if (info_bar_view_) + min_y = std::min(min_y, info_bar_view_->GetY()); + + if (bookmark_bar_view_.get()) + min_y = std::min(min_y, bookmark_bar_view_->GetY()); + + return min_y; +} + +SkBitmap** XPFrame::GetFrameBitmaps() { + if (is_off_the_record_) + return g_otr_bitmaps; + else + return g_bitmaps; +} + +void XPFrame::Layout() { + CRect client_rect; + GetClientRect(&client_rect); + int width = client_rect.Width(); + int height = client_rect.Height(); + + root_view_.SetBounds(0, 0, width, height); + frame_view_->SetBounds(0, 0, width, height); + + CSize preferred_size; + + if (IsZoomed()) { + close_button_->GetPreferredSize(&preferred_size); + close_button_->SetImageAlignment(ChromeViews::Button::ALIGN_LEFT, + ChromeViews::Button::ALIGN_BOTTOM); + close_button_->SetBounds(width - preferred_size.cx - + kWindowControlsRightZoomedOffset, + 0, + preferred_size.cx + + kWindowControlsRightZoomedOffset, + preferred_size.cy + + kWindowControlsTopZoomedOffset); + + max_button_->SetVisible(false); + + restore_button_->SetVisible(true); + restore_button_->GetPreferredSize(&preferred_size); + restore_button_->SetImageAlignment(ChromeViews::Button::ALIGN_LEFT, + ChromeViews::Button::ALIGN_BOTTOM); + restore_button_->SetBounds(close_button_->GetX() - preferred_size.cx, + 0, + preferred_size.cx, + preferred_size.cy + + kWindowControlsTopZoomedOffset); + + min_button_->GetPreferredSize(&preferred_size); + min_button_->SetImageAlignment(ChromeViews::Button::ALIGN_LEFT, + ChromeViews::Button::ALIGN_BOTTOM); + min_button_->SetBounds(restore_button_->GetX() - preferred_size.cx, + 0, + preferred_size.cx, + preferred_size.cy + + kWindowControlsTopZoomedOffset); + + } else { + close_button_->GetPreferredSize(&preferred_size); + close_button_->SetImageAlignment(ChromeViews::Button::ALIGN_LEFT, + ChromeViews::Button::ALIGN_TOP); + close_button_->SetBounds(width - kWindowControlsRightOffset - + preferred_size.cx, + kWindowControlsTopOffset, + preferred_size.cx, + preferred_size.cy); + + restore_button_->SetVisible(false); + + max_button_->SetVisible(true); + max_button_->GetPreferredSize(&preferred_size); + max_button_->SetImageAlignment(ChromeViews::Button::ALIGN_LEFT, + ChromeViews::Button::ALIGN_TOP); + max_button_->SetBounds(close_button_->GetX() - preferred_size.cx, + kWindowControlsTopOffset, + preferred_size.cx, + preferred_size.cy); + + min_button_->GetPreferredSize(&preferred_size); + min_button_->SetImageAlignment(ChromeViews::Button::ALIGN_LEFT, + ChromeViews::Button::ALIGN_TOP); + min_button_->SetBounds(max_button_->GetX() - preferred_size.cx, + kWindowControlsTopOffset, + preferred_size.cx, + preferred_size.cy); + } + + int right_limit = min_button_->GetX(); + int left_margin; + int right_margin; + int bottom_margin; + int top_margin; + + SkBitmap** bitmaps = GetFrameBitmaps(); + if (IsZoomed()) { + right_limit -= kZoomedStripPadding; + top_margin = kZoomedTopMargin; + bottom_margin = kZoomedBottomMargin; + left_margin = 0; + right_margin = 0; + } else { + top_margin = kTopMargin; + bottom_margin = g_bottom_margin; + left_margin = g_left_margin; + right_margin = g_right_margin; + } + + int last_y = top_margin - 1; + if (IsTabStripVisible()) { + int tab_strip_x = left_margin; + + if (is_off_the_record_) { + CSize otr_image_size; + off_the_record_image_->GetPreferredSize(&otr_image_size); + tab_strip_x += otr_image_size.cx + (2 * kOTRImageHorizMargin); + if (IsZoomed()) { + off_the_record_image_->SetBounds(left_margin + kOTRImageHorizMargin, + top_margin + 1, + otr_image_size.cx, + tabstrip_->GetPreferredHeight() - + kToolbarOverlapVertOffset - 1); + } else { + off_the_record_image_->SetBounds(left_margin + kOTRImageHorizMargin, + top_margin - 1 + + tabstrip_->GetPreferredHeight() - + otr_image_size.cy - + kOTRImageVertMargin, + otr_image_size.cx, + otr_image_size.cy); + } + } + + if (distributor_logo_) { + if (IsZoomed()) { + distributor_logo_->SetVisible(false); + } else { + CSize distributor_logo_size; + distributor_logo_->GetPreferredSize(&distributor_logo_size); + distributor_logo_->SetVisible(true); + distributor_logo_->SetBounds(min_button_->GetX() - + distributor_logo_size.cx - + kDistributorLogoHorizontalOffset, + kDistributorLogoVerticalOffset, + distributor_logo_size.cx, + distributor_logo_size.cy); + } + } + + tabstrip_->SetBounds(tab_strip_x, top_margin - 1, + right_limit - tab_strip_x - right_margin, + tabstrip_->GetPreferredHeight()); + + last_y = tabstrip_->GetY() + tabstrip_->GetHeight(); + } else { + tabstrip_->SetBounds(0, 0, 0, 0); + tabstrip_->SetVisible(false); + if (is_off_the_record_) + off_the_record_image_->SetVisible(false); + } + + int browser_view_width = width - left_margin - right_margin; +#ifdef CHROME_PERSONALIZATION + if (PersonalizationEnabled()) + Personalization::AdjustBrowserView(personalization_, &browser_view_width); +#endif + + if (IsToolBarVisible()) { + browser_view_->SetVisible(true); + browser_view_->SetBounds(left_margin, + last_y - kToolbarOverlapVertOffset, + browser_view_width, + bitmaps[CT_TOP_CENTER]->height()); + browser_view_->Layout(); + title_bar_height_ = browser_view_->GetY(); + last_y = browser_view_->GetY() + browser_view_->GetHeight(); + } else { + // If the tab strip is visible, we need to expose the toolbar for a small + // offset. (kCollapsedToolbarHeight). + if (IsTabStripVisible()) { + title_bar_height_ = last_y; + last_y += kCollapsedToolbarHeight; + } else { + last_y = std::max(kMinTitleBarHeight, + close_button_->GetY() + close_button_->GetHeight()); + title_bar_height_ = last_y; + } + browser_view_->SetVisible(false); + } + + int browser_h = height - last_y - bottom_margin; + if (shelf_view_) { + shelf_view_->GetPreferredSize(&preferred_size); + shelf_view_->SetBounds(left_margin, + height - bottom_margin - preferred_size.cy, + width - left_margin - right_margin, + preferred_size.cy); + browser_h -= preferred_size.cy; + } + + int bookmark_bar_height = 0; + + CSize bookmark_bar_size; + CSize info_bar_size; + + if (bookmark_bar_view_.get()) { + bookmark_bar_view_->GetPreferredSize(&bookmark_bar_size); + bookmark_bar_height = bookmark_bar_size.cy; + } + + if (info_bar_view_) + info_bar_view_->GetPreferredSize(&info_bar_size); + + // If we're showing a bookmarks bar in the new tab page style and we + // have an infobar showing, we need to flip them. + if (info_bar_view_ && + bookmark_bar_view_.get() && + bookmark_bar_view_->IsNewTabPage() && + !bookmark_bar_view_->IsAlwaysShown()) { + info_bar_view_->SetBounds(left_margin, + last_y, + client_rect.Width() - left_margin - right_margin, + info_bar_size.cy); + browser_h -= info_bar_size.cy; + last_y += info_bar_size.cy; + + last_y -= kSeparationLineHeight; + + bookmark_bar_view_->SetBounds(left_margin, + last_y, + client_rect.Width() - left_margin - + right_margin, + bookmark_bar_size.cy); + browser_h -= (bookmark_bar_size.cy - kSeparationLineHeight); + last_y += bookmark_bar_size.cy; + } else { + if (bookmark_bar_view_.get()) { + // We want our bookmarks bar to be responsible for drawing its own + // separator, so we let it overlap ours. + last_y -= kSeparationLineHeight; + + bookmark_bar_view_->SetBounds(left_margin, + last_y, + client_rect.Width() - left_margin - + right_margin, + bookmark_bar_size.cy); + browser_h -= (bookmark_bar_size.cy - kSeparationLineHeight); + last_y += bookmark_bar_size.cy; + } + + if (info_bar_view_) { + info_bar_view_->SetBounds(left_margin, + last_y, + client_rect.Width() - + left_margin - right_margin, + info_bar_size.cy); + browser_h -= info_bar_size.cy; + last_y += info_bar_size.cy; + } + } + + tab_contents_container_->SetBounds(left_margin, + last_y, + width - left_margin - right_margin, + browser_h); +#ifdef CHROME_PERSONALIZATION + if (PersonalizationEnabled()) { + Personalization::ConfigureFramePersonalization(personalization_, + browser_view_, top_margin); + } +#endif + + browser_view_->LayoutStatusBubble(last_y + browser_h); + + frame_view_->SchedulePaint(); +} + +// This is called when we receive WM_ENDSESSION. We have 5 seconds to quit +// the application or we are going to be flagged as flaky. +void XPFrame::OnEndSession(BOOL ending, UINT logoff) { + tabstrip_->AbortActiveDragSession(); + FrameUtil::EndSession(); +} + +// Note: called directly by the handler macros to handle WM_CLOSE messages. +void XPFrame::Close() { + // You cannot close a frame for which there is an active originating drag + // session. + if (tabstrip_->IsDragSessionActive()) + return; + + // Give beforeunload handlers the chance to cancel the close before we hide + // the window below. + if (!browser_->ShouldCloseWindow()) + return; + + // We call this here so that the window position gets saved before moving + // the window into hyperspace. + if (!saved_window_placement_ && should_save_window_placement_ && browser_) { + browser_->SaveWindowPlacement(); + browser_->SaveWindowPlacementToDatabase(); + saved_window_placement_ = true; + } + + if (browser_ && !browser_->tabstrip_model()->empty()) { + // Tab strip isn't empty. Hide the window (so it appears to have closed + // immediately) and close all the tabs, allowing the renderers to shut + // down. When the tab strip is empty we'll be called back recursively. + if (current_action_ == FA_RESIZING) + StopWindowResize(); + // NOTE: Don't use ShowWindow(SW_HIDE) here, otherwise end session blocks + // here. + SetWindowPos(NULL, 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER); + browser_->OnWindowClosing(); + } else { + // Empty tab strip, it's now safe to do the final clean-up. + + root_view_.OnViewContainerDestroyed(); + + NotificationService::current()->Notify( + NOTIFY_WINDOW_CLOSED, Source<HWND>(m_hWnd), + NotificationService::NoDetails()); + DestroyWindow(); + } +} + +void XPFrame::OnFinalMessage(HWND hwnd) { + delete this; +} + +void XPFrame::SetAcceleratorTable( + std::map<Accelerator, int>* accelerator_table) { + accelerator_table_.reset(accelerator_table); +} + +bool XPFrame::GetAccelerator(int cmd_id, ChromeViews::Accelerator* accelerator) + { + std::map<ChromeViews::Accelerator, int>::iterator it = + accelerator_table_->begin(); + for (; it != accelerator_table_->end(); ++it) { + if (it->second == cmd_id) { + *accelerator = it->first; + return true; + } + } + return false; +} + + +bool XPFrame::AcceleratorPressed(const Accelerator& accelerator) { + DCHECK(accelerator_table_.get()); + std::map<Accelerator, int>::const_iterator iter = + accelerator_table_->find(accelerator); + DCHECK(iter != accelerator_table_->end()); + + int command_id = iter->second; + if (browser_->SupportsCommand(command_id) && + browser_->IsCommandEnabled(command_id)) { + browser_->ExecuteCommand(command_id); + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Events +// +//////////////////////////////////////////////////////////////////////////////// +LRESULT XPFrame::OnSettingChange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled) { + // Set this to false, if we actually handle the message, we'll set it to + // true below. + handled = FALSE; + if (w_param != SPI_SETWORKAREA) + return 0; // Return value is effectively ignored in atlwin.h. + + win_util::AdjustWindowToFit(m_hWnd); + handled = TRUE; + return 0; // Return value is effectively ignored in atlwin.h. +} + +LRESULT XPFrame::OnNCCalcSize(BOOL w_param, LPARAM l_param) { + // By default the client side is set to the window size which is what + // we want. + return 0; +} + +LRESULT XPFrame::OnNCPaint(HRGN param) { + return 0; +} + +LRESULT XPFrame::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled) { + tooltip_manager_->OnMouse(u_msg, w_param, l_param); + handled = FALSE; + return 0; +} + +LRESULT XPFrame::OnNotify(int w_param, NMHDR* l_param) { + bool handled; + LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled); + SetMsgHandled(handled); + return result; +} + +void XPFrame::OnMove(const CSize& size) { + if (!saved_window_placement_ && should_save_window_placement_) + browser_->SaveWindowPlacementToDatabase(); + + browser_->WindowMoved(); +} + +void XPFrame::OnMoving(UINT param, const LPRECT new_bounds) { + // We want to let the browser know that the window moved so that it can + // update the positions of any dependent WS_POPUPs + browser_->WindowMoved(); +} + +void XPFrame::OnSize(UINT param, const CSize& size) { + if (IsZoomed()) { + SetWindowRgn(NULL, TRUE); + } else if (IsIconic()) { + // After minimizing the window, Windows will send us an OnSize + // message where size is equal to the bounds of the entry in the + // task bar. This is obviously bogus for our purposes and will + // just confuse Layout() so bail. + return; + } else { + PointBuffer o; + + // Redefine the window visible region for the new size + o.AddPoint(0, 3); + o.AddPoint(1, 1); + o.AddPoint(3, 0); + + o.AddPoint(size.cx - 3, 0); + o.AddPoint(size.cx - 1, 1); + o.AddPoint(size.cx - 1, 3); + o.AddPoint(size.cx - 0, 3); + + o.AddPoint(size.cx, size.cy); + o.AddPoint(0, size.cy); + + // When resizing we don't want an extra paint to limit flicker + SetWindowRgn(o.GetCurrentPolygonRegion(), + current_action_ == FA_RESIZING ? FALSE : TRUE); + } + + // Layout our views + Layout(); + + // We paint immediately during a resize because it will feel laggy otherwise. + if (root_view_.NeedsPainting(false)) { + RedrawWindow(root_view_.GetScheduledPaintRect(), + NULL, + RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); + MessageLoopForUI::current()->PumpOutPendingPaintMessages(); + } + + if (!saved_window_placement_ && should_save_window_placement_) + browser_->SaveWindowPlacementToDatabase(); +} + +void XPFrame::OnNCLButtonDown(UINT flags, const CPoint& pt) { + // DefWindowProc implementation for WM_NCLBUTTONDOWN will allow a + // maximized window to move if the window size is less than screen + // size. We have to handle this message to suppress this behavior. + if (ShouldWorkAroundAutoHideTaskbar() && IsZoomed()) { + if (GetForegroundWindow() != m_hWnd) { + SetForegroundWindow(m_hWnd); + } + } else { + SetMsgHandled(FALSE); + } +} + +void XPFrame::OnNCMButtonDown(UINT flags, const CPoint& pt) { + // The point is in screen coordinate system so we need to convert + CRect window_rect; + GetWindowRect(&window_rect); + CPoint point(pt); + point.x -= window_rect.left; + point.y -= window_rect.top; + + // Yes we need to add MK_MBUTTON. Windows doesn't include it + OnMouseButtonDown(flags | MK_MBUTTON, point); +} + +void XPFrame::OnNCRButtonDown(UINT flags, const CPoint& pt) { + // The point is in screen coordinate system so we need to convert + CRect window_rect; + GetWindowRect(&window_rect); + CPoint point(pt); + point.x -= window_rect.left; + point.y -= window_rect.top; + + // Yes we need to add MK_RBUTTON. Windows doesn't include it + OnMouseButtonDown(flags | MK_RBUTTON, point); +} + +void XPFrame::OnMouseButtonDown(UINT flags, const CPoint& pt) { + using namespace ChromeViews; + if (m_hWnd == NULL || !IsWindowVisible()) { + return; + } + + CRect original_rect; + + GetWindowRect(&original_rect); + int width = original_rect.Width(); + int height= original_rect.Height(); + + if (!ProcessMousePressed(pt, flags, FALSE)) { + // Edge case when showing a menu that will close the window. + if (!IsVisible()) + return; + if (flags & MK_LBUTTON) { + if (!IsZoomed()) { + ResizeMode rm = ComputeResizeMode(pt.x, pt.y, width, height); + if (rm != RM_UNDEFINED) { + StartWindowResize(rm, pt); + } + } + } else if (flags & MK_RBUTTON && pt.y < title_bar_height_) { + CRect r; + ::GetWindowRect(*this, &r); + ShowSystemMenu(r.left + pt.x, r.top + pt.y); + } + } +} + +void XPFrame::OnMouseButtonUp(UINT flags, const CPoint& pt) { + if (m_hWnd == NULL) { + return; + } + + if (flags & MK_LBUTTON) { + switch (current_action_) { + case FA_RESIZING: + StopWindowResize(); + break; + case FA_FORWARDING: + ProcessMouseReleased(pt, flags); + break; + } + } else { + ProcessMouseReleased(pt, flags); + } +} + +void XPFrame::OnMouseButtonDblClk(UINT flags, const CPoint& pt) { + if (m_hWnd == NULL) { + return; + } + + if (!ProcessMousePressed(pt, flags, TRUE)) { + CRect original_rect; + GetWindowRect(&original_rect); + int width = original_rect.Width(); + int height= original_rect.Height(); + + // If the user double clicked on a resize area, ignore. + if (ComputeResizeMode(pt.x, pt.y, width, height) == RM_UNDEFINED && + pt.y < title_bar_height_) { + if (flags & MK_LBUTTON) { + if (IsZoomed()) { + ShowWindow(SW_RESTORE); + } else { + ShowWindow(SW_MAXIMIZE); + } + } + } + } +} + +void XPFrame::OnLButtonUp(UINT flags, const CPoint& pt) { + OnMouseButtonUp(flags | MK_LBUTTON, pt); +} + +void XPFrame::OnMButtonUp(UINT flags, const CPoint& pt) { + OnMouseButtonUp(flags | MK_MBUTTON, pt); +} + +void XPFrame::OnRButtonUp(UINT flags, const CPoint& pt) { + OnMouseButtonUp(flags | MK_RBUTTON, pt); +} + +void XPFrame::OnMouseMove(UINT flags, const CPoint& pt) { + if (m_hWnd == NULL) { + return; + } + + switch (current_action_) { + case FA_NONE: { + ArmOnMouseLeave(); + ProcessMouseMoved(pt, flags); + if (!IsZoomed()) { + CRect r; + GetWindowRect(&r); + XPFrame::ResizeMode rm = ComputeResizeMode(pt.x, + pt.y, + r.Width(), + r.Height()); + SetResizeCursor(rm); + } + break; + } + case FA_RESIZING: { + ProcessWindowResize(pt); + break; + } + case FA_FORWARDING: { + ProcessMouseDragged(pt, flags); + break; + } + } +} + +void XPFrame::OnMouseLeave() { + if (m_hWnd == NULL) { + return; + } + ProcessMouseExited(); + on_mouse_leave_armed_ = FALSE; +} + +LRESULT XPFrame::OnGetObject(UINT uMsg, WPARAM w_param, LPARAM object_id) { + LRESULT reference_result = static_cast<LRESULT>(0L); + + // Accessibility readers will send an OBJID_CLIENT message + if (OBJID_CLIENT == object_id) { + // If our MSAA root is already created, reuse that pointer. Otherwise, + // create a new one. + if (!accessibility_root_) { + CComObject<ViewAccessibility>* instance = NULL; + + HRESULT hr = CComObject<ViewAccessibility>::CreateInstance(&instance); + DCHECK(SUCCEEDED(hr)); + + if (!instance) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + CComPtr<IAccessible> accessibility_instance(instance); + + if (!SUCCEEDED(instance->Initialize(&root_view_))) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + // All is well, assign the temp instance to the class smart pointer + accessibility_root_.Attach(accessibility_instance.Detach()); + + if (!accessibility_root_) { + // Return with failure. + return static_cast<LRESULT>(0L); + } + + // Notify that an instance of IAccessible was allocated for m_hWnd + ::NotifyWinEvent(EVENT_OBJECT_CREATE, m_hWnd, OBJID_CLIENT, + CHILDID_SELF); + } + + // Create a reference to ViewAccessibility that MSAA will marshall + // to the client. + reference_result = LresultFromObject(IID_IAccessible, w_param, + static_cast<IAccessible*>(accessibility_root_)); + } + return reference_result; +} + +void XPFrame::OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags) { + ChromeViews::KeyEvent event(ChromeViews::Event::ET_KEY_PRESSED, c, + rep_cnt, flags); + root_view_.ProcessKeyEvent(event); +} + +void XPFrame::OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags) { + ChromeViews::KeyEvent event(ChromeViews::Event::ET_KEY_RELEASED, c, + rep_cnt, flags); + root_view_.ProcessKeyEvent(event); +} + +void XPFrame::OnActivate(UINT n_state, BOOL is_minimized, HWND other) { + if (FrameUtil::ActivateAppModalDialog(browser_)) + return; + + // We get deactivation notices before the window is deactivated, + // so we need our Paint methods to know which type of window to + // draw. + is_active_ = (n_state != WA_INACTIVE); + + if (!is_minimized) { + browser_->WindowActivationChanged(is_active_); + + // Redraw the frame. + frame_view_->SchedulePaint(); + + // We need to force a paint now, as a user dragging a window + // will block painting operations while the move is in progress. + PaintNow(root_view_.GetScheduledPaintRect()); + } +} + +int XPFrame::OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message) { + return FrameUtil::ActivateAppModalDialog(browser_) ? MA_NOACTIVATEANDEAT + : MA_ACTIVATE; +} + +void XPFrame::OnPaint(HDC dc) { + root_view_.OnPaint(*this); +} + +LRESULT XPFrame::OnEraseBkgnd(HDC dc) { + SetMsgHandled(TRUE); + return 1; +} + +void XPFrame::OnMinMaxInfo(LPMINMAXINFO mm_info) { + // From MINMAXINFO documentation: + // For systems with multiple monitors, the ptMaxSize and ptMaxPosition members + // describe the maximized size and position of the window on the primary + // monitor, even if the window ultimately maximizes onto a secondary monitor. + // In that case, the window manager adjusts these values to compensate for + // differences between the primary monitor and the monitor that displays the + // window. Thus, if the user leaves ptMaxSize untouched, a window on a monitor + // larger than the primary monitor maximizes to the size of the larger + // monitor. + // + // But what the documentation doesn't say is that we need to compensate for + // the taskbar. :/ + // + // - So use the primary monitor for position and size calculation. + // - Take in account the existence or not of the task bar in the destination + // monitor and adjust accordingly. + // 99% of the time, they will contain mostly the same information. + + HMONITOR primary_monitor = ::MonitorFromWindow(NULL, + MONITOR_DEFAULTTOPRIMARY); + MONITORINFO primary_info; + primary_info.cbSize = sizeof(primary_info); + GetMonitorInfo(primary_monitor, &primary_info); + + HMONITOR destination_monitor = ::MonitorFromWindow(m_hWnd, + MONITOR_DEFAULTTONEAREST); + MONITORINFO destination_info; + destination_info.cbSize = sizeof(destination_info); + GetMonitorInfo(destination_monitor, &destination_info); + + // Take in account the destination monitor taskbar location but the primary + // monitor size. + int primary_monitor_width = + primary_info.rcMonitor.right - primary_info.rcMonitor.left; + int primary_monitor_height = + primary_info.rcMonitor.bottom - primary_info.rcMonitor.top; + mm_info->ptMaxSize.x = + primary_monitor_width - + (destination_info.rcMonitor.right - destination_info.rcWork.right) - + (destination_info.rcWork.left - destination_info.rcMonitor.left); + mm_info->ptMaxSize.y = + primary_monitor_height - + (destination_info.rcMonitor.bottom - destination_info.rcWork.bottom) - + (destination_info.rcWork.top - destination_info.rcMonitor.top); + + mm_info->ptMaxPosition.x = destination_info.rcWork.left - + destination_info.rcMonitor.left; + mm_info->ptMaxPosition.y = destination_info.rcWork.top - + destination_info.rcMonitor.top; + + if (primary_monitor == destination_monitor) { + // Only add support for auto-hidding taskbar on primary monitor. + if (ShouldWorkAroundAutoHideTaskbar() && + EqualRect(&destination_info.rcWork, &destination_info.rcMonitor)) { + mm_info->ptMaxSize.y--; + } + } else { + // If the taskbar is on the second monitor, the difference in monitor size + // won't be added. The reason: if the maximized size is less than the + // primary monitor size, it won't get resized to the full screen of the + // destination monitor (!) The position will get fixed in any case, just not + // the size. The problem is that if we preemptly add the monitor size + // difference, the window will get larger than the primary monitor size and + // Windows will add (again) the monitor size difference! + // + // So for now, simply don't support the taskbar on a secondary monitor with + // different monitor sizes. +#ifdef BUG_943445_FIXED + if (mm_info->ptMaxSize.x < primary_monitor_width || + mm_info->ptMaxSize.y < primary_monitor_height) { + int dst_monitor_width = destination_info.rcMonitor.right - + destination_info.rcMonitor.left; + mm_info->ptMaxSize.x += (dst_monitor_width - primary_monitor_width); + int dst_monitor_height = destination_info.rcMonitor.bottom - + destination_info.rcMonitor.top; + mm_info->ptMaxSize.y += (dst_monitor_height - primary_monitor_height); + } +#endif // BUG_943445_FIXED + } + // If you fully understand what's going on, you can now appreciate the joyness + // of programming on Windows. +} + +void XPFrame::OnCaptureChanged(HWND hwnd) { + if (current_action_ == FA_FORWARDING) + root_view_.ProcessMouseDragCanceled(); + current_action_ = FA_NONE; +} + +LRESULT XPFrame::OnNCHitTest(const CPoint& pt) { + CPoint p(pt); + CRect r; + GetWindowRect(&r); + + // Convert from screen to window coordinates + p.x -= r.left; + p.y -= r.top; + + if (!IsTabStripVisible() && + ComputeResizeMode(p.x, p.y, r.Width(), r.Height()) == RM_UNDEFINED && + root_view_.GetViewForPoint(p) == frame_view_) { + return HTCAPTION; + } + + CPoint tsp(p); + ChromeViews::View::ConvertPointToView(&root_view_, tabstrip_, &tsp); + + // If the mouse is over the tabstrip. Check if we should move the window or + // capture the mouse. + if (tabstrip_->CanProcessInputEvents() && tabstrip_->HitTest(tsp)) { + // The top few pixels of a tab strip are a dropshadow - as we're pretty + // starved of draggable area, let's give it to window dragging (this + // also makes sense visually. + if (!IsZoomed() && tsp.y < kTabShadowSize) + return HTCAPTION; + + ChromeViews::View* v = tabstrip_->GetViewForPoint(tsp); + // If there is not tab at this location, claim the hit was in the title + // bar to get a move action. + if (v == tabstrip_) + return HTCAPTION; + + // If the view under mouse is a tab, check if the tab strip allows tab + // dragging or not. If not, return caption to get window dragging. + if (v->GetClassName() == Tab::kTabClassName && + !tabstrip_->HasAvailableDragActions()) + return HTCAPTION; + } else { + // The mouse is not above the tab strip. If there is no control under it, + // let's move the window. + if (ComputeResizeMode(p.x, p.y, r.Width(), r.Height()) == RM_UNDEFINED) { + ChromeViews::View* v = root_view_.GetViewForPoint(p); + if (v == frame_view_ || v == off_the_record_image_ || + v == distributor_logo_) { + return HTCAPTION; + } + } + } + + SetMsgHandled(FALSE); + return 0; +} + +void XPFrame::ArmOnMouseLeave() { + if (!on_mouse_leave_armed_) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = *this; + tme.dwHoverTime = 0; + TrackMouseEvent(&tme); + on_mouse_leave_armed_ = TRUE; + } +} + +void XPFrame::OnInitMenu(HMENU menu) { + BOOL is_iconic = IsIconic(); + BOOL is_zoomed = IsZoomed(); + + if (is_iconic || is_zoomed) { + ::EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); + ::EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + ::EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + if (is_iconic) { + ::EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED); + ::EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_DISABLED | + MF_GRAYED); + } else { + ::EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_DISABLED | + MF_GRAYED); + ::EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED); + } + } else { + ::EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + ::EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_ENABLED); + ::EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_ENABLED); + ::EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED); + ::EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED); + } +} + +void XPFrame::ShowSystemMenu(int x, int y) { + HMENU system_menu = ::GetSystemMenu(*this, FALSE); + int id = ::TrackPopupMenu(system_menu, + TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, + x, + y, + 0, + *this, + NULL); + if (id) { + ::SendMessage(*this, + WM_SYSCOMMAND, + id, + 0); + } +} + +LRESULT XPFrame::OnNCActivate(BOOL param) { + if (ignore_ncactivate_) { + ignore_ncactivate_ = false; + return DefWindowProc(WM_NCACTIVATE, TRUE, 0); + } + SetMsgHandled(false); + return 0; +} + +BOOL XPFrame::OnPowerBroadcast(DWORD power_event, DWORD data) { + if (PBT_APMSUSPEND == power_event) { + SuspendController::OnSuspend(browser_->profile()); + return TRUE; + } else if (PBT_APMRESUMEAUTOMATIC == power_event) { + SuspendController::OnResume(browser_->profile()); + return TRUE; + } + + SetMsgHandled(FALSE); + return FALSE; +} + +void XPFrame::OnThemeChanged() { + // Notify NativeTheme. + gfx::NativeTheme::instance()->CloseHandles(); +} + +LRESULT XPFrame::OnAppCommand( + HWND w_param, short app_command, WORD device, int keystate) { + if (browser_ && !browser_->ExecuteWindowsAppCommand(app_command)) + SetMsgHandled(FALSE); + return 0; +} + +void XPFrame::OnCommand(UINT notification_code, + int command_id, + HWND window) { + if (browser_ && browser_->SupportsCommand(command_id)) { + browser_->ExecuteCommand(command_id); + } else { + SetMsgHandled(FALSE); + } +} + +void XPFrame::OnSysCommand(UINT notification_code, CPoint click) { + switch (notification_code) { + case SC_CLOSE: + Close(); + break; + case SC_MAXIMIZE: + ShowWindow(IsZoomed() ? SW_RESTORE : SW_MAXIMIZE); + break; + case IDC_TASKMANAGER: + if (browser_) + browser_->ExecuteCommand(IDC_TASKMANAGER); + break; + + // Note that we avoid calling ShowWindow(SW_SHOWMINIMIZED) when we get a + // minimized system command because doing so will minimize the window but + // won't put the window at the bottom of the z-order window list. Instead, + // we pass the minimized event to the default window procedure. + case SC_MINIMIZE: + default: + // Use the default implementation for any other command. + SetMsgHandled(FALSE); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Button:::ButtonListener +// +//////////////////////////////////////////////////////////////////////////////// + +void XPFrame::ButtonPressed(ChromeViews::BaseButton *sender) { + switch (sender->GetTag()) { + case MINIATURIZE_TAG: + // We deliberately don't call ShowWindow(SW_SHOWMINIMIZED) directly + // because doing that will minimize the window, but won't put the window + // in the right z-order location. + // + // In order to minimize the window correctly, we need to post a system + // command which will be passed to the default window procedure for + // correct handling. + ::PostMessage(*this, WM_SYSCOMMAND, SC_MINIMIZE, 0); + break; + case MAXIMIZE_TAG: + ShowWindow(SW_MAXIMIZE); + break; + case RESTORE_TAG: + ShowWindow(SW_RESTORE); + break; + case CLOSE_TAG: + Close(); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Window move and resize +// +//////////////////////////////////////////////////////////////////////////////// + +bool XPFrame::ShouldRefreshCurrentTabContents() { + if (browser_->tabstrip_model()) { + TabContents* tc = browser_->GetSelectedTabContents(); + if (tc) { + HWND tc_hwnd = tc->GetContainerHWND(); + return !!(::GetWindowLongPtr(tc_hwnd, GWL_STYLE) & WS_CLIPCHILDREN); + } + } + return false; +} + +void XPFrame::StartWindowResize(ResizeMode mode, const CPoint &pt) { + SetCapture(); + current_action_ = FA_RESIZING; + current_resize_mode_ = mode; + + SetResizeCursor(mode); + + GetWindowRect(&previous_bounds_); + drag_origin_ = pt; + drag_origin_.x += previous_bounds_.left; + drag_origin_.y += previous_bounds_.top; +} + +void XPFrame::ProcessWindowResize(const CPoint &pt) { + CPoint current(pt); + CRect rect; + CRect new_rect(previous_bounds_); + CPoint initial(drag_origin_); + GetWindowRect(&rect); + + current.x += rect.left; + current.y += rect.top; + + switch (current_resize_mode_) { + case RM_NORTH: + new_rect.top = std::min(new_rect.bottom - minimum_size_.cy, + new_rect.top + (current.y - initial.y)); + break; + case RM_NORTH_EAST: + new_rect.top = std::min(new_rect.bottom - minimum_size_.cy, + new_rect.top + (current.y - initial.y)); + new_rect.right = std::max(new_rect.left + minimum_size_.cx, + new_rect.right + (current.x - initial.x)); + break; + case RM_EAST: + new_rect.right = std::max(new_rect.left + minimum_size_.cx, + new_rect.right + (current.x - initial.x)); + break; + case RM_SOUTH_EAST: + new_rect.right = std::max(new_rect.left + minimum_size_.cx, + new_rect.right + (current.x - initial.x)); + new_rect.bottom = std::max(new_rect.top + minimum_size_.cy, + new_rect.bottom + (current.y - initial.y)); + break; + case RM_SOUTH: + new_rect.bottom = std::max(new_rect.top + minimum_size_.cy, + new_rect.bottom + (current.y - initial.y)); + break; + case RM_SOUTH_WEST: + new_rect.left = std::min(new_rect.right - minimum_size_.cx, + new_rect.left + (current.x - initial.x)); + new_rect.bottom = std::max(new_rect.top + minimum_size_.cy, + new_rect.bottom + (current.y - initial.y)); + break; + case RM_WEST: + new_rect.left = std::min(new_rect.right - minimum_size_.cx, + new_rect.left + (current.x - initial.x)); + break; + case RM_NORTH_WEST: + new_rect.left = std::min(new_rect.right - minimum_size_.cx, + new_rect.left + (current.x - initial.x)); + new_rect.top = std::min(new_rect.bottom - minimum_size_.cy, + new_rect.top + (current.y - initial.y)); + break; + } + + if (!EqualRect(rect, new_rect)) { + // Performing the refresh appears to be faster than simply calling + // MoveWindow(... , TRUE) + MoveWindow(new_rect.left, + new_rect.top, + new_rect.Width(), + new_rect.Height(), + FALSE); + HWND h = GetDesktopWindow(); + HRGN rgn = ::CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom); + HRGN rgn2 = ::CreateRectRgn(new_rect.left, + new_rect.top, + new_rect.right, + new_rect.bottom); + + // Erase the corners + HRGN rgn3 = ::CreateRectRgn(rect.left, + rect.top, + rect.left + kCurvedCornerSize, + rect.top + kCurvedCornerSize); + HRGN rgn4 = ::CreateRectRgn(rect.right - kCurvedCornerSize, + rect.top, + rect.right, + rect.top + kCurvedCornerSize); + HRGN rgn5 = ::CreateRectRgn(new_rect.left, + new_rect.top, + new_rect.left + kCurvedCornerSize, + new_rect.top + kCurvedCornerSize); + HRGN rgn6 = ::CreateRectRgn(new_rect.right - kCurvedCornerSize, + new_rect.top, + new_rect.right, + new_rect.top + kCurvedCornerSize); + + ::CombineRgn(rgn, rgn, rgn2, RGN_OR); + ::CombineRgn(rgn, rgn, rgn3, RGN_OR); + ::CombineRgn(rgn, rgn, rgn4, RGN_OR); + ::CombineRgn(rgn, rgn, rgn5, RGN_OR); + ::CombineRgn(rgn, rgn, rgn6, RGN_OR); + + ::RedrawWindow(h, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); + ::DeleteObject(rgn); + ::DeleteObject(rgn2); + ::DeleteObject(rgn3); + ::DeleteObject(rgn4); + ::DeleteObject(rgn5); + ::DeleteObject(rgn6); + } +} + +void XPFrame::StopWindowResize() { + current_action_ = FA_NONE; + ReleaseCapture(); +} + +XPFrame::ResizeMode XPFrame::ComputeResizeMode(int x, + int y, + int width, + int height) { + // Make sure we're not over a window control (they overlap our resize area). + if (x >= min_button_->GetX() && + x < close_button_->GetX() + close_button_->GetWidth() && + y >= min_button_->GetY() && + y < min_button_->GetY() + min_button_->GetHeight()) { + return RM_UNDEFINED; + } + + ResizeMode mode = RM_UNDEFINED; + + // WEST / SOUTH_WEST / NORTH_WEST edge + if (x < kResizeAreaSize) { + if (y < kResizeAreaCornerSize) { + mode = RM_NORTH_WEST; + } else if (y >= (height - kResizeAreaCornerSize)) { + mode = RM_SOUTH_WEST; + } else { + mode = RM_WEST; + } + // SOUTH_WEST / NORTH_WEST horizontal extensions + } else if (x < kResizeAreaCornerSize) { + if (y < kResizeAreaNorthSize) { + mode = RM_NORTH_WEST; + } else if (y >= (height - kResizeAreaSize)) { + mode = RM_SOUTH_WEST; + } + // EAST / SOUTH_EAST / NORTH_EAST edge + } else if (x >= (width - kResizeAreaSize)) { + if (y < kResizeAreaCornerSize) { + mode = RM_NORTH_EAST; + } else if (y >= (height - kResizeAreaCornerSize)) { + mode = RM_SOUTH_EAST; + } else if (x >= (width - kResizeAreaSize)) { + mode = RM_EAST; + } + // EAST / SOUTH_EAST / NORTH_EAST horizontal extensions + } else if (x >= (width - kResizeAreaCornerSize)) { + if (y < kResizeAreaNorthSize) { + mode = RM_NORTH_EAST; + } else if (y >= (height - kResizeAreaSize)) { + mode = RM_SOUTH_EAST; + } + // NORTH edge + } else if (y < kResizeAreaNorthSize) { + mode = RM_NORTH; + // SOUTH edge + } else if (y >= (height - kResizeAreaSize)) { + mode = RM_SOUTH; + } + + return mode; +} + +void XPFrame::SetResizeCursor(ResizeMode r_mode) { + static ResizeCursor map[] = { RC_VERTICAL, // unefined + RC_VERTICAL, RC_NESW, RC_HORIZONTAL, RC_NWSE, + RC_VERTICAL, RC_NESW, RC_HORIZONTAL, RC_NWSE }; + + if (r_mode == RM_UNDEFINED) { + if (previous_cursor_) { + SetCursor(previous_cursor_); + previous_cursor_ = NULL; + } + } else { + HCURSOR cursor = g_resize_cursors[map[r_mode]]; + HCURSOR prev_cursor = SetCursor(cursor); + if (prev_cursor != cursor) { + previous_cursor_ = cursor; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// ViewContainer +// +//////////////////////////////////////////////////////////////////////////////// + +void XPFrame::GetBounds(CRect *out, bool including_frame) const { + // We ignore including_frame because our XP frame doesn't have any NC area + GetWindowRect(out); +} + +bool XPFrame::IsMaximized() { + return !!IsZoomed(); +} + +gfx::Rect XPFrame::GetBoundsForContentBounds(const gfx::Rect content_rect) { + if (tab_contents_container_->GetX() == 0 && + tab_contents_container_->GetWidth() == 0) { + Layout(); + } + + CPoint p(0, 0); + ChromeViews::View::ConvertPointToViewContainer(tab_contents_container_, &p); + CRect bounds; + GetBounds(&bounds, true); + + gfx::Rect r; + r.set_x(content_rect.x() - p.x); + r.set_y(content_rect.y() - p.y); + r.set_width(p.x + content_rect.width() + + (bounds.Width() - (p.x + tab_contents_container_->GetWidth()))); + r.set_height(p.y + content_rect.height() + + (bounds.Height() - (p.y + + tab_contents_container_->GetHeight()))); + return r; +} + +void XPFrame::InfoBubbleShowing() { + ignore_ncactivate_ = true; + paint_as_active_ = true; +} + +void XPFrame::InfoBubbleClosing() { + paint_as_active_ = false; + BrowserWindow::InfoBubbleClosing(); + // How we render the frame has changed, we need to force a paint otherwise + // visually the user won't be able to tell. + InvalidateRect(NULL, false); +} + +ToolbarStarToggle* XPFrame::GetStarButton() const { + return browser_view_->GetStarButton(); +} + +LocationBarView* XPFrame::GetLocationBarView() const { + return browser_view_->GetLocationBarView(); +} + +GoButton* XPFrame::GetGoButton() const { + return browser_view_->GetGoButton(); +} + +BookmarkBarView* XPFrame::GetBookmarkBarView() { + TabContents* current_tab = browser_->GetSelectedTabContents(); + if (!current_tab || !current_tab->profile()) + return NULL; + + if (!bookmark_bar_view_.get()) { + bookmark_bar_view_.reset(new BookmarkBarView(current_tab->profile(), + browser_)); + bookmark_bar_view_->SetParentOwned(false); + } else { + bookmark_bar_view_->SetProfile(current_tab->profile()); + } + bookmark_bar_view_->SetPageNavigator(current_tab); + return bookmark_bar_view_.get(); +} + +BrowserView* XPFrame::GetBrowserView() const { + return browser_view_; +} + +void XPFrame::UpdateToolbar(TabContents* contents, bool should_restore_state) { + browser_view_->UpdateToolbar(contents, should_restore_state); +} + +void XPFrame::ProfileChanged(Profile* profile) { + browser_view_->ProfileChanged(profile); +} + +void XPFrame::FocusToolbar() { + browser_view_->FocusToolbar(); +} + +bool XPFrame::IsBookmarkBarVisible() const { + if (!bookmark_bar_view_.get()) + return false; + + if (bookmark_bar_view_->IsNewTabPage() || bookmark_bar_view_->IsAnimating()) + return true; + + CSize sz; + bookmark_bar_view_->GetPreferredSize(&sz); + // 1 is the minimum in GetPreferredSize for the bookmark bar. + return sz.cy > 1; +} + +void XPFrame::MoveToFront(bool should_activate) { + int flags = SWP_NOMOVE | SWP_NOSIZE; + if (!should_activate) { + flags |= SWP_NOACTIVATE; + } + SetWindowPos(HWND_TOP, 0, 0, 0, 0, flags); + SetForegroundWindow(*this); +} + +HWND XPFrame::GetHWND() const { + return m_hWnd; +} + +void XPFrame::PaintNow(const CRect& update_rect) { + if (!update_rect.IsRectNull() && IsVisible()) { + RedrawWindow(update_rect, + NULL, + // While we don't seem to need RDW_NOERASE here for correctness + // (unlike Vista), I don't know whether it would hurt. + RDW_INVALIDATE | RDW_ALLCHILDREN); + } +} + +ChromeViews::RootView* XPFrame::GetRootView() { + return const_cast<ChromeViews::RootView*>(&root_view_); +} + +bool XPFrame::IsVisible() { + return !!::IsWindowVisible(*this); +} + +bool XPFrame::IsActive() { + return win_util::IsWindowActive(*this); +} + +bool XPFrame::ProcessMousePressed(const CPoint &pt, + UINT flags, + bool dbl_click) { + using namespace ChromeViews; + MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED, + pt.x, + pt.y, + (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) | + Event::ConvertWindowsFlags(flags)); + if (root_view_.OnMousePressed(mouse_pressed)) { + // If an additional button is pressed during a drag session we don't want + // to call SetCapture() again as it will result in no more events. + if (current_action_ != FA_FORWARDING) { + current_action_ = FA_FORWARDING; + SetCapture(); + } + return TRUE; + } + return FALSE; +} + +void XPFrame::ProcessMouseDragged(const CPoint &pt, UINT flags) { + using namespace ChromeViews; + MouseEvent drag_event(Event::ET_MOUSE_DRAGGED, + pt.x, + pt.y, + Event::ConvertWindowsFlags(flags)); + root_view_.OnMouseDragged(drag_event); +} + +void XPFrame::ProcessMouseReleased(const CPoint &pt, UINT flags) { + using namespace ChromeViews; + + current_action_ = FA_NONE; + ReleaseCapture(); + + MouseEvent mouse_released(Event::ET_MOUSE_RELEASED, + pt.x, + pt.y, + Event::ConvertWindowsFlags(flags)); + root_view_.OnMouseReleased(mouse_released, false); +} + +void XPFrame::ProcessMouseMoved(const CPoint& pt, UINT flags) { + using namespace ChromeViews; + MouseEvent mouse_move(Event::ET_MOUSE_MOVED, + pt.x, + pt.y, + Event::ConvertWindowsFlags(flags)); + root_view_.OnMouseMoved(mouse_move); +} + +void XPFrame::ProcessMouseExited() { + root_view_.ProcessOnMouseExited(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// XPFrameView +// +//////////////////////////////////////////////////////////////////////////////// + +void XPFrame::XPFrameView::PaintFrameBorder(ChromeCanvas* canvas) { + int width = GetWidth(); + int height = GetHeight(); + int x, y; + x = 0; + y = 0; + + static const SkBitmap * top_left_corner; + static const SkBitmap * top_center; + static const SkBitmap * top_right_corner; + static const SkBitmap * left_side; + static const SkBitmap * right_side; + static const SkBitmap * bottom_left_corner; + static const SkBitmap * bottom_center; + static const SkBitmap * bottom_right_corner; + + SkBitmap** bitmaps = parent_->GetFrameBitmaps(); + + if (parent_->PaintAsActive()) { + top_left_corner = bitmaps[TOP_LEFT_CORNER]; + top_center = bitmaps[TOP_CENTER]; + top_right_corner = bitmaps[TOP_RIGHT_CORNER]; + left_side = bitmaps[LEFT_SIDE]; + right_side = bitmaps[RIGHT_SIDE]; + bottom_left_corner = bitmaps[BOTTOM_LEFT_CORNER]; + bottom_center = bitmaps[BOTTOM_CENTER]; + bottom_right_corner = bitmaps[BOTTOM_RIGHT_CORNER]; + } else { + top_left_corner = bitmaps[DE_TOP_LEFT_CORNER]; + top_center = bitmaps[DE_TOP_CENTER]; + top_right_corner = bitmaps[DE_TOP_RIGHT_CORNER]; + left_side = bitmaps[DE_LEFT_SIDE]; + right_side = bitmaps[DE_RIGHT_SIDE]; + bottom_left_corner = bitmaps[DE_BOTTOM_LEFT_CORNER]; + bottom_center = bitmaps[DE_BOTTOM_CENTER]; + bottom_right_corner = bitmaps[DE_BOTTOM_RIGHT_CORNER]; + } + + int variable_width = width - top_left_corner->width() - + top_right_corner->width(); + int variable_height = height - top_right_corner->height() - + bottom_right_corner->height(); + + // Top + canvas->DrawBitmapInt(*top_left_corner, x, y); + canvas->TileImageInt(*top_center, + x + top_left_corner->width(), + y, + variable_width, + top_center->height()); + x = width - top_right_corner->width(); + canvas->DrawBitmapInt(*top_right_corner, x, y); + + // Right side + canvas->TileImageInt(*right_side, + x, + top_right_corner->height(), + right_side->width(), + variable_height); + + // Bottom + canvas->DrawBitmapInt(*bottom_right_corner, + width - bottom_right_corner->width(), + height - bottom_right_corner->height()); + canvas->TileImageInt(*bottom_center, + bottom_left_corner->width(), + height - bottom_center->height(), + variable_width, + bottom_center->height()); + canvas->DrawBitmapInt(*bottom_left_corner, + 0, + height - bottom_left_corner->height()); + + // Left + canvas->TileImageInt(*left_side, + 0, + top_left_corner->height(), + left_side->width(), + variable_height); +} + +void XPFrame::XPFrameView::PaintFrameBorderZoomed(ChromeCanvas* canvas) { + int width = GetWidth(); + int height = GetHeight(); + + static const SkBitmap * maximized_top; + static const SkBitmap * maximized_bottom; + + SkBitmap** bitmaps = parent_->GetFrameBitmaps(); + if (parent_->PaintAsActive()) { + maximized_top = bitmaps[TOP_CENTER]; + maximized_bottom = bitmaps[BOTTOM_CENTER]; + } else { + maximized_top = bitmaps[DE_TOP_CENTER]; + maximized_bottom = bitmaps[DE_BOTTOM_CENTER]; + } + + canvas->TileImageInt(*maximized_top, + 0, + 0, + width, + maximized_top->height()); + canvas->TileImageInt(*maximized_bottom, + 0, + height - maximized_bottom->height(), + width, + maximized_bottom->height()); +} + +void XPFrame::XPFrameView::PaintContentsBorder(ChromeCanvas* canvas, + int x, + int y, + int w, + int h) { + SkBitmap** bitmaps = parent_->GetFrameBitmaps(); + + int ro, bo; + ro = x + w - bitmaps[CT_TOP_RIGHT_CORNER]->width(); + bo = y + h - bitmaps[CT_BOTTOM_RIGHT_CORNER]->height(); + int start_y; + + if (parent_->IsTabStripVisible() || parent_->IsToolBarVisible()) { + int top_height = bitmaps[CT_TOP_RIGHT_CORNER]->height(); + canvas->DrawBitmapInt(*bitmaps[CT_TOP_LEFT_CORNER], x, y); + + canvas->TileImageInt(*bitmaps[CT_TOP_CENTER], + x + bitmaps[CT_TOP_LEFT_CORNER]->width(), + y, + w - bitmaps[CT_TOP_LEFT_CORNER]->width() - + bitmaps[CT_TOP_RIGHT_CORNER]->width(), + bitmaps[CT_TOP_CENTER]->height()); + + canvas->DrawBitmapInt(*bitmaps[CT_TOP_RIGHT_CORNER], ro, y); + start_y = y + bitmaps[CT_TOP_RIGHT_CORNER]->height(); + + // If the toolbar is not visible, we need to draw a line at the top of the + // actual contents. + if (!parent_->IsToolBarVisible()) { + canvas->FillRectInt(kSeparationLineColor, + x + bitmaps[CT_TOP_LEFT_CORNER]->width(), + y + kCollapsedToolbarHeight + + kToolbarOverlapVertOffset - kSeparationLineHeight, + w - bitmaps[CT_TOP_LEFT_CORNER]->width() - + bitmaps[CT_TOP_RIGHT_CORNER]->width(), + kSeparationLineHeight); + } + } else { + int by = y - bitmaps[APP_TOP_LEFT]->height() + 1; + canvas->DrawBitmapInt(*bitmaps[APP_TOP_LEFT], x, by); + canvas->TileImageInt(*bitmaps[APP_TOP_CENTER], + x + bitmaps[APP_TOP_LEFT]->width(), + by, + w - bitmaps[APP_TOP_LEFT]->width() - + bitmaps[APP_TOP_RIGHT]->width(), + bitmaps[APP_TOP_CENTER]->height()); + canvas->DrawBitmapInt(*bitmaps[APP_TOP_RIGHT], + x + w - bitmaps[APP_TOP_RIGHT]->width(), + by); + start_y = y + 1; + } + + canvas->TileImageInt(*bitmaps[CT_RIGHT_SIDE], + ro, + start_y, + bitmaps[CT_RIGHT_SIDE]->width(), + bo - start_y); + + canvas->DrawBitmapInt(*bitmaps[CT_BOTTOM_RIGHT_CORNER], + x + w - bitmaps[CT_BOTTOM_RIGHT_CORNER]->width(), + bo); + + canvas->TileImageInt(*bitmaps[CT_BOTTOM_CENTER], + x + bitmaps[CT_BOTTOM_LEFT_CORNER]->width(), + bo, + w - (bitmaps[CT_BOTTOM_LEFT_CORNER]->width() + + bitmaps[CT_BOTTOM_RIGHT_CORNER]->width()), + bitmaps[CT_BOTTOM_CENTER]->height()); + + canvas->DrawBitmapInt(*bitmaps[CT_BOTTOM_LEFT_CORNER], x, bo); + + canvas->TileImageInt(*bitmaps[CT_LEFT_SIDE], + x, + start_y, + bitmaps[CT_LEFT_SIDE]->width(), + bo - start_y); +} + +void XPFrame::XPFrameView::PaintContentsBorderZoomed(ChromeCanvas* canvas, + int x, + int y, + int w) { + SkBitmap** bitmaps = parent_->GetFrameBitmaps(); + canvas->TileImageInt(*bitmaps[CT_TOP_CENTER], + x, + y, + w, + bitmaps[CT_TOP_CENTER]->height()); + + // If the toolbar is not visible, we need to draw a line at the top of the + // actual contents. + if (!parent_->IsToolBarVisible()) { + canvas->FillRectInt(kSeparationLineColor, x, y + kCollapsedToolbarHeight + + kToolbarOverlapVertOffset - 1, w, 1); + } +} + +void XPFrame::XPFrameView::Paint(ChromeCanvas* canvas) { + canvas->save(); + + // When painting the border, exclude the contents area. This will prevent the + // border bitmaps (which might be larger than the visible area) from coming + // into the content area when there is no tab painted yet. + int x = parent_->tab_contents_container_->GetX(); + int y = parent_->tab_contents_container_->GetY(); + SkRect clip; + clip.set(SkIntToScalar(x), SkIntToScalar(y), + SkIntToScalar(x + parent_->tab_contents_container_->GetWidth()), + SkIntToScalar(y + parent_->tab_contents_container_->GetHeight())); + canvas->clipRect(clip, SkRegion::kDifference_Op); + + if (parent_->IsZoomed()) { + PaintFrameBorderZoomed(canvas); + int y; + bool should_draw_separator = false; + if (parent_->IsToolBarVisible()) { + y = parent_->browser_view_->GetY(); + } else if (parent_->IsTabStripVisible()) { + y = parent_->GetContentsYOrigin() - kCollapsedToolbarHeight - + kToolbarOverlapVertOffset; + } else { + y = parent_->GetContentsYOrigin(); + } + + PaintContentsBorderZoomed(canvas, 0, y, GetWidth()); + } else { + PaintFrameBorder(canvas); + int y, height; + if (parent_->IsToolBarVisible()) { + y = parent_->browser_view_->GetY(); + height = GetHeight() - (parent_->browser_view_->GetY() + + kContentBorderVertBottomOffset); + } else { + if (parent_->IsTabStripVisible()) { + y = parent_->GetContentsYOrigin() - kCollapsedToolbarHeight - + kToolbarOverlapVertOffset; + } else { + y = parent_->GetContentsYOrigin(); + } + height = GetHeight() - y - kContentBorderVertBottomOffset; + } + + PaintContentsBorder(canvas, kContentBorderHorizOffset, y, + GetWidth() - (2 * kContentBorderHorizOffset), + height); + } + + canvas->restore(); +} + +bool XPFrame::XPFrameView::GetAccessibleRole(VARIANT* role) { + DCHECK(role); + + role->vt = VT_I4; + role->lVal = ROLE_SYSTEM_CLIENT; + return true; +} + +bool XPFrame::XPFrameView::GetAccessibleName(std::wstring* name) { + if (!accessible_name_.empty()) { + name->assign(accessible_name_); + return true; + } + return false; +} + +void XPFrame::XPFrameView::SetAccessibleName(const std::wstring& name) { + accessible_name_.assign(name); +} + +bool XPFrame::XPFrameView::ShouldForwardToTabStrip( + const ChromeViews::DropTargetEvent& event) { + if (!FrameView::ShouldForwardToTabStrip(event)) + return false; + if (parent_->IsZoomed() && event.GetX() >= parent_->min_button_->GetX() && + event.GetY() < (parent_->min_button_->GetY() + + parent_->min_button_->GetHeight())) { + return false; + } + return true; +} + +void XPFrame::ShelfVisibilityChanged() { + ShelfVisibilityChangedImpl(browser_->GetSelectedTabContents()); +} + +void XPFrame::SelectedTabToolbarSizeChanged(bool is_animating) { + if (is_animating) { + tab_contents_container_->set_fast_resize(true); + ShelfVisibilityChanged(); + tab_contents_container_->set_fast_resize(false); + } else { + ShelfVisibilityChanged(); + tab_contents_container_->UpdateHWNDBounds(); + } +} + +bool XPFrame::UpdateChildViewAndLayout(ChromeViews::View* new_view, + ChromeViews::View** view) { + DCHECK(view); + if (*view == new_view) { + // The views haven't changed, if the views pref changed schedule a layout. + if (new_view) { + CSize pref_size; + new_view->GetPreferredSize(&pref_size); + if (pref_size.cy != new_view->GetHeight()) + return true; + } + return false; + } + + // The views differ, and one may be null (but not both). Remove the old + // view (if it non-null), and add the new one (if it is non-null). If the + // height has changed, schedule a layout, otherwise reuse the existing + // bounds to avoid scheduling a layout. + + int current_height = 0; + if (*view) { + current_height = (*view)->GetHeight(); + root_view_.RemoveChildView(*view); + } + + int new_height = 0; + if (new_view) { + CSize preferred_size; + new_view->GetPreferredSize(&preferred_size); + new_height = preferred_size.cy; + root_view_.AddChildView(new_view); + } + bool changed = false; + if (new_height != current_height) { + changed = true; + } else if (new_view && *view) { + // The view changed, but the new view wants the same size, give it the + // bounds of the last view and have it repaint. + CRect last_bounds; + (*view)->GetBounds(&last_bounds); + new_view->SetBounds(last_bounds.left, last_bounds.top, + last_bounds.Width(), last_bounds.Height()); + new_view->SchedulePaint(); + } else if (new_view) { + DCHECK(new_height == 0); + // The heights are the same, but the old view is null. This only happens + // when the height is zero. Zero out the bounds. + new_view->SetBounds(0, 0, 0, 0); + } + *view = new_view; + return changed; +} + +void XPFrame::SetWindowTitle(const std::wstring& title) { + SetWindowText(title.c_str()); +} + +void XPFrame::Activate() { + if (IsIconic()) + ShowWindow(SW_RESTORE); + MoveToFront(true); +} + +void XPFrame::FlashFrame() { + FLASHWINFO flash_window_info; + flash_window_info.cbSize = sizeof(FLASHWINFO); + flash_window_info.hwnd = GetHWND(); + flash_window_info.dwFlags = FLASHW_ALL; + flash_window_info.uCount = 4; + flash_window_info.dwTimeout = 0; + ::FlashWindowEx(&flash_window_info); +} + +void XPFrame::ShowTabContents(TabContents* selected_contents) { + tab_contents_container_->SetTabContents(selected_contents); + + // Force a LoadingStateChanged notification because the TabContents + // could be loading (such as when the user unconstrains a tab. + if (selected_contents && selected_contents->delegate()) + selected_contents->delegate()->LoadingStateChanged(selected_contents); + + ShelfVisibilityChangedImpl(selected_contents); +} + +TabStrip* XPFrame::GetTabStrip() const { + return tabstrip_; +} + +gfx::Rect XPFrame::GetNormalBounds() { + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + const bool ret = !!GetWindowPlacement(&wp); + DCHECK(ret); + return gfx::Rect(wp.rcNormalPosition); +} + +void XPFrame::ContinueDetachConstrainedWindowDrag(const gfx::Point& mouse_pt, + int frame_component) { + // Need to force a paint at this point so that the newly created window looks + // correct. (Otherwise parts of the tabstrip are clipped). + CRect cr; + GetClientRect(&cr); + PaintNow(cr); + + // The user's mouse is already moving, and the left button is down, but we + // need to start moving this frame, so we _post_ it a NCLBUTTONDOWN message + // with the HTCAPTION flag to trick windows into believing the user just + // started dragging on the title bar. All the frame moving is then handled + // automatically by windows. Note that we use PostMessage here since we need + // to return to the message loop first otherwise Windows' built in move code + // will not be able to be triggered. + POINTS pts; + pts.x = mouse_pt.x(); + pts.y = mouse_pt.y(); + if (frame_component == HTCAPTION) { + // XPFrame uses windows' standard move code, so this works. + PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, reinterpret_cast<LPARAM>(&pts)); + } else { + // Because xpframe does its own resizing, and does not respond properly to + // WM_NCHITTEST, there's no reliable way for us to handle other frame + // component types. Alas. This will be corrected when XPFrame subclasses + // ChromeViews::CustomFrameWindow, some day. + } +} + +void XPFrame::SizeToContents(const gfx::Rect& contents_bounds) { + // First we need to ensure everything has an initial size. Currently, the + // window has the wrong size, but that's OK, doing this will allow us to + // figure out how big all the UI bits are. + Layout(); + + // Then we calculate the size of the window chrome, this is the stuff that + // needs to be positioned around the edges of contents_bounds. + CRect bounds; + tab_contents_container_->GetBounds(&bounds); + CRect cr; + GetClientRect(&cr); + int toolbar_height = bounds.top; + int left_edge_width = bounds.left; + int right_edge_width = cr.Width() - bounds.right; + int bottom_edge_height = cr.Height() - bounds.bottom; + + // Now resize the window. This will result in Layout() getting called again + // and the contents getting sized to the value specified in |contents_bounds| + SetWindowPos(NULL, contents_bounds.x() - left_edge_width, + contents_bounds.y() - toolbar_height, + contents_bounds.width() + left_edge_width + right_edge_width, + contents_bounds.height() + toolbar_height + bottom_edge_height, + SWP_NOZORDER | SWP_NOACTIVATE); +} + +bool XPFrame::ShouldWorkAroundAutoHideTaskbar() { + // Check the command line flag to see if we want to prevent + // the work around for maximize and auto-hide task bar. + // See bug#861590 + static bool should_work_around_auto_hide_taskbar = true; + return should_work_around_auto_hide_taskbar; +} + +void XPFrame::SetIsOffTheRecord(bool value) { + is_off_the_record_ = value; +} + +void XPFrame::DestroyBrowser() { + // TODO(beng): (Cleanup) tidy this up, just fixing the build red for now. + // Need to do this first, before the browser_ is deleted and we can't remove + // the tabstrip from the model's observer list because the model was + // destroyed with browser_. + if (browser_) { + if (bookmark_bar_view_.get() && bookmark_bar_view_->GetParent()) { + // The bookmark bar should not be parented by the time we get here. + // If you hit this NOTREACHED file a bug with the trace. + NOTREACHED(); + bookmark_bar_view_->GetParent()->RemoveChildView(bookmark_bar_view_.get()); + } + + // Explicitly delete the BookmarkBarView now. That way we don't have to + // worry about the BookmarkBarView potentially outliving the Browser & + // Profile. + bookmark_bar_view_.reset(NULL); + + browser_->tabstrip_model()->RemoveObserver(tabstrip_); + delete browser_; + browser_ = NULL; + } +} + +void XPFrame::ShelfVisibilityChangedImpl(TabContents* current_tab) { + // Coalesce layouts. + bool changed = false; + + ChromeViews::View* new_shelf = NULL; + if (current_tab && current_tab->IsDownloadShelfVisible()) + new_shelf = current_tab->GetDownloadShelfView(); + changed |= UpdateChildViewAndLayout(new_shelf, &shelf_view_); + + ChromeViews::View* new_info_bar = NULL; + if (current_tab && current_tab->IsInfoBarVisible()) + new_info_bar = current_tab->GetInfoBarView(); + changed |= UpdateChildViewAndLayout(new_info_bar, &info_bar_view_); + + ChromeViews::View* new_bookmark_bar_view = NULL; + if (SupportsBookmarkBar()) + new_bookmark_bar_view = GetBookmarkBarView(); + changed |= UpdateChildViewAndLayout(new_bookmark_bar_view, + &active_bookmark_bar_); + + // Only do a layout if the current contents is non-null. We assume that if the + // contents is NULL, we're either being destroyed, or ShowTabContents is going + // to be invoked with a non-null TabContents again so that there is no need + // in doing a layout now (and would result in extra work/invalidation on + // tab switches). + if (changed && current_tab) + Layout(); +} + diff --git a/chrome/browser/views/old_frames/xp_frame.h b/chrome/browser/views/old_frames/xp_frame.h new file mode 100644 index 0000000..e91ffff --- /dev/null +++ b/chrome/browser/views/old_frames/xp_frame.h @@ -0,0 +1,528 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_OLD_FRAMES_XP_FRAME_H__ +#define CHROME_BROWSER_VIEWS_OLD_FRAMES_XP_FRAME_H__ + +#include <windows.h> +#include <atlbase.h> +#include <atlcrack.h> +#include <atlapp.h> +#include <atlframe.h> + +#include "base/message_loop.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/views/old_frames/frame_view.h" +#include "chrome/browser/views/status_bubble.h" +#include "chrome/views/view_container.h" +#include "chrome/views/button.h" +#include "chrome/views/hwnd_view.h" +#include "chrome/views/root_view.h" +#include "chrome/views/image_view.h" +#ifdef CHROME_PERSONALIZATION +#include "chrome/personalization/personalization.h" +#endif + +#define XP_FRAME_CLASSNAME L"Chrome_XPFrame" + +class BrowserView; +class BookmarkBarView; +class Browser; +class TabContentsContainerView; +class TabStrip; +class TemporaryPlaceholder; + +//////////////////////////////////////////////////////////////////////////////// +// +// XPFrame class +// +// A CWindowImpl subclass that implements our main frame on Windows XP +// +// The window paints and handles its title bar and controls. It also supports +// a ChromeView hierarchy for the tabs and toolbar +// +//////////////////////////////////////////////////////////////////////////////// +class XPFrame : public BrowserWindow, + public CWindowImpl<XPFrame, + CWindow, + CWinTraits<WS_SYSMENU | + WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | + WS_CLIPCHILDREN>>, + public ChromeViews::BaseButton::ButtonListener, + public ChromeViews::ViewContainer, + public ChromeViews::AcceleratorTarget { + public: + + // Create a new XPFrame given the bounds and provided browser. + // |bounds| may be empty to let Windows decide where to place the window. + // The browser_window object acts both as a container for the actual + // browser contents as well as a source for the tab strip and the toolbar. + // |is_off_the_record| defines whether this window should represent an off the + // record session. + // + // Note: this method creates an HWND for the frame but doesn't initialize + // the view hierarchy. The browser creates its HWND from the frame HWND + // and then calls Init() on the frame to finalize the initialization + static XPFrame* CreateFrame(const gfx::Rect& bounds, Browser* browser, + bool is_off_the_record); + + //////////////////////////////////////////////////////////////////////////////// + // BrowserWindow implementation + //////////////////////////////////////////////////////////////////////////////// + virtual ~XPFrame(); + virtual void Init(); + virtual void Show(int command, bool adjust_to_fit); + virtual void Close(); + virtual void* GetPlatformID(); + virtual void SetAcceleratorTable( + std::map<ChromeViews::Accelerator, int>* accelerator_table); + virtual bool AcceleratorPressed(const ChromeViews::Accelerator& accelerator); + virtual gfx::Rect GetNormalBounds(); + virtual bool IsMaximized(); + virtual gfx::Rect GetBoundsForContentBounds(const gfx::Rect content_rect); + virtual void InfoBubbleShowing(); + virtual void InfoBubbleClosing(); + virtual ToolbarStarToggle* GetStarButton() const; + virtual LocationBarView* GetLocationBarView() const; + virtual GoButton* GetGoButton() const; + virtual BookmarkBarView* GetBookmarkBarView(); + virtual BrowserView* GetBrowserView() const; + virtual void UpdateToolbar(TabContents* contents, bool should_restore_state); + virtual void ProfileChanged(Profile* profile); + virtual void FocusToolbar(); + virtual bool IsBookmarkBarVisible() const; + + // + // CWindowImpl event management magic. See atlcrack.h + // + DECLARE_FRAME_WND_CLASS_EX(XP_FRAME_CLASSNAME, + IDR_MAINFRAME, + CS_DBLCLKS, + WHITE_BRUSH) + + BEGIN_MSG_MAP(HaloFrame) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange) + MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange) + MESSAGE_RANGE_HANDLER(WM_SETTINGCHANGE, WM_SETTINGCHANGE, OnSettingChange) + MSG_WM_NCCALCSIZE(OnNCCalcSize); + MSG_WM_NCPAINT(OnNCPaint); + + MSG_WM_NCACTIVATE(OnNCActivate) + MSG_WM_LBUTTONDOWN(OnMouseButtonDown) + MSG_WM_LBUTTONUP(OnLButtonUp); + MSG_WM_LBUTTONDBLCLK(OnMouseButtonDblClk) + MSG_WM_MBUTTONDOWN(OnMouseButtonDown) + MSG_WM_MBUTTONUP(OnMButtonUp); + MSG_WM_MBUTTONDBLCLK(OnMouseButtonDblClk); + MSG_WM_RBUTTONDOWN(OnMouseButtonDown) + MSG_WM_NCLBUTTONDOWN(OnNCLButtonDown) + MSG_WM_NCMBUTTONDOWN(OnNCMButtonDown) + MSG_WM_NCRBUTTONDOWN(OnNCRButtonDown) + MSG_WM_RBUTTONUP(OnRButtonUp); + MSG_WM_RBUTTONDBLCLK(OnMouseButtonDblClk); + MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject); // To avoid edit atlcrack.h. + MSG_WM_KEYDOWN(OnKeyDown); + MSG_WM_KEYUP(OnKeyUp); + MSG_WM_MOUSEMOVE(OnMouseMove) + MSG_WM_MOUSELEAVE(OnMouseLeave) + MSG_WM_CLOSE(Close) // Note: Calls Close() directly, there is no OnClose() + MSG_WM_ENDSESSION(OnEndSession) + MSG_WM_APPCOMMAND(OnAppCommand) + MSG_WM_COMMAND(OnCommand) + MSG_WM_SYSCOMMAND(OnSysCommand) + MSG_WM_ACTIVATE(OnActivate) + MSG_WM_PAINT(OnPaint) + MSG_WM_ERASEBKGND(OnEraseBkgnd) + MSG_WM_GETMINMAXINFO(OnMinMaxInfo) + MSG_WM_CAPTURECHANGED(OnCaptureChanged) + MSG_WM_SIZE(OnSize) + MSG_WM_MOVE(OnMove) + MSG_WM_MOVING(OnMoving) + MSG_WM_NCHITTEST(OnNCHitTest) + MSG_WM_INITMENU(OnInitMenu) + MSG_WM_NOTIFY(OnNotify) + MSG_WM_MOUSEACTIVATE(OnMouseActivate) + MSG_WM_POWERBROADCAST(OnPowerBroadcast) + MSG_WM_THEMECHANGED(OnThemeChanged) + REFLECT_NOTIFICATIONS() + END_MSG_MAP() + + void OnFinalMessage(HWND hwnd); + + // ChromeViews::BaseButton::ButtonListener + void ButtonPressed(ChromeViews::BaseButton *sender); + + // + // ViewContainer + virtual void GetBounds(CRect *out, bool including_frame) const; + virtual void MoveToFront(bool should_activate); + virtual HWND GetHWND() const; + virtual void PaintNow(const CRect& update_rect); + virtual ChromeViews::RootView* GetRootView(); + virtual bool IsVisible(); + virtual bool IsActive(); + virtual ChromeViews::TooltipManager* GetTooltipManager(); + virtual StatusBubble* GetStatusBubble(); + virtual bool GetAccelerator(int cmd_id, + ChromeViews::Accelerator* accelerator); + + virtual void ShelfVisibilityChanged(); + virtual void SelectedTabToolbarSizeChanged(bool is_animating); + virtual void SetWindowTitle(const std::wstring& title); + virtual void Activate(); + virtual void FlashFrame(); + + virtual void ShowTabContents(TabContents* contents); + virtual TabStrip* GetTabStrip() const; + virtual void ContinueDetachConstrainedWindowDrag(const gfx::Point& mouse_pt, + int frame_component); + void SizeToContents(const gfx::Rect& contents_bounds); + + // Returns true if the frame should be rendered in an active state. + bool PaintAsActive() const { return is_active_ || paint_as_active_; } + + protected: + // Invoked after the HWND has been created but before the window is showing. + // This registers tooltips. If you override, be sure and invoke this + // implementation. + virtual void InitAfterHWNDCreated(); + + XPFrame(Browser* browser); + + // Offer subclasses an opportunity to change how the tabstrip is created. + // The default implementation allocates a normal tab strip. + virtual TabStrip* CreateTabStrip(Browser* browser); + + // Override and return false if no tab strip or toolbar should be visible. + // Default method returns true. + virtual bool IsTabStripVisible() const { return true; } + + // Override and return false if no toolbar should be visible. Default method + // returns true. + virtual bool IsToolBarVisible() const { return true; } + +#ifdef CHROME_PERSONALIZATION + virtual bool PersonalizationEnabled() const { + return personalization_enabled_; + } + + void EnablePersonalization(bool enable_personalization) { + personalization_enabled_ = enable_personalization; + } +#endif + + // Return the frame view. + ChromeViews::View* GetFrameView() { return frame_view_; } + + // Return the tab contents container. + TabContentsContainerView* GetTabContentsContainer() { + return tab_contents_container_; + } + + // Return the X origin of the the first frame control button. + int GetButtonXOrigin() { + return min_button_->GetX(); + } + + // Return the Y location of the contents or infobar. + int GetContentsYOrigin(); + + // Give subclasses an opportunity to never show the bookmark bar. We use this + // for the application window. Default method returns true. + virtual bool SupportsBookmarkBar() const { return true; } + + virtual LRESULT OnNCHitTest(const CPoint& pt); + + // Layout all views given the available size + virtual void Layout(); + + // Set whether this frame represents an off the record session. This is + // currently only called during initialization. + void SetIsOffTheRecord(bool value); + + virtual void DestroyBrowser(); + + // The Browser instance that created this instance + Browser* browser_; + private: + enum FrameAction {FA_NONE = 0, FA_RESIZING, FA_FORWARDING}; + + enum ResizeMode {RM_UNDEFINED = 0, RM_NORTH, RM_NORTH_EAST, RM_EAST, + RM_SOUTH_EAST, RM_SOUTH, RM_SOUTH_WEST, RM_WEST, + RM_NORTH_WEST}; + + enum ResizeCursor {RC_VERTICAL = 0, RC_HORIZONTAL, RC_NESW, RC_NWSE}; + + LRESULT OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled); + LRESULT OnNotify(int w_param, NMHDR* hdr); + LRESULT OnSettingChange(UINT u_msg, WPARAM w_param, LPARAM l_param, + BOOL& handled); + + // The view we use for our background + class XPFrameView : public FrameView { + public: + XPFrameView(XPFrame* parent) : FrameView(parent), parent_(parent) { + } + virtual void Paint(ChromeCanvas* canvas); + virtual std::string GetClassName() const { + return "chrome/browser/views/XPFrameView"; + } + // Accessibility information + bool GetAccessibleRole(VARIANT* role); + + // Returns a brief, identifying string, containing a unique, readable name. + bool GetAccessibleName(std::wstring* name); + + // Assigns an accessible string name. + void SetAccessibleName(const std::wstring& name); + + protected: + // Overriden to return false if maximized and over the min/max/close + // button. + virtual bool ShouldForwardToTabStrip( + const ChromeViews::DropTargetEvent& event); + + private: + void PaintFrameBorder(ChromeCanvas* canvas); + void PaintFrameBorderZoomed(ChromeCanvas* canvas); + void PaintContentsBorder(ChromeCanvas* canvas, + int x, + int y, + int w, + int h); + void PaintContentsBorderZoomed(ChromeCanvas* canvas, + int x, + int y, + int w); + XPFrame* parent_; + + // Storage of strings needed for accessibility. + std::wstring accessible_name_; + + DISALLOW_EVIL_CONSTRUCTORS(XPFrameView); + }; + + friend class XPFrameView; + + // + // Windows event handlers + // + + void OnEndSession(BOOL ending, UINT logoff); + + LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param); + LRESULT OnNCPaint(HRGN param); + + void OnMove(const CSize& size); + void OnMoving(UINT param, const LPRECT new_bounds); + void OnSize(UINT param, const CSize& size); + void OnMouseButtonDown(UINT flags, const CPoint& pt); + void OnNCLButtonDown(UINT flags, const CPoint& pt); + void OnNCMButtonDown(UINT flags, const CPoint& pt); + void OnNCRButtonDown(UINT flags, const CPoint& pt); + void OnMouseButtonUp(UINT flags, const CPoint& pt); + void OnMouseButtonDblClk(UINT flags, const CPoint& pt); + void OnLButtonUp(UINT flags, const CPoint& pt); + void OnMButtonUp(UINT flags, const CPoint& pt); + void OnRButtonUp(UINT flags, const CPoint& pt); + void OnMouseMove(UINT flags, const CPoint& pt); + void OnMouseLeave(); + void OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags); + void OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags); + LRESULT OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param); + + LRESULT OnAppCommand( + HWND w_param, short app_command, WORD device, int keystate); + void OnCommand(UINT notification_code, int command_id, HWND window); + void OnSysCommand(UINT notification_code, CPoint click); + void OnActivate(UINT n_state, BOOL is_minimized, HWND other); + int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message); + void OnPaint(HDC dc); + LRESULT OnEraseBkgnd(HDC dc); + void OnMinMaxInfo(LPMINMAXINFO mm_info); + void OnCaptureChanged(HWND hwnd); + void OnInitMenu(HMENU menu); + void ArmOnMouseLeave(); + void ShowSystemMenu(int x, int y); + + LRESULT OnNCActivate(BOOL param); + BOOL OnPowerBroadcast(DWORD power_event, DWORD data); + void OnThemeChanged(); + + // Window resize + // Note: we cannot use the standard window resize because we don't have + // a frame. Returning HTSIZE from WM_NCHITTEST doesn't work + void StartWindowResize(ResizeMode mode, const CPoint &pt); + void ProcessWindowResize(const CPoint &pt); + void StopWindowResize(); + + // Compute a ResizeMode given a point (x,y) and the current size + // of the window (width,height). This method returns UNDEFINED + // if no resizing should occur. + ResizeMode ComputeResizeMode(int x, int y, int width, int height); + + // + // Change the cursor as needed given the desired ResizeMode + void SetResizeCursor(ResizeMode r_mode); + + // Check whether the selected tab needs some extra painting during + // move or resize because it obstructs its contents (WebContents) + bool ShouldRefreshCurrentTabContents(); + + // + // View events propagation + // + bool ProcessMousePressed(const CPoint& pt, UINT flags, bool dbl_click); + void ProcessMouseDragged(const CPoint& pt, UINT flags); + void ProcessMouseReleased(const CPoint& pt, UINT flags); + void ProcessMouseMoved(const CPoint &pt, UINT flags); + void ProcessMouseExited(); + + // Updates either the infobar or the bottom shelf depending on the views + // passed in. + void UpdateShelfViews(int view_top, int preferred_height, + ChromeViews::View* new_view, + ChromeViews::View** current_view, + int* last_height); + + // If the workaround to prevent taskbar from hiding behind maximizing + // xp_frame is enabled. + bool ShouldWorkAroundAutoHideTaskbar(); + + // Updates a single view. If *view differs from new_view the old view is + // removed and the new view is added. + // + // This is intended to be used when swapping in/out child views that are + // referenced via a field. + // + // This function returns true if anything was changed. The caller should + // ensure that Layout() is eventually called in this case. + bool UpdateChildViewAndLayout(ChromeViews::View* new_view, + ChromeViews::View** view); + + // Return the set of bitmaps that should be used to draw this frame. + SkBitmap** GetFrameBitmaps(); + + // Implementation for ShelfVisibilityChanged(). Updates the various shelf + // fields. If one of the shelves has changed (or it's size has changed) and + // current_tab is non-NULL layout occurs. + void ShelfVisibilityChangedImpl(TabContents* current_tab); + + // Root view + ChromeViews::RootView root_view_; + + // Top level view used to render the frame itself including the title bar + XPFrameView* frame_view_; + + // Browser contents + TabContentsContainerView* tab_contents_container_; + + // Frame buttons + ChromeViews::Button* min_button_; + ChromeViews::Button* max_button_; + ChromeViews::Button* restore_button_; + ChromeViews::Button* close_button_; + + // Whether we should save the bounds of the window. We don't want to + // save the default size of windows for certain classes of windows + // like unconstrained popups. Defaults to true. + bool should_save_window_placement_; + + // Whether we saved the window placement yet. + bool saved_window_placement_; + + // Current frame ui action + FrameAction current_action_; + + // Whether the frame is currently active + bool is_active_; + + // whether we are expecting a mouse leave event + bool on_mouse_leave_armed_; + + // Point containing the coordinate of the first event during + // a window dragging or resizing session + CPoint drag_origin_; + + // Rectangle containing the original window bounds during + // a window dragging or resizing session. It is in screen + // coordinate system + CRect previous_bounds_; + + // Initialize static members the first time this is invoked + static void InitializeIfNeeded(); + + // cursor storage + HCURSOR previous_cursor_; + + // Current resize mode + ResizeMode current_resize_mode_; + + // Frame min size + CSize minimum_size_; + + scoped_ptr<ChromeViews::TooltipManager> tooltip_manager_; + + // A view positioned at the bottom of the frame. + ChromeViews::View* shelf_view_; + + // A view positioned beneath the bookmark bar. + // Implementation mirrors shelf_view_ + ChromeViews::View* info_bar_view_; + + // The view that contains the tabs and any associated controls. + TabStrip* tabstrip_; + + // The bookmark bar. This is lazily created. + scoped_ptr<BookmarkBarView> bookmark_bar_view_; + + // The visible bookmark bar. NULL if none is visible. + ChromeViews::View* active_bookmark_bar_; + + // The optional container for the off the record icon. + ChromeViews::ImageView* off_the_record_image_; + + // The container for the distributor logo. + ChromeViews::ImageView* distributor_logo_; + + // We need to own the text of the menu, the Windows API does not copy it. + std::wstring task_manager_label_text_; + + // A mapping between accelerators and commands. + scoped_ptr<std::map<ChromeViews::Accelerator, int>> accelerator_table_; + + // Whether this frame represents an off the record session. + bool is_off_the_record_; + +#ifdef CHROME_PERSONALIZATION + FramePersonalization personalization_; + bool personalization_enabled_; +#endif + + // Set during layout. Total height of the title bar. + int title_bar_height_; + + static bool g_initialized; + static HCURSOR g_resize_cursors[4]; + static SkBitmap** g_bitmaps; + static SkBitmap** g_otr_bitmaps; + + // Instance of accessibility information and handling for MSAA root + CComPtr<IAccessible> accessibility_root_; + + // See note in VistaFrame for a description of this. + bool ignore_ncactivate_; + bool paint_as_active_; + + // A view that holds the client-area contents of the browser window. + BrowserView* browser_view_; + + DISALLOW_EVIL_CONSTRUCTORS(XPFrame); +}; + +#endif // CHROME_BROWSER_VIEWS_OLD_FRAMES_XP_FRAME_H__ + diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index 2b8dc61..1bafdca 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -13,7 +13,6 @@ #include "chrome/browser/view_ids.h" #include "chrome/browser/views/tabs/dragged_tab_controller.h" #include "chrome/browser/views/tabs/tab.h" -#include "chrome/browser/vista_frame.h" #include "chrome/browser/web_contents.h" #include "chrome/common/drag_drop_types.h" #include "chrome/common/gfx/chrome_canvas.h" |