From 32670b07a6c42634f446e3d471f42a9fb40090f2 Mon Sep 17 00:00:00 2001 From: "ben@chromium.org" Date: Tue, 3 Mar 2009 00:28:00 +0000 Subject: Support DWM switching. This completes the collapsing of window types and browser frames around a single class: views::Window. CustomFrameWindow is removed with this change. The Browser window is represented by a single views::Window subclass: BrowserFrame, which replaces both AeroGlassFrame and OpaqueFrame. NonClientView is now a container of two sibling classes - the Window's ClientView (in the Browser's case, BrowserView), and a NonClientFrameView subclass, which provides the rendering for the non-client portions of the window. These Views are siblings rather than the ClientView a child of the NonClientFrameView because when the DWM is toggled, the ClientView would have to be re-parented. Many Views make the assumption they are only inserted into a View hierarchy once, and so this is problematic. By having the views be siblings, this is avoided. With this in mind, all of the former NonClientViews now become NonClientFrameView subclasses: DefaultNonClientView -> CustomFrameView (non-existent, NonClientView) -> NativeFrameView AeroGlassNonClientView -> GlassBrowserFrameView OpaqueNonClientView -> OpaqueBrowserFrameView The latter two derive from NonClientFrameView via BrowserNonClientFrameView, which adds some extras. I also had to modify the TabRenderer class to know how to drop its cache of tab background images when the theme changes since it uses different ones for Glass and non-Glass. This change also fixes a few non-client flicker issues relating to window non-client activation by using more ScopedRedrawLocks. (Touches info_bubble.cc, window.cc) Bugs fixed: http://crbug.com/153 http://crbug.com/747 http://crbug.com/2371 http://crbug.com/3264 http://crbug.com/8234 Plumbing for http://crbug.com/8247 Design docs: http://dev.chromium.org/developers/design-documents/views-windowing http://dev.chromium.org/developers/design-documents/browser-window Review URL: http://codereview.chromium.org/27317 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10757 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/browser_focus_uitest.cc | 2 +- chrome/browser/views/browser_views.vcproj | 26 +- chrome/browser/views/constrained_window_impl.cc | 183 ++-- chrome/browser/views/constrained_window_impl.h | 17 +- chrome/browser/views/frame/aero_glass_frame.cc | 243 ----- chrome/browser/views/frame/aero_glass_frame.h | 95 -- .../views/frame/aero_glass_non_client_view.cc | 365 ------- .../views/frame/aero_glass_non_client_view.h | 87 -- chrome/browser/views/frame/browser_frame.cc | 191 ++++ chrome/browser/views/frame/browser_frame.h | 108 +- chrome/browser/views/frame/browser_view.cc | 70 +- .../browser/views/frame/browser_window_factory.cc | 50 - .../views/frame/glass_browser_frame_view.cc | 423 ++++++++ .../browser/views/frame/glass_browser_frame_view.h | 107 ++ .../views/frame/opaque_browser_frame_view.cc | 1067 +++++++++++++++++++ .../views/frame/opaque_browser_frame_view.h | 167 +++ chrome/browser/views/frame/opaque_frame.cc | 139 --- chrome/browser/views/frame/opaque_frame.h | 74 -- .../browser/views/frame/opaque_non_client_view.cc | 1071 -------------------- .../browser/views/frame/opaque_non_client_view.h | 168 --- chrome/browser/views/hung_renderer_view.cc | 2 +- chrome/browser/views/info_bubble.cc | 3 +- chrome/browser/views/tabs/tab_renderer.cc | 54 +- chrome/browser/views/tabs/tab_renderer.h | 4 + chrome/browser/views/tabs/tab_strip.cc | 3 +- chrome/browser/views/toolbar_view.cc | 12 +- chrome/browser/views/toolbar_view.h | 2 +- chrome/views/custom_frame_view.cc | 698 +++++++++++++ chrome/views/custom_frame_view.h | 123 +++ chrome/views/custom_frame_window.cc | 506 --------- chrome/views/custom_frame_window.h | 103 -- chrome/views/default_non_client_view.cc | 711 ------------- chrome/views/default_non_client_view.h | 128 --- chrome/views/native_frame_view.cc | 61 ++ chrome/views/native_frame_view.h | 38 + chrome/views/non_client_view.cc | 135 ++- chrome/views/non_client_view.h | 186 +++- chrome/views/root_view.cc | 4 + chrome/views/root_view.h | 4 + chrome/views/view.cc | 6 + chrome/views/view.h | 8 + chrome/views/views.vcproj | 20 +- chrome/views/widget.h | 8 +- chrome/views/widget_win.cc | 2 +- chrome/views/widget_win.h | 19 +- chrome/views/window.cc | 159 +-- chrome/views/window.h | 76 +- 47 files changed, 3580 insertions(+), 4148 deletions(-) delete mode 100644 chrome/browser/views/frame/aero_glass_frame.cc delete mode 100644 chrome/browser/views/frame/aero_glass_frame.h delete mode 100644 chrome/browser/views/frame/aero_glass_non_client_view.cc delete mode 100644 chrome/browser/views/frame/aero_glass_non_client_view.h create mode 100644 chrome/browser/views/frame/browser_frame.cc delete mode 100644 chrome/browser/views/frame/browser_window_factory.cc create mode 100644 chrome/browser/views/frame/glass_browser_frame_view.cc create mode 100644 chrome/browser/views/frame/glass_browser_frame_view.h create mode 100644 chrome/browser/views/frame/opaque_browser_frame_view.cc create mode 100644 chrome/browser/views/frame/opaque_browser_frame_view.h delete mode 100644 chrome/browser/views/frame/opaque_frame.cc delete mode 100644 chrome/browser/views/frame/opaque_frame.h delete mode 100644 chrome/browser/views/frame/opaque_non_client_view.cc delete mode 100644 chrome/browser/views/frame/opaque_non_client_view.h create mode 100644 chrome/views/custom_frame_view.cc create mode 100644 chrome/views/custom_frame_view.h delete mode 100644 chrome/views/custom_frame_window.cc delete mode 100644 chrome/views/custom_frame_window.h delete mode 100644 chrome/views/default_non_client_view.cc delete mode 100644 chrome/views/default_non_client_view.h create mode 100644 chrome/views/native_frame_view.cc create mode 100644 chrome/views/native_frame_view.h diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc index 6ff0f35..d920a012 100644 --- a/chrome/browser/browser_focus_uitest.cc +++ b/chrome/browser/browser_focus_uitest.cc @@ -245,7 +245,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) { HWND hwnd = reinterpret_cast(browser()->window()->GetNativeHandle()); BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); ASSERT_TRUE(browser_view); - EXPECT_TRUE(browser_view->frame()->GetWindow()->IsActive()); + EXPECT_TRUE(browser_view->frame()->IsActive()); // Close the 2nd browser to avoid a DCHECK(). HWND hwnd2 = reinterpret_cast(browser2->window()->GetNativeHandle()); diff --git a/chrome/browser/views/browser_views.vcproj b/chrome/browser/views/browser_views.vcproj index 92d345d..41b7bb1 100644 --- a/chrome/browser/views/browser_views.vcproj +++ b/chrome/browser/views/browser_views.vcproj @@ -125,19 +125,7 @@ Name="Frame" > - - - - - - - - diff --git a/chrome/browser/views/constrained_window_impl.cc b/chrome/browser/views/constrained_window_impl.cc index 8b57d18..8005457 100644 --- a/chrome/browser/views/constrained_window_impl.cc +++ b/chrome/browser/views/constrained_window_impl.cc @@ -184,22 +184,22 @@ SkBitmap* VistaWindowResources::bitmaps_[]; SkBitmap* OTRWindowResources::bitmaps_[]; //////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowNonClientView +// ConstrainedWindowFrameView -class ConstrainedWindowNonClientView - : public views::NonClientView, +class ConstrainedWindowFrameView + : public views::NonClientFrameView, public views::BaseButton::ButtonListener { public: - ConstrainedWindowNonClientView(ConstrainedWindowImpl* container, - TabContents* owner); - virtual ~ConstrainedWindowNonClientView(); + explicit ConstrainedWindowFrameView(ConstrainedWindowImpl* container); + virtual ~ConstrainedWindowFrameView(); void UpdateWindowTitle(); - // Overridden from views::NonClientView: - virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; - virtual gfx::Size CalculateWindowSizeForClientSize(int width, - int height) const; + // Overridden from views::NonClientFrameView: + virtual gfx::Rect GetBoundsForClientView() const; + virtual bool AlwaysUseCustomFrame() const; + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const; virtual gfx::Point GetSystemMenuPoint() const; virtual int NonClientHitTest(const gfx::Point& point); virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); @@ -209,7 +209,7 @@ class ConstrainedWindowNonClientView // Overridden from views::View: virtual void Paint(ChromeCanvas* canvas); virtual void Layout(); - virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + virtual void ThemeChanged(); // Overridden from views::BaseButton::ButtonListener: virtual void ButtonPressed(views::BaseButton* sender); @@ -242,11 +242,17 @@ class ConstrainedWindowNonClientView void LayoutTitleBar(); void LayoutClientView(); + // Returns the bounds of the client area for the specified view size. + gfx::Rect CalculateClientAreaBounds(int width, int height) const; + SkColor GetTitleColor() const { return (container_->owner()->profile()->IsOffTheRecord() || !win_util::ShouldUseVistaFrame()) ? SK_ColorWHITE : SK_ColorBLACK; } + // Loads the appropriate set of WindowResources for the frame view. + void InitWindowResources(); + ConstrainedWindowImpl* container_; scoped_ptr resources_; @@ -255,15 +261,18 @@ class ConstrainedWindowNonClientView views::Button* close_button_; + // The bounds of the ClientView. + gfx::Rect client_view_bounds_; + static void InitClass(); // The font to be used to render the titlebar text. static ChromeFont title_font_; - DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowNonClientView); + DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowFrameView); }; -ChromeFont ConstrainedWindowNonClientView::title_font_; +ChromeFont ConstrainedWindowFrameView::title_font_; namespace { // The frame border is only visible in restored mode and is hardcoded to 4 px on @@ -294,23 +303,15 @@ const SkColor kContentsBorderColor = SkColorSetRGB(219, 235, 255); } //////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowNonClientView, public: +// ConstrainedWindowFrameView, public: -ConstrainedWindowNonClientView::ConstrainedWindowNonClientView( - ConstrainedWindowImpl* container, TabContents* owner) - : NonClientView(), +ConstrainedWindowFrameView::ConstrainedWindowFrameView( + ConstrainedWindowImpl* container) + : NonClientFrameView(), container_(container), close_button_(new views::Button) { InitClass(); - if (owner->profile()->IsOffTheRecord()) { - resources_.reset(new OTRWindowResources); - } else { - if (win_util::ShouldUseVistaFrame()) { - resources_.reset(new VistaWindowResources); - } else { - resources_.reset(new XPWindowResources); - } - } + InitWindowResources(); close_button_->SetImage(views::Button::BS_NORMAL, resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON)); @@ -324,35 +325,37 @@ ConstrainedWindowNonClientView::ConstrainedWindowNonClientView( AddChildView(close_button_); } -ConstrainedWindowNonClientView::~ConstrainedWindowNonClientView() { +ConstrainedWindowFrameView::~ConstrainedWindowFrameView() { } -void ConstrainedWindowNonClientView::UpdateWindowTitle() { +void ConstrainedWindowFrameView::UpdateWindowTitle() { SchedulePaint(title_bounds_, false); } //////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowNonClientView, views::NonClientView implementation: +// ConstrainedWindowFrameView, views::NonClientFrameView implementation: -gfx::Rect ConstrainedWindowNonClientView::CalculateClientAreaBounds( - int width, - int height) const { - int top_height = NonClientTopBorderHeight(); - int border_thickness = NonClientBorderThickness(); - return gfx::Rect(border_thickness, top_height, - std::max(0, width - (2 * border_thickness)), - std::max(0, height - top_height - border_thickness)); +gfx::Rect ConstrainedWindowFrameView::GetBoundsForClientView() const { + return client_view_bounds_; } -gfx::Size ConstrainedWindowNonClientView::CalculateWindowSizeForClientSize( - int width, - int height) const { +bool ConstrainedWindowFrameView::AlwaysUseCustomFrame() const { + // Constrained windows always use the custom frame - they just have a + // different set of bitmaps. + return true; +} + +gfx::Rect ConstrainedWindowFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + int top_height = NonClientTopBorderHeight(); int border_thickness = NonClientBorderThickness(); - return gfx::Size(width + (2 * border_thickness), - height + NonClientTopBorderHeight() + border_thickness); + return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), + std::max(0, client_bounds.y() - top_height), + client_bounds.width() + (2 * border_thickness), + client_bounds.height() + top_height + border_thickness); } -gfx::Point ConstrainedWindowNonClientView::GetSystemMenuPoint() const { +gfx::Point ConstrainedWindowFrameView::GetSystemMenuPoint() const { // Doesn't really matter, since we never show system menus on constrained // windows... gfx::Point system_menu_point(FrameBorderThickness(), @@ -361,7 +364,7 @@ gfx::Point ConstrainedWindowNonClientView::GetSystemMenuPoint() const { return system_menu_point; } -int ConstrainedWindowNonClientView::NonClientHitTest(const gfx::Point& point) { +int ConstrainedWindowFrameView::NonClientHitTest(const gfx::Point& point) { if (!bounds().Contains(point)) return HTNOWHERE; @@ -380,8 +383,8 @@ int ConstrainedWindowNonClientView::NonClientHitTest(const gfx::Point& point) { return (window_component == HTNOWHERE) ? HTCAPTION : window_component; } -void ConstrainedWindowNonClientView::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) { +void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { DCHECK(window_mask); // Redefine the window visible region for the new size. @@ -403,60 +406,55 @@ void ConstrainedWindowNonClientView::GetWindowMask(const gfx::Size& size, window_mask->close(); } -void ConstrainedWindowNonClientView::EnableClose(bool enable) { +void ConstrainedWindowFrameView::EnableClose(bool enable) { close_button_->SetEnabled(enable); } //////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowNonClientView, views::View implementation: +// ConstrainedWindowFrameView, views::View implementation: -void ConstrainedWindowNonClientView::Paint(ChromeCanvas* canvas) { +void ConstrainedWindowFrameView::Paint(ChromeCanvas* canvas) { PaintFrameBorder(canvas); PaintTitleBar(canvas); PaintClientEdge(canvas); } -void ConstrainedWindowNonClientView::Layout() { +void ConstrainedWindowFrameView::Layout() { LayoutWindowControls(); LayoutTitleBar(); LayoutClientView(); } -void ConstrainedWindowNonClientView::ViewHierarchyChanged(bool is_add, - View *parent, - View *child) { - // Add our Client View as we are added to the Container so that if we are - // subsequently resized all the parent-child relationships are established. - if (is_add && GetWidget() && child == this) - AddChildView(container_->client_view()); +void ConstrainedWindowFrameView::ThemeChanged() { + InitWindowResources(); } //////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowNonClientView, views::BaseButton::Button +// ConstrainedWindowFrameView, views::BaseButton::Button // implementation: -void ConstrainedWindowNonClientView::ButtonPressed(views::BaseButton* sender) { +void ConstrainedWindowFrameView::ButtonPressed(views::BaseButton* sender) { if (sender == close_button_) container_->ExecuteSystemMenuCommand(SC_CLOSE); } //////////////////////////////////////////////////////////////////////////////// -// ConstrainedWindowNonClientView, private: +// ConstrainedWindowFrameView, private: -int ConstrainedWindowNonClientView::FrameBorderThickness() const { +int ConstrainedWindowFrameView::FrameBorderThickness() const { return kFrameBorderThickness; } -int ConstrainedWindowNonClientView::NonClientBorderThickness() const { +int ConstrainedWindowFrameView::NonClientBorderThickness() const { return FrameBorderThickness() + kClientEdgeThickness; } -int ConstrainedWindowNonClientView::NonClientTopBorderHeight() const { +int ConstrainedWindowFrameView::NonClientTopBorderHeight() const { int title_top_spacing, title_thickness; return TitleCoordinates(&title_top_spacing, &title_thickness); } -int ConstrainedWindowNonClientView::TitleCoordinates( +int ConstrainedWindowFrameView::TitleCoordinates( int* title_top_spacing, int* title_thickness) const { int frame_thickness = FrameBorderThickness(); @@ -470,7 +468,7 @@ int ConstrainedWindowNonClientView::TitleCoordinates( return *title_top_spacing + *title_thickness + title_bottom_spacing; } -void ConstrainedWindowNonClientView::PaintFrameBorder(ChromeCanvas* canvas) { +void ConstrainedWindowFrameView::PaintFrameBorder(ChromeCanvas* canvas) { SkBitmap* top_left_corner = resources_->GetPartBitmap(FRAME_TOP_LEFT_CORNER); SkBitmap* top_right_corner = resources_->GetPartBitmap(FRAME_TOP_RIGHT_CORNER); @@ -514,13 +512,13 @@ void ConstrainedWindowNonClientView::PaintFrameBorder(ChromeCanvas* canvas) { height() - top_left_corner->height() - bottom_left_corner->height()); } -void ConstrainedWindowNonClientView::PaintTitleBar(ChromeCanvas* canvas) { +void ConstrainedWindowFrameView::PaintTitleBar(ChromeCanvas* canvas) { canvas->DrawStringInt(container_->GetWindowTitle(), title_font_, GetTitleColor(), MirroredLeftPointForRect(title_bounds_), title_bounds_.y(), title_bounds_.width(), title_bounds_.height()); } -void ConstrainedWindowNonClientView::PaintClientEdge(ChromeCanvas* canvas) { +void ConstrainedWindowFrameView::PaintClientEdge(ChromeCanvas* canvas) { gfx::Rect client_edge_bounds(CalculateClientAreaBounds(width(), height())); client_edge_bounds.Inset(-kClientEdgeThickness, -kClientEdgeThickness); gfx::Rect frame_shadow_bounds(client_edge_bounds); @@ -535,7 +533,7 @@ void ConstrainedWindowNonClientView::PaintClientEdge(ChromeCanvas* canvas) { client_edge_bounds.height()); } -void ConstrainedWindowNonClientView::LayoutWindowControls() { +void ConstrainedWindowFrameView::LayoutWindowControls() { gfx::Size close_button_size = close_button_->GetPreferredSize(); close_button_->SetBounds( width() - close_button_size.width() - FrameBorderThickness(), @@ -543,7 +541,7 @@ void ConstrainedWindowNonClientView::LayoutWindowControls() { close_button_size.height()); } -void ConstrainedWindowNonClientView::LayoutTitleBar() { +void ConstrainedWindowFrameView::LayoutTitleBar() { // Size the title. int title_x = FrameBorderThickness() + kIconLeftSpacing; int title_top_spacing, title_thickness; @@ -554,13 +552,34 @@ void ConstrainedWindowNonClientView::LayoutTitleBar() { title_font_.height()); } -void ConstrainedWindowNonClientView::LayoutClientView() { - container_->client_view()->SetBounds(CalculateClientAreaBounds(width(), - height())); +void ConstrainedWindowFrameView::LayoutClientView() { + client_view_bounds_ = CalculateClientAreaBounds(width(), height()); +} + +gfx::Rect ConstrainedWindowFrameView::CalculateClientAreaBounds( + int width, + int height) const { + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(border_thickness, top_height, + std::max(0, width - (2 * border_thickness)), + std::max(0, height - top_height - border_thickness)); +} + +void ConstrainedWindowFrameView::InitWindowResources() { + if (container_->owner()->profile()->IsOffTheRecord()) { + resources_.reset(new OTRWindowResources); + } else { + if (win_util::ShouldUseVistaFrame()) { + resources_.reset(new VistaWindowResources); + } else { + resources_.reset(new XPWindowResources); + } + } } // static -void ConstrainedWindowNonClientView::InitClass() { +void ConstrainedWindowFrameView::InitClass() { static bool initialized = false; if (!initialized) { title_font_ = win_util::GetWindowTitleFont(); @@ -583,8 +602,8 @@ ConstrainedWindowImpl::~ConstrainedWindowImpl() { //////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowImpl, ConstrainedWindow implementation: -ConstrainedWindowNonClientView* ConstrainedWindowImpl::non_client_view() { - return static_cast(non_client_view_); +views::NonClientFrameView* ConstrainedWindowImpl::CreateFrameViewForWindow() { + return new ConstrainedWindowFrameView(this); } void ConstrainedWindowImpl::UpdateWindowTitle() { @@ -652,13 +671,13 @@ const gfx::Rect& ConstrainedWindowImpl::GetCurrentBounds() const { ConstrainedWindowImpl::ConstrainedWindowImpl( TabContents* owner, views::WindowDelegate* window_delegate) - : CustomFrameWindow(window_delegate, - new ConstrainedWindowNonClientView(this, owner)) { - Init(owner); + : Window(window_delegate), + owner_(owner) { + non_client_view_->SetFrameView(CreateFrameViewForWindow()); + Init(); } -void ConstrainedWindowImpl::Init(TabContents* owner) { - owner_ = owner; +void ConstrainedWindowImpl::Init() { focus_restoration_disabled_ = false; set_window_style(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU); @@ -666,13 +685,13 @@ void ConstrainedWindowImpl::Init(TabContents* owner) { } void ConstrainedWindowImpl::InitAsDialog(const gfx::Rect& initial_bounds) { - CustomFrameWindow::Init(owner_->GetNativeView(), initial_bounds); + Window::Init(owner_->GetNativeView(), initial_bounds); ActivateConstrainedWindow(); } void ConstrainedWindowImpl::UpdateUI(unsigned int changed_flags) { if (changed_flags & TabContents::INVALIDATE_TITLE) - non_client_view()->UpdateWindowTitle(); + UpdateWindowTitle(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/views/constrained_window_impl.h b/chrome/browser/views/constrained_window_impl.h index 229555e..30e6303 100644 --- a/chrome/browser/views/constrained_window_impl.h +++ b/chrome/browser/views/constrained_window_impl.h @@ -8,11 +8,11 @@ #include "base/gfx/rect.h" #include "chrome/browser/tab_contents/constrained_window.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" -#include "chrome/views/custom_frame_window.h" +#include "chrome/views/window.h" class ConstrainedTabContentsWindowDelegate; class ConstrainedWindowAnimation; -class ConstrainedWindowNonClientView; +class ConstrainedWindowFrameView; namespace views { class HWNDView; class WindowDelegate; @@ -25,20 +25,15 @@ class WindowDelegate; // a child HWND with a custom window frame. // class ConstrainedWindowImpl : public ConstrainedWindow, - public views::CustomFrameWindow { + public views::Window { public: virtual ~ConstrainedWindowImpl(); // Returns the TabContents that constrains this Constrained Window. TabContents* owner() const { return owner_; } - // Returns the non-client view inside this Constrained Window. - // NOTE: Defining the function body here would require pulling in the - // declarations of ConstrainedWindowNonClientView, as well as all the classes - // it depends on, from the .cc file; the benefit isn't worth it. - ConstrainedWindowNonClientView* non_client_view(); - - // Overridden from views::CustomFrameWindow: + // Overridden from views::Window: + virtual views::NonClientFrameView* CreateFrameViewForWindow(); virtual void UpdateWindowTitle(); // Overridden from ConstrainedWindow: @@ -64,7 +59,7 @@ class ConstrainedWindowImpl : public ConstrainedWindow, // ConstrainedWindow. ConstrainedWindowImpl(TabContents* owner, views::WindowDelegate* window_delegate); - void Init(TabContents* owner); + void Init(); // Initialize the Constrained Window as a Constrained Dialog containing a // views::View client area. diff --git a/chrome/browser/views/frame/aero_glass_frame.cc b/chrome/browser/views/frame/aero_glass_frame.cc deleted file mode 100644 index bc9b0f2..0000000 --- a/chrome/browser/views/frame/aero_glass_frame.cc +++ /dev/null @@ -1,243 +0,0 @@ -// 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/frame/aero_glass_frame.h" - -#include - -#include "chrome/browser/browser_list.h" -#include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/frame/aero_glass_non_client_view.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/views/window_delegate.h" -#include "grit/theme_resources.h" - -// static - -static const int kClientEdgeThickness = 3; - -HICON AeroGlassFrame::throbber_icons_[AeroGlassFrame::kThrobberIconCount]; - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassFrame, public: - -AeroGlassFrame::AeroGlassFrame(BrowserView* browser_view) - : Window(browser_view), - browser_view_(browser_view), - frame_initialized_(false), - throbber_running_(false), - throbber_frame_(0) { - non_client_view_ = new AeroGlassNonClientView(this, browser_view); - browser_view_->set_frame(this); - - if (window_delegate()->ShouldShowWindowIcon()) - InitThrobberIcons(); -} - -AeroGlassFrame::~AeroGlassFrame() { -} - -void AeroGlassFrame::Init() { - Window::Init(NULL, gfx::Rect()); -} - -int AeroGlassFrame::GetMinimizeButtonOffset() const { - TITLEBARINFOEX titlebar_info; - titlebar_info.cbSize = sizeof(TITLEBARINFOEX); - SendMessage(GetHWND(), WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info); - - CPoint minimize_button_corner(titlebar_info.rgrect[2].left, - titlebar_info.rgrect[2].top); - MapWindowPoints(HWND_DESKTOP, GetHWND(), &minimize_button_corner, 1); - - return minimize_button_corner.x; -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassFrame, BrowserFrame implementation: - -gfx::Rect AeroGlassFrame::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) { - RECT rect = client_bounds.ToRECT(); - AdjustWindowRectEx(&rect, window_style(), FALSE, window_ex_style()); - return gfx::Rect(rect); -} - -gfx::Rect AeroGlassFrame::GetBoundsForTabStrip(TabStrip* tabstrip) const { - return GetAeroGlassNonClientView()->GetBoundsForTabStrip(tabstrip); -} - -void AeroGlassFrame::UpdateThrobber(bool running) { - if (throbber_running_) { - if (running) { - DisplayNextThrobberFrame(); - } else { - StopThrobber(); - } - } else if (running) { - StartThrobber(); - } -} - -views::Window* AeroGlassFrame::GetWindow() { - return this; -} - -const views::Window* AeroGlassFrame::GetWindow() const { - return this; -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassFrame, views::WidgetWin overrides: - -bool AeroGlassFrame::AcceleratorPressed(views::Accelerator* accelerator) { - return browser_view_->AcceleratorPressed(*accelerator); -} - -bool AeroGlassFrame::GetAccelerator(int cmd_id, - views::Accelerator* accelerator) { - return browser_view_->GetAccelerator(cmd_id, accelerator); -} - -void AeroGlassFrame::OnInitMenuPopup(HMENU menu, UINT position, - BOOL is_system_menu) { - browser_view_->PrepareToRunSystemMenu(menu); -} - -void AeroGlassFrame::OnEnterSizeMove() { - browser_view_->WindowMoveOrResizeStarted(); -} - -void AeroGlassFrame::OnEndSession(BOOL ending, UINT logoff) { - BrowserList::WindowsSessionEnding(); -} - -LRESULT AeroGlassFrame::OnMouseActivate(HWND window, UINT hittest_code, - UINT message) { - return browser_view_->ActivateAppModalDialog() ? MA_NOACTIVATEANDEAT - : MA_ACTIVATE; -} - -void AeroGlassFrame::OnMove(const CPoint& point) { - browser_view_->WindowMoved(); -} - -void AeroGlassFrame::OnMoving(UINT param, const RECT* new_bounds) { - browser_view_->WindowMoved(); -} - -LRESULT AeroGlassFrame::OnNCActivate(BOOL active) { - if (browser_view_->ActivateAppModalDialog()) - return TRUE; - - if (!frame_initialized_) { - if (browser_view_->IsBrowserTypeNormal()) { - ::SetWindowPos(GetHWND(), NULL, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); - UpdateDWMFrame(); - } - frame_initialized_ = true; - } - browser_view_->ActivationChanged(!!active); - SetMsgHandled(false); - return TRUE; -} - -LRESULT AeroGlassFrame::OnNCCalcSize(BOOL mode, LPARAM l_param) { - if (!browser_view_->IsBrowserTypeNormal() || !mode) { - SetMsgHandled(FALSE); - return 0; - } - - // In fullscreen mode, we make the whole window client area. - if (!browser_view_->IsFullscreen()) { - NCCALCSIZE_PARAMS* params = reinterpret_cast(l_param); - int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); - params->rgrc[0].left += (border_thickness - kClientEdgeThickness); - params->rgrc[0].right -= (border_thickness - kClientEdgeThickness); - params->rgrc[0].bottom -= (border_thickness - kClientEdgeThickness); - } - - UpdateDWMFrame(); - - SetMsgHandled(TRUE); - return 0; -} - -LRESULT AeroGlassFrame::OnNCHitTest(const CPoint& pt) { - LRESULT result; - if (DwmDefWindowProc(GetHWND(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y), - &result)) { - return result; - } - return Window::OnNCHitTest(pt); -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassFrame, views::CustomFrameWindow overrides: - -int AeroGlassFrame::GetShowState() const { - return browser_view_->GetShowState(); -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassFrame, private: - -void AeroGlassFrame::UpdateDWMFrame() { - // Nothing to do yet. - if (!client_view()) - return; - - // In fullscreen mode, we don't extend glass into the client area at all, - // because the GDI-drawn text in the web content composited over it will - // become semi-transparent over any glass area. - MARGINS margins = { 0 }; - if (!browser_view_->IsFullscreen()) { - margins.cxLeftWidth = kClientEdgeThickness + 1; - margins.cxRightWidth = kClientEdgeThickness + 1; - margins.cyTopHeight = - GetBoundsForTabStrip(browser_view_->tabstrip()).bottom(); - margins.cyBottomHeight = kClientEdgeThickness + 1; - } - DwmExtendFrameIntoClientArea(GetHWND(), &margins); -} - -AeroGlassNonClientView* AeroGlassFrame::GetAeroGlassNonClientView() const { - // We can safely assume that this conversion is true. - return static_cast(non_client_view_); -} - -void AeroGlassFrame::StartThrobber() { - if (!throbber_running_) { - throbber_running_ = true; - throbber_frame_ = 0; - InitThrobberIcons(); - ::SendMessage(GetHWND(), WM_SETICON, static_cast(ICON_SMALL), - reinterpret_cast(throbber_icons_[throbber_frame_])); - } -} - -void AeroGlassFrame::StopThrobber() { - if (throbber_running_) - throbber_running_ = false; -} - -void AeroGlassFrame::DisplayNextThrobberFrame() { - throbber_frame_ = (throbber_frame_ + 1) % kThrobberIconCount; - ::SendMessage(GetHWND(), WM_SETICON, static_cast(ICON_SMALL), - reinterpret_cast(throbber_icons_[throbber_frame_])); -} - -// static -void AeroGlassFrame::InitThrobberIcons() { - static bool initialized = false; - if (!initialized) { - ResourceBundle &rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < kThrobberIconCount; ++i) { - throbber_icons_[i] = rb.LoadThemeIcon(IDR_THROBBER_01 + i); - DCHECK(throbber_icons_[i]); - } - initialized = true; - } -} diff --git a/chrome/browser/views/frame/aero_glass_frame.h b/chrome/browser/views/frame/aero_glass_frame.h deleted file mode 100644 index 4c7e2f8..0000000 --- a/chrome/browser/views/frame/aero_glass_frame.h +++ /dev/null @@ -1,95 +0,0 @@ -// 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_FRAME_AERO_GLASS_FRAME_H_ -#define CHROME_BROWSER_VIEWS_FRAME_AERO_GLASS_FRAME_H_ - -#include "chrome/browser/views/frame/browser_frame.h" -#include "chrome/views/window.h" - -class AeroGlassNonClientView; -class BrowserView; - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassFrame -// -// AeroGlassFrame is a Window subclass that provides the window frame on -// Windows Vista with DWM desktop compositing enabled. The window's non-client -// areas are drawn by the system. -// -class AeroGlassFrame : public BrowserFrame, - public views::Window { - public: - explicit AeroGlassFrame(BrowserView* browser_view); - virtual ~AeroGlassFrame(); - - void Init(); - - // Determine the distance of the left edge of the minimize button from the - // left edge of the window. Used in our Non-Client View's Layout. - int GetMinimizeButtonOffset() const; - - // Overridden from BrowserFrame: - virtual gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds); - virtual void SizeToContents(const gfx::Rect& contents_bounds) {} - virtual gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const; - virtual void UpdateThrobber(bool running); - virtual views::Window* GetWindow(); - virtual const views::Window* GetWindow() const; - - protected: - // Overridden from views::WidgetWin: - virtual bool AcceleratorPressed(views::Accelerator* accelerator); - virtual bool GetAccelerator(int cmd_id, views::Accelerator* accelerator); - virtual void OnInitMenuPopup(HMENU menu, UINT position, BOOL is_system_menu); - virtual void OnEnterSizeMove(); - virtual void OnEndSession(BOOL ending, UINT logoff); - virtual LRESULT OnMouseActivate(HWND window, - UINT hittest_code, - UINT message); - virtual void OnMove(const CPoint& point); - virtual void OnMoving(UINT param, const RECT* new_bounds); - virtual LRESULT OnNCActivate(BOOL active); - virtual LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param); - virtual LRESULT OnNCHitTest(const CPoint& pt); - - // Overridden from views::Window: - virtual int GetShowState() const; - virtual bool IsAppWindow() const { return true; } - - private: - // Updates the DWM with the frame bounds. - void UpdateDWMFrame(); - - // Return a pointer to the concrete type of our non-client view. - AeroGlassNonClientView* GetAeroGlassNonClientView() const; - - // Starts/Stops the window throbber running. - void StartThrobber(); - void StopThrobber(); - - // Displays the next throbber frame. - void DisplayNextThrobberFrame(); - - // The BrowserView is our ClientView. This is a pointer to it. - BrowserView* browser_view_; - - bool frame_initialized_; - - // Whether or not the window throbber is currently animating. - bool throbber_running_; - - // The index of the current frame of the throbber animation. - int throbber_frame_; - - static const int kThrobberIconCount = 24; - static HICON throbber_icons_[kThrobberIconCount]; - static void InitThrobberIcons(); - - DISALLOW_EVIL_CONSTRUCTORS(AeroGlassFrame); -}; - -#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_AERO_GLASS_FRAME_H_ - diff --git a/chrome/browser/views/frame/aero_glass_non_client_view.cc b/chrome/browser/views/frame/aero_glass_non_client_view.cc deleted file mode 100644 index 93031d1..0000000 --- a/chrome/browser/views/frame/aero_glass_non_client_view.cc +++ /dev/null @@ -1,365 +0,0 @@ -// 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/frame/aero_glass_non_client_view.h" - -#include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/tabs/tab_strip.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/views/client_view.h" -#include "chrome/views/window_resources.h" -#include "grit/theme_resources.h" - -// An enumeration of bitmap resources used by this window. -enum { - // Client Edge Border. - FRAME_CLIENT_EDGE_TOP_LEFT, - FRAME_CLIENT_EDGE_TOP, - FRAME_CLIENT_EDGE_TOP_RIGHT, - FRAME_CLIENT_EDGE_RIGHT, - FRAME_CLIENT_EDGE_BOTTOM_RIGHT, - FRAME_CLIENT_EDGE_BOTTOM, - FRAME_CLIENT_EDGE_BOTTOM_LEFT, - FRAME_CLIENT_EDGE_LEFT, - - FRAME_PART_BITMAP_COUNT // Must be last. -}; - -class AeroGlassWindowResources { - public: - AeroGlassWindowResources() { - InitClass(); - } - virtual ~AeroGlassWindowResources() { } - - virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - IDR_CONTENT_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, - IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, - IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, - IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); - - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - - DISALLOW_EVIL_CONSTRUCTORS(AeroGlassWindowResources); -}; - -// static -SkBitmap* AeroGlassWindowResources::standard_frame_bitmaps_[]; - -AeroGlassWindowResources* AeroGlassNonClientView::resources_ = NULL; -SkBitmap* AeroGlassNonClientView::distributor_logo_ = NULL; - -namespace { -// There are 3 px of client edge drawn inside the outer frame borders. -const int kNonClientBorderThickness = 3; -// Besides the frame border, there's another 11 px of empty space atop the -// window in restored mode, to use to drag the window around. -const int kNonClientRestoredExtraThickness = 11; -// In the window corners, the resize areas don't actually expand bigger, but the -// 16 px at the end of the top and bottom edges triggers diagonal resizing. -const int kResizeAreaCornerSize = 16; -// The distributor logo is drawn 3 px from the top of the window. -static const int kLogoTopSpacing = 3; -// In maximized mode, the OTR avatar starts 2 px below the top of the screen, so -// that it doesn't extend into the "3D edge" portion of the titlebar. -const int kOTRMaximizedTopSpacing = 2; -// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the -// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the -// user). -const int kOTRBottomSpacing = 2; -// There are 2 px on each side of the OTR avatar (between the frame border and -// it on the left, and between it and the tabstrip on the right). -const int kOTRSideSpacing = 2; -// In restored mode, the New Tab button isn't at the same height as the caption -// buttons, but the space will look cluttered if it actually slides under them, -// so we stop it when the gap between the two is down to 5 px. -const int kNewTabCaptionRestoredSpacing = 5; -// In maximized mode, where the New Tab button and the caption buttons are at -// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid -// looking too cluttered. -const int kNewTabCaptionMaximizedSpacing = 16; -// When there's a distributor logo, we leave a 7 px gap between it and the -// caption buttons. -const int kLogoCaptionSpacing = 7; -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassNonClientView, public: - -AeroGlassNonClientView::AeroGlassNonClientView(AeroGlassFrame* frame, - BrowserView* browser_view) - : frame_(frame), - browser_view_(browser_view) { - InitClass(); -} - -AeroGlassNonClientView::~AeroGlassNonClientView() { -} - -gfx::Rect AeroGlassNonClientView::GetBoundsForTabStrip(TabStrip* tabstrip) { - int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ? - (otr_avatar_bounds_.right() + kOTRSideSpacing) : - NonClientBorderThickness(); - int tabstrip_width = frame_->GetMinimizeButtonOffset() - tabstrip_x - - (frame_->IsMaximized() ? - kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing); - return gfx::Rect(tabstrip_x, NonClientTopBorderHeight(), - std::max(0, tabstrip_width), tabstrip->GetPreferredHeight()); -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassNonClientView, views::NonClientView implementation: - -gfx::Rect AeroGlassNonClientView::CalculateClientAreaBounds(int width, - int height) const { - if (!browser_view_->IsTabStripVisible()) - return gfx::Rect(0, 0, this->width(), this->height()); - - int top_height = NonClientTopBorderHeight(); - int border_thickness = NonClientBorderThickness(); - return gfx::Rect(border_thickness, top_height, - std::max(0, width - (2 * border_thickness)), - std::max(0, height - top_height - border_thickness)); -} - -gfx::Size AeroGlassNonClientView::CalculateWindowSizeForClientSize( - int width, - int height) const { - if (!browser_view_->IsTabStripVisible()) - return gfx::Size(width, height); - - int border_thickness = NonClientBorderThickness(); - return gfx::Size(width + (2 * border_thickness), - height + NonClientTopBorderHeight() + border_thickness); -} - -gfx::Point AeroGlassNonClientView::GetSystemMenuPoint() const { - gfx::Point system_menu_point; - if (browser_view_->IsBrowserTypeNormal()) { - // The X coordinate conditional is because in maximized mode the frame edge - // and the client edge are both offscreen, whereas in the opaque frame - // (where we don't do this trick) maximized windows have no client edge and - // only the frame edge is offscreen. - system_menu_point.SetPoint(NonClientBorderThickness() - - (browser_view_->CanCurrentlyResize() ? kClientEdgeThickness : 0), - NonClientTopBorderHeight() + browser_view_->GetTabStripHeight() - - (browser_view_->IsFullscreen() ? 0 : kClientEdgeThickness)); - } else { - system_menu_point.SetPoint(0, -kFrameShadowThickness); - } - ConvertPointToScreen(this, &system_menu_point); - return system_menu_point; -} - -int AeroGlassNonClientView::NonClientHitTest(const gfx::Point& point) { - // If the browser isn't in normal mode, we haven't customized the frame, so - // Windows can figure this out. If the point isn't within our bounds, then - // it's in the native portion of the frame, so again Windows can figure it - // out. - if (!browser_view_->IsBrowserTypeNormal() || !bounds().Contains(point)) - return HTNOWHERE; - - int frame_component = frame_->client_view()->NonClientHitTest(point); - if (frame_component != HTNOWHERE) - return frame_component; - - int border_thickness = FrameBorderThickness(); - int window_component = GetHTComponentForFrame(point, border_thickness, - NonClientBorderThickness(), border_thickness, - kResizeAreaCornerSize - border_thickness, - frame_->window_delegate()->CanResize()); - // Fall back to the caption if no other component matches. - return (window_component == HTNOWHERE) ? HTCAPTION : window_component; -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassNonClientView, views::View overrides: - -void AeroGlassNonClientView::Paint(ChromeCanvas* canvas) { - if (!browser_view_->IsTabStripVisible()) - return; // Nothing is visible, so don't bother to paint. - - PaintDistributorLogo(canvas); - PaintToolbarBackground(canvas); - PaintOTRAvatar(canvas); - PaintClientEdge(canvas); -} - -void AeroGlassNonClientView::Layout() { - LayoutDistributorLogo(); - LayoutOTRAvatar(); - LayoutClientView(); -} - -void AeroGlassNonClientView::ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child) { - if (is_add && child == this) { - DCHECK(GetWidget()); - DCHECK(frame_->client_view()->GetParent() != this); - AddChildView(frame_->client_view()); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// AeroGlassNonClientView, private: - -int AeroGlassNonClientView::FrameBorderThickness() const { - return browser_view_->IsFullscreen() ? 0 : GetSystemMetrics(SM_CXSIZEFRAME); -} - -int AeroGlassNonClientView::NonClientBorderThickness() const { - return browser_view_->IsFullscreen() ? 0 : kNonClientBorderThickness; -} - -int AeroGlassNonClientView::NonClientTopBorderHeight() const { - return FrameBorderThickness() + (browser_view_->CanCurrentlyResize() ? - kNonClientRestoredExtraThickness : 0); -} - -void AeroGlassNonClientView::PaintDistributorLogo(ChromeCanvas* canvas) { - // The distributor logo is only painted when the frame is not maximized and - // when we actually have a logo. - if (!frame_->IsMaximized() && distributor_logo_) { - // NOTE: We don't mirror the logo placement here because the outer frame - // itself isn't mirrored in RTL. This is a bug; if it is fixed, this should - // be mirrored as in opaque_non_client_view.cc. - canvas->DrawBitmapInt(*distributor_logo_, logo_bounds_.x(), - logo_bounds_.y()); - } -} - -void AeroGlassNonClientView::PaintToolbarBackground(ChromeCanvas* canvas) { - gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds()); - gfx::Point toolbar_origin(toolbar_bounds.origin()); - View::ConvertPointToView(frame_->client_view(), this, &toolbar_origin); - toolbar_bounds.set_origin(toolbar_origin); - - SkBitmap* toolbar_left = - resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT); - canvas->DrawBitmapInt(*toolbar_left, - toolbar_bounds.x() - toolbar_left->width(), - toolbar_bounds.y()); - - SkBitmap* toolbar_center = - resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); - canvas->TileImageInt(*toolbar_center, toolbar_bounds.x(), toolbar_bounds.y(), - toolbar_bounds.width(), toolbar_center->height()); - - canvas->DrawBitmapInt(*resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT), - toolbar_bounds.right(), toolbar_bounds.y()); -} - -void AeroGlassNonClientView::PaintOTRAvatar(ChromeCanvas* canvas) { - if (!browser_view_->ShouldShowOffTheRecordAvatar()) - return; - - SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); - canvas->DrawBitmapInt(otr_avatar_icon, 0, - (otr_avatar_icon.height() - otr_avatar_bounds_.height()) / 2, - otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), - MirroredLeftPointForRect(otr_avatar_bounds_), otr_avatar_bounds_.y(), - otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), false); -} - -void AeroGlassNonClientView::PaintClientEdge(ChromeCanvas* canvas) { - // The client edges start below the toolbar upper corner images regardless - // of how tall the toolbar itself is. - int client_area_top = - frame_->client_view()->y() + browser_view_->GetToolbarBounds().y() + - resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT)->height(); - - gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height()); - int client_area_bottom = - std::max(client_area_top, height() - NonClientBorderThickness()); - int client_area_height = client_area_bottom - client_area_top; - SkBitmap* right = resources_->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT); - canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, - right->width(), client_area_height); - - canvas->DrawBitmapInt( - *resources_->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT), - client_area_bounds.right(), client_area_bottom); - - SkBitmap* bottom = resources_->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM); - canvas->TileImageInt(*bottom, client_area_bounds.x(), - client_area_bottom, client_area_bounds.width(), - bottom->height()); - - SkBitmap* bottom_left = - resources_->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT); - canvas->DrawBitmapInt(*bottom_left, - client_area_bounds.x() - bottom_left->width(), client_area_bottom); - - SkBitmap* left = resources_->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); - canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), - client_area_top, left->width(), client_area_height); -} - -void AeroGlassNonClientView::LayoutDistributorLogo() { - if (distributor_logo_) { - logo_bounds_.SetRect(frame_->GetMinimizeButtonOffset() - - distributor_logo_->width() - kLogoCaptionSpacing, kLogoTopSpacing, - distributor_logo_->width(), distributor_logo_->height()); - } else { - logo_bounds_.SetRect(frame_->GetMinimizeButtonOffset(), kLogoTopSpacing, 0, - 0); - } -} - -void AeroGlassNonClientView::LayoutOTRAvatar() { - SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); - int top_height = NonClientTopBorderHeight(); - int tabstrip_height, otr_height; - if (browser_view_->IsTabStripVisible()) { - tabstrip_height = browser_view_->GetTabStripHeight() - kOTRBottomSpacing; - otr_height = frame_->IsMaximized() ? - (tabstrip_height - kOTRMaximizedTopSpacing) : - otr_avatar_icon.height(); - } else { - tabstrip_height = otr_height = 0; - } - otr_avatar_bounds_.SetRect(NonClientBorderThickness() + kOTRSideSpacing, - top_height + tabstrip_height - otr_height, - otr_avatar_icon.width(), otr_height); -} - -void AeroGlassNonClientView::LayoutClientView() { - frame_->client_view()->SetBounds(CalculateClientAreaBounds(width(), - height())); -} - -// static -void AeroGlassNonClientView::InitClass() { - static bool initialized = false; - if (!initialized) { - resources_ = new AeroGlassWindowResources; - -#if defined(GOOGLE_CHROME_BUILD) - distributor_logo_ = ResourceBundle::GetSharedInstance(). - GetBitmapNamed(IDR_DISTRIBUTOR_LOGO); -#endif - - initialized = true; - } -} - diff --git a/chrome/browser/views/frame/aero_glass_non_client_view.h b/chrome/browser/views/frame/aero_glass_non_client_view.h deleted file mode 100644 index 5023ea0..0000000 --- a/chrome/browser/views/frame/aero_glass_non_client_view.h +++ /dev/null @@ -1,87 +0,0 @@ -// 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_FRAME_AERO_GLASS_NON_CLIENT_VIEW_H_ -#define CHROME_BROWSER_VIEWS_FRAME_AERO_GLASS_NON_CLIENT_VIEW_H_ - -#include "chrome/browser/views/frame/aero_glass_frame.h" -#include "chrome/views/non_client_view.h" -#include "chrome/views/button.h" - -class BrowserView; -class AeroGlassWindowResources; - -class AeroGlassNonClientView : public views::NonClientView { - public: - // Constructs a non-client view for an AeroGlassFrame. - AeroGlassNonClientView(AeroGlassFrame* frame, BrowserView* browser_view); - virtual ~AeroGlassNonClientView(); - - // Retrieve the bounds for the specified |tabstrip|, in the coordinate system - // of the non-client view (which whould be window coordinates). - gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip); - - protected: - // Overridden from views::NonClientView: - virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; - virtual gfx::Size CalculateWindowSizeForClientSize(int width, - int height) const; - virtual gfx::Point GetSystemMenuPoint() const; - virtual int NonClientHitTest(const gfx::Point& point); - virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) { } - virtual void EnableClose(bool enable) { } - virtual void ResetWindowControls() { } - - // Overridden from views::View: - virtual void Paint(ChromeCanvas* canvas); - virtual void Layout(); - virtual void ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child); - - private: - // Returns the thickness of the border that makes up the window frame edges. - // This does not include any client edge. - int FrameBorderThickness() const; - - // Returns the thickness of the entire nonclient left, right, and bottom - // borders, including both the window frame and any client edge. - int NonClientBorderThickness() const; - - // Returns the height of the entire nonclient top border, including the window - // frame, any title area, and any connected client edge. - int NonClientTopBorderHeight() const; - - // Paint various sub-components of this view. - void PaintDistributorLogo(ChromeCanvas* canvas); - void PaintToolbarBackground(ChromeCanvas* canvas); - void PaintOTRAvatar(ChromeCanvas* canvas); - void PaintClientEdge(ChromeCanvas* canvas); - - // Layout various sub-components of this view. - void LayoutDistributorLogo(); - void LayoutOTRAvatar(); - void LayoutClientView(); - - // The layout rect of the distributor logo, if visible. - gfx::Rect logo_bounds_; - - // The layout rect of the OTR avatar icon, if visible. - gfx::Rect otr_avatar_bounds_; - - // The frame that hosts this view. - AeroGlassFrame* frame_; - - // The BrowserView hosted within this View. - BrowserView* browser_view_; - - static void InitClass(); - static SkBitmap* distributor_logo_; - static AeroGlassWindowResources* resources_; - - DISALLOW_EVIL_CONSTRUCTORS(AeroGlassNonClientView); -}; - -#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_AERO_GLASS_NON_CLIENT_VIEW_H_ - diff --git a/chrome/browser/views/frame/browser_frame.cc b/chrome/browser/views/frame/browser_frame.cc new file mode 100644 index 0000000..ac7f2d5 --- /dev/null +++ b/chrome/browser/views/frame/browser_frame.cc @@ -0,0 +1,191 @@ +// 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/frame/browser_frame.h" + +#include + +#include "chrome/browser/browser_list.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/frame/glass_browser_frame_view.h" +#include "chrome/browser/views/frame/opaque_browser_frame_view.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/win_util.h" +#include "chrome/views/window_delegate.h" +#include "grit/theme_resources.h" + +// static +static const int kClientEdgeThickness = 3; + +/////////////////////////////////////////////////////////////////////////////// +// BrowserFrame, public: + +BrowserFrame::BrowserFrame(BrowserView* browser_view) + : Window(browser_view), + browser_view_(browser_view), + frame_initialized_(false) { + browser_view_->set_frame(this); + non_client_view_->SetFrameView(CreateFrameViewForWindow()); +} + +BrowserFrame::~BrowserFrame() { +} + +void BrowserFrame::Init() { + Window::Init(NULL, gfx::Rect()); +} + +int BrowserFrame::GetMinimizeButtonOffset() const { + TITLEBARINFOEX titlebar_info; + titlebar_info.cbSize = sizeof(TITLEBARINFOEX); + SendMessage(GetHWND(), WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info); + + CPoint minimize_button_corner(titlebar_info.rgrect[2].left, + titlebar_info.rgrect[2].top); + MapWindowPoints(HWND_DESKTOP, GetHWND(), &minimize_button_corner, 1); + + return minimize_button_corner.x; +} + +gfx::Rect BrowserFrame::GetBoundsForTabStrip(TabStrip* tabstrip) const { + return browser_frame_view_->GetBoundsForTabStrip(tabstrip); +} + +void BrowserFrame::UpdateThrobber(bool running) { + browser_frame_view_->UpdateThrobber(running); +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserFrame, views::WidgetWin overrides: + +bool BrowserFrame::AcceleratorPressed(views::Accelerator* accelerator) { + return browser_view_->AcceleratorPressed(*accelerator); +} + +bool BrowserFrame::GetAccelerator(int cmd_id, views::Accelerator* accelerator) { + return browser_view_->GetAccelerator(cmd_id, accelerator); +} + +void BrowserFrame::OnEndSession(BOOL ending, UINT logoff) { + BrowserList::WindowsSessionEnding(); +} + +void BrowserFrame::OnEnterSizeMove() { + browser_view_->WindowMoveOrResizeStarted(); +} + +void BrowserFrame::OnInitMenuPopup(HMENU menu, UINT position, + BOOL is_system_menu) { + browser_view_->PrepareToRunSystemMenu(menu); +} + +LRESULT BrowserFrame::OnMouseActivate(HWND window, UINT hittest_code, + UINT message) { + return browser_view_->ActivateAppModalDialog() ? MA_NOACTIVATEANDEAT + : MA_ACTIVATE; +} + +void BrowserFrame::OnMove(const CPoint& point) { + browser_view_->WindowMoved(); +} + +void BrowserFrame::OnMoving(UINT param, const RECT* new_bounds) { + browser_view_->WindowMoved(); +} + +LRESULT BrowserFrame::OnNCActivate(BOOL active) { + if (browser_view_->ActivateAppModalDialog()) + return TRUE; + + // Perform first time initialization of the DWM frame insets, only if we're + // using the native frame. + if (non_client_view_->UseNativeFrame() && !frame_initialized_) { + if (browser_view_->IsBrowserTypeNormal()) { + ::SetWindowPos(GetHWND(), NULL, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); + UpdateDWMFrame(); + } + frame_initialized_ = true; + } + browser_view_->ActivationChanged(!!active); + return Window::OnNCActivate(active); +} + +LRESULT BrowserFrame::OnNCCalcSize(BOOL mode, LPARAM l_param) { + // We don't adjust the client area unless we're a tabbed browser window and + // are using the native frame. + if (!non_client_view_->UseNativeFrame() || + !browser_view_->IsBrowserTypeNormal() || !mode) { + return Window::OnNCCalcSize(mode, l_param); + } + + // In fullscreen mode, we make the whole window client area. + if (!browser_view_->IsFullscreen()) { + NCCALCSIZE_PARAMS* params = reinterpret_cast(l_param); + int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); + params->rgrc[0].left += (border_thickness - kClientEdgeThickness); + params->rgrc[0].right -= (border_thickness - kClientEdgeThickness); + params->rgrc[0].bottom -= (border_thickness - kClientEdgeThickness); + } + + UpdateDWMFrame(); + + SetMsgHandled(TRUE); + return 0; +} + +LRESULT BrowserFrame::OnNCHitTest(const CPoint& pt) { + // Only do DWM hit-testing when we are using the native frame. + if (non_client_view_->UseNativeFrame()) { + LRESULT result; + if (DwmDefWindowProc(GetHWND(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y), + &result)) { + return result; + } + } + return Window::OnNCHitTest(pt); +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserFrame, views::CustomFrameWindow overrides: + +int BrowserFrame::GetShowState() const { + return browser_view_->GetShowState(); +} + +views::NonClientFrameView* BrowserFrame::CreateFrameViewForWindow() { + if (non_client_view_->UseNativeFrame()) + browser_frame_view_ = new GlassBrowserFrameView(this, browser_view_); + else + browser_frame_view_ = new OpaqueBrowserFrameView(this, browser_view_); + return browser_frame_view_; +} + +void BrowserFrame::UpdateFrameAfterFrameChange() { + Window::UpdateFrameAfterFrameChange(); + UpdateDWMFrame(); +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserFrame, private: + +void BrowserFrame::UpdateDWMFrame() { + // Nothing to do yet. + if (!client_view()) + return; + + // In fullscreen mode, we don't extend glass into the client area at all, + // because the GDI-drawn text in the web content composited over it will + // become semi-transparent over any glass area. + MARGINS margins = { 0 }; + if (!browser_view_->IsFullscreen()) { + margins.cxLeftWidth = kClientEdgeThickness + 1; + margins.cxRightWidth = kClientEdgeThickness + 1; + margins.cyTopHeight = + GetBoundsForTabStrip(browser_view_->tabstrip()).bottom(); + margins.cyBottomHeight = kClientEdgeThickness + 1; + } + DwmExtendFrameIntoClientArea(GetHWND(), &margins); +} + diff --git a/chrome/browser/views/frame/browser_frame.h b/chrome/browser/views/frame/browser_frame.h index ee908b5..c7efcab 100644 --- a/chrome/browser/views/frame/browser_frame.h +++ b/chrome/browser/views/frame/browser_frame.h @@ -2,63 +2,91 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_H_ -#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_H_ +#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_ +#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_ +#include "chrome/views/window.h" + +class AeroGlassNonClientView; class BrowserView; -namespace views { -class Window; -} -namespace gfx { -class Rect; -} +class NonClientFrameView; class TabStrip; +// A specialization of the NonClientFrameView object that provides additional +// Browser-specific methods. +class BrowserNonClientFrameView : public views::NonClientFrameView { + public: + BrowserNonClientFrameView() : NonClientFrameView() {} + virtual ~BrowserNonClientFrameView() {} + + // Returns the bounds within which the TabStrip should be laid out. + virtual gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const = 0; + + // Updates the throbber. + virtual void UpdateThrobber(bool running) = 0; +}; + /////////////////////////////////////////////////////////////////////////////// // BrowserFrame // -// BrowserFrame is an interface that represents a top level browser window -// frame. Implementations of this interface exist to supply the browser window -// for specific environments, e.g. Vista with Aero Glass enabled. +// BrowserFrame is a Window subclass that provides the window frame for the +// Chrome browser window. // -class BrowserFrame { +class BrowserFrame : public views::Window { public: - // TODO(beng): We should _not_ have to expose this method here... it's only - // because BrowserView needs it to implement BrowserWindow - // because we're doing popup setup in browser.cc when we - // shouldn't be... - virtual gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) = 0; + explicit BrowserFrame(BrowserView* browser_view); + virtual ~BrowserFrame(); - // Sizes the frame assuming the contents view's bounds are as specified. - virtual void SizeToContents(const gfx::Rect& contents_bounds) = 0; + // Initialize the frame. Creates the Window. + void Init(); - // Retrieve the bounds for the specified |tabstrip|, in window coordinates. - virtual gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const = 0; + // Determine the distance of the left edge of the minimize button from the + // left edge of the window. Used in our Non-Client View's Layout. + int GetMinimizeButtonOffset() const; - // Updates the current frame of the Throbber animation, if applicable. - // |running| is whether or not the throbber should be running. - virtual void UpdateThrobber(bool running) = 0; + // Retrieves the bounds, in non-client view coordinates for the specified + // TabStrip. + gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const; + + // Tells the frame to update the throbber. + void UpdateThrobber(bool running); + + protected: + // Overridden from views::WidgetWin: + virtual bool AcceleratorPressed(views::Accelerator* accelerator); + virtual bool GetAccelerator(int cmd_id, views::Accelerator* accelerator); + virtual void OnInitMenuPopup(HMENU menu, UINT position, BOOL is_system_menu); + virtual void OnEnterSizeMove(); + virtual void OnEndSession(BOOL ending, UINT logoff); + virtual LRESULT OnMouseActivate(HWND window, + UINT hittest_code, + UINT message); + virtual void OnMove(const CPoint& point); + virtual void OnMoving(UINT param, const RECT* new_bounds); + virtual LRESULT OnNCActivate(BOOL active); + virtual LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param); + virtual LRESULT OnNCHitTest(const CPoint& pt); + + // Overridden from views::Window: + virtual int GetShowState() const; + virtual bool IsAppWindow() const { return true; } + virtual views::NonClientFrameView* CreateFrameViewForWindow(); + virtual void UpdateFrameAfterFrameChange(); - // Returns the views::Window associated with this frame. - virtual views::Window* GetWindow() = 0; - virtual const views::Window* GetWindow() const = 0; + private: + // Updates the DWM with the frame bounds. + void UpdateDWMFrame(); - enum FrameType { - FRAMETYPE_OPAQUE, - FRAMETYPE_AERO_GLASS - }; + // The BrowserView is our ClientView. This is a pointer to it. + BrowserView* browser_view_; - // Returns the FrameType that should be constructed given the current system - // settings. - static FrameType GetActiveFrameType(); + // A pointer to our NonClientFrameView as a BrowserNonClientFrameView. + BrowserNonClientFrameView* browser_frame_view_; - // Creates a BrowserFrame instance for the specified FrameType and - // BrowserView. - static BrowserFrame* CreateForBrowserView(FrameType type, - BrowserView* browser_view); + bool frame_initialized_; + DISALLOW_EVIL_CONSTRUCTORS(BrowserFrame); }; -#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_H_ +#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_FRAME_ diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index f287485..72e8e8f 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/command_line.h" - #include "chrome/browser/views/frame/browser_view.h" +#include "base/command_line.h" #include "base/file_version_info.h" #include "base/time.h" #include "chrome/app/chrome_dll_resource.h" @@ -367,19 +366,6 @@ bool BrowserView::GetAccelerator(int cmd_id, views::Accelerator* accelerator) { return false; } -bool BrowserView::SystemCommandReceived(UINT notification_code, - const gfx::Point& point) { - bool handled = false; - - if (browser_->command_updater()->SupportsCommand(notification_code) && - browser_->command_updater()->IsCommandEnabled(notification_code)) { - browser_->ExecuteCommand(notification_code); - handled = true; - } - - return handled; -} - void BrowserView::AddViewToDropList(views::View* view) { dropable_views_.insert(view); } @@ -489,8 +475,8 @@ void BrowserView::Init() { void BrowserView::Show() { // If the window is already visible, just activate it. - if (frame_->GetWindow()->IsVisible()) { - frame_->GetWindow()->Activate(); + if (frame_->IsVisible()) { + frame_->Activate(); return; } @@ -508,32 +494,29 @@ void BrowserView::Show() { if (selected_tab_contents) selected_tab_contents->RestoreFocus(); - frame_->GetWindow()->Show(); - int show_state = frame_->GetWindow()->GetShowState(); - if (show_state == SW_SHOWNORMAL || show_state == SW_SHOWMAXIMIZED) - frame_->GetWindow()->Activate(); + frame_->Show(); } void BrowserView::SetBounds(const gfx::Rect& bounds) { - frame_->GetWindow()->SetBounds(bounds); + frame_->SetBounds(bounds); } void BrowserView::Close() { - frame_->GetWindow()->Close(); + frame_->Close(); } void BrowserView::Activate() { - frame_->GetWindow()->Activate(); + frame_->Activate(); } bool BrowserView::IsActive() const { - return frame_->GetWindow()->IsActive(); + return frame_->IsActive(); } void BrowserView::FlashFrame() { FLASHWINFO fwi; fwi.cbSize = sizeof(fwi); - fwi.hwnd = frame_->GetWindow()->GetHWND(); + fwi.hwnd = frame_->GetHWND(); fwi.dwFlags = FLASHW_ALL; fwi.uCount = 4; fwi.dwTimeout = 0; @@ -564,9 +547,9 @@ void BrowserView::SelectedTabToolbarSizeChanged(bool is_animating) { } void BrowserView::UpdateTitleBar() { - frame_->GetWindow()->UpdateWindowTitle(); + frame_->UpdateWindowTitle(); if (ShouldShowWindowIcon()) - frame_->GetWindow()->UpdateWindowIcon(); + frame_->UpdateWindowIcon(); } void BrowserView::UpdateLoadingAnimations(bool should_animate) { @@ -598,13 +581,13 @@ gfx::Rect BrowserView::GetNormalBounds() const { WINDOWPLACEMENT wp; wp.length = sizeof(wp); - const bool ret = !!GetWindowPlacement(frame_->GetWindow()->GetHWND(), &wp); + const bool ret = !!GetWindowPlacement(frame_->GetHWND(), &wp); DCHECK(ret); return gfx::Rect(wp.rcNormalPosition); } bool BrowserView::IsMaximized() const { - return frame_->GetWindow()->IsMaximized(); + return frame_->IsMaximized(); } void BrowserView::SetFullscreen(bool fullscreen) { @@ -637,7 +620,7 @@ void BrowserView::SetFullscreen(bool fullscreen) { // taskbar if the window is in the maximized state. saved_window_info_.maximized = IsMaximized(); if (saved_window_info_.maximized) - frame_->GetWindow()->ExecuteSystemMenuCommand(SC_RESTORE); + frame_->ExecuteSystemMenuCommand(SC_RESTORE); saved_window_info_.style = GetWindowLong(hwnd, GWL_STYLE); saved_window_info_.ex_style = GetWindowLong(hwnd, GWL_EXSTYLE); GetWindowRect(hwnd, &saved_window_info_.window_rect); @@ -667,7 +650,7 @@ void BrowserView::SetFullscreen(bool fullscreen) { new_rect.height(), SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); if (saved_window_info_.maximized) - frame_->GetWindow()->ExecuteSystemMenuCommand(SC_MAXIMIZE); + frame_->ExecuteSystemMenuCommand(SC_MAXIMIZE); } // Turn fullscreen bubble on or off. @@ -999,6 +982,8 @@ bool BrowserView::ShouldShowWindowIcon() const { } bool BrowserView::ExecuteWindowsCommand(int command_id) { + // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND. + // Translate WM_APPCOMMAND command ids into a command id that the browser // knows how to handle. int command_id_from_app_command = GetCommandIDForAppCommandID(command_id); @@ -1047,7 +1032,8 @@ bool BrowserView::GetSavedWindowBounds(gfx::Rect* bounds) const { bounds->height() + toolbar_->GetPreferredSize().height()); } - gfx::Rect window_rect = frame_->GetWindowBoundsForClientBounds(*bounds); + gfx::Rect window_rect = + frame_->GetWindowBoundsForClientBounds(*bounds); window_rect.set_origin(bounds->origin()); // When we are given x/y coordinates of 0 on a created popup window, @@ -1102,7 +1088,7 @@ bool BrowserView::CanClose() const { // Tab strip isn't empty. Hide the frame (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 again. - frame_->GetWindow()->Hide(); + frame_->Hide(); browser_->OnWindowClosing(); return false; } @@ -1110,7 +1096,7 @@ bool BrowserView::CanClose() const { // Empty TabStripModel, it's now safe to allow the Window to be closed. NotificationService::current()->Notify( NotificationType::WINDOW_CLOSED, - Source(frame_->GetWindow()->GetHWND()), + Source(frame_->GetHWND()), NotificationService::NoDetails()); return true; } @@ -1123,7 +1109,7 @@ int BrowserView::NonClientHitTest(const gfx::Point& point) { if (CanCurrentlyResize()) { CRect client_rect; - ::GetClientRect(frame_->GetWindow()->GetHWND(), &client_rect); + ::GetClientRect(frame_->GetHWND(), &client_rect); gfx::Size resize_corner_size = ResizeCorner::GetSize(); gfx::Rect resize_corner_rect(client_rect.right - resize_corner_size.width(), client_rect.bottom - resize_corner_size.height(), @@ -1283,7 +1269,7 @@ int BrowserView::OnPerformDrop(const views::DropTargetEvent& event) { // BrowserView, private: void BrowserView::InitSystemMenu() { - HMENU system_menu = GetSystemMenu(frame_->GetWindow()->GetHWND(), FALSE); + HMENU system_menu = GetSystemMenu(frame_->GetHWND(), FALSE); system_menu_.reset(new Menu(system_menu)); int insertion_index = std::max(0, system_menu_->ItemCount() - 1); // We add the menu items in reverse order so that insertion_index never needs @@ -1434,7 +1420,7 @@ void BrowserView::LayoutStatusBubble(int top) { // In restored mode, the client area has a client edge between it and the // frame. int overlap = kStatusBubbleOverlap + - (IsMaximized() ? 0 : views::NonClientView::kClientEdgeThickness); + (IsMaximized() ? 0 : views::NonClientFrameView::kClientEdgeThickness); gfx::Point origin(-overlap, top - kStatusBubbleHeight + overlap); ConvertPointToView(this, GetParent(), &origin); status_bubble_->SetBounds(origin.x(), origin.y(), width() / 3, @@ -1679,3 +1665,11 @@ void BrowserView::InitClass() { initialized = true; } } + +// static +BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { + BrowserView* browser_view = new BrowserView(browser); + (new BrowserFrame(browser_view))->Init(); + return browser_view; +} + diff --git a/chrome/browser/views/frame/browser_window_factory.cc b/chrome/browser/views/frame/browser_window_factory.cc deleted file mode 100644 index 9a6853b..0000000 --- a/chrome/browser/views/frame/browser_window_factory.cc +++ /dev/null @@ -1,50 +0,0 @@ -// 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 "base/command_line.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/browser_process.h" // TODO(beng): remove once done. -#include "chrome/browser/browser_window.h" -#include "chrome/browser/views/frame/aero_glass_frame.h" -#include "chrome/browser/views/frame/browser_frame.h" -#include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/frame/opaque_frame.h" -#include "chrome/common/win_util.h" - -/////////////////////////////////////////////////////////////////////////////// -// BrowserWindow, public: - -// static -BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) { - BrowserView* browser_view = new BrowserView(browser); - BrowserFrame::CreateForBrowserView(BrowserFrame::GetActiveFrameType(), - browser_view); - return browser_view; -} - -/////////////////////////////////////////////////////////////////////////////// -// BrowserFrame, public: - -// static -BrowserFrame::FrameType BrowserFrame::GetActiveFrameType() { - return win_util::ShouldUseVistaFrame() ? BrowserFrame::FRAMETYPE_AERO_GLASS - : BrowserFrame::FRAMETYPE_OPAQUE; -} - -// static -BrowserFrame* BrowserFrame::CreateForBrowserView(BrowserFrame::FrameType type, - BrowserView* browser_view) { - if (type == FRAMETYPE_OPAQUE) { - OpaqueFrame* frame = new OpaqueFrame(browser_view); - frame->Init(); - return frame; - } else if (type == FRAMETYPE_AERO_GLASS) { - AeroGlassFrame* frame = new AeroGlassFrame(browser_view); - frame->Init(); - return frame; - } - NOTREACHED() << "Unsupported frame type"; - return NULL; -} - diff --git a/chrome/browser/views/frame/glass_browser_frame_view.cc b/chrome/browser/views/frame/glass_browser_frame_view.cc new file mode 100644 index 0000000..54982d7 --- /dev/null +++ b/chrome/browser/views/frame/glass_browser_frame_view.cc @@ -0,0 +1,423 @@ +// 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/frame/glass_browser_frame_view.h" + +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/views/client_view.h" +#include "chrome/views/window_resources.h" +#include "grit/theme_resources.h" + +// An enumeration of bitmap resources used by this window. +enum { + // Client Edge Border. + FRAME_CLIENT_EDGE_TOP_LEFT, + FRAME_CLIENT_EDGE_TOP, + FRAME_CLIENT_EDGE_TOP_RIGHT, + FRAME_CLIENT_EDGE_RIGHT, + FRAME_CLIENT_EDGE_BOTTOM_RIGHT, + FRAME_CLIENT_EDGE_BOTTOM, + FRAME_CLIENT_EDGE_BOTTOM_LEFT, + FRAME_CLIENT_EDGE_LEFT, + + FRAME_PART_BITMAP_COUNT // Must be last. +}; + +class GlassBrowserWindowResources { + public: + GlassBrowserWindowResources() { + InitClass(); + } + virtual ~GlassBrowserWindowResources() { } + + virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + IDR_CONTENT_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); + + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + + DISALLOW_EVIL_CONSTRUCTORS(GlassBrowserWindowResources); +}; + +// static +SkBitmap* GlassBrowserWindowResources::standard_frame_bitmaps_[]; + +GlassBrowserWindowResources* GlassBrowserFrameView::resources_ = NULL; +SkBitmap* GlassBrowserFrameView::distributor_logo_ = NULL; +HICON GlassBrowserFrameView::throbber_icons_[GlassBrowserFrameView::kThrobberIconCount]; + +namespace { +// There are 3 px of client edge drawn inside the outer frame borders. +const int kNonClientBorderThickness = 3; +// Besides the frame border, there's another 11 px of empty space atop the +// window in restored mode, to use to drag the window around. +const int kNonClientRestoredExtraThickness = 11; +// In the window corners, the resize areas don't actually expand bigger, but the +// 16 px at the end of the top and bottom edges triggers diagonal resizing. +const int kResizeAreaCornerSize = 16; +// The distributor logo is drawn 3 px from the top of the window. +static const int kLogoTopSpacing = 3; +// In maximized mode, the OTR avatar starts 2 px below the top of the screen, so +// that it doesn't extend into the "3D edge" portion of the titlebar. +const int kOTRMaximizedTopSpacing = 2; +// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the +// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the +// user). +const int kOTRBottomSpacing = 2; +// There are 2 px on each side of the OTR avatar (between the frame border and +// it on the left, and between it and the tabstrip on the right). +const int kOTRSideSpacing = 2; +// In restored mode, the New Tab button isn't at the same height as the caption +// buttons, but the space will look cluttered if it actually slides under them, +// so we stop it when the gap between the two is down to 5 px. +const int kNewTabCaptionRestoredSpacing = 5; +// In maximized mode, where the New Tab button and the caption buttons are at +// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid +// looking too cluttered. +const int kNewTabCaptionMaximizedSpacing = 16; +// When there's a distributor logo, we leave a 7 px gap between it and the +// caption buttons. +const int kLogoCaptionSpacing = 7; +} + +/////////////////////////////////////////////////////////////////////////////// +// GlassBrowserFrameView, public: + +GlassBrowserFrameView::GlassBrowserFrameView(BrowserFrame* frame, + BrowserView* browser_view) + : BrowserNonClientFrameView(), + frame_(frame), + browser_view_(browser_view), + throbber_running_(false), + throbber_frame_(0) { + InitClass(); + if (frame_->window_delegate()->ShouldShowWindowIcon()) + InitThrobberIcons(); +} + +GlassBrowserFrameView::~GlassBrowserFrameView() { +} + +/////////////////////////////////////////////////////////////////////////////// +// GlassBrowserFrameView, BrowserNonClientFrameView implementation: + +gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip( + TabStrip* tabstrip) const { + int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ? + (otr_avatar_bounds_.right() + kOTRSideSpacing) : + NonClientBorderThickness(); + int tabstrip_width = frame_->GetMinimizeButtonOffset() - tabstrip_x - + (frame_->IsMaximized() ? + kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing); + return gfx::Rect(tabstrip_x, NonClientTopBorderHeight(), + std::max(0, tabstrip_width), tabstrip->GetPreferredHeight()); +} + +void GlassBrowserFrameView::UpdateThrobber(bool running) { + if (throbber_running_) { + if (running) { + DisplayNextThrobberFrame(); + } else { + StopThrobber(); + } + } else if (running) { + StartThrobber(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// GlassBrowserFrameView, views::NonClientFrameView implementation: + +gfx::Rect GlassBrowserFrameView::GetBoundsForClientView() const { + return client_view_bounds_; +} + +gfx::Rect GlassBrowserFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + if (!browser_view_->IsTabStripVisible()) { + // If we don't have a tabstrip, we're either a popup or an app window, in + // which case we have a standard size non-client area and can just use + // AdjustWindowRectEx to obtain it. + RECT rect = client_bounds.ToRECT(); + AdjustWindowRectEx(&rect, frame_->window_style(), FALSE, + frame_->window_ex_style()); + return gfx::Rect(rect); + } + + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), + std::max(0, client_bounds.y() - top_height), + client_bounds.width() + (2 * border_thickness), + client_bounds.height() + top_height + border_thickness); +} + +gfx::Point GlassBrowserFrameView::GetSystemMenuPoint() const { + gfx::Point system_menu_point; + if (browser_view_->IsBrowserTypeNormal()) { + // The maximized mode bit here is because in maximized mode the frame edge + // and the client edge are both offscreen, whereas in the opaque frame + // (where we don't do this trick) maximized windows have no client edge and + // only the frame edge is offscreen. + system_menu_point.SetPoint(NonClientBorderThickness() - + (frame_->IsMaximized() ? 0 : kClientEdgeThickness), + NonClientTopBorderHeight() + browser_view_->GetTabStripHeight() - + kClientEdgeThickness); + } else { + system_menu_point.SetPoint(0, -kFrameShadowThickness); + } + ConvertPointToScreen(this, &system_menu_point); + return system_menu_point; +} + +int GlassBrowserFrameView::NonClientHitTest(const gfx::Point& point) { + // If the browser isn't in normal mode, we haven't customized the frame, so + // Windows can figure this out. If the point isn't within our bounds, then + // it's in the native portion of the frame, so again Windows can figure it + // out. + if (!browser_view_->IsBrowserTypeNormal() || !bounds().Contains(point)) + return HTNOWHERE; + + int frame_component = frame_->client_view()->NonClientHitTest(point); + if (frame_component != HTNOWHERE) + return frame_component; + + int border_thickness = FrameBorderThickness(); + int window_component = GetHTComponentForFrame(point, border_thickness, + NonClientBorderThickness(), border_thickness, + kResizeAreaCornerSize - border_thickness, + frame_->window_delegate()->CanResize()); + // Fall back to the caption if no other component matches. + return (window_component == HTNOWHERE) ? HTCAPTION : window_component; +} + +/////////////////////////////////////////////////////////////////////////////// +// GlassBrowserFrameView, views::View overrides: + +void GlassBrowserFrameView::Paint(ChromeCanvas* canvas) { + if (!browser_view_->IsTabStripVisible()) + return; // Nothing is visible, so don't bother to paint. + + PaintDistributorLogo(canvas); + PaintToolbarBackground(canvas); + PaintOTRAvatar(canvas); + PaintClientEdge(canvas); +} + +void GlassBrowserFrameView::Layout() { + LayoutDistributorLogo(); + LayoutOTRAvatar(); + LayoutClientView(); +} + +/////////////////////////////////////////////////////////////////////////////// +// GlassBrowserFrameView, private: + +int GlassBrowserFrameView::FrameBorderThickness() const { + return GetSystemMetrics(SM_CXSIZEFRAME); +} + +int GlassBrowserFrameView::NonClientBorderThickness() const { + return kNonClientBorderThickness; +} + +int GlassBrowserFrameView::NonClientTopBorderHeight() const { + return FrameBorderThickness() + + (frame_->IsMaximized() ? 0 : kNonClientRestoredExtraThickness); +} + +void GlassBrowserFrameView::PaintDistributorLogo(ChromeCanvas* canvas) { + // The distributor logo is only painted when the frame is not maximized and + // when we actually have a logo. + if (!frame_->IsMaximized() && distributor_logo_) { + // NOTE: We don't mirror the logo placement here because the outer frame + // itself isn't mirrored in RTL. This is a bug; if it is fixed, this should + // be mirrored as in opaque_non_client_view.cc. + canvas->DrawBitmapInt(*distributor_logo_, logo_bounds_.x(), + logo_bounds_.y()); + } +} + +void GlassBrowserFrameView::PaintToolbarBackground(ChromeCanvas* canvas) { + gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds()); + gfx::Point toolbar_origin(toolbar_bounds.origin()); + View::ConvertPointToView(frame_->client_view(), this, &toolbar_origin); + toolbar_bounds.set_origin(toolbar_origin); + + SkBitmap* toolbar_left = + resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT); + canvas->DrawBitmapInt(*toolbar_left, + toolbar_bounds.x() - toolbar_left->width(), + toolbar_bounds.y()); + + SkBitmap* toolbar_center = + resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); + canvas->TileImageInt(*toolbar_center, toolbar_bounds.x(), toolbar_bounds.y(), + toolbar_bounds.width(), toolbar_center->height()); + + canvas->DrawBitmapInt(*resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT), + toolbar_bounds.right(), toolbar_bounds.y()); +} + +void GlassBrowserFrameView::PaintOTRAvatar(ChromeCanvas* canvas) { + if (!browser_view_->ShouldShowOffTheRecordAvatar()) + return; + + SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); + canvas->DrawBitmapInt(otr_avatar_icon, 0, + (otr_avatar_icon.height() - otr_avatar_bounds_.height()) / 2, + otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), + MirroredLeftPointForRect(otr_avatar_bounds_), otr_avatar_bounds_.y(), + otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), false); +} + +void GlassBrowserFrameView::PaintClientEdge(ChromeCanvas* canvas) { + // The client edges start below the toolbar upper corner images regardless + // of how tall the toolbar itself is. + int client_area_top = + frame_->client_view()->y() + browser_view_->GetToolbarBounds().y() + + resources_->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT)->height(); + + gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height()); + int client_area_bottom = + std::max(client_area_top, height() - NonClientBorderThickness()); + int client_area_height = client_area_bottom - client_area_top; + SkBitmap* right = resources_->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT); + canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, + right->width(), client_area_height); + + canvas->DrawBitmapInt( + *resources_->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT), + client_area_bounds.right(), client_area_bottom); + + SkBitmap* bottom = resources_->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM); + canvas->TileImageInt(*bottom, client_area_bounds.x(), + client_area_bottom, client_area_bounds.width(), + bottom->height()); + + SkBitmap* bottom_left = + resources_->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT); + canvas->DrawBitmapInt(*bottom_left, + client_area_bounds.x() - bottom_left->width(), client_area_bottom); + + SkBitmap* left = resources_->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); + canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), + client_area_top, left->width(), client_area_height); +} + +void GlassBrowserFrameView::LayoutDistributorLogo() { + if (distributor_logo_) { + logo_bounds_.SetRect(frame_->GetMinimizeButtonOffset() - + distributor_logo_->width() - kLogoCaptionSpacing, kLogoTopSpacing, + distributor_logo_->width(), distributor_logo_->height()); + } else { + logo_bounds_.SetRect(frame_->GetMinimizeButtonOffset(), kLogoTopSpacing, 0, + 0); + } +} + +void GlassBrowserFrameView::LayoutOTRAvatar() { + SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); + int top_height = NonClientTopBorderHeight(); + int tabstrip_height, otr_height; + if (browser_view_->IsTabStripVisible()) { + tabstrip_height = browser_view_->GetTabStripHeight() - kOTRBottomSpacing; + otr_height = frame_->IsMaximized() ? + (tabstrip_height - kOTRMaximizedTopSpacing) : + otr_avatar_icon.height(); + } else { + tabstrip_height = otr_height = 0; + } + otr_avatar_bounds_.SetRect(NonClientBorderThickness() + kOTRSideSpacing, + top_height + tabstrip_height - otr_height, + otr_avatar_icon.width(), otr_height); +} + +void GlassBrowserFrameView::LayoutClientView() { + client_view_bounds_ = CalculateClientAreaBounds(width(), height()); +} + +gfx::Rect GlassBrowserFrameView::CalculateClientAreaBounds(int width, + int height) const { + if (!browser_view_->IsTabStripVisible()) + return gfx::Rect(0, 0, this->width(), this->height()); + + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(border_thickness, top_height, + std::max(0, width - (2 * border_thickness)), + std::max(0, height - top_height - border_thickness)); +} + +void GlassBrowserFrameView::StartThrobber() { + if (!throbber_running_) { + throbber_running_ = true; + throbber_frame_ = 0; + InitThrobberIcons(); + SendMessage(frame_->GetHWND(), WM_SETICON, static_cast(ICON_SMALL), + reinterpret_cast(throbber_icons_[throbber_frame_])); + } +} + +void GlassBrowserFrameView::StopThrobber() { + if (throbber_running_) + throbber_running_ = false; +} + +void GlassBrowserFrameView::DisplayNextThrobberFrame() { + throbber_frame_ = (throbber_frame_ + 1) % kThrobberIconCount; + SendMessage(frame_->GetHWND(), WM_SETICON, static_cast(ICON_SMALL), + reinterpret_cast(throbber_icons_[throbber_frame_])); +} + +// static +void GlassBrowserFrameView::InitThrobberIcons() { + static bool initialized = false; + if (!initialized) { + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < kThrobberIconCount; ++i) { + throbber_icons_[i] = rb.LoadThemeIcon(IDR_THROBBER_01 + i); + DCHECK(throbber_icons_[i]); + } + initialized = true; + } +} + +// static +void GlassBrowserFrameView::InitClass() { + static bool initialized = false; + if (!initialized) { + resources_ = new GlassBrowserWindowResources; + +#if defined(GOOGLE_CHROME_BUILD) + distributor_logo_ = ResourceBundle::GetSharedInstance(). + GetBitmapNamed(IDR_DISTRIBUTOR_LOGO); +#endif + + initialized = true; + } +} + diff --git a/chrome/browser/views/frame/glass_browser_frame_view.h b/chrome/browser/views/frame/glass_browser_frame_view.h new file mode 100644 index 0000000..f325dde --- /dev/null +++ b/chrome/browser/views/frame/glass_browser_frame_view.h @@ -0,0 +1,107 @@ +// 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_FRAME_GLASS_BROWSER_FRAME_VIEW_H_ +#define CHROME_BROWSER_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_ + +#include "chrome/browser/views/frame/browser_frame.h" +#include "chrome/views/non_client_view.h" +#include "chrome/views/button.h" + +class BrowserView; +class GlassBrowserWindowResources; + +class GlassBrowserFrameView : public BrowserNonClientFrameView { + public: + // Constructs a non-client view for an BrowserFrame. + GlassBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view); + virtual ~GlassBrowserFrameView(); + + // Overridden from BrowserNonClientFrameView: + virtual gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const; + virtual void UpdateThrobber(bool running); + + // Overridden from views::NonClientFrameView: + virtual gfx::Rect GetBoundsForClientView() const; + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const; + virtual gfx::Point GetSystemMenuPoint() const; + virtual int NonClientHitTest(const gfx::Point& point); + virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) { } + virtual void EnableClose(bool enable) { } + virtual void ResetWindowControls() { } + + protected: + // Overridden from views::View: + virtual void Paint(ChromeCanvas* canvas); + virtual void Layout(); + + private: + // Returns the thickness of the border that makes up the window frame edges. + // This does not include any client edge. + int FrameBorderThickness() const; + + // Returns the thickness of the entire nonclient left, right, and bottom + // borders, including both the window frame and any client edge. + int NonClientBorderThickness() const; + + // Returns the height of the entire nonclient top border, including the window + // frame, any title area, and any connected client edge. + int NonClientTopBorderHeight() const; + + // Paint various sub-components of this view. + void PaintDistributorLogo(ChromeCanvas* canvas); + void PaintToolbarBackground(ChromeCanvas* canvas); + void PaintOTRAvatar(ChromeCanvas* canvas); + void PaintClientEdge(ChromeCanvas* canvas); + + // Layout various sub-components of this view. + void LayoutDistributorLogo(); + void LayoutOTRAvatar(); + void LayoutClientView(); + + // Returns the bounds of the client area for the specified view size. + gfx::Rect CalculateClientAreaBounds(int width, int height) const; + + // Starts/Stops the window throbber running. + void StartThrobber(); + void StopThrobber(); + + // Displays the next throbber frame. + void DisplayNextThrobberFrame(); + + // The layout rect of the distributor logo, if visible. + gfx::Rect logo_bounds_; + + // The layout rect of the OTR avatar icon, if visible. + gfx::Rect otr_avatar_bounds_; + + // The frame that hosts this view. + BrowserFrame* frame_; + + // The BrowserView hosted within this View. + BrowserView* browser_view_; + + // The bounds of the ClientView. + gfx::Rect client_view_bounds_; + + // Whether or not the window throbber is currently animating. + bool throbber_running_; + + // The index of the current frame of the throbber animation. + int throbber_frame_; + + static void InitClass(); + static SkBitmap* distributor_logo_; + static GlassBrowserWindowResources* resources_; + + static const int kThrobberIconCount = 24; + static HICON throbber_icons_[kThrobberIconCount]; + static void InitThrobberIcons(); + + DISALLOW_EVIL_CONSTRUCTORS(GlassBrowserFrameView); +}; + +#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_GLASS_BROWSER_FRAME_VIEW_H_ + diff --git a/chrome/browser/views/frame/opaque_browser_frame_view.cc b/chrome/browser/views/frame/opaque_browser_frame_view.cc new file mode 100644 index 0000000..98a71c3 --- /dev/null +++ b/chrome/browser/views/frame/opaque_browser_frame_view.cc @@ -0,0 +1,1067 @@ +// 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/frame/opaque_browser_frame_view.h" + +#include "chrome/browser/views/frame/browser_frame.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/views/tabs/tab_strip.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/chrome_font.h" +#include "chrome/common/gfx/path.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/win_util.h" +#include "chrome/views/root_view.h" +#include "chrome/views/window_resources.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" + +// An enumeration of bitmap resources used by this window. +enum { + // Window Controls. + FRAME_CLOSE_BUTTON_ICON, + FRAME_CLOSE_BUTTON_ICON_H, + FRAME_CLOSE_BUTTON_ICON_P, + FRAME_CLOSE_BUTTON_ICON_SA, + FRAME_CLOSE_BUTTON_ICON_SA_H, + FRAME_CLOSE_BUTTON_ICON_SA_P, + FRAME_RESTORE_BUTTON_ICON, + FRAME_RESTORE_BUTTON_ICON_H, + FRAME_RESTORE_BUTTON_ICON_P, + FRAME_MAXIMIZE_BUTTON_ICON, + FRAME_MAXIMIZE_BUTTON_ICON_H, + FRAME_MAXIMIZE_BUTTON_ICON_P, + FRAME_MINIMIZE_BUTTON_ICON, + FRAME_MINIMIZE_BUTTON_ICON_H, + FRAME_MINIMIZE_BUTTON_ICON_P, + + // Window Frame Border. + FRAME_BOTTOM_EDGE, + FRAME_BOTTOM_LEFT_CORNER, + FRAME_BOTTOM_RIGHT_CORNER, + FRAME_LEFT_EDGE, + FRAME_RIGHT_EDGE, + FRAME_TOP_EDGE, + FRAME_TOP_LEFT_CORNER, + FRAME_TOP_RIGHT_CORNER, + + // Client Edge Border. + FRAME_CLIENT_EDGE_TOP_LEFT, + FRAME_CLIENT_EDGE_TOP, + FRAME_CLIENT_EDGE_TOP_RIGHT, + FRAME_CLIENT_EDGE_RIGHT, + FRAME_CLIENT_EDGE_BOTTOM_RIGHT, + FRAME_CLIENT_EDGE_BOTTOM, + FRAME_CLIENT_EDGE_BOTTOM_LEFT, + FRAME_CLIENT_EDGE_LEFT, + + // No-toolbar client edge. + FRAME_NO_TOOLBAR_TOP_LEFT, + FRAME_NO_TOOLBAR_TOP_CENTER, + FRAME_NO_TOOLBAR_TOP_RIGHT, + + FRAME_PART_BITMAP_COUNT // Must be last. +}; + +class ActiveWindowResources : public views::WindowResources { + public: + ActiveWindowResources() { + InitClass(); + } + virtual ~ActiveWindowResources() { } + + // WindowResources implementation: + virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, + IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, + IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, + IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, + IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, + 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_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, + IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + + DISALLOW_EVIL_CONSTRUCTORS(ActiveWindowResources); +}; + +class InactiveWindowResources : public views::WindowResources { + public: + InactiveWindowResources() { + InitClass(); + } + virtual ~InactiveWindowResources() { } + + // WindowResources implementation: + virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, + IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, + IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, + IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, + IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, + 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_CONTENT_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, + IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + + DISALLOW_EVIL_CONSTRUCTORS(InactiveWindowResources); +}; + +class OTRActiveWindowResources : public views::WindowResources { + public: + OTRActiveWindowResources() { + InitClass(); + } + virtual ~OTRActiveWindowResources() { } + + // WindowResources implementation: + virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, + IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, + IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, + IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, + IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, + 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_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, + IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + + DISALLOW_EVIL_CONSTRUCTORS(OTRActiveWindowResources); +}; + +class OTRInactiveWindowResources : public views::WindowResources { + public: + OTRInactiveWindowResources() { + InitClass(); + } + virtual ~OTRInactiveWindowResources() { } + + // WindowResources implementation: + virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, + IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, + IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, + IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, + IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, + 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_CONTENT_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, + IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, + IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, + IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, + IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + + DISALLOW_EVIL_CONSTRUCTORS(OTRInactiveWindowResources); +}; + +// static +SkBitmap* ActiveWindowResources::standard_frame_bitmaps_[]; +SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[]; +SkBitmap* OTRActiveWindowResources::standard_frame_bitmaps_[]; +SkBitmap* OTRInactiveWindowResources::standard_frame_bitmaps_[]; + +views::WindowResources* OpaqueBrowserFrameView::active_resources_ = NULL; +views::WindowResources* OpaqueBrowserFrameView::inactive_resources_ = NULL; +views::WindowResources* OpaqueBrowserFrameView::active_otr_resources_ = NULL; +views::WindowResources* OpaqueBrowserFrameView::inactive_otr_resources_ = NULL; +SkBitmap* OpaqueBrowserFrameView::distributor_logo_ = NULL; +ChromeFont OpaqueBrowserFrameView::title_font_; + +namespace { +// The frame border is only visible in restored mode and is hardcoded to 4 px on +// each side regardless of the system window border size. +const int kFrameBorderThickness = 4; +// Besides the frame border, there's another 11 px of empty space atop the +// window in restored mode, to use to drag the window around. +const int kNonClientRestoredExtraThickness = 11; +// While resize areas on Windows are normally the same size as the window +// borders, our top area is shrunk by 1 px to make it easier to move the window +// around with our thinner top grabbable strip. (Incidentally, our side and +// bottom resize areas don't match the frame border thickness either -- they +// span the whole nonclient area, so there's no "dead zone" for the mouse.) +const int kTopResizeAdjust = 1; +// In the window corners, the resize areas don't actually expand bigger, but the +// 16 px at the end of each edge triggers diagonal resizing. +const int kResizeAreaCornerSize = 16; +// The titlebar never shrinks to less than 18 px tall, plus the height of the +// frame border and any bottom edge. +const int kTitlebarMinimumHeight = 18; +// The icon is inset 2 px from the left frame border. +const int kIconLeftSpacing = 2; +// The icon takes up 16/25th of the available titlebar height. (This is +// expressed as two ints to avoid precision losses leading to off-by-one pixel +// errors.) +const int kIconHeightFractionNumerator = 16; +const int kIconHeightFractionDenominator = 25; +// The icon never shrinks below 16 px on a side. +const int kIconMinimumSize = 16; +// Because our frame border has a different "3D look" than Windows', with a less +// cluttered top edge, we need to shift the icon up by 1 px in restored mode so +// it looks more centered. +const int kIconRestoredAdjust = 1; +// There is a 4 px gap between the icon and the title text. +const int kIconTitleSpacing = 4; +// The title text starts 2 px below the bottom of the top frame border. +const int kTitleTopSpacing = 2; +// There is a 5 px gap between the title text and the distributor logo (if +// present) or caption buttons. +const int kTitleLogoSpacing = 5; +// In maximized mode, the OTR avatar starts 2 px below the top of the screen, so +// that it doesn't extend into the "3D edge" portion of the titlebar. +const int kOTRMaximizedTopSpacing = 2; +// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the +// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the +// user). +const int kOTRBottomSpacing = 2; +// There are 2 px on each side of the OTR avatar (between the frame border and +// it on the left, and between it and the tabstrip on the right). +const int kOTRSideSpacing = 2; +// In restored mode, the New Tab button isn't at the same height as the caption +// buttons, but the space will look cluttered if it actually slides under them, +// so we stop it when the gap between the two is down to 5 px. +const int kNewTabCaptionRestoredSpacing = 5; +// In maximized mode, where the New Tab button and the caption buttons are at +// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid +// looking too cluttered. +const int kNewTabCaptionMaximizedSpacing = 16; +// When there's a distributor logo, we leave a 7 px gap between it and the +// caption buttons. +const int kLogoCaptionSpacing = 7; +// The caption buttons are always drawn 1 px down from the visible top of the +// window (the true top in restored mode, or the top of the screen in maximized +// mode). +const int kCaptionTopSpacing = 1; +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, public: + +OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame, + BrowserView* browser_view) + : BrowserNonClientFrameView(), + minimize_button_(new views::Button), + maximize_button_(new views::Button), + restore_button_(new views::Button), + close_button_(new views::Button), + window_icon_(NULL), + frame_(frame), + browser_view_(browser_view) { + InitClass(); + if (browser_view->IsOffTheRecord()) { + if (!active_otr_resources_) { + // Lazy load OTR resources only when we first show an OTR frame. + active_otr_resources_ = new OTRActiveWindowResources; + inactive_otr_resources_ = new OTRInactiveWindowResources; + } + current_active_resources_ = active_otr_resources_; + current_inactive_resources_= inactive_otr_resources_; + } else { + current_active_resources_ = active_resources_; + current_inactive_resources_ = inactive_resources_; + } + + views::WindowResources* resources = current_active_resources_; + minimize_button_->SetImage( + views::Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON)); + minimize_button_->SetImage( + views::Button::BS_HOT, + resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_H)); + minimize_button_->SetImage( + views::Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_P)); + minimize_button_->SetListener(this, -1); + minimize_button_->SetAccessibleName( + l10n_util::GetString(IDS_ACCNAME_MINIMIZE)); + AddChildView(minimize_button_); + + maximize_button_->SetImage( + views::Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON)); + maximize_button_->SetImage( + views::Button::BS_HOT, + resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_H)); + maximize_button_->SetImage( + views::Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_P)); + maximize_button_->SetListener(this, -1); + maximize_button_->SetAccessibleName( + l10n_util::GetString(IDS_ACCNAME_MAXIMIZE)); + AddChildView(maximize_button_); + + restore_button_->SetImage( + views::Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON)); + restore_button_->SetImage( + views::Button::BS_HOT, + resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_H)); + restore_button_->SetImage( + views::Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_P)); + restore_button_->SetListener(this, -1); + restore_button_->SetAccessibleName( + l10n_util::GetString(IDS_ACCNAME_RESTORE)); + AddChildView(restore_button_); + + close_button_->SetImage( + views::Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON)); + close_button_->SetImage( + views::Button::BS_HOT, + resources->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_H)); + close_button_->SetImage( + views::Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_P)); + close_button_->SetListener(this, -1); + close_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); + AddChildView(close_button_); + + // Initializing the TabIconView is expensive, so only do it if we need to. + if (browser_view_->ShouldShowWindowIcon()) { + window_icon_ = new TabIconView(this); + window_icon_->set_is_light(true); + AddChildView(window_icon_); + window_icon_->Update(); + } + // Only load the title font if we're going to need to use it to paint. + // Loading fonts is expensive. + if (browser_view_->ShouldShowWindowTitle()) + InitAppWindowResources(); +} + +OpaqueBrowserFrameView::~OpaqueBrowserFrameView() { +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, BrowserNonClientFrameView implementation: + +gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip( + TabStrip* tabstrip) const { + int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ? + (otr_avatar_bounds_.right() + kOTRSideSpacing) : + NonClientBorderThickness(); + int tabstrip_width = minimize_button_->x() - tabstrip_x - + (frame_->IsMaximized() ? + kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing); + return gfx::Rect(tabstrip_x, NonClientTopBorderHeight(), + std::max(0, tabstrip_width), tabstrip->GetPreferredHeight()); +} + +void OpaqueBrowserFrameView::UpdateThrobber(bool running) { + if (window_icon_) + window_icon_->Update(); +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, views::NonClientFrameView implementation: + +gfx::Rect OpaqueBrowserFrameView::GetBoundsForClientView() const { + return client_view_bounds_; +} + +gfx::Rect OpaqueBrowserFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), + std::max(0, client_bounds.y() - top_height), + client_bounds.width() + (2 * border_thickness), + client_bounds.height() + top_height + border_thickness); +} + +gfx::Point OpaqueBrowserFrameView::GetSystemMenuPoint() const { + gfx::Point system_menu_point(FrameBorderThickness(), + NonClientTopBorderHeight() + browser_view_->GetTabStripHeight() - + kClientEdgeThickness); + ConvertPointToScreen(this, &system_menu_point); + return system_menu_point; +} + +int OpaqueBrowserFrameView::NonClientHitTest(const gfx::Point& point) { + if (!bounds().Contains(point)) + return HTNOWHERE; + + int frame_component = frame_->client_view()->NonClientHitTest(point); + if (frame_component != HTNOWHERE) + return frame_component; + + // Then see if the point is within any of the window controls. + if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) + return HTCLOSE; + if (restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTMAXBUTTON; + if (maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTMAXBUTTON; + if (minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTMINBUTTON; + if (window_icon_ && + window_icon_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) + return HTSYSMENU; + + int window_component = GetHTComponentForFrame(point, TopResizeHeight(), + NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, + frame_->window_delegate()->CanResize()); + // Fall back to the caption if no other component matches. + return (window_component == HTNOWHERE) ? HTCAPTION : window_component; +} + +void OpaqueBrowserFrameView::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { + DCHECK(window_mask); + + if (browser_view_->IsFullscreen()) + return; + + // Redefine the window visible region for the new size. + window_mask->moveTo(0, 3); + window_mask->lineTo(1, 2); + window_mask->lineTo(1, 1); + window_mask->lineTo(2, 1); + window_mask->lineTo(3, 0); + + window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); + window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); + window_mask->lineTo(SkIntToScalar(size.width()), 3); + + window_mask->lineTo(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + window_mask->lineTo(0, SkIntToScalar(size.height())); + window_mask->close(); +} + +void OpaqueBrowserFrameView::EnableClose(bool enable) { + close_button_->SetEnabled(enable); +} + +void OpaqueBrowserFrameView::ResetWindowControls() { + restore_button_->SetState(views::Button::BS_NORMAL); + minimize_button_->SetState(views::Button::BS_NORMAL); + maximize_button_->SetState(views::Button::BS_NORMAL); + // The close button isn't affected by this constraint. +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, views::View overrides: + +void OpaqueBrowserFrameView::Paint(ChromeCanvas* canvas) { + if (browser_view_->IsFullscreen()) + return; // Nothing is visible, so don't bother to paint. + + if (frame_->IsMaximized()) + PaintMaximizedFrameBorder(canvas); + else + PaintRestoredFrameBorder(canvas); + PaintDistributorLogo(canvas); + PaintTitleBar(canvas); + PaintToolbarBackground(canvas); + PaintOTRAvatar(canvas); + if (!frame_->IsMaximized()) + PaintRestoredClientEdge(canvas); +} + +void OpaqueBrowserFrameView::Layout() { + LayoutWindowControls(); + LayoutDistributorLogo(); + LayoutTitleBar(); + LayoutOTRAvatar(); + LayoutClientView(); +} + +views::View* OpaqueBrowserFrameView::GetViewForPoint(const gfx::Point& point, + bool can_create_floating) { + // We override this function because the ClientView can overlap the non - + // client view, making it impossible to click on the window controls. We need + // to ensure the window controls are checked _first_. + views::View* views[] = + { close_button_, restore_button_, maximize_button_, minimize_button_ }; + for (int i = 0; i < arraysize(views); ++i) { + if (!views[i]->IsVisible()) + continue; + // Apply mirroring transformation on view bounds for RTL chrome. + if (views[i]->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) + return views[i]; + } + return View::GetViewForPoint(point, can_create_floating); +} + +void OpaqueBrowserFrameView::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (is_add && child == this) { + // The Accessibility glue looks for the product name on these two views to + // determine if this is in fact a Chrome window. + GetRootView()->SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); + SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); + } +} + +bool OpaqueBrowserFrameView::GetAccessibleRole(VARIANT* role) { + DCHECK(role); + // We aren't actually the client area of the window, but we act like it as + // far as MSAA and the UI tests are concerned. + role->vt = VT_I4; + role->lVal = ROLE_SYSTEM_CLIENT; + return true; +} + +bool OpaqueBrowserFrameView::GetAccessibleName(std::wstring* name) { + if (!accessible_name_.empty()) { + *name = accessible_name_; + return true; + } + return false; +} + +void OpaqueBrowserFrameView::SetAccessibleName(const std::wstring& name) { + accessible_name_ = name; +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, views::BaseButton::ButtonListener implementation: + +void OpaqueBrowserFrameView::ButtonPressed(views::BaseButton* sender) { + if (sender == minimize_button_) + frame_->ExecuteSystemMenuCommand(SC_MINIMIZE); + else if (sender == maximize_button_) + frame_->ExecuteSystemMenuCommand(SC_MAXIMIZE); + else if (sender == restore_button_) + frame_->ExecuteSystemMenuCommand(SC_RESTORE); + else if (sender == close_button_) + frame_->ExecuteSystemMenuCommand(SC_CLOSE); +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, TabIconView::TabContentsProvider implementation: + +bool OpaqueBrowserFrameView::ShouldTabIconViewAnimate() const { + // This function is queried during the creation of the window as the + // TabIconView we host is initialized, so we need to NULL check the selected + // TabContents because in this condition there is not yet a selected tab. + TabContents* current_tab = browser_view_->GetSelectedTabContents(); + return current_tab ? current_tab->is_loading() : false; +} + +SkBitmap OpaqueBrowserFrameView::GetFavIconForTabIconView() { + return frame_->window_delegate()->GetWindowIcon(); +} + +/////////////////////////////////////////////////////////////////////////////// +// OpaqueBrowserFrameView, private: + +int OpaqueBrowserFrameView::FrameBorderThickness() const { + if (browser_view_->IsFullscreen()) + return 0; + return frame_->IsMaximized() ? + GetSystemMetrics(SM_CXSIZEFRAME) : kFrameBorderThickness; +} + +int OpaqueBrowserFrameView::TopResizeHeight() const { + return FrameBorderThickness() - kTopResizeAdjust; +} + +int OpaqueBrowserFrameView::NonClientBorderThickness() const { + // When we fill the screen, we don't show a client edge. + return FrameBorderThickness() + + (browser_view_->CanCurrentlyResize() ? kClientEdgeThickness : 0); +} + +int OpaqueBrowserFrameView::NonClientTopBorderHeight() const { + if (frame_->window_delegate()->ShouldShowWindowTitle()) { + int title_top_spacing, title_thickness; + return TitleCoordinates(&title_top_spacing, &title_thickness); + } + + return FrameBorderThickness() + (browser_view_->CanCurrentlyResize() ? + kNonClientRestoredExtraThickness : 0); +} + +int OpaqueBrowserFrameView::UnavailablePixelsAtBottomOfNonClientHeight() const { + // Tricky: When a toolbar is edging the titlebar, it not only draws its own + // shadow and client edge, but an extra, light "shadow" pixel as well, which + // is treated as available space. Thus the nonclient area actually _fails_ to + // include some available pixels, leading to a negative number here. + if (browser_view_->IsToolbarVisible()) + return -kFrameShadowThickness; + + return kFrameShadowThickness + + (frame_->IsMaximized() ? 0 : kClientEdgeThickness); +} + +int OpaqueBrowserFrameView::TitleCoordinates(int* title_top_spacing, + int* title_thickness) const { + int frame_thickness = FrameBorderThickness(); + int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; + *title_top_spacing = frame_thickness + kTitleTopSpacing; + // The bottom spacing should be the same apparent height as the top spacing. + // Because the actual top spacing height varies based on the system border + // thickness, we calculate this based on the restored top spacing and then + // adjust for maximized mode. We also don't include the frame shadow here, + // since while it's part of the bottom spacing it will be added in at the end + // as necessary (when a toolbar is present, the "shadow" is actually drawn by + // the toolbar). + int title_bottom_spacing = + kFrameBorderThickness + kTitleTopSpacing - kFrameShadowThickness; + if (frame_->IsMaximized()) { + // When we maximize, the top border appears to be chopped off; shift the + // title down to stay centered within the remaining space. + int title_adjust = (kFrameBorderThickness / 2); + *title_top_spacing += title_adjust; + title_bottom_spacing -= title_adjust; + } + *title_thickness = std::max(title_font_.height(), + min_titlebar_height - *title_top_spacing - title_bottom_spacing); + return *title_top_spacing + *title_thickness + title_bottom_spacing + + UnavailablePixelsAtBottomOfNonClientHeight(); +} + +void OpaqueBrowserFrameView::PaintRestoredFrameBorder(ChromeCanvas* canvas) { + SkBitmap* top_left_corner = resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER); + SkBitmap* top_right_corner = + resources()->GetPartBitmap(FRAME_TOP_RIGHT_CORNER); + SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); + SkBitmap* right_edge = resources()->GetPartBitmap(FRAME_RIGHT_EDGE); + SkBitmap* left_edge = resources()->GetPartBitmap(FRAME_LEFT_EDGE); + SkBitmap* bottom_left_corner = + resources()->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER); + SkBitmap* bottom_right_corner = + resources()->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER); + SkBitmap* bottom_edge = resources()->GetPartBitmap(FRAME_BOTTOM_EDGE); + + // Top. + canvas->DrawBitmapInt(*top_left_corner, 0, 0); + canvas->TileImageInt(*top_edge, top_left_corner->width(), 0, + width() - top_right_corner->width(), top_edge->height()); + canvas->DrawBitmapInt(*top_right_corner, + width() - top_right_corner->width(), 0); + // Note: When we don't have a toolbar, we need to draw some kind of bottom + // edge here. Because the App Window graphics we use for this have an + // attached client edge and their sizing algorithm is a little involved, we do + // all this in PaintRestoredClientEdge(). + + // Right. + canvas->TileImageInt(*right_edge, width() - right_edge->width(), + top_right_corner->height(), right_edge->width(), + height() - top_right_corner->height() - + bottom_right_corner->height()); + + // Bottom. + canvas->DrawBitmapInt(*bottom_right_corner, + width() - bottom_right_corner->width(), + height() - bottom_right_corner->height()); + canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(), + height() - bottom_edge->height(), + width() - bottom_left_corner->width() - + bottom_right_corner->width(), + bottom_edge->height()); + canvas->DrawBitmapInt(*bottom_left_corner, 0, + height() - bottom_left_corner->height()); + + // Left. + canvas->TileImageInt(*left_edge, 0, top_left_corner->height(), + left_edge->width(), + height() - top_left_corner->height() - bottom_left_corner->height()); +} + +void OpaqueBrowserFrameView::PaintMaximizedFrameBorder(ChromeCanvas* canvas) { + SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); + canvas->TileImageInt(*top_edge, 0, FrameBorderThickness(), width(), + top_edge->height()); + + if (!browser_view_->IsToolbarVisible()) { + // There's no toolbar to edge the frame border, so we need to draw a bottom + // edge. The graphic we use for this has a built in client edge, so we clip + // it off the bottom. + SkBitmap* top_center = + resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_CENTER); + int edge_height = top_center->height() - kClientEdgeThickness; + canvas->TileImageInt(*top_center, 0, + frame_->client_view()->y() - edge_height, width(), edge_height); + } +} + +void OpaqueBrowserFrameView::PaintDistributorLogo(ChromeCanvas* canvas) { + // The distributor logo is only painted when the frame is not maximized and + // when we actually have a logo. + if (!frame_->IsMaximized() && distributor_logo_) { + canvas->DrawBitmapInt(*distributor_logo_, + MirroredLeftPointForRect(logo_bounds_), logo_bounds_.y()); + } +} + +void OpaqueBrowserFrameView::PaintTitleBar(ChromeCanvas* canvas) { + // The window icon is painted by the TabIconView. + views::WindowDelegate* d = frame_->window_delegate(); + if (d->ShouldShowWindowTitle()) { + canvas->DrawStringInt(d->GetWindowTitle(), title_font_, SK_ColorWHITE, + MirroredLeftPointForRect(title_bounds_), title_bounds_.y(), + title_bounds_.width(), title_bounds_.height()); + /* TODO(pkasting): If this window is active, we should also draw a drop + * shadow on the title. This is tricky, because we don't want to hardcode a + * shadow color (since we want to work with various themes), but we can't + * alpha-blend either (since the Windows text APIs don't really do this). + * So we'd need to sample the background color at the right location and + * synthesize a good shadow color. */ + } +} + +void OpaqueBrowserFrameView::PaintToolbarBackground(ChromeCanvas* canvas) { + if (!browser_view_->IsToolbarVisible()) + return; + + gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds()); + gfx::Point toolbar_origin(toolbar_bounds.origin()); + View::ConvertPointToView(frame_->client_view(), this, &toolbar_origin); + toolbar_bounds.set_origin(toolbar_origin); + + SkBitmap* toolbar_left = + resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT); + canvas->DrawBitmapInt(*toolbar_left, + toolbar_bounds.x() - toolbar_left->width(), + toolbar_bounds.y()); + + // Gross hack: We split the toolbar image into two pieces, since sometimes + // (popup mode) the toolbar isn't tall enough to show the whole image. The + // split happens between the top shadow section and the bottom gradient + // section so that we never break the gradient. + int split_point = kFrameShadowThickness * 2; + SkBitmap* toolbar_center = + resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); + canvas->TileImageInt(*toolbar_center, 0, 0, toolbar_bounds.x(), + toolbar_bounds.y(), toolbar_bounds.width(), split_point); + canvas->TileImageInt(*toolbar_center, 0, + toolbar_center->height() - toolbar_bounds.height() + split_point, + toolbar_bounds.x(), toolbar_bounds.y() + split_point, + toolbar_bounds.width(), toolbar_bounds.height() - split_point); + + canvas->DrawBitmapInt( + *resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT), + toolbar_bounds.right(), toolbar_bounds.y()); +} + +void OpaqueBrowserFrameView::PaintOTRAvatar(ChromeCanvas* canvas) { + if (!browser_view_->ShouldShowOffTheRecordAvatar()) + return; + + SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); + canvas->DrawBitmapInt(otr_avatar_icon, 0, + (otr_avatar_icon.height() - otr_avatar_bounds_.height()) / 2, + otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), + MirroredLeftPointForRect(otr_avatar_bounds_), otr_avatar_bounds_.y(), + otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), false); +} + +void OpaqueBrowserFrameView::PaintRestoredClientEdge(ChromeCanvas* canvas) { + int client_area_top = frame_->client_view()->y(); + + gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height()); + if (browser_view_->IsToolbarVisible()) { + // The client edges start below the toolbar upper corner images regardless + // of how tall the toolbar itself is. + client_area_top += browser_view_->GetToolbarBounds().y() + + resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT)->height(); + } else { + // The toolbar isn't going to draw a client edge for us, so draw one + // ourselves. + // This next calculation is necessary because the top center bitmap is + // shorter than the top left and right bitmaps. We need their top edges to + // line up, and we need the left and right edges to start below the corners' + // bottoms. + SkBitmap* top_center = + resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_CENTER); + SkBitmap* top_left = resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_LEFT); + int top_edge_y = client_area_top - top_center->height(); + client_area_top = top_edge_y + top_left->height(); + canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(), + top_edge_y); + canvas->TileImageInt(*top_center, client_area_bounds.x(), top_edge_y, + client_area_bounds.width(), top_center->height()); + canvas->DrawBitmapInt( + *resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_RIGHT), + client_area_bounds.right(), top_edge_y); + } + + int client_area_bottom = + std::max(client_area_top, height() - NonClientBorderThickness()); + int client_area_height = client_area_bottom - client_area_top; + SkBitmap* right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT); + canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, + right->width(), client_area_height); + + canvas->DrawBitmapInt( + *resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT), + client_area_bounds.right(), client_area_bottom); + + SkBitmap* bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM); + canvas->TileImageInt(*bottom, client_area_bounds.x(), + client_area_bottom, client_area_bounds.width(), + bottom->height()); + + SkBitmap* bottom_left = + resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT); + canvas->DrawBitmapInt(*bottom_left, + client_area_bounds.x() - bottom_left->width(), client_area_bottom); + + SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); + canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), + client_area_top, left->width(), client_area_height); +} + +void OpaqueBrowserFrameView::LayoutWindowControls() { + close_button_->SetImageAlignment(views::Button::ALIGN_LEFT, + views::Button::ALIGN_BOTTOM); + // Maximized buttons start at window top so that even if their images aren't + // drawn flush with the screen edge, they still obey Fitts' Law. + bool is_maximized = frame_->IsMaximized(); + int frame_thickness = FrameBorderThickness(); + int caption_y = is_maximized ? frame_thickness : kCaptionTopSpacing; + int top_extra_height = is_maximized ? kCaptionTopSpacing : 0; + // There should always be the same number of non-shadow pixels visible to the + // side of the caption buttons. In maximized mode we extend the rightmost + // button to the screen corner to obey Fitts' Law. + int right_extra_width = is_maximized ? + (kFrameBorderThickness - kFrameShadowThickness) : 0; + int right_spacing = is_maximized ? + (GetSystemMetrics(SM_CXSIZEFRAME) + right_extra_width) : frame_thickness; + gfx::Size close_button_size = close_button_->GetPreferredSize(); + close_button_->SetBounds(width() - close_button_size.width() - right_spacing, + caption_y, + close_button_size.width() + right_extra_width, + close_button_size.height() + top_extra_height); + + // When the window is restored, we show a maximized button; otherwise, we show + // a restore button. + bool is_restored = !is_maximized && !frame_->IsMinimized(); + views::Button* invisible_button = is_restored ? + restore_button_ : maximize_button_; + invisible_button->SetVisible(false); + + views::Button* visible_button = is_restored ? + maximize_button_ : restore_button_; + visible_button->SetVisible(true); + visible_button->SetImageAlignment(views::Button::ALIGN_LEFT, + views::Button::ALIGN_BOTTOM); + gfx::Size visible_button_size = visible_button->GetPreferredSize(); + visible_button->SetBounds(close_button_->x() - visible_button_size.width(), + caption_y, visible_button_size.width(), + visible_button_size.height() + top_extra_height); + + minimize_button_->SetVisible(true); + minimize_button_->SetImageAlignment(views::Button::ALIGN_LEFT, + views::Button::ALIGN_BOTTOM); + gfx::Size minimize_button_size = minimize_button_->GetPreferredSize(); + minimize_button_->SetBounds( + visible_button->x() - minimize_button_size.width(), caption_y, + minimize_button_size.width(), + minimize_button_size.height() + top_extra_height); +} + +void OpaqueBrowserFrameView::LayoutDistributorLogo() { + // Always lay out the logo, even when it's not present, so we can lay out the + // window title based on its position. + if (distributor_logo_) { + logo_bounds_.SetRect(minimize_button_->x() - distributor_logo_->width() - + kLogoCaptionSpacing, TopResizeHeight(), distributor_logo_->width(), + distributor_logo_->height()); + } else { + logo_bounds_.SetRect(minimize_button_->x(), TopResizeHeight(), 0, 0); + } +} + +void OpaqueBrowserFrameView::LayoutTitleBar() { + // Always lay out the icon, even when it's not present, so we can lay out the + // window title based on its position. + int frame_thickness = FrameBorderThickness(); + int icon_x = frame_thickness + kIconLeftSpacing; + + // The usable height of the titlebar area is the total height minus the top + // resize border and any edge area we draw at its bottom. + int title_top_spacing, title_thickness; + int top_height = TitleCoordinates(&title_top_spacing, &title_thickness); + int available_height = top_height - frame_thickness - + UnavailablePixelsAtBottomOfNonClientHeight(); + + // The icon takes up a constant fraction of the available height, down to a + // minimum size, and is always an even number of pixels on a side (presumably + // to make scaled icons look better). It's centered within the usable height. + int icon_size = std::max((available_height * kIconHeightFractionNumerator / + kIconHeightFractionDenominator) / 2 * 2, kIconMinimumSize); + int icon_y = ((available_height - icon_size) / 2) + frame_thickness; + + // Hack: Our frame border has a different "3D look" than Windows'. Theirs has + // a more complex gradient on the top that they push their icon/title below; + // then the maximized window cuts this off and the icon/title are centered in + // the remaining space. Because the apparent shape of our border is simpler, + // using the same positioning makes things look slightly uncentered with + // restored windows, so we come up to compensate. + if (!frame_->IsMaximized()) + icon_y -= kIconRestoredAdjust; + + views::WindowDelegate* d = frame_->window_delegate(); + if (!d->ShouldShowWindowIcon()) + icon_size = 0; + if (window_icon_) + window_icon_->SetBounds(icon_x, icon_y, icon_size, icon_size); + + // Size the title, if visible. + if (d->ShouldShowWindowTitle()) { + int title_x = icon_x + icon_size + + (d->ShouldShowWindowIcon() ? kIconTitleSpacing : 0); + title_bounds_.SetRect(title_x, + title_top_spacing + ((title_thickness - title_font_.height()) / 2), + std::max(0, logo_bounds_.x() - kTitleLogoSpacing - title_x), + title_font_.height()); + } +} + +void OpaqueBrowserFrameView::LayoutOTRAvatar() { + SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); + int top_height = NonClientTopBorderHeight(); + int tabstrip_height, otr_height; + if (browser_view_->IsTabStripVisible()) { + tabstrip_height = browser_view_->GetTabStripHeight() - kOTRBottomSpacing; + otr_height = frame_->IsMaximized() ? + (tabstrip_height - kOTRMaximizedTopSpacing) : + otr_avatar_icon.height(); + } else { + tabstrip_height = otr_height = 0; + } + otr_avatar_bounds_.SetRect(NonClientBorderThickness() + kOTRSideSpacing, + top_height + tabstrip_height - otr_height, + otr_avatar_icon.width(), otr_height); +} + +void OpaqueBrowserFrameView::LayoutClientView() { + client_view_bounds_ = CalculateClientAreaBounds(width(), height()); +} + +gfx::Rect OpaqueBrowserFrameView::CalculateClientAreaBounds(int width, + int height) const { + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(border_thickness, top_height, + std::max(0, width - (2 * border_thickness)), + std::max(0, height - top_height - border_thickness)); +} + +// static +void OpaqueBrowserFrameView::InitClass() { + static bool initialized = false; + if (!initialized) { + active_resources_ = new ActiveWindowResources; + inactive_resources_ = new InactiveWindowResources; + +#if defined(GOOGLE_CHROME_BUILD) + distributor_logo_ = ResourceBundle::GetSharedInstance(). + GetBitmapNamed(IDR_DISTRIBUTOR_LOGO_LIGHT); +#endif + + initialized = true; + } +} + +// static +void OpaqueBrowserFrameView::InitAppWindowResources() { + static bool initialized = false; + if (!initialized) { + title_font_ = win_util::GetWindowTitleFont(); + initialized = true; + } +} diff --git a/chrome/browser/views/frame/opaque_browser_frame_view.h b/chrome/browser/views/frame/opaque_browser_frame_view.h new file mode 100644 index 0000000..7eed20d --- /dev/null +++ b/chrome/browser/views/frame/opaque_browser_frame_view.h @@ -0,0 +1,167 @@ +// 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_FRAME_OPAQUE_BROWSER_FRAME_VIEW_H_ +#define CHROME_BROWSER_VIEWS_FRAME_OPAQUE_BROWSER_FRAME_VIEW_H_ + +#include "chrome/browser/views/frame/browser_frame.h" +#include "chrome/browser/views/tab_icon_view.h" +#include "chrome/views/non_client_view.h" +#include "chrome/views/button.h" + +class BrowserView; +class ChromeFont; +class TabContents; +class TabStrip; +namespace views { +class WindowResources; +} + +class OpaqueBrowserFrameView : public BrowserNonClientFrameView, + public views::BaseButton::ButtonListener, + public TabIconView::TabIconViewModel { + public: + // Constructs a non-client view for an BrowserFrame. |is_otr| specifies if the + // frame was created "off-the-record" and as such different bitmaps should be + // used to render the frame. + OpaqueBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view); + virtual ~OpaqueBrowserFrameView(); + + // Overridden from BrowserNonClientFrameView: + virtual gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const; + virtual void UpdateThrobber(bool running); + + protected: + // Overridden from views::NonClientFrameView: + virtual gfx::Rect GetBoundsForClientView() const; + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const; + virtual gfx::Point GetSystemMenuPoint() const; + virtual int NonClientHitTest(const gfx::Point& point); + virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); + virtual void EnableClose(bool enable); + virtual void ResetWindowControls(); + + // Overridden from views::View: + virtual void Paint(ChromeCanvas* canvas); + virtual void Layout(); + virtual views::View* GetViewForPoint(const gfx::Point& point, + bool can_create_floating); + virtual void ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child); + virtual bool GetAccessibleRole(VARIANT* role); + virtual bool GetAccessibleName(std::wstring* name); + virtual void SetAccessibleName(const std::wstring& name); + + // Overridden from views::BaseButton::ButtonListener: + virtual void ButtonPressed(views::BaseButton* sender); + + // Overridden from TabIconView::TabIconViewModel: + virtual bool ShouldTabIconViewAnimate() const; + virtual SkBitmap GetFavIconForTabIconView(); + + private: + // Returns the thickness of the border that makes up the window frame edges. + // This does not include any client edge. + int FrameBorderThickness() const; + + // Returns the height of the top resize area. This is smaller than the frame + // border height in order to increase the window draggable area. + int TopResizeHeight() const; + + // Returns the thickness of the entire nonclient left, right, and bottom + // borders, including both the window frame and any client edge. + int NonClientBorderThickness() const; + + // Returns the height of the entire nonclient top border, including the window + // frame, any title area, and any connected client edge. + int NonClientTopBorderHeight() const; + + // The nonclient area at the top of the window may include some "unavailable" + // pixels at its bottom: a dark shadow along the bottom of the titlebar and a + // client edge. These vary from mode to mode, so this function returns the + // number of such pixels the nonclient height includes. + int UnavailablePixelsAtBottomOfNonClientHeight() const; + + // Calculates multiple values related to title layout. Returns the height of + // the entire titlebar including any connected client edge. + int TitleCoordinates(int* title_top_spacing, + int* title_thickness) const; + + // Paint various sub-components of this view. The *FrameBorder() functions + // also paint the background of the titlebar area, since the top frame border + // and titlebar background are a contiguous component. + void PaintRestoredFrameBorder(ChromeCanvas* canvas); + void PaintMaximizedFrameBorder(ChromeCanvas* canvas); + void PaintDistributorLogo(ChromeCanvas* canvas); + void PaintTitleBar(ChromeCanvas* canvas); + void PaintToolbarBackground(ChromeCanvas* canvas); + void PaintOTRAvatar(ChromeCanvas* canvas); + void PaintRestoredClientEdge(ChromeCanvas* canvas); + + // Layout various sub-components of this view. + void LayoutWindowControls(); + void LayoutDistributorLogo(); + void LayoutTitleBar(); + void LayoutOTRAvatar(); + void LayoutClientView(); + + // Returns the bounds of the client area for the specified view size. + gfx::Rect CalculateClientAreaBounds(int width, int height) const; + + // Returns the set of resources to use to paint this view. + views::WindowResources* resources() const { + return frame_->is_active() || paint_as_active() ? + current_active_resources_ : current_inactive_resources_; + } + + // The layout rect of the title, if visible. + gfx::Rect title_bounds_; + + // The layout rect of the distributor logo, if visible. + gfx::Rect logo_bounds_; + + // The layout rect of the OTR avatar icon, if visible. + gfx::Rect otr_avatar_bounds_; + + // Window controls. + views::Button* minimize_button_; + views::Button* maximize_button_; + views::Button* restore_button_; + views::Button* close_button_; + + // The Window icon. + TabIconView* window_icon_; + + // The frame that hosts this view. + BrowserFrame* frame_; + + // The BrowserView hosted within this View. + BrowserView* browser_view_; + + // The bounds of the ClientView. + gfx::Rect client_view_bounds_; + + // The resources currently used to paint this view. + views::WindowResources* current_active_resources_; + views::WindowResources* current_inactive_resources_; + + // The accessible name of this view. + std::wstring accessible_name_; + + static void InitClass(); + static void InitAppWindowResources(); + static SkBitmap* distributor_logo_; + static views::WindowResources* active_resources_; + static views::WindowResources* inactive_resources_; + static views::WindowResources* active_otr_resources_; + static views::WindowResources* inactive_otr_resources_; + static ChromeFont title_font_; + + DISALLOW_EVIL_CONSTRUCTORS(OpaqueBrowserFrameView); +}; + +#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_OPAQUE_BROWSER_FRAME_VIEW_H_ + diff --git a/chrome/browser/views/frame/opaque_frame.cc b/chrome/browser/views/frame/opaque_frame.cc deleted file mode 100644 index 066bcad..0000000 --- a/chrome/browser/views/frame/opaque_frame.cc +++ /dev/null @@ -1,139 +0,0 @@ -// 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/frame/opaque_frame.h" - -#include "chrome/browser/browser_list.h" -#include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/frame/opaque_non_client_view.h" -#include "chrome/browser/views/tabs/tab_strip.h" -#include "chrome/views/window_delegate.h" - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueFrame, public: - -OpaqueFrame::OpaqueFrame(BrowserView* browser_view) - : CustomFrameWindow(browser_view, new OpaqueNonClientView(this, - browser_view)), - browser_view_(browser_view) { - browser_view_->set_frame(this); -} - -OpaqueFrame::~OpaqueFrame() { -} - -void OpaqueFrame::Init() { - CustomFrameWindow::Init(NULL, gfx::Rect()); -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueFrame, BrowserFrame implementation: - -gfx::Rect OpaqueFrame::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) { - return GetOpaqueNonClientView()->GetWindowBoundsForClientBounds( - client_bounds); -} - -void OpaqueFrame::SizeToContents(const gfx::Rect& contents_bounds) { - gfx::Rect window_bounds = GetOpaqueNonClientView()-> - GetWindowBoundsForClientBounds(contents_bounds); - SetBounds(window_bounds); -} - -gfx::Rect OpaqueFrame::GetBoundsForTabStrip(TabStrip* tabstrip) const { - return GetOpaqueNonClientView()->GetBoundsForTabStrip(tabstrip); -} - -void OpaqueFrame::UpdateThrobber(bool running) { - // TODO(beng): pass |running| through rather than letting - // OpaqueNonClientView's TabIconView try and figure it out. - // The throbber doesn't run in the Windows TaskBar, so we just update the - // non-client view. Updating the taskbar is muy expensivo. - GetOpaqueNonClientView()->UpdateWindowIcon(); -} - -views::Window* OpaqueFrame::GetWindow() { - return this; -} - -const views::Window* OpaqueFrame::GetWindow() const { - return this; -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueFrame, views::CustomFrameWindow overrides: - -void OpaqueFrame::UpdateWindowIcon() { - CustomFrameWindow::UpdateWindowIcon(); - GetOpaqueNonClientView()->UpdateWindowIcon(); -} - -int OpaqueFrame::GetShowState() const { - return browser_view_->GetShowState(); -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueFrame, views::WidgetWin overrides: - -bool OpaqueFrame::AcceleratorPressed(views::Accelerator* accelerator) { - return browser_view_->AcceleratorPressed(*accelerator); -} - -bool OpaqueFrame::GetAccelerator(int cmd_id, views::Accelerator* accelerator) { - return browser_view_->GetAccelerator(cmd_id, accelerator); -} - -void OpaqueFrame::OnEndSession(BOOL ending, UINT logoff) { - BrowserList::WindowsSessionEnding(); -} - -void OpaqueFrame::OnEnterSizeMove() { - browser_view_->WindowMoveOrResizeStarted(); -} - -void OpaqueFrame::OnInitMenuPopup(HMENU menu, UINT position, - BOOL is_system_menu) { - browser_view_->PrepareToRunSystemMenu(menu); -} - -LRESULT OpaqueFrame::OnMouseActivate(HWND window, UINT hittest_code, - UINT message) { - return browser_view_->ActivateAppModalDialog() ? MA_NOACTIVATEANDEAT - : MA_ACTIVATE; -} - -void OpaqueFrame::OnMove(const CPoint& point) { - browser_view_->WindowMoved(); -} - -void OpaqueFrame::OnMoving(UINT param, const RECT* new_bounds) { - browser_view_->WindowMoved(); -} - -LRESULT OpaqueFrame::OnNCActivate(BOOL active) { - if (browser_view_->ActivateAppModalDialog()) - return TRUE; - - CustomFrameWindow::OnNCActivate(active); - browser_view_->ActivationChanged(!!active); - return TRUE; -} - -void OpaqueFrame::OnSysCommand(UINT notification_code, CPoint click) { - if (!browser_view_->SystemCommandReceived(notification_code, - gfx::Point(click))) { - // Use the default implementation for any other command. - CustomFrameWindow::OnSysCommand(notification_code, click); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueFrame, private: - -OpaqueNonClientView* OpaqueFrame::GetOpaqueNonClientView() const { - // We can safely assume that this conversion is true. - return static_cast(non_client_view_); -} - diff --git a/chrome/browser/views/frame/opaque_frame.h b/chrome/browser/views/frame/opaque_frame.h deleted file mode 100644 index 7042002..0000000 --- a/chrome/browser/views/frame/opaque_frame.h +++ /dev/null @@ -1,74 +0,0 @@ -// 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_FRAME_OPAQUE_FRAME_H_ -#define CHROME_BROWSER_VIEWS_FRAME_OPAQUE_FRAME_H_ - -#include "chrome/browser/views/frame/browser_frame.h" -#include "chrome/views/custom_frame_window.h" - -class BrowserView; -namespace views { -class Window; -} -class OpaqueNonClientView; -class TabStrip; - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueFrame -// -// OpaqueFrame is a CustomFrameWindow subclass that in conjunction with -// OpaqueNonClientView provides the window frame on Windows XP and on Windows -// Vista when DWM desktop compositing is disabled. The window title and -// borders are provided with bitmaps. -// -class OpaqueFrame : public BrowserFrame, - public views::CustomFrameWindow { - public: - explicit OpaqueFrame(BrowserView* browser_view); - virtual ~OpaqueFrame(); - - void Init(); - - protected: - // Overridden from BrowserFrame: - virtual gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds); - virtual void SizeToContents(const gfx::Rect& contents_bounds); - virtual gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip) const; - virtual void UpdateThrobber(bool running); - virtual views::Window* GetWindow(); - virtual const views::Window* GetWindow() const; - - // Overridden from views::CustomFrameWindow: - virtual void UpdateWindowIcon(); - virtual int GetShowState() const; - virtual bool IsAppWindow() const { return true; } - - // Overridden from views::WidgetWin: - virtual bool AcceleratorPressed(views::Accelerator* accelerator); - virtual bool GetAccelerator(int cmd_id, views::Accelerator* accelerator); - virtual void OnEnterSizeMove(); - virtual void OnEndSession(BOOL ending, UINT logoff); - virtual void OnInitMenuPopup(HMENU menu, UINT position, BOOL is_system_menu); - virtual LRESULT OnMouseActivate(HWND window, - UINT hittest_code, - UINT message); - virtual void OnMove(const CPoint& point); - virtual void OnMoving(UINT param, const RECT* new_bounds); - virtual LRESULT OnNCActivate(BOOL active); - virtual void OnSysCommand(UINT notification_code, CPoint click); - - private: - // Return a pointer to the concrete type of our non-client view. - OpaqueNonClientView* GetOpaqueNonClientView() const; - - // The BrowserView is our ClientView. This is a pointer to it. - BrowserView* browser_view_; - - DISALLOW_EVIL_CONSTRUCTORS(OpaqueFrame); -}; - -#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_OPAQUE_FRAME_H_ - diff --git a/chrome/browser/views/frame/opaque_non_client_view.cc b/chrome/browser/views/frame/opaque_non_client_view.cc deleted file mode 100644 index 2ed23f8..0000000 --- a/chrome/browser/views/frame/opaque_non_client_view.cc +++ /dev/null @@ -1,1071 +0,0 @@ -// 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/frame/opaque_non_client_view.h" - -#include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/tabs/tab_strip.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/gfx/chrome_font.h" -#include "chrome/common/gfx/path.h" -#include "chrome/common/l10n_util.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/common/win_util.h" -#include "chrome/views/root_view.h" -#include "chrome/views/window_resources.h" -#include "grit/chromium_strings.h" -#include "grit/generated_resources.h" -#include "grit/theme_resources.h" - -// An enumeration of bitmap resources used by this window. -enum { - // Window Controls. - FRAME_CLOSE_BUTTON_ICON, - FRAME_CLOSE_BUTTON_ICON_H, - FRAME_CLOSE_BUTTON_ICON_P, - FRAME_CLOSE_BUTTON_ICON_SA, - FRAME_CLOSE_BUTTON_ICON_SA_H, - FRAME_CLOSE_BUTTON_ICON_SA_P, - FRAME_RESTORE_BUTTON_ICON, - FRAME_RESTORE_BUTTON_ICON_H, - FRAME_RESTORE_BUTTON_ICON_P, - FRAME_MAXIMIZE_BUTTON_ICON, - FRAME_MAXIMIZE_BUTTON_ICON_H, - FRAME_MAXIMIZE_BUTTON_ICON_P, - FRAME_MINIMIZE_BUTTON_ICON, - FRAME_MINIMIZE_BUTTON_ICON_H, - FRAME_MINIMIZE_BUTTON_ICON_P, - - // Window Frame Border. - FRAME_BOTTOM_EDGE, - FRAME_BOTTOM_LEFT_CORNER, - FRAME_BOTTOM_RIGHT_CORNER, - FRAME_LEFT_EDGE, - FRAME_RIGHT_EDGE, - FRAME_TOP_EDGE, - FRAME_TOP_LEFT_CORNER, - FRAME_TOP_RIGHT_CORNER, - - // Client Edge Border. - FRAME_CLIENT_EDGE_TOP_LEFT, - FRAME_CLIENT_EDGE_TOP, - FRAME_CLIENT_EDGE_TOP_RIGHT, - FRAME_CLIENT_EDGE_RIGHT, - FRAME_CLIENT_EDGE_BOTTOM_RIGHT, - FRAME_CLIENT_EDGE_BOTTOM, - FRAME_CLIENT_EDGE_BOTTOM_LEFT, - FRAME_CLIENT_EDGE_LEFT, - - // No-toolbar client edge. - FRAME_NO_TOOLBAR_TOP_LEFT, - FRAME_NO_TOOLBAR_TOP_CENTER, - FRAME_NO_TOOLBAR_TOP_RIGHT, - - FRAME_PART_BITMAP_COUNT // Must be last. -}; - -class ActiveWindowResources : public views::WindowResources { - public: - ActiveWindowResources() { - InitClass(); - } - virtual ~ActiveWindowResources() { } - - // WindowResources implementation: - virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, - IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, - IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, - IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, - IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, - 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_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, - IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, - IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, - IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, - IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - - DISALLOW_EVIL_CONSTRUCTORS(ActiveWindowResources); -}; - -class InactiveWindowResources : public views::WindowResources { - public: - InactiveWindowResources() { - InitClass(); - } - virtual ~InactiveWindowResources() { } - - // WindowResources implementation: - virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, - IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, - IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, - IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, - IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, - 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_CONTENT_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, - IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, - IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, - IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, - IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - - DISALLOW_EVIL_CONSTRUCTORS(InactiveWindowResources); -}; - -class OTRActiveWindowResources : public views::WindowResources { - public: - OTRActiveWindowResources() { - InitClass(); - } - virtual ~OTRActiveWindowResources() { } - - // WindowResources implementation: - virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, - IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, - IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, - IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, - IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, - 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_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, - IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, - IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, - IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, - IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - - DISALLOW_EVIL_CONSTRUCTORS(OTRActiveWindowResources); -}; - -class OTRInactiveWindowResources : public views::WindowResources { - public: - OTRInactiveWindowResources() { - InitClass(); - } - virtual ~OTRInactiveWindowResources() { } - - // WindowResources implementation: - virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, - IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, - IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, - IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, - IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, - 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_CONTENT_TOP_LEFT_CORNER, IDR_CONTENT_TOP_CENTER, - IDR_CONTENT_TOP_RIGHT_CORNER, IDR_CONTENT_RIGHT_SIDE, - IDR_CONTENT_BOTTOM_RIGHT_CORNER, IDR_CONTENT_BOTTOM_CENTER, - IDR_CONTENT_BOTTOM_LEFT_CORNER, IDR_CONTENT_LEFT_SIDE, - IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(kFramePartBitmapIds[i]); - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - - DISALLOW_EVIL_CONSTRUCTORS(OTRInactiveWindowResources); -}; - -// static -SkBitmap* ActiveWindowResources::standard_frame_bitmaps_[]; -SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[]; -SkBitmap* OTRActiveWindowResources::standard_frame_bitmaps_[]; -SkBitmap* OTRInactiveWindowResources::standard_frame_bitmaps_[]; - -views::WindowResources* OpaqueNonClientView::active_resources_ = NULL; -views::WindowResources* OpaqueNonClientView::inactive_resources_ = NULL; -views::WindowResources* OpaqueNonClientView::active_otr_resources_ = NULL; -views::WindowResources* OpaqueNonClientView::inactive_otr_resources_ = NULL; -SkBitmap* OpaqueNonClientView::distributor_logo_ = NULL; -ChromeFont OpaqueNonClientView::title_font_; - -namespace { -// The frame border is only visible in restored mode and is hardcoded to 4 px on -// each side regardless of the system window border size. -const int kFrameBorderThickness = 4; -// Besides the frame border, there's another 11 px of empty space atop the -// window in restored mode, to use to drag the window around. -const int kNonClientRestoredExtraThickness = 11; -// While resize areas on Windows are normally the same size as the window -// borders, our top area is shrunk by 1 px to make it easier to move the window -// around with our thinner top grabbable strip. (Incidentally, our side and -// bottom resize areas don't match the frame border thickness either -- they -// span the whole nonclient area, so there's no "dead zone" for the mouse.) -const int kTopResizeAdjust = 1; -// In the window corners, the resize areas don't actually expand bigger, but the -// 16 px at the end of each edge triggers diagonal resizing. -const int kResizeAreaCornerSize = 16; -// The titlebar never shrinks to less than 18 px tall, plus the height of the -// frame border and any bottom edge. -const int kTitlebarMinimumHeight = 18; -// The icon is inset 2 px from the left frame border. -const int kIconLeftSpacing = 2; -// The icon takes up 16/25th of the available titlebar height. (This is -// expressed as two ints to avoid precision losses leading to off-by-one pixel -// errors.) -const int kIconHeightFractionNumerator = 16; -const int kIconHeightFractionDenominator = 25; -// The icon never shrinks below 16 px on a side. -const int kIconMinimumSize = 16; -// Because our frame border has a different "3D look" than Windows', with a less -// cluttered top edge, we need to shift the icon up by 1 px in restored mode so -// it looks more centered. -const int kIconRestoredAdjust = 1; -// There is a 4 px gap between the icon and the title text. -const int kIconTitleSpacing = 4; -// The title text starts 2 px below the bottom of the top frame border. -const int kTitleTopSpacing = 2; -// There is a 5 px gap between the title text and the distributor logo (if -// present) or caption buttons. -const int kTitleLogoSpacing = 5; -// In maximized mode, the OTR avatar starts 2 px below the top of the screen, so -// that it doesn't extend into the "3D edge" portion of the titlebar. -const int kOTRMaximizedTopSpacing = 2; -// The OTR avatar ends 2 px above the bottom of the tabstrip (which, given the -// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the -// user). -const int kOTRBottomSpacing = 2; -// There are 2 px on each side of the OTR avatar (between the frame border and -// it on the left, and between it and the tabstrip on the right). -const int kOTRSideSpacing = 2; -// In restored mode, the New Tab button isn't at the same height as the caption -// buttons, but the space will look cluttered if it actually slides under them, -// so we stop it when the gap between the two is down to 5 px. -const int kNewTabCaptionRestoredSpacing = 5; -// In maximized mode, where the New Tab button and the caption buttons are at -// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid -// looking too cluttered. -const int kNewTabCaptionMaximizedSpacing = 16; -// When there's a distributor logo, we leave a 7 px gap between it and the -// caption buttons. -const int kLogoCaptionSpacing = 7; -// The caption buttons are always drawn 1 px down from the visible top of the -// window (the true top in restored mode, or the top of the screen in maximized -// mode). -const int kCaptionTopSpacing = 1; -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueNonClientView, public: - -OpaqueNonClientView::OpaqueNonClientView(OpaqueFrame* frame, - BrowserView* browser_view) - : NonClientView(), - minimize_button_(new views::Button), - maximize_button_(new views::Button), - restore_button_(new views::Button), - close_button_(new views::Button), - window_icon_(NULL), - frame_(frame), - browser_view_(browser_view) { - InitClass(); - if (browser_view->IsOffTheRecord()) { - if (!active_otr_resources_) { - // Lazy load OTR resources only when we first show an OTR frame. - active_otr_resources_ = new OTRActiveWindowResources; - inactive_otr_resources_ = new OTRInactiveWindowResources; - } - current_active_resources_ = active_otr_resources_; - current_inactive_resources_= inactive_otr_resources_; - } else { - current_active_resources_ = active_resources_; - current_inactive_resources_ = inactive_resources_; - } - - views::WindowResources* resources = current_active_resources_; - minimize_button_->SetImage( - views::Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON)); - minimize_button_->SetImage( - views::Button::BS_HOT, - resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_H)); - minimize_button_->SetImage( - views::Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_P)); - minimize_button_->SetListener(this, -1); - minimize_button_->SetAccessibleName( - l10n_util::GetString(IDS_ACCNAME_MINIMIZE)); - AddChildView(minimize_button_); - - maximize_button_->SetImage( - views::Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON)); - maximize_button_->SetImage( - views::Button::BS_HOT, - resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_H)); - maximize_button_->SetImage( - views::Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_P)); - maximize_button_->SetListener(this, -1); - maximize_button_->SetAccessibleName( - l10n_util::GetString(IDS_ACCNAME_MAXIMIZE)); - AddChildView(maximize_button_); - - restore_button_->SetImage( - views::Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON)); - restore_button_->SetImage( - views::Button::BS_HOT, - resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_H)); - restore_button_->SetImage( - views::Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_P)); - restore_button_->SetListener(this, -1); - restore_button_->SetAccessibleName( - l10n_util::GetString(IDS_ACCNAME_RESTORE)); - AddChildView(restore_button_); - - close_button_->SetImage( - views::Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON)); - close_button_->SetImage( - views::Button::BS_HOT, - resources->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_H)); - close_button_->SetImage( - views::Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_P)); - close_button_->SetListener(this, -1); - close_button_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE)); - AddChildView(close_button_); - - // Initializing the TabIconView is expensive, so only do it if we need to. - if (browser_view_->ShouldShowWindowIcon()) { - window_icon_ = new TabIconView(this); - window_icon_->set_is_light(true); - AddChildView(window_icon_); - window_icon_->Update(); - } - // Only load the title font if we're going to need to use it to paint. - // Loading fonts is expensive. - if (browser_view_->ShouldShowWindowTitle()) - InitAppWindowResources(); -} - -OpaqueNonClientView::~OpaqueNonClientView() { -} - -gfx::Rect OpaqueNonClientView::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) { - int top_height = NonClientTopBorderHeight(); - int border_thickness = NonClientBorderThickness(); - return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), - std::max(0, client_bounds.y() - top_height), - client_bounds.width() + (2 * border_thickness), - client_bounds.height() + top_height + border_thickness); -} - -gfx::Rect OpaqueNonClientView::GetBoundsForTabStrip(TabStrip* tabstrip) { - int tabstrip_x = browser_view_->ShouldShowOffTheRecordAvatar() ? - (otr_avatar_bounds_.right() + kOTRSideSpacing) : - NonClientBorderThickness(); - int tabstrip_width = minimize_button_->x() - tabstrip_x - - (frame_->IsMaximized() ? - kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing); - return gfx::Rect(tabstrip_x, NonClientTopBorderHeight(), - std::max(0, tabstrip_width), tabstrip->GetPreferredHeight()); -} - -void OpaqueNonClientView::UpdateWindowIcon() { - if (window_icon_) - window_icon_->Update(); -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueNonClientView, views::NonClientView implementation: - -gfx::Rect OpaqueNonClientView::CalculateClientAreaBounds(int width, - int height) const { - int top_height = NonClientTopBorderHeight(); - int border_thickness = NonClientBorderThickness(); - return gfx::Rect(border_thickness, top_height, - std::max(0, width - (2 * border_thickness)), - std::max(0, height - top_height - border_thickness)); -} - -gfx::Size OpaqueNonClientView::CalculateWindowSizeForClientSize( - int width, - int height) const { - int border_thickness = NonClientBorderThickness(); - return gfx::Size(width + (2 * border_thickness), - height + NonClientTopBorderHeight() + border_thickness); -} - -gfx::Point OpaqueNonClientView::GetSystemMenuPoint() const { - gfx::Point system_menu_point(FrameBorderThickness(), - NonClientTopBorderHeight() + browser_view_->GetTabStripHeight() - - (browser_view_->IsFullscreen() ? 0 : kClientEdgeThickness)); - ConvertPointToScreen(this, &system_menu_point); - return system_menu_point; -} - -int OpaqueNonClientView::NonClientHitTest(const gfx::Point& point) { - if (!bounds().Contains(point)) - return HTNOWHERE; - - int frame_component = frame_->client_view()->NonClientHitTest(point); - if (frame_component != HTNOWHERE) - return frame_component; - - // Then see if the point is within any of the window controls. - if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) - return HTCLOSE; - if (restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTMAXBUTTON; - if (maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTMAXBUTTON; - if (minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTMINBUTTON; - if (window_icon_ && - window_icon_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) - return HTSYSMENU; - - int window_component = GetHTComponentForFrame(point, TopResizeHeight(), - NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, - frame_->window_delegate()->CanResize()); - // Fall back to the caption if no other component matches. - return (window_component == HTNOWHERE) ? HTCAPTION : window_component; -} - -void OpaqueNonClientView::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) { - DCHECK(window_mask); - - if (browser_view_->IsFullscreen()) - return; - - // Redefine the window visible region for the new size. - window_mask->moveTo(0, 3); - window_mask->lineTo(1, 2); - window_mask->lineTo(1, 1); - window_mask->lineTo(2, 1); - window_mask->lineTo(3, 0); - - window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); - window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); - window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); - window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); - window_mask->lineTo(SkIntToScalar(size.width()), 3); - - window_mask->lineTo(SkIntToScalar(size.width()), - SkIntToScalar(size.height())); - window_mask->lineTo(0, SkIntToScalar(size.height())); - window_mask->close(); -} - -void OpaqueNonClientView::EnableClose(bool enable) { - close_button_->SetEnabled(enable); -} - -void OpaqueNonClientView::ResetWindowControls() { - restore_button_->SetState(views::Button::BS_NORMAL); - minimize_button_->SetState(views::Button::BS_NORMAL); - maximize_button_->SetState(views::Button::BS_NORMAL); - // The close button isn't affected by this constraint. -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueNonClientView, views::View overrides: - -void OpaqueNonClientView::Paint(ChromeCanvas* canvas) { - if (browser_view_->IsFullscreen()) - return; // Nothing is visible, so don't bother to paint. - - if (frame_->IsMaximized()) - PaintMaximizedFrameBorder(canvas); - else - PaintRestoredFrameBorder(canvas); - PaintDistributorLogo(canvas); - PaintTitleBar(canvas); - PaintToolbarBackground(canvas); - PaintOTRAvatar(canvas); - if (!frame_->IsMaximized()) - PaintRestoredClientEdge(canvas); -} - -void OpaqueNonClientView::Layout() { - LayoutWindowControls(); - LayoutDistributorLogo(); - LayoutTitleBar(); - LayoutOTRAvatar(); - LayoutClientView(); -} - -views::View* OpaqueNonClientView::GetViewForPoint(const gfx::Point& point, - bool can_create_floating) { - // We override this function because the ClientView can overlap the non - - // client view, making it impossible to click on the window controls. We need - // to ensure the window controls are checked _first_. - views::View* views[] = - { close_button_, restore_button_, maximize_button_, minimize_button_ }; - for (int i = 0; i < arraysize(views); ++i) { - if (!views[i]->IsVisible()) - continue; - // Apply mirroring transformation on view bounds for RTL chrome. - if (views[i]->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) - return views[i]; - } - return View::GetViewForPoint(point, can_create_floating); -} - -void OpaqueNonClientView::ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child) { - if (is_add && child == this) { - DCHECK(GetWidget()); - DCHECK(frame_->client_view()->GetParent() != this); - AddChildView(frame_->client_view()); - - // The Accessibility glue looks for the product name on these two views to - // determine if this is in fact a Chrome window. - GetRootView()->SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); - SetAccessibleName(l10n_util::GetString(IDS_PRODUCT_NAME)); - } -} - -bool OpaqueNonClientView::GetAccessibleRole(VARIANT* role) { - DCHECK(role); - // We aren't actually the client area of the window, but we act like it as - // far as MSAA and the UI tests are concerned. - role->vt = VT_I4; - role->lVal = ROLE_SYSTEM_CLIENT; - return true; -} - -bool OpaqueNonClientView::GetAccessibleName(std::wstring* name) { - if (!accessible_name_.empty()) { - *name = accessible_name_; - return true; - } - return false; -} - -void OpaqueNonClientView::SetAccessibleName(const std::wstring& name) { - accessible_name_ = name; -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueNonClientView, views::BaseButton::ButtonListener implementation: - -void OpaqueNonClientView::ButtonPressed(views::BaseButton* sender) { - if (sender == minimize_button_) - frame_->ExecuteSystemMenuCommand(SC_MINIMIZE); - else if (sender == maximize_button_) - frame_->ExecuteSystemMenuCommand(SC_MAXIMIZE); - else if (sender == restore_button_) - frame_->ExecuteSystemMenuCommand(SC_RESTORE); - else if (sender == close_button_) - frame_->ExecuteSystemMenuCommand(SC_CLOSE); -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueNonClientView, TabIconView::TabContentsProvider implementation: - -bool OpaqueNonClientView::ShouldTabIconViewAnimate() const { - // This function is queried during the creation of the window as the - // TabIconView we host is initialized, so we need to NULL check the selected - // TabContents because in this condition there is not yet a selected tab. - TabContents* current_tab = browser_view_->GetSelectedTabContents(); - return current_tab ? current_tab->is_loading() : false; -} - -SkBitmap OpaqueNonClientView::GetFavIconForTabIconView() { - return frame_->window_delegate()->GetWindowIcon(); -} - -/////////////////////////////////////////////////////////////////////////////// -// OpaqueNonClientView, private: - -int OpaqueNonClientView::FrameBorderThickness() const { - if (browser_view_->IsFullscreen()) - return 0; - return frame_->IsMaximized() ? - GetSystemMetrics(SM_CXSIZEFRAME) : kFrameBorderThickness; -} - -int OpaqueNonClientView::TopResizeHeight() const { - return FrameBorderThickness() - kTopResizeAdjust; -} - -int OpaqueNonClientView::NonClientBorderThickness() const { - // When we fill the screen, we don't show a client edge. - return FrameBorderThickness() + - (browser_view_->CanCurrentlyResize() ? kClientEdgeThickness : 0); -} - -int OpaqueNonClientView::NonClientTopBorderHeight() const { - if (frame_->window_delegate()->ShouldShowWindowTitle()) { - int title_top_spacing, title_thickness; - return TitleCoordinates(&title_top_spacing, &title_thickness); - } - - return FrameBorderThickness() + (browser_view_->CanCurrentlyResize() ? - kNonClientRestoredExtraThickness : 0); -} - -int OpaqueNonClientView::UnavailablePixelsAtBottomOfNonClientHeight() const { - // Tricky: When a toolbar is edging the titlebar, it not only draws its own - // shadow and client edge, but an extra, light "shadow" pixel as well, which - // is treated as available space. Thus the nonclient area actually _fails_ to - // include some available pixels, leading to a negative number here. - if (browser_view_->IsToolbarVisible()) - return -kFrameShadowThickness; - - return kFrameShadowThickness + - (frame_->IsMaximized() ? 0 : kClientEdgeThickness); -} - -int OpaqueNonClientView::TitleCoordinates(int* title_top_spacing, - int* title_thickness) const { - int frame_thickness = FrameBorderThickness(); - int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; - *title_top_spacing = frame_thickness + kTitleTopSpacing; - // The bottom spacing should be the same apparent height as the top spacing. - // Because the actual top spacing height varies based on the system border - // thickness, we calculate this based on the restored top spacing and then - // adjust for maximized mode. We also don't include the frame shadow here, - // since while it's part of the bottom spacing it will be added in at the end - // as necessary (when a toolbar is present, the "shadow" is actually drawn by - // the toolbar). - int title_bottom_spacing = - kFrameBorderThickness + kTitleTopSpacing - kFrameShadowThickness; - if (frame_->IsMaximized()) { - // When we maximize, the top border appears to be chopped off; shift the - // title down to stay centered within the remaining space. - int title_adjust = (kFrameBorderThickness / 2); - *title_top_spacing += title_adjust; - title_bottom_spacing -= title_adjust; - } - *title_thickness = std::max(title_font_.height(), - min_titlebar_height - *title_top_spacing - title_bottom_spacing); - return *title_top_spacing + *title_thickness + title_bottom_spacing + - UnavailablePixelsAtBottomOfNonClientHeight(); -} - -void OpaqueNonClientView::PaintRestoredFrameBorder(ChromeCanvas* canvas) { - SkBitmap* top_left_corner = resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER); - SkBitmap* top_right_corner = - resources()->GetPartBitmap(FRAME_TOP_RIGHT_CORNER); - SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); - SkBitmap* right_edge = resources()->GetPartBitmap(FRAME_RIGHT_EDGE); - SkBitmap* left_edge = resources()->GetPartBitmap(FRAME_LEFT_EDGE); - SkBitmap* bottom_left_corner = - resources()->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER); - SkBitmap* bottom_right_corner = - resources()->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER); - SkBitmap* bottom_edge = resources()->GetPartBitmap(FRAME_BOTTOM_EDGE); - - // Top. - canvas->DrawBitmapInt(*top_left_corner, 0, 0); - canvas->TileImageInt(*top_edge, top_left_corner->width(), 0, - width() - top_right_corner->width(), top_edge->height()); - canvas->DrawBitmapInt(*top_right_corner, - width() - top_right_corner->width(), 0); - // Note: When we don't have a toolbar, we need to draw some kind of bottom - // edge here. Because the App Window graphics we use for this have an - // attached client edge and their sizing algorithm is a little involved, we do - // all this in PaintRestoredClientEdge(). - - // Right. - canvas->TileImageInt(*right_edge, width() - right_edge->width(), - top_right_corner->height(), right_edge->width(), - height() - top_right_corner->height() - - bottom_right_corner->height()); - - // Bottom. - canvas->DrawBitmapInt(*bottom_right_corner, - width() - bottom_right_corner->width(), - height() - bottom_right_corner->height()); - canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(), - height() - bottom_edge->height(), - width() - bottom_left_corner->width() - - bottom_right_corner->width(), - bottom_edge->height()); - canvas->DrawBitmapInt(*bottom_left_corner, 0, - height() - bottom_left_corner->height()); - - // Left. - canvas->TileImageInt(*left_edge, 0, top_left_corner->height(), - left_edge->width(), - height() - top_left_corner->height() - bottom_left_corner->height()); -} - -void OpaqueNonClientView::PaintMaximizedFrameBorder(ChromeCanvas* canvas) { - SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); - canvas->TileImageInt(*top_edge, 0, FrameBorderThickness(), width(), - top_edge->height()); - - if (!browser_view_->IsToolbarVisible()) { - // There's no toolbar to edge the frame border, so we need to draw a bottom - // edge. The graphic we use for this has a built in client edge, so we clip - // it off the bottom. - SkBitmap* top_center = - resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_CENTER); - int edge_height = top_center->height() - kClientEdgeThickness; - canvas->TileImageInt(*top_center, 0, - frame_->client_view()->y() - edge_height, width(), edge_height); - } -} - -void OpaqueNonClientView::PaintDistributorLogo(ChromeCanvas* canvas) { - // The distributor logo is only painted when the frame is not maximized and - // when we actually have a logo. - if (!frame_->IsMaximized() && distributor_logo_) { - canvas->DrawBitmapInt(*distributor_logo_, - MirroredLeftPointForRect(logo_bounds_), logo_bounds_.y()); - } -} - -void OpaqueNonClientView::PaintTitleBar(ChromeCanvas* canvas) { - // The window icon is painted by the TabIconView. - views::WindowDelegate* d = frame_->window_delegate(); - if (d->ShouldShowWindowTitle()) { - canvas->DrawStringInt(d->GetWindowTitle(), title_font_, SK_ColorWHITE, - MirroredLeftPointForRect(title_bounds_), title_bounds_.y(), - title_bounds_.width(), title_bounds_.height()); - /* TODO(pkasting): If this window is active, we should also draw a drop - * shadow on the title. This is tricky, because we don't want to hardcode a - * shadow color (since we want to work with various themes), but we can't - * alpha-blend either (since the Windows text APIs don't really do this). - * So we'd need to sample the background color at the right location and - * synthesize a good shadow color. */ - } -} - -void OpaqueNonClientView::PaintToolbarBackground(ChromeCanvas* canvas) { - if (!browser_view_->IsToolbarVisible()) - return; - - gfx::Rect toolbar_bounds(browser_view_->GetToolbarBounds()); - gfx::Point toolbar_origin(toolbar_bounds.origin()); - View::ConvertPointToView(frame_->client_view(), this, &toolbar_origin); - toolbar_bounds.set_origin(toolbar_origin); - - SkBitmap* toolbar_left = - resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT); - canvas->DrawBitmapInt(*toolbar_left, - toolbar_bounds.x() - toolbar_left->width(), - toolbar_bounds.y()); - - // Gross hack: We split the toolbar image into two pieces, since sometimes - // (popup mode) the toolbar isn't tall enough to show the whole image. The - // split happens between the top shadow section and the bottom gradient - // section so that we never break the gradient. - int split_point = kFrameShadowThickness * 2; - SkBitmap* toolbar_center = - resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); - canvas->TileImageInt(*toolbar_center, 0, 0, toolbar_bounds.x(), - toolbar_bounds.y(), toolbar_bounds.width(), split_point); - canvas->TileImageInt(*toolbar_center, 0, - toolbar_center->height() - toolbar_bounds.height() + split_point, - toolbar_bounds.x(), toolbar_bounds.y() + split_point, - toolbar_bounds.width(), toolbar_bounds.height() - split_point); - - canvas->DrawBitmapInt( - *resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT), - toolbar_bounds.right(), toolbar_bounds.y()); -} - -void OpaqueNonClientView::PaintOTRAvatar(ChromeCanvas* canvas) { - if (!browser_view_->ShouldShowOffTheRecordAvatar()) - return; - - SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); - canvas->DrawBitmapInt(otr_avatar_icon, 0, - (otr_avatar_icon.height() - otr_avatar_bounds_.height()) / 2, - otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), - MirroredLeftPointForRect(otr_avatar_bounds_), otr_avatar_bounds_.y(), - otr_avatar_bounds_.width(), otr_avatar_bounds_.height(), false); -} - -void OpaqueNonClientView::PaintRestoredClientEdge(ChromeCanvas* canvas) { - int client_area_top = frame_->client_view()->y(); - - gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height()); - if (browser_view_->IsToolbarVisible()) { - // The client edges start below the toolbar upper corner images regardless - // of how tall the toolbar itself is. - client_area_top += browser_view_->GetToolbarBounds().y() + - resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT)->height(); - } else { - // The toolbar isn't going to draw a client edge for us, so draw one - // ourselves. - // This next calculation is necessary because the top center bitmap is - // shorter than the top left and right bitmaps. We need their top edges to - // line up, and we need the left and right edges to start below the corners' - // bottoms. - SkBitmap* top_center = - resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_CENTER); - SkBitmap* top_left = resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_LEFT); - int top_edge_y = client_area_top - top_center->height(); - client_area_top = top_edge_y + top_left->height(); - canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(), - top_edge_y); - canvas->TileImageInt(*top_center, client_area_bounds.x(), top_edge_y, - client_area_bounds.width(), top_center->height()); - canvas->DrawBitmapInt( - *resources()->GetPartBitmap(FRAME_NO_TOOLBAR_TOP_RIGHT), - client_area_bounds.right(), top_edge_y); - } - - int client_area_bottom = - std::max(client_area_top, height() - NonClientBorderThickness()); - int client_area_height = client_area_bottom - client_area_top; - SkBitmap* right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT); - canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, - right->width(), client_area_height); - - canvas->DrawBitmapInt( - *resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT), - client_area_bounds.right(), client_area_bottom); - - SkBitmap* bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM); - canvas->TileImageInt(*bottom, client_area_bounds.x(), - client_area_bottom, client_area_bounds.width(), - bottom->height()); - - SkBitmap* bottom_left = - resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT); - canvas->DrawBitmapInt(*bottom_left, - client_area_bounds.x() - bottom_left->width(), client_area_bottom); - - SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); - canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), - client_area_top, left->width(), client_area_height); -} - -void OpaqueNonClientView::LayoutWindowControls() { - close_button_->SetImageAlignment(views::Button::ALIGN_LEFT, - views::Button::ALIGN_BOTTOM); - // Maximized buttons start at window top so that even if their images aren't - // drawn flush with the screen edge, they still obey Fitts' Law. - bool is_maximized = frame_->IsMaximized(); - int frame_thickness = FrameBorderThickness(); - int caption_y = is_maximized ? frame_thickness : kCaptionTopSpacing; - int top_extra_height = is_maximized ? kCaptionTopSpacing : 0; - // There should always be the same number of non-shadow pixels visible to the - // side of the caption buttons. In maximized mode we extend the rightmost - // button to the screen corner to obey Fitts' Law. - int right_extra_width = is_maximized ? - (kFrameBorderThickness - kFrameShadowThickness) : 0; - int right_spacing = is_maximized ? - (GetSystemMetrics(SM_CXSIZEFRAME) + right_extra_width) : frame_thickness; - gfx::Size close_button_size = close_button_->GetPreferredSize(); - close_button_->SetBounds(width() - close_button_size.width() - right_spacing, - caption_y, - close_button_size.width() + right_extra_width, - close_button_size.height() + top_extra_height); - - // When the window is restored, we show a maximized button; otherwise, we show - // a restore button. - bool is_restored = !is_maximized && !frame_->IsMinimized(); - views::Button* invisible_button = is_restored ? - restore_button_ : maximize_button_; - invisible_button->SetVisible(false); - - views::Button* visible_button = is_restored ? - maximize_button_ : restore_button_; - visible_button->SetVisible(true); - visible_button->SetImageAlignment(views::Button::ALIGN_LEFT, - views::Button::ALIGN_BOTTOM); - gfx::Size visible_button_size = visible_button->GetPreferredSize(); - visible_button->SetBounds(close_button_->x() - visible_button_size.width(), - caption_y, visible_button_size.width(), - visible_button_size.height() + top_extra_height); - - minimize_button_->SetVisible(true); - minimize_button_->SetImageAlignment(views::Button::ALIGN_LEFT, - views::Button::ALIGN_BOTTOM); - gfx::Size minimize_button_size = minimize_button_->GetPreferredSize(); - minimize_button_->SetBounds( - visible_button->x() - minimize_button_size.width(), caption_y, - minimize_button_size.width(), - minimize_button_size.height() + top_extra_height); -} - -void OpaqueNonClientView::LayoutDistributorLogo() { - // Always lay out the logo, even when it's not present, so we can lay out the - // window title based on its position. - if (distributor_logo_) { - logo_bounds_.SetRect(minimize_button_->x() - distributor_logo_->width() - - kLogoCaptionSpacing, TopResizeHeight(), distributor_logo_->width(), - distributor_logo_->height()); - } else { - logo_bounds_.SetRect(minimize_button_->x(), TopResizeHeight(), 0, 0); - } -} - -void OpaqueNonClientView::LayoutTitleBar() { - // Always lay out the icon, even when it's not present, so we can lay out the - // window title based on its position. - int frame_thickness = FrameBorderThickness(); - int icon_x = frame_thickness + kIconLeftSpacing; - - // The usable height of the titlebar area is the total height minus the top - // resize border and any edge area we draw at its bottom. - int title_top_spacing, title_thickness; - int top_height = TitleCoordinates(&title_top_spacing, &title_thickness); - int available_height = top_height - frame_thickness - - UnavailablePixelsAtBottomOfNonClientHeight(); - - // The icon takes up a constant fraction of the available height, down to a - // minimum size, and is always an even number of pixels on a side (presumably - // to make scaled icons look better). It's centered within the usable height. - int icon_size = std::max((available_height * kIconHeightFractionNumerator / - kIconHeightFractionDenominator) / 2 * 2, kIconMinimumSize); - int icon_y = ((available_height - icon_size) / 2) + frame_thickness; - - // Hack: Our frame border has a different "3D look" than Windows'. Theirs has - // a more complex gradient on the top that they push their icon/title below; - // then the maximized window cuts this off and the icon/title are centered in - // the remaining space. Because the apparent shape of our border is simpler, - // using the same positioning makes things look slightly uncentered with - // restored windows, so we come up to compensate. - if (!frame_->IsMaximized()) - icon_y -= kIconRestoredAdjust; - - views::WindowDelegate* d = frame_->window_delegate(); - if (!d->ShouldShowWindowIcon()) - icon_size = 0; - if (window_icon_) - window_icon_->SetBounds(icon_x, icon_y, icon_size, icon_size); - - // Size the title, if visible. - if (d->ShouldShowWindowTitle()) { - int title_x = icon_x + icon_size + - (d->ShouldShowWindowIcon() ? kIconTitleSpacing : 0); - title_bounds_.SetRect(title_x, - title_top_spacing + ((title_thickness - title_font_.height()) / 2), - std::max(0, logo_bounds_.x() - kTitleLogoSpacing - title_x), - title_font_.height()); - } -} - -void OpaqueNonClientView::LayoutOTRAvatar() { - SkBitmap otr_avatar_icon = browser_view_->GetOTRAvatarIcon(); - int top_height = NonClientTopBorderHeight(); - int tabstrip_height, otr_height; - if (browser_view_->IsTabStripVisible()) { - tabstrip_height = browser_view_->GetTabStripHeight() - kOTRBottomSpacing; - otr_height = frame_->IsMaximized() ? - (tabstrip_height - kOTRMaximizedTopSpacing) : - otr_avatar_icon.height(); - } else { - tabstrip_height = otr_height = 0; - } - otr_avatar_bounds_.SetRect(NonClientBorderThickness() + kOTRSideSpacing, - top_height + tabstrip_height - otr_height, - otr_avatar_icon.width(), otr_height); -} - -void OpaqueNonClientView::LayoutClientView() { - frame_->client_view()->SetBounds(CalculateClientAreaBounds(width(), - height())); -} - -// static -void OpaqueNonClientView::InitClass() { - static bool initialized = false; - if (!initialized) { - active_resources_ = new ActiveWindowResources; - inactive_resources_ = new InactiveWindowResources; - -#if defined(GOOGLE_CHROME_BUILD) - distributor_logo_ = ResourceBundle::GetSharedInstance(). - GetBitmapNamed(IDR_DISTRIBUTOR_LOGO_LIGHT); -#endif - - initialized = true; - } -} - -// static -void OpaqueNonClientView::InitAppWindowResources() { - static bool initialized = false; - if (!initialized) { - title_font_ = win_util::GetWindowTitleFont(); - initialized = true; - } -} diff --git a/chrome/browser/views/frame/opaque_non_client_view.h b/chrome/browser/views/frame/opaque_non_client_view.h deleted file mode 100644 index 6160b9d..0000000 --- a/chrome/browser/views/frame/opaque_non_client_view.h +++ /dev/null @@ -1,168 +0,0 @@ -// 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_FRAME_OPAQUE_NON_CLIENT_VIEW_H_ -#define CHROME_BROWSER_VIEWS_FRAME_OPAQUE_NON_CLIENT_VIEW_H_ - -#include "chrome/browser/views/frame/opaque_frame.h" -#include "chrome/browser/views/tab_icon_view.h" -#include "chrome/views/non_client_view.h" -#include "chrome/views/button.h" - -class BrowserView; -class ChromeFont; -class OpaqueFrame; -class TabContents; -class TabStrip; -namespace views { -class WindowResources; -} - -class OpaqueNonClientView : public views::NonClientView, - public views::BaseButton::ButtonListener, - public TabIconView::TabIconViewModel { - public: - // Constructs a non-client view for an OpaqueFrame. |is_otr| specifies if the - // frame was created "off-the-record" and as such different bitmaps should be - // used to render the frame. - OpaqueNonClientView(OpaqueFrame* frame, BrowserView* browser_view); - virtual ~OpaqueNonClientView(); - - // Retrieve the bounds of the window for the specified contents bounds. - gfx::Rect GetWindowBoundsForClientBounds(const gfx::Rect& client_bounds); - - // Retrieve the bounds for the specified |tabstrip|, in the coordinate system - // of the non-client view (which whould be window coordinates). - gfx::Rect GetBoundsForTabStrip(TabStrip* tabstrip); - - // Updates the window icon/throbber. - void UpdateWindowIcon(); - - protected: - // Overridden from views::NonClientView: - virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; - virtual gfx::Size CalculateWindowSizeForClientSize(int width, - int height) const; - virtual gfx::Point GetSystemMenuPoint() const; - virtual int NonClientHitTest(const gfx::Point& point); - virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); - virtual void EnableClose(bool enable); - virtual void ResetWindowControls(); - - // Overridden from views::View: - virtual void Paint(ChromeCanvas* canvas); - virtual void Layout(); - virtual views::View* GetViewForPoint(const gfx::Point& point, - bool can_create_floating); - virtual void ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child); - virtual bool GetAccessibleRole(VARIANT* role); - virtual bool GetAccessibleName(std::wstring* name); - virtual void SetAccessibleName(const std::wstring& name); - - // Overridden from views::BaseButton::ButtonListener: - virtual void ButtonPressed(views::BaseButton* sender); - - // Overridden from TabIconView::TabIconViewModel: - virtual bool ShouldTabIconViewAnimate() const; - virtual SkBitmap GetFavIconForTabIconView(); - - private: - // Returns the thickness of the border that makes up the window frame edges. - // This does not include any client edge. - int FrameBorderThickness() const; - - // Returns the height of the top resize area. This is smaller than the frame - // border height in order to increase the window draggable area. - int TopResizeHeight() const; - - // Returns the thickness of the entire nonclient left, right, and bottom - // borders, including both the window frame and any client edge. - int NonClientBorderThickness() const; - - // Returns the height of the entire nonclient top border, including the window - // frame, any title area, and any connected client edge. - int NonClientTopBorderHeight() const; - - // The nonclient area at the top of the window may include some "unavailable" - // pixels at its bottom: a dark shadow along the bottom of the titlebar and a - // client edge. These vary from mode to mode, so this function returns the - // number of such pixels the nonclient height includes. - int UnavailablePixelsAtBottomOfNonClientHeight() const; - - // Calculates multiple values related to title layout. Returns the height of - // the entire titlebar including any connected client edge. - int TitleCoordinates(int* title_top_spacing, - int* title_thickness) const; - - // Paint various sub-components of this view. The *FrameBorder() functions - // also paint the background of the titlebar area, since the top frame border - // and titlebar background are a contiguous component. - void PaintRestoredFrameBorder(ChromeCanvas* canvas); - void PaintMaximizedFrameBorder(ChromeCanvas* canvas); - void PaintDistributorLogo(ChromeCanvas* canvas); - void PaintTitleBar(ChromeCanvas* canvas); - void PaintToolbarBackground(ChromeCanvas* canvas); - void PaintOTRAvatar(ChromeCanvas* canvas); - void PaintRestoredClientEdge(ChromeCanvas* canvas); - - // Layout various sub-components of this view. - void LayoutWindowControls(); - void LayoutDistributorLogo(); - void LayoutTitleBar(); - void LayoutOTRAvatar(); - void LayoutClientView(); - - // Returns the set of resources to use to paint this view. - views::WindowResources* resources() const { - return frame_->is_active() || paint_as_active() ? - current_active_resources_ : current_inactive_resources_; - } - - // The layout rect of the title, if visible. - gfx::Rect title_bounds_; - - // The layout rect of the distributor logo, if visible. - gfx::Rect logo_bounds_; - - // The layout rect of the OTR avatar icon, if visible. - gfx::Rect otr_avatar_bounds_; - - // Window controls. - views::Button* minimize_button_; - views::Button* maximize_button_; - views::Button* restore_button_; - views::Button* close_button_; - - // The Window icon. - TabIconView* window_icon_; - - // The frame that hosts this view. - OpaqueFrame* frame_; - - // The BrowserView hosted within this View. - BrowserView* browser_view_; - - // The resources currently used to paint this view. - views::WindowResources* current_active_resources_; - views::WindowResources* current_inactive_resources_; - - // The accessible name of this view. - std::wstring accessible_name_; - - static void InitClass(); - static void InitAppWindowResources(); - static SkBitmap* distributor_logo_; - static views::WindowResources* active_resources_; - static views::WindowResources* inactive_resources_; - static views::WindowResources* active_otr_resources_; - static views::WindowResources* inactive_otr_resources_; - static ChromeFont title_font_; - - DISALLOW_EVIL_CONSTRUCTORS(OpaqueNonClientView); -}; - -#endif // #ifndef CHROME_BROWSER_VIEWS_FRAME_OPAQUE_NON_CLIENT_VIEW_H_ - diff --git a/chrome/browser/views/hung_renderer_view.cc b/chrome/browser/views/hung_renderer_view.cc index a539ea8..a293bb9 100644 --- a/chrome/browser/views/hung_renderer_view.cc +++ b/chrome/browser/views/hung_renderer_view.cc @@ -16,13 +16,13 @@ #include "chrome/common/logging_chrome.h" #include "chrome/common/resource_bundle.h" #include "chrome/views/client_view.h" -#include "chrome/views/custom_frame_window.h" #include "chrome/views/dialog_delegate.h" #include "chrome/views/grid_layout.h" #include "chrome/views/group_table_view.h" #include "chrome/views/image_view.h" #include "chrome/views/label.h" #include "chrome/views/native_button.h" +#include "chrome/views/window.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" diff --git a/chrome/browser/views/info_bubble.cc b/chrome/browser/views/info_bubble.cc index 3ab8ec0..8c030d6 100644 --- a/chrome/browser/views/info_bubble.cc +++ b/chrome/browser/views/info_bubble.cc @@ -100,7 +100,7 @@ void InfoBubble::Init(HWND parent_hwnd, DCHECK(BrowserView::GetBrowserViewForHWND(owning_frame_hwnd)); parent_ = reinterpret_cast(win_util::GetWindowUserData( owning_frame_hwnd)); - parent_->DisableInactiveRendering(true); + parent_->DisableInactiveRendering(); if (kInfoBubbleCornerTopLeft == NULL) { kInfoBubbleCornerTopLeft = ResourceBundle::GetSharedInstance() @@ -207,7 +207,6 @@ void InfoBubble::Close(bool closed_by_escape) { // We don't fade out because it looks terrible. if (delegate_) delegate_->InfoBubbleClosing(this, closed_by_escape); - parent_->DisableInactiveRendering(false); closed_ = true; WidgetWin::Close(); } diff --git a/chrome/browser/views/tabs/tab_renderer.cc b/chrome/browser/views/tabs/tab_renderer.cc index cc7cf4c..1580d05 100644 --- a/chrome/browser/views/tabs/tab_renderer.cc +++ b/chrome/browser/views/tabs/tab_renderer.cc @@ -15,6 +15,7 @@ #include "chrome/common/l10n_util.h" #include "chrome/common/resource_bundle.h" #include "chrome/common/win_util.h" +#include "chrome/views/window.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "skia/ext/image_operations.h" @@ -78,6 +79,31 @@ static int download_icon_height = 0; namespace { +// Loads the images to be used for the tab background. Uses the images for +// Vista if |use_vista_images| is true. +void LoadTabImages(bool use_vista_images) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + if (use_vista_images) { + tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_V); + tab_inactive_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_V); + tab_inactive_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_V); + + // Our Vista frame doesn't change background color to show OTR, + // so we continue to use the existing background tabs. + tab_inactive_otr_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_V); + tab_inactive_otr_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_V); + tab_inactive_otr_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_V); + } else { + tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT); + tab_inactive_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER); + tab_inactive_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT); + + tab_inactive_otr_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_OTR); + tab_inactive_otr_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_OTR); + tab_inactive_otr_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_OTR); + } +} + void InitResources() { static bool initialized = false; if (!initialized) { @@ -97,25 +123,7 @@ void InitResources() { tab_active_l_width = tab_active_l->width(); tab_active_r_width = tab_active_r->width(); - if (win_util::ShouldUseVistaFrame()) { - tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_V); - tab_inactive_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_V); - tab_inactive_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_V); - - // Our Vista frame doesn't change background color to show OTR, - // so we continue to use the existing background tabs. - tab_inactive_otr_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_V); - tab_inactive_otr_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_V); - tab_inactive_otr_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_V); - } else { - tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT); - tab_inactive_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER); - tab_inactive_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT); - - tab_inactive_otr_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT_OTR); - tab_inactive_otr_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER_OTR); - tab_inactive_otr_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT_OTR); - } + LoadTabImages(win_util::ShouldUseVistaFrame()); tab_hover_l = rb.GetBitmapNamed(IDR_TAB_HOVER_LEFT); tab_hover_c = rb.GetBitmapNamed(IDR_TAB_HOVER_CENTER); @@ -535,6 +543,12 @@ void TabRenderer::OnMouseExited(const views::MouseEvent& e) { hover_animation_->Hide(); } +void TabRenderer::ThemeChanged() { + if (GetWidget() && GetWidget()->AsWindow()) + LoadTabImages(GetWidget()->AsWindow()->UseNativeFrame()); + View::ThemeChanged(); +} + /////////////////////////////////////////////////////////////////////////////// // TabRenderer, AnimationDelegate implementation: @@ -566,7 +580,7 @@ void TabRenderer::PaintTabBackground(ChromeCanvas* canvas) { animation = pulse_animation_.get(); if (animation->GetCurrentValue() > 0) { PaintHoverTabBackground(canvas, animation->GetCurrentValue() * - (win_util::ShouldUseVistaFrame() ? + (GetWidget()->AsWindow()->UseNativeFrame() ? kHoverOpacityVista : kHoverOpacity)); } else { PaintInactiveTabBackground(canvas); diff --git a/chrome/browser/views/tabs/tab_renderer.h b/chrome/browser/views/tabs/tab_renderer.h index 9cad816..68df3e3 100644 --- a/chrome/browser/views/tabs/tab_renderer.h +++ b/chrome/browser/views/tabs/tab_renderer.h @@ -76,6 +76,7 @@ class TabRenderer : public views::View, virtual void Layout(); virtual void OnMouseEntered(const views::MouseEvent& event); virtual void OnMouseExited(const views::MouseEvent& event); + virtual void ThemeChanged(); // Overridden from AnimationDelegate: virtual void AnimationProgressed(const Animation* animation); @@ -166,6 +167,9 @@ class TabRenderer : public views::View, bool should_display_crashed_favicon_; + static void InitClass(); + static bool initialized_; + DISALLOW_EVIL_CONSTRUCTORS(TabRenderer); }; diff --git a/chrome/browser/views/tabs/tab_strip.cc b/chrome/browser/views/tabs/tab_strip.cc index fceb5af..e3ec025 100644 --- a/chrome/browser/views/tabs/tab_strip.cc +++ b/chrome/browser/views/tabs/tab_strip.cc @@ -25,6 +25,7 @@ #include "chrome/common/win_util.h" #include "chrome/views/image_view.h" #include "chrome/views/painter.h" +#include "chrome/views/window.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -618,7 +619,7 @@ void TabStrip::PaintChildren(ChromeCanvas* canvas) { } } - if (win_util::ShouldUseVistaFrame()) { + if (GetWidget()->AsWindow()->UseNativeFrame()) { // Make sure unselected tabs are somewhat transparent. SkPaint paint; paint.setColor(SkColorSetARGB(200, 255, 255, 255)); diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc index dd88eff..25c7161 100644 --- a/chrome/browser/views/toolbar_view.cc +++ b/chrome/browser/views/toolbar_view.cc @@ -47,7 +47,7 @@ #include "chrome/views/label.h" #include "chrome/views/non_client_view.h" #include "chrome/views/tooltip_manager.h" -#include "chrome/views/widget.h" +#include "chrome/views/window.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" @@ -354,7 +354,7 @@ void BrowserToolbarView::Paint(ChromeCanvas* canvas) { // For glass, we need to draw a black line below the location bar to separate // it from the content area. For non-glass, the NonClientView draws the // toolbar background below the location bar for us. - if (win_util::ShouldUseVistaFrame()) + if (GetWidget()->AsWindow()->UseNativeFrame()) canvas->FillRectInt(SK_ColorBLACK, 0, height() - 1, width(), 1); } @@ -497,8 +497,9 @@ gfx::Size BrowserToolbarView::GetPreferredSize() { return gfx::Size(0, normal_background.height()); } - int vertical_spacing = PopupTopSpacing() + (win_util::ShouldUseVistaFrame() ? - kPopupBottomSpacingGlass : kPopupBottomSpacingNonGlass); + int vertical_spacing = PopupTopSpacing() + + (GetWidget()->AsWindow()->UseNativeFrame() ? kPopupBottomSpacingGlass + : kPopupBottomSpacingNonGlass); return gfx::Size(0, location_bar_->GetPreferredSize().height() + vertical_spacing); } @@ -806,7 +807,8 @@ void BrowserToolbarView::ButtonPressed(views::BaseButton* sender) { // static int BrowserToolbarView::PopupTopSpacing() { - return win_util::ShouldUseVistaFrame() ? 0 : kPopupTopSpacingNonGlass; + return GetWidget()->AsWindow()->UseNativeFrame() ? 0 + : kPopupTopSpacingNonGlass; } void BrowserToolbarView::Observe(NotificationType type, diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h index 1712ef4..970b378 100644 --- a/chrome/browser/views/toolbar_view.h +++ b/chrome/browser/views/toolbar_view.h @@ -131,7 +131,7 @@ class BrowserToolbarView : public views::View, }; // Returns the number of pixels above the location bar in non-normal display. - static int PopupTopSpacing(); + int PopupTopSpacing(); // NotificationObserver virtual void Observe(NotificationType type, diff --git a/chrome/views/custom_frame_view.cc b/chrome/views/custom_frame_view.cc new file mode 100644 index 0000000..54303f6 --- /dev/null +++ b/chrome/views/custom_frame_view.cc @@ -0,0 +1,698 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/views/custom_frame_view.h" + +#include "base/win_util.h" +#include "chrome/common/gfx/path.h" +#include "chrome/common/gfx/chrome_canvas.h" +#include "chrome/common/gfx/chrome_font.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/win_util.h" +#include "chrome/views/client_view.h" +#include "chrome/views/window_delegate.h" +#include "grit/theme_resources.h" + +namespace views { + +// An enumeration of bitmap resources used by this window. +enum { + FRAME_PART_BITMAP_FIRST = 0, // Must be first. + + // Window Controls. + FRAME_CLOSE_BUTTON_ICON, + FRAME_CLOSE_BUTTON_ICON_H, + FRAME_CLOSE_BUTTON_ICON_P, + FRAME_CLOSE_BUTTON_ICON_SA, + FRAME_CLOSE_BUTTON_ICON_SA_H, + FRAME_CLOSE_BUTTON_ICON_SA_P, + FRAME_RESTORE_BUTTON_ICON, + FRAME_RESTORE_BUTTON_ICON_H, + FRAME_RESTORE_BUTTON_ICON_P, + FRAME_MAXIMIZE_BUTTON_ICON, + FRAME_MAXIMIZE_BUTTON_ICON_H, + FRAME_MAXIMIZE_BUTTON_ICON_P, + FRAME_MINIMIZE_BUTTON_ICON, + FRAME_MINIMIZE_BUTTON_ICON_H, + FRAME_MINIMIZE_BUTTON_ICON_P, + + // Window Frame Border. + FRAME_BOTTOM_EDGE, + FRAME_BOTTOM_LEFT_CORNER, + FRAME_BOTTOM_RIGHT_CORNER, + FRAME_LEFT_EDGE, + FRAME_RIGHT_EDGE, + FRAME_TOP_EDGE, + FRAME_TOP_LEFT_CORNER, + FRAME_TOP_RIGHT_CORNER, + + // Client Edge Border. + FRAME_CLIENT_EDGE_TOP_LEFT, + FRAME_CLIENT_EDGE_TOP, + FRAME_CLIENT_EDGE_TOP_RIGHT, + FRAME_CLIENT_EDGE_RIGHT, + FRAME_CLIENT_EDGE_BOTTOM_RIGHT, + FRAME_CLIENT_EDGE_BOTTOM, + FRAME_CLIENT_EDGE_BOTTOM_LEFT, + FRAME_CLIENT_EDGE_LEFT, + + FRAME_PART_BITMAP_COUNT // Must be last. +}; + +class ActiveWindowResources : public WindowResources { + public: + ActiveWindowResources() { + InitClass(); + } + virtual ~ActiveWindowResources() { + } + + // WindowResources implementation: + virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + 0, + IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, + IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, + IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, + IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, + IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, + 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_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, + IDR_CONTENT_RIGHT_SIDE, IDR_CONTENT_BOTTOM_RIGHT_CORNER, + IDR_CONTENT_BOTTOM_CENTER, IDR_CONTENT_BOTTOM_LEFT_CORNER, + IDR_CONTENT_LEFT_SIDE, + 0 + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) { + int id = kFramePartBitmapIds[i]; + if (id != 0) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(id); + } + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + static ChromeFont title_font_; + + DISALLOW_EVIL_CONSTRUCTORS(ActiveWindowResources); +}; + +class InactiveWindowResources : public WindowResources { + public: + InactiveWindowResources() { + InitClass(); + } + virtual ~InactiveWindowResources() { + } + + // WindowResources implementation: + virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const { + return standard_frame_bitmaps_[part]; + } + + private: + static void InitClass() { + static bool initialized = false; + if (!initialized) { + static const int kFramePartBitmapIds[] = { + 0, + IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, + IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, + IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, + IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, + IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, + 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, + IDR_CONTENT_RIGHT_SIDE, IDR_CONTENT_BOTTOM_RIGHT_CORNER, + IDR_CONTENT_BOTTOM_CENTER, IDR_CONTENT_BOTTOM_LEFT_CORNER, + IDR_CONTENT_LEFT_SIDE, + 0 + }; + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) { + int id = kFramePartBitmapIds[i]; + if (id != 0) + standard_frame_bitmaps_[i] = rb.GetBitmapNamed(id); + } + initialized = true; + } + } + + static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; + + DISALLOW_EVIL_CONSTRUCTORS(InactiveWindowResources); +}; + +// static +SkBitmap* ActiveWindowResources::standard_frame_bitmaps_[]; +SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[]; + +// static +WindowResources* CustomFrameView::active_resources_ = NULL; +WindowResources* CustomFrameView::inactive_resources_ = NULL; +ChromeFont CustomFrameView::title_font_; + +namespace { +// The frame border is only visible in restored mode and is hardcoded to 4 px on +// each side regardless of the system window border size. +const int kFrameBorderThickness = 4; +// Various edges of the frame border have a 1 px shadow along their edges; in a +// few cases we shift elements based on this amount for visual appeal. +const int kFrameShadowThickness = 1; +// While resize areas on Windows are normally the same size as the window +// borders, our top area is shrunk by 1 px to make it easier to move the window +// around with our thinner top grabbable strip. (Incidentally, our side and +// bottom resize areas don't match the frame border thickness either -- they +// span the whole nonclient area, so there's no "dead zone" for the mouse.) +const int kTopResizeAdjust = 1; +// In the window corners, the resize areas don't actually expand bigger, but the +// 16 px at the end of each edge triggers diagonal resizing. +const int kResizeAreaCornerSize = 16; +// The titlebar never shrinks to less than 18 px tall, plus the height of the +// frame border and any bottom edge. +const int kTitlebarMinimumHeight = 18; +// The icon is inset 2 px from the left frame border. +const int kIconLeftSpacing = 2; +// The icon takes up 16/25th of the available titlebar height. (This is +// expressed as two ints to avoid precision losses leading to off-by-one pixel +// errors.) +const int kIconHeightFractionNumerator = 16; +const int kIconHeightFractionDenominator = 25; +// The icon never shrinks below 16 px on a side. +const int kIconMinimumSize = 16; +// Because our frame border has a different "3D look" than Windows', with a less +// cluttered top edge, we need to shift the icon up by 1 px in restored mode so +// it looks more centered. +const int kIconRestoredAdjust = 1; +// There is a 4 px gap between the icon and the title text. +const int kIconTitleSpacing = 4; +// The title text starts 2 px below the bottom of the top frame border. +const int kTitleTopSpacing = 2; +// There is a 5 px gap between the title text and the caption buttons. +const int kTitleCaptionSpacing = 5; +// The caption buttons are always drawn 1 px down from the visible top of the +// window (the true top in restored mode, or the top of the screen in maximized +// mode). +const int kCaptionTopSpacing = 1; +} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameView, public: + +CustomFrameView::CustomFrameView(Window* frame) + : NonClientFrameView(), + close_button_(new Button), + restore_button_(new Button), + maximize_button_(new Button), + minimize_button_(new Button), + system_menu_button_(new Button), + should_show_minmax_buttons_(false), + frame_(frame) { + InitClass(); + WindowResources* resources = active_resources_; + + // Close button images will be set in LayoutWindowControls(). + close_button_->SetListener(this, -1); + AddChildView(close_button_); + + restore_button_->SetImage(Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON)); + restore_button_->SetImage(Button::BS_HOT, + resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_H)); + restore_button_->SetImage(Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_P)); + restore_button_->SetListener(this, -1); + AddChildView(restore_button_); + + maximize_button_->SetImage(Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON)); + maximize_button_->SetImage(Button::BS_HOT, + resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_H)); + maximize_button_->SetImage(Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_P)); + maximize_button_->SetListener(this, -1); + AddChildView(maximize_button_); + + minimize_button_->SetImage(Button::BS_NORMAL, + resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON)); + minimize_button_->SetImage(Button::BS_HOT, + resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_H)); + minimize_button_->SetImage(Button::BS_PUSHED, + resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_P)); + minimize_button_->SetListener(this, -1); + AddChildView(minimize_button_); + + should_show_minmax_buttons_ = frame_->window_delegate()->CanMaximize(); + + AddChildView(system_menu_button_); +} + +CustomFrameView::~CustomFrameView() { +} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameView, NonClientFrameView implementation: + +gfx::Rect CustomFrameView::GetBoundsForClientView() const { + return client_view_bounds_; +} + +gfx::Rect CustomFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), + std::max(0, client_bounds.y() - top_height), + client_bounds.width() + (2 * border_thickness), + client_bounds.height() + top_height + border_thickness); +} + +gfx::Point CustomFrameView::GetSystemMenuPoint() const { + gfx::Point system_menu_point(FrameBorderThickness(), + NonClientTopBorderHeight() - BottomEdgeThicknessWithinNonClientHeight()); + ConvertPointToScreen(this, &system_menu_point); + return system_menu_point; +} + +int CustomFrameView::NonClientHitTest(const gfx::Point& point) { + // Then see if the point is within any of the window controls. + if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) + return HTCLOSE; + if (restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTMAXBUTTON; + if (maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTMAXBUTTON; + if (minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTMINBUTTON; + if (system_menu_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( + point)) + return HTSYSMENU; + + int window_component = GetHTComponentForFrame(point, FrameBorderThickness(), + NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, + frame_->window_delegate()->CanResize()); + // Fall back to the caption if no other component matches. + return (window_component == HTNOWHERE) ? HTCAPTION : window_component; +} + +void CustomFrameView::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { + DCHECK(window_mask); + + // Redefine the window visible region for the new size. + window_mask->moveTo(0, 3); + window_mask->lineTo(1, 2); + window_mask->lineTo(1, 1); + window_mask->lineTo(2, 1); + window_mask->lineTo(3, 0); + + window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); + window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); + window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); + window_mask->lineTo(SkIntToScalar(size.width()), 3); + + window_mask->lineTo(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + window_mask->lineTo(0, SkIntToScalar(size.height())); + window_mask->close(); +} + +void CustomFrameView::EnableClose(bool enable) { + close_button_->SetEnabled(enable); +} + +void CustomFrameView::ResetWindowControls() { + restore_button_->SetState(Button::BS_NORMAL); + minimize_button_->SetState(Button::BS_NORMAL); + maximize_button_->SetState(Button::BS_NORMAL); + // The close button isn't affected by this constraint. +} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameView, View overrides: + +void CustomFrameView::Paint(ChromeCanvas* canvas) { + if (frame_->IsMaximized()) + PaintMaximizedFrameBorder(canvas); + else + PaintRestoredFrameBorder(canvas); + PaintTitleBar(canvas); + if (!frame_->IsMaximized()) + PaintRestoredClientEdge(canvas); +} + +void CustomFrameView::Layout() { + LayoutWindowControls(); + LayoutTitleBar(); + LayoutClientView(); +} + +gfx::Size CustomFrameView::GetPreferredSize() { + gfx::Size pref = frame_->client_view()->GetPreferredSize(); + DCHECK(pref.width() > 0 && pref.height() > 0); + gfx::Rect bounds(0, 0, pref.width(), pref.height()); + return frame_->GetWindowBoundsForClientBounds(bounds).size(); +} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameView, BaseButton::ButtonListener implementation: + +void CustomFrameView::ButtonPressed(BaseButton* sender) { + if (sender == close_button_) + frame_->ExecuteSystemMenuCommand(SC_CLOSE); + else if (sender == minimize_button_) + frame_->ExecuteSystemMenuCommand(SC_MINIMIZE); + else if (sender == maximize_button_) + frame_->ExecuteSystemMenuCommand(SC_MAXIMIZE); + else if (sender == restore_button_) + frame_->ExecuteSystemMenuCommand(SC_RESTORE); +} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameView, private: + +int CustomFrameView::FrameBorderThickness() const { + return frame_->IsMaximized() ? + GetSystemMetrics(SM_CXSIZEFRAME) : kFrameBorderThickness; +} + +int CustomFrameView::NonClientBorderThickness() const { + // In maximized mode, we don't show a client edge. + return FrameBorderThickness() + + (frame_->IsMaximized() ? 0 : kClientEdgeThickness); +} + +int CustomFrameView::NonClientTopBorderHeight() const { + int title_top_spacing, title_thickness; + return TitleCoordinates(&title_top_spacing, &title_thickness); +} + +int CustomFrameView::BottomEdgeThicknessWithinNonClientHeight() const { + return kFrameShadowThickness + + (frame_->IsMaximized() ? 0 : kClientEdgeThickness); +} + +int CustomFrameView::TitleCoordinates(int* title_top_spacing, + int* title_thickness) const { + int frame_thickness = FrameBorderThickness(); + int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; + *title_top_spacing = frame_thickness + kTitleTopSpacing; + // The bottom spacing should be the same apparent height as the top spacing. + // Because the actual top spacing height varies based on the system border + // thickness, we calculate this based on the restored top spacing and then + // adjust for maximized mode. We also don't include the frame shadow here, + // since while it's part of the bottom spacing it will be added in at the end. + int title_bottom_spacing = + kFrameBorderThickness + kTitleTopSpacing - kFrameShadowThickness; + if (frame_->IsMaximized()) { + // When we maximize, the top border appears to be chopped off; shift the + // title down to stay centered within the remaining space. + int title_adjust = (kFrameBorderThickness / 2); + *title_top_spacing += title_adjust; + title_bottom_spacing -= title_adjust; + } + *title_thickness = std::max(title_font_.height(), + min_titlebar_height - *title_top_spacing - title_bottom_spacing); + return *title_top_spacing + *title_thickness + title_bottom_spacing + + BottomEdgeThicknessWithinNonClientHeight(); +} + +void CustomFrameView::PaintRestoredFrameBorder(ChromeCanvas* canvas) { + SkBitmap* top_left_corner = resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER); + SkBitmap* top_right_corner = + resources()->GetPartBitmap(FRAME_TOP_RIGHT_CORNER); + SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); + SkBitmap* right_edge = resources()->GetPartBitmap(FRAME_RIGHT_EDGE); + SkBitmap* left_edge = resources()->GetPartBitmap(FRAME_LEFT_EDGE); + SkBitmap* bottom_left_corner = + resources()->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER); + SkBitmap* bottom_right_corner = + resources()->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER); + SkBitmap* bottom_edge = resources()->GetPartBitmap(FRAME_BOTTOM_EDGE); + + // Top. + canvas->DrawBitmapInt(*top_left_corner, 0, 0); + canvas->TileImageInt(*top_edge, top_left_corner->width(), 0, + width() - top_right_corner->width(), top_edge->height()); + canvas->DrawBitmapInt(*top_right_corner, + width() - top_right_corner->width(), 0); + + // Right. + canvas->TileImageInt(*right_edge, width() - right_edge->width(), + top_right_corner->height(), right_edge->width(), + height() - top_right_corner->height() - + bottom_right_corner->height()); + + // Bottom. + canvas->DrawBitmapInt(*bottom_right_corner, + width() - bottom_right_corner->width(), + height() - bottom_right_corner->height()); + canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(), + height() - bottom_edge->height(), + width() - bottom_left_corner->width() - + bottom_right_corner->width(), + bottom_edge->height()); + canvas->DrawBitmapInt(*bottom_left_corner, 0, + height() - bottom_left_corner->height()); + + // Left. + canvas->TileImageInt(*left_edge, 0, top_left_corner->height(), + left_edge->width(), + height() - top_left_corner->height() - bottom_left_corner->height()); +} + +void CustomFrameView::PaintMaximizedFrameBorder( + ChromeCanvas* canvas) { + SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); + canvas->TileImageInt(*top_edge, 0, FrameBorderThickness(), width(), + top_edge->height()); + + // The bottom of the titlebar actually comes from the top of the Client Edge + // graphic, with the actual client edge clipped off the bottom. + SkBitmap* titlebar_bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); + int edge_height = titlebar_bottom->height() - kClientEdgeThickness; + canvas->TileImageInt(*titlebar_bottom, 0, + frame_->client_view()->y() - edge_height, width(), edge_height); +} + +void CustomFrameView::PaintTitleBar(ChromeCanvas* canvas) { + WindowDelegate* d = frame_->window_delegate(); + + // It seems like in some conditions we can be asked to paint after the window + // that contains us is WM_DESTROYed. At this point, our delegate is NULL. The + // correct long term fix may be to shut down the RootView in WM_DESTROY. + if (!d) + return; + + canvas->DrawStringInt(d->GetWindowTitle(), title_font_, SK_ColorWHITE, + MirroredLeftPointForRect(title_bounds_), title_bounds_.y(), + title_bounds_.width(), title_bounds_.height()); +} + +void CustomFrameView::PaintRestoredClientEdge(ChromeCanvas* canvas) { + gfx::Rect client_area_bounds = frame_->client_view()->bounds(); + int client_area_top = client_area_bounds.y(); + + SkBitmap* top_left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT); + SkBitmap* top = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); + SkBitmap* top_right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT); + SkBitmap* right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT); + SkBitmap* bottom_right = + resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT); + SkBitmap* bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM); + SkBitmap* bottom_left = + resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT); + SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); + + // Top. + // This next calculation is necessary because the top center bitmap is shorter + // than the top left and right bitmaps. We need their top edges to line up, + // and we need the left and right edges to start below the corners' bottoms. + int top_edge_y = client_area_top - top->height(); + client_area_top = top_edge_y + top_left->height(); + canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(), + top_edge_y); + canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y, + client_area_bounds.width(), top->height()); + canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y); + + // Right. + int client_area_bottom = + std::max(client_area_top, client_area_bounds.bottom()); + int client_area_height = client_area_bottom - client_area_top; + canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, + right->width(), client_area_height); + + // Bottom. + canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(), + client_area_bottom); + canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom, + client_area_bounds.width(), bottom_right->height()); + canvas->DrawBitmapInt(*bottom_left, + client_area_bounds.x() - bottom_left->width(), client_area_bottom); + + // Left. + canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), + client_area_top, left->width(), client_area_height); +} + +void CustomFrameView::LayoutWindowControls() { + close_button_->SetImageAlignment(Button::ALIGN_LEFT, Button::ALIGN_BOTTOM); + // Maximized buttons start at window top so that even if their images aren't + // drawn flush with the screen edge, they still obey Fitts' Law. + bool is_maximized = frame_->IsMaximized(); + int frame_thickness = FrameBorderThickness(); + int caption_y = is_maximized ? frame_thickness : kCaptionTopSpacing; + int top_extra_height = is_maximized ? kCaptionTopSpacing : 0; + // There should always be the same number of non-shadow pixels visible to the + // side of the caption buttons. In maximized mode we extend the rightmost + // button to the screen corner to obey Fitts' Law. + int right_extra_width = is_maximized ? + (kFrameBorderThickness - kFrameShadowThickness) : 0; + int right_spacing = is_maximized ? + (GetSystemMetrics(SM_CXSIZEFRAME) + right_extra_width) : frame_thickness; + gfx::Size close_button_size = close_button_->GetPreferredSize(); + close_button_->SetBounds(width() - close_button_size.width() - right_spacing, + caption_y, + close_button_size.width() + right_extra_width, + close_button_size.height() + top_extra_height); + + // When the window is restored, we show a maximized button; otherwise, we show + // a restore button. + bool is_restored = !is_maximized && !frame_->IsMinimized(); + views::Button* invisible_button = is_restored ? + restore_button_ : maximize_button_; + invisible_button->SetVisible(false); + + views::Button* visible_button = is_restored ? + maximize_button_ : restore_button_; + FramePartBitmap normal_part, hot_part, pushed_part; + if (should_show_minmax_buttons_) { + visible_button->SetVisible(true); + visible_button->SetImageAlignment(Button::ALIGN_LEFT, Button::ALIGN_BOTTOM); + gfx::Size visible_button_size = visible_button->GetPreferredSize(); + visible_button->SetBounds(close_button_->x() - visible_button_size.width(), + caption_y, visible_button_size.width(), + visible_button_size.height() + top_extra_height); + + minimize_button_->SetVisible(true); + minimize_button_->SetImageAlignment(Button::ALIGN_LEFT, + Button::ALIGN_BOTTOM); + gfx::Size minimize_button_size = minimize_button_->GetPreferredSize(); + minimize_button_->SetBounds( + visible_button->x() - minimize_button_size.width(), caption_y, + minimize_button_size.width(), + minimize_button_size.height() + top_extra_height); + + normal_part = FRAME_CLOSE_BUTTON_ICON; + hot_part = FRAME_CLOSE_BUTTON_ICON_H; + pushed_part = FRAME_CLOSE_BUTTON_ICON_P; + } else { + visible_button->SetVisible(false); + minimize_button_->SetVisible(false); + + normal_part = FRAME_CLOSE_BUTTON_ICON_SA; + hot_part = FRAME_CLOSE_BUTTON_ICON_SA_H; + pushed_part = FRAME_CLOSE_BUTTON_ICON_SA_P; + } + + close_button_->SetImage(Button::BS_NORMAL, + active_resources_->GetPartBitmap(normal_part)); + close_button_->SetImage(Button::BS_HOT, + active_resources_->GetPartBitmap(hot_part)); + close_button_->SetImage(Button::BS_PUSHED, + active_resources_->GetPartBitmap(pushed_part)); +} + +void CustomFrameView::LayoutTitleBar() { + // Always lay out the icon, even when it's not present, so we can lay out the + // window title based on its position. + int frame_thickness = FrameBorderThickness(); + int icon_x = frame_thickness + kIconLeftSpacing; + + // The usable height of the titlebar area is the total height minus the top + // resize border and any edge area we draw at its bottom. + int title_top_spacing, title_thickness; + int top_height = TitleCoordinates(&title_top_spacing, &title_thickness); + int available_height = top_height - frame_thickness - + BottomEdgeThicknessWithinNonClientHeight(); + + // The icon takes up a constant fraction of the available height, down to a + // minimum size, and is always an even number of pixels on a side (presumably + // to make scaled icons look better). It's centered within the usable height. + int icon_size = std::max((available_height * kIconHeightFractionNumerator / + kIconHeightFractionDenominator) / 2 * 2, kIconMinimumSize); + int icon_y = ((available_height - icon_size) / 2) + frame_thickness; + + // Hack: Our frame border has a different "3D look" than Windows'. Theirs has + // a more complex gradient on the top that they push their icon/title below; + // then the maximized window cuts this off and the icon/title are centered in + // the remaining space. Because the apparent shape of our border is simpler, + // using the same positioning makes things look slightly uncentered with + // restored windows, so we come up to compensate. + if (!frame_->IsMaximized()) + icon_y -= kIconRestoredAdjust; + + views::WindowDelegate* d = frame_->window_delegate(); + if (!d->ShouldShowWindowIcon()) + icon_size = 0; + system_menu_button_->SetBounds(icon_x, icon_y, icon_size, icon_size); + + // Size the title. + int icon_right = icon_x + icon_size; + int title_x = + icon_right + (d->ShouldShowWindowIcon() ? kIconTitleSpacing : 0); + int title_right = (should_show_minmax_buttons_ ? + minimize_button_->x() : close_button_->x()) - kTitleCaptionSpacing; + title_bounds_.SetRect(title_x, + title_top_spacing + ((title_thickness - title_font_.height()) / 2), + std::max(0, title_right - title_x), title_font_.height()); +} + +void CustomFrameView::LayoutClientView() { + int top_height = NonClientTopBorderHeight(); + int border_thickness = NonClientBorderThickness(); + client_view_bounds_.SetRect( + border_thickness, + top_height, + std::max(0, width() - (2 * border_thickness)), + std::max(0, height() - top_height - border_thickness)); +} + +// static +void CustomFrameView::InitClass() { + static bool initialized = false; + if (!initialized) { + active_resources_ = new ActiveWindowResources; + inactive_resources_ = new InactiveWindowResources; + + title_font_ = win_util::GetWindowTitleFont(); + + initialized = true; + } +} + +} // namespace views + diff --git a/chrome/views/custom_frame_view.h b/chrome/views/custom_frame_view.h new file mode 100644 index 0000000..0a34f2d --- /dev/null +++ b/chrome/views/custom_frame_view.h @@ -0,0 +1,123 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_VIEWS_CUSTOM_FRAME_VIEW_H_ +#define CHROME_VIEWS_CUSTOM_FRAME_VIEW_H_ + +#include "chrome/views/button.h" +#include "chrome/views/non_client_view.h" +#include "chrome/views/window.h" +#include "chrome/views/window_resources.h" + +namespace gfx{ +class Size; +class Path; +class Point; +} +class ChromeCanvas; +class ChromeFont; + +namespace views { + +/////////////////////////////////////////////////////////////////////////////// +// +// CustomFrameView +// +// A ChromeView that provides the non client frame for Windows. This means +// rendering the non-standard window caption, border, and controls. +// +//////////////////////////////////////////////////////////////////////////////// +class CustomFrameView : public NonClientFrameView, + public BaseButton::ButtonListener { + public: + explicit CustomFrameView(Window* frame); + virtual ~CustomFrameView(); + + // Overridden from views::NonClientFrameView: + virtual gfx::Rect GetBoundsForClientView() const; + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const; + virtual gfx::Point GetSystemMenuPoint() const; + virtual int NonClientHitTest(const gfx::Point& point); + virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); + virtual void EnableClose(bool enable); + virtual void ResetWindowControls(); + + // View overrides: + virtual void Paint(ChromeCanvas* canvas); + virtual void Layout(); + virtual gfx::Size GetPreferredSize(); + + // BaseButton::ButtonListener implementation: + virtual void ButtonPressed(BaseButton* sender); + + private: + // Returns the thickness of the border that makes up the window frame edges. + // This does not include any client edge. + int FrameBorderThickness() const; + + // Returns the thickness of the entire nonclient left, right, and bottom + // borders, including both the window frame and any client edge. + int NonClientBorderThickness() const; + + // Returns the height of the entire nonclient top border, including the window + // frame, any title area, and any connected client edge. + int NonClientTopBorderHeight() const; + + // A bottom border, and, in restored mode, a client edge are drawn at the + // bottom of the titlebar. This returns the total height drawn. + int BottomEdgeThicknessWithinNonClientHeight() const; + + // Calculates multiple values related to title layout. Returns the height of + // the entire titlebar including any connected client edge. + int TitleCoordinates(int* title_top_spacing, + int* title_thickness) const; + + // Paint various sub-components of this view. + void PaintRestoredFrameBorder(ChromeCanvas* canvas); + void PaintMaximizedFrameBorder(ChromeCanvas* canvas); + void PaintTitleBar(ChromeCanvas* canvas); + void PaintRestoredClientEdge(ChromeCanvas* canvas); + + // Layout various sub-components of this view. + void LayoutWindowControls(); + void LayoutTitleBar(); + void LayoutClientView(); + + // Returns the resource collection to be used when rendering the window. + WindowResources* resources() const { + return frame_->is_active() || paint_as_active() ? active_resources_ + : inactive_resources_; + } + + // The bounds of the client view, in this view's coordinates. + gfx::Rect client_view_bounds_; + + // The layout rect of the title, if visible. + gfx::Rect title_bounds_; + + // Window controls. + Button* close_button_; + Button* restore_button_; + Button* maximize_button_; + Button* minimize_button_; + Button* system_menu_button_; // Uses the window icon if visible. + bool should_show_minmax_buttons_; + + // The window that owns this view. + Window* frame_; + + // Initialize various static resources. + static void InitClass(); + static WindowResources* active_resources_; + static WindowResources* inactive_resources_; + static ChromeFont title_font_; + + DISALLOW_EVIL_CONSTRUCTORS(CustomFrameView); +}; + +} // namespace views + +#endif // #ifndef CHROME_VIEWS_CUSTOM_FRAME_VIEW_H_ + diff --git a/chrome/views/custom_frame_window.cc b/chrome/views/custom_frame_window.cc deleted file mode 100644 index 0ae6158..0000000 --- a/chrome/views/custom_frame_window.cc +++ /dev/null @@ -1,506 +0,0 @@ -// 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/views/custom_frame_window.h" - -#include "base/gfx/point.h" -#include "base/gfx/size.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/gfx/path.h" -#include "chrome/common/l10n_util.h" -#include "chrome/common/win_util.h" -#include "chrome/views/client_view.h" -#include "chrome/views/default_non_client_view.h" -#include "chrome/views/root_view.h" -#include "chrome/views/window_delegate.h" -#include "grit/generated_resources.h" - -namespace views { - -// A scoping class that prevents a window from being able to redraw in response -// to invalidations that may occur within it for the lifetime of the object. -// -// Why would we want such a thing? Well, it turns out Windows has some -// "unorthodox" behavior when it comes to painting its non-client areas. -// Occasionally, Windows will paint portions of the default non-client area -// right over the top of the custom frame. This is not simply fixed by handling -// WM_NCPAINT/WM_PAINT, with some investigation it turns out that this -// rendering is being done *inside* the default implementation of some message -// handlers and functions: -// . WM_SETTEXT -// . WM_SETICON -// . WM_NCLBUTTONDOWN -// . EnableMenuItem, called from our WM_INITMENU handler -// The solution is to handle these messages and call DefWindowProc ourselves, -// but prevent the window from being able to update itself for the duration of -// the call. We do this with this class, which automatically calls its -// associated CustomFrameWindow's lock and unlock functions as it is created -// and destroyed. See documentation in those methods for the technique used. -// -// IMPORTANT: Do not use this scoping object for large scopes or periods of -// time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh). -// -// I would love to hear Raymond Chen's explanation for all this. And maybe a -// list of other messages that this applies to ;-) -class CustomFrameWindow::ScopedRedrawLock { - public: - explicit ScopedRedrawLock(CustomFrameWindow* window) : window_(window) { - window_->LockUpdates(); - } - - ~ScopedRedrawLock() { - window_->UnlockUpdates(); - } - - private: - // The window having its style changed. - CustomFrameWindow* window_; -}; - -HCURSOR CustomFrameWindow::resize_cursors_[6]; - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameWindow, public: - -CustomFrameWindow::CustomFrameWindow(WindowDelegate* window_delegate) - : Window(window_delegate), - is_active_(false), - lock_updates_(false), - saved_window_style_(0) { - InitClass(); - non_client_view_ = new DefaultNonClientView(this); -} - -CustomFrameWindow::CustomFrameWindow(WindowDelegate* window_delegate, - NonClientView* non_client_view) - : Window(window_delegate) { - InitClass(); - non_client_view_ = non_client_view; -} - -CustomFrameWindow::~CustomFrameWindow() { -} - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameWindow, Window overrides: - -void CustomFrameWindow::Init(HWND parent, const gfx::Rect& bounds) { - // TODO(beng): (Cleanup) Right now, the only way to specify a different - // non-client view is to subclass this object and provide one - // by setting this member before calling Init. - if (!non_client_view_) - non_client_view_ = new DefaultNonClientView(this); - Window::Init(parent, bounds); - - ResetWindowRegion(); -} - -void CustomFrameWindow::UpdateWindowTitle() { - // Layout winds up causing the title to be re-validated during - // string measurement. - non_client_view_->Layout(); - // Must call the base class too so that places like the Task Bar get updated. - Window::UpdateWindowTitle(); -} - -void CustomFrameWindow::UpdateWindowIcon() { - // The icon will be re-validated during painting. - non_client_view_->SchedulePaint(); - // Call the base class so that places like the Task Bar get updated. - Window::UpdateWindowIcon(); -} - -void CustomFrameWindow::EnableClose(bool enable) { - non_client_view_->EnableClose(enable); - // Make sure the SysMenu changes to reflect this change as well. - Window::EnableClose(enable); -} - -void CustomFrameWindow::DisableInactiveRendering(bool disable) { - Window::DisableInactiveRendering(disable); - non_client_view_->set_paint_as_active(disable); - if (!disable) - non_client_view_->SchedulePaint(); -} - -void CustomFrameWindow::SizeWindowToDefault() { - gfx::Size pref = client_view()->GetPreferredSize(); - DCHECK(pref.width() > 0 && pref.height() > 0); - gfx::Size window_size = - non_client_view_->CalculateWindowSizeForClientSize(pref.width(), - pref.height()); - win_util::CenterAndSizeWindow(owning_window(), GetHWND(), - window_size.ToSIZE(), false); -} - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameWindow, WidgetWin overrides: - -static void EnableMenuItem(HMENU menu, UINT command, bool enabled) { - UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED); - EnableMenuItem(menu, command, flags); -} - -void CustomFrameWindow::OnInitMenu(HMENU menu) { - bool is_minimized = IsMinimized(); - bool is_maximized = IsMaximized(); - bool is_restored = !is_minimized && !is_maximized; - - ScopedRedrawLock lock(this); - EnableMenuItem(menu, SC_RESTORE, !is_restored); - EnableMenuItem(menu, SC_MOVE, is_restored); - EnableMenuItem(menu, SC_SIZE, window_delegate()->CanResize() && is_restored); - EnableMenuItem(menu, SC_MAXIMIZE, - window_delegate()->CanMaximize() && !is_maximized); - EnableMenuItem(menu, SC_MINIMIZE, - window_delegate()->CanMaximize() && !is_minimized); -} - -void CustomFrameWindow::OnMouseLeave() { - bool process_mouse_exited = true; - POINT pt; - if (GetCursorPos(&pt)) { - LRESULT ht_component = - ::SendMessage(GetHWND(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y)); - if (ht_component != HTNOWHERE) { - // If the mouse moved into a part of the window's non-client area, then - // don't send a mouse exited event since the mouse is still within the - // bounds of the ChromeView that's rendering the frame. Note that we do - // _NOT_ do this for windows with native frames, since in that case the - // mouse really will have left the bounds of the RootView. - process_mouse_exited = false; - } - } - - if (process_mouse_exited) - ProcessMouseExited(); -} - -LRESULT CustomFrameWindow::OnNCActivate(BOOL active) { - is_active_ = !!active; - - // We can get WM_NCACTIVATE before we're actually visible. If we're not - // visible, no need to paint. - if (IsWindowVisible(GetHWND())) { - non_client_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()); - } - - // Defering to our parent as it is important that the NCActivate message gets - // DefProc'ed or the task bar won't show our process as active. - // See bug http://crbug.com/4513. - return Window::OnNCActivate(active); -} - -LRESULT CustomFrameWindow::OnNCCalcSize(BOOL mode, LPARAM l_param) { - // We need to repaint all when the window bounds change. - return WVR_REDRAW; -} - -LRESULT CustomFrameWindow::OnNCHitTest(const CPoint& point) { - // NC points are in screen coordinates. - CPoint temp = point; - MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1); - return non_client_view_->NonClientHitTest(gfx::Point(temp.x, temp.y)); -} - -struct ClipState { - // The window being painted. - HWND parent; - - // DC painting to. - HDC dc; - - // Origin of the window in terms of the screen. - int x; - int y; -}; - -// See comments in OnNCPaint for details of this function. -static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) { - ClipState* clip_state = reinterpret_cast(param); - if (GetParent(window) == clip_state->parent && IsWindowVisible(window)) { - RECT bounds; - GetWindowRect(window, &bounds); - ExcludeClipRect(clip_state->dc, - bounds.left - clip_state->x, - bounds.top - clip_state->y, - bounds.right - clip_state->x, - bounds.bottom - clip_state->y); - } - return TRUE; -} - -void CustomFrameWindow::OnNCPaint(HRGN rgn) { - // We have an NC region and need to paint it. We expand the NC region to - // include the dirty region of the root view. This is done to minimize - // paints. - CRect window_rect; - GetWindowRect(&window_rect); - - if (window_rect.Width() != root_view_->width() || - window_rect.Height() != root_view_->height()) { - // If the size of the window differs from the size of the root view it - // means we're being asked to paint before we've gotten a WM_SIZE. This can - // happen when the user is interactively resizing the window. To avoid - // mass flickering we don't do anything here. Once we get the WM_SIZE we'll - // reset the region of the window which triggers another WM_NCPAINT and - // all is well. - return; - } - - CRect dirty_region; - // A value of 1 indicates paint all. - if (!rgn || rgn == reinterpret_cast(1)) { - dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height()); - } else { - RECT rgn_bounding_box; - GetRgnBox(rgn, &rgn_bounding_box); - if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect)) - return; // Dirty region doesn't intersect window bounds, bale. - - // rgn_bounding_box is in screen coordinates. Map it to window coordinates. - OffsetRect(&dirty_region, -window_rect.left, -window_rect.top); - } - - // In theory GetDCEx should do what we want, but I couldn't get it to work. - // In particular the docs mentiond DCX_CLIPCHILDREN, but as far as I can tell - // it doesn't work at all. So, instead we get the DC for the window then - // manually clip out the children. - HDC dc = GetWindowDC(GetHWND()); - ClipState clip_state; - clip_state.x = window_rect.left; - clip_state.y = window_rect.top; - clip_state.parent = GetHWND(); - clip_state.dc = dc; - EnumChildWindows(GetHWND(), &ClipDCToChild, - reinterpret_cast(&clip_state)); - - RootView* root_view = GetRootView(); - CRect old_paint_region = root_view->GetScheduledPaintRectConstrainedToSize(); - - if (!old_paint_region.IsRectEmpty()) { - // The root view has a region that needs to be painted. Include it in the - // region we're going to paint. - - CRect tmp = dirty_region; - UnionRect(&dirty_region, &tmp, &old_paint_region); - } - - root_view->SchedulePaint(gfx::Rect(dirty_region), false); - - // ChromeCanvasPaints destructor does the actual painting. As such, wrap the - // following in a block to force paint to occur so that we can release the dc. - { - ChromeCanvasPaint canvas(dc, opaque(), dirty_region.left, dirty_region.top, - dirty_region.Width(), dirty_region.Height()); - - root_view->ProcessPaint(&canvas); - } - - ReleaseDC(GetHWND(), dc); -} - -void CustomFrameWindow::OnNCLButtonDown(UINT ht_component, - const CPoint& point) { - switch (ht_component) { - case HTCLOSE: - case HTMINBUTTON: - case HTMAXBUTTON: { - // When the mouse is pressed down in these specific non-client areas, we - // need to tell the RootView to send the mouse pressed event (which sets - // capture, allowing subsequent WM_LBUTTONUP (note, _not_ WM_NCLBUTTONUP) - // to fire so that the appropriate WM_SYSCOMMAND can be sent by the - // applicable button's ButtonListener. We _have_ to do this this way - // rather than letting Windows just send the syscommand itself (as would - // happen if we never did this dance) because for some insane reason - // DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed window - // control button appearance, in the Windows classic style, over our - // view! Ick! By handling this message we prevent Windows from doing this - // undesirable thing, but that means we need to roll the sys-command - // handling ourselves. - ProcessNCMousePress(point, MK_LBUTTON); - return; - } - default: - Window::OnNCLButtonDown(ht_component, point); - /* - if (!IsMsgHandled()) { - // Window::OnNCLButtonDown set the message as unhandled. This normally - // means WidgetWin::ProcessWindowMessage will pass it to - // DefWindowProc. Sadly, DefWindowProc for WM_NCLBUTTONDOWN does weird - // non-client painting, so we need to call it directly here inside a - // scoped update lock. - ScopedRedrawLock lock(this); - DefWindowProc(GetHWND(), WM_NCLBUTTONDOWN, ht_component, - MAKELPARAM(point.x, point.y)); - SetMsgHandled(TRUE); - } - */ - break; - } -} - -LRESULT CustomFrameWindow::OnNCUAHDrawCaption(UINT msg, WPARAM w_param, - LPARAM l_param) { - // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for - // an explanation about why we need to handle this message. - SetMsgHandled(TRUE); - return 0; -} - -LRESULT CustomFrameWindow::OnNCUAHDrawFrame(UINT msg, WPARAM w_param, - LPARAM l_param) { - // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for - // an explanation about why we need to handle this message. - SetMsgHandled(TRUE); - return 0; -} - -LRESULT CustomFrameWindow::OnSetCursor(HWND window, UINT hittest_code, - UINT message) { - int index = RC_NORMAL; - switch (hittest_code) { - case HTTOP: - case HTBOTTOM: - index = RC_VERTICAL; - break; - case HTTOPLEFT: - case HTBOTTOMRIGHT: - index = RC_NWSE; - break; - case HTTOPRIGHT: - case HTBOTTOMLEFT: - index = RC_NESW; - break; - case HTLEFT: - case HTRIGHT: - index = RC_HORIZONTAL; - break; - case HTCAPTION: - case HTCLIENT: - index = RC_NORMAL; - break; - } - SetCursor(resize_cursors_[index]); - return 0; -} - -LRESULT CustomFrameWindow::OnSetIcon(UINT size_type, HICON new_icon) { - ScopedRedrawLock lock(this); - return DefWindowProc(GetHWND(), WM_SETICON, size_type, - reinterpret_cast(new_icon)); -} - -LRESULT CustomFrameWindow::OnSetText(const wchar_t* text) { - ScopedRedrawLock lock(this); - return DefWindowProc(GetHWND(), WM_SETTEXT, NULL, - reinterpret_cast(text)); -} - -void CustomFrameWindow::OnSize(UINT param, const CSize& size) { - Window::OnSize(param, size); - - // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've - // invoked OnSize we ensure the RootView has been layed out. - ResetWindowRegion(); -} - -void CustomFrameWindow::OnSysCommand(UINT notification_code, CPoint click) { - // Windows uses the 4 lower order bits of |notification_code| for type- - // specific information so we must exclude this when comparing. - static const int sc_mask = 0xFFF0; - if ((notification_code & sc_mask) == SC_MINIMIZE || - (notification_code & sc_mask) == SC_MAXIMIZE || - (notification_code & sc_mask) == SC_RESTORE) { - non_client_view_->ResetWindowControls(); - } else if ((notification_code & sc_mask) == SC_MOVE || - (notification_code & sc_mask) == SC_SIZE) { - if (lock_updates_) { - // We were locked, before entering a resize or move modal loop. Now that - // we've begun to move the window, we need to unlock updates so that the - // sizing/moving feedback can be continuous. - UnlockUpdates(); - } - } - Window::OnSysCommand(notification_code, click); -} - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameWindow, private: - -// static -void CustomFrameWindow::InitClass() { - static bool initialized = false; - if (!initialized) { - resize_cursors_[RC_NORMAL] = LoadCursor(NULL, IDC_ARROW); - resize_cursors_[RC_VERTICAL] = LoadCursor(NULL, IDC_SIZENS); - resize_cursors_[RC_HORIZONTAL] = LoadCursor(NULL, IDC_SIZEWE); - resize_cursors_[RC_NESW] = LoadCursor(NULL, IDC_SIZENESW); - resize_cursors_[RC_NWSE] = LoadCursor(NULL, IDC_SIZENWSE); - initialized = true; - } -} - -void CustomFrameWindow::LockUpdates() { - lock_updates_ = true; - saved_window_style_ = GetWindowLong(GetHWND(), GWL_STYLE); - SetWindowLong(GetHWND(), GWL_STYLE, saved_window_style_ & ~WS_VISIBLE); -} - -void CustomFrameWindow::UnlockUpdates() { - SetWindowLong(GetHWND(), GWL_STYLE, saved_window_style_); - lock_updates_ = false; -} - -void CustomFrameWindow::ResetWindowRegion() { - // Changing the window region is going to force a paint. Only change the - // window region if the region really differs. - HRGN current_rgn = CreateRectRgn(0, 0, 0, 0); - int current_rgn_result = GetWindowRgn(GetHWND(), current_rgn); - - CRect window_rect; - GetWindowRect(&window_rect); - HRGN new_region; - if (IsMaximized()) { - HMONITOR monitor = MonitorFromWindow(GetHWND(), MONITOR_DEFAULTTONEAREST); - MONITORINFO mi; - mi.cbSize = sizeof mi; - GetMonitorInfo(monitor, &mi); - CRect work_rect = mi.rcWork; - work_rect.OffsetRect(-window_rect.left, -window_rect.top); - new_region = CreateRectRgnIndirect(&work_rect); - } else { - gfx::Path window_mask; - non_client_view_->GetWindowMask(gfx::Size(window_rect.Width(), - window_rect.Height()), - &window_mask); - new_region = window_mask.CreateHRGN(); - } - - if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) { - // SetWindowRgn takes ownership of the HRGN created by CreateHRGN. - SetWindowRgn(new_region, TRUE); - } else { - DeleteObject(new_region); - } - - DeleteObject(current_rgn); -} - -void CustomFrameWindow::ProcessNCMousePress(const CPoint& point, int flags) { - CPoint temp = point; - MapWindowPoints(HWND_DESKTOP, GetHWND(), &temp, 1); - UINT message_flags = 0; - if ((GetKeyState(VK_CONTROL) & 0x80) == 0x80) - message_flags |= MK_CONTROL; - if ((GetKeyState(VK_SHIFT) & 0x80) == 0x80) - message_flags |= MK_SHIFT; - message_flags |= flags; - ProcessMousePressed(temp, message_flags, false, false); -} - -} // namespace views diff --git a/chrome/views/custom_frame_window.h b/chrome/views/custom_frame_window.h deleted file mode 100644 index f5b6334..0000000 --- a/chrome/views/custom_frame_window.h +++ /dev/null @@ -1,103 +0,0 @@ -// 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_VIEWS_CUSTOM_FRAME_WINDOW_H__ -#define CHROME_VIEWS_CUSTOM_FRAME_WINDOW_H__ - -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/views/window.h" -#include "chrome/views/window_delegate.h" - -namespace views { - -class NonClientView; - -//////////////////////////////////////////////////////////////////////////////// -// -// CustomFrameWindow -// -// A CustomFrameWindow is a Window subclass that implements the Chrome-style -// window frame used on Windows XP and Vista without DWM Composition. -// See documentation in window.h for more information about the capabilities -// of this window type. -// -//////////////////////////////////////////////////////////////////////////////// -class CustomFrameWindow : public Window { - public: - explicit CustomFrameWindow(WindowDelegate* window_delegate); - CustomFrameWindow(WindowDelegate* window_delegate, - NonClientView* non_client_view); - virtual ~CustomFrameWindow(); - - // Returns whether or not the frame is active. - bool is_active() const { return is_active_; } - - // Overridden from Window: - virtual void Init(HWND parent, const gfx::Rect& bounds); - virtual void UpdateWindowTitle(); - virtual void UpdateWindowIcon(); - - protected: - // Overridden from Window: - virtual void SizeWindowToDefault(); - virtual void EnableClose(bool enable); - virtual void DisableInactiveRendering(bool disable); - - // Overridden from WidgetWin: - virtual void OnInitMenu(HMENU menu); - virtual void OnMouseLeave(); - virtual LRESULT OnNCActivate(BOOL active); - virtual LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param); - virtual LRESULT OnNCHitTest(const CPoint& point); - virtual void OnNCPaint(HRGN rgn); - virtual void OnNCLButtonDown(UINT ht_component, const CPoint& point); - virtual LRESULT OnNCUAHDrawCaption(UINT msg, WPARAM w_param, LPARAM l_param); - virtual LRESULT OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param); - virtual LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT message); - virtual LRESULT OnSetIcon(UINT size_type, HICON new_icon); - virtual LRESULT OnSetText(const wchar_t* text); - virtual void OnSize(UINT param, const CSize& size); - virtual void OnSysCommand(UINT notification_code, CPoint click); - - private: - class ScopedRedrawLock; - - // Lock or unlock the window from being able to redraw itself in response to - // updates to its invalid region. - void LockUpdates(); - void UnlockUpdates(); - - // Resets the window region. - void ResetWindowRegion(); - - // Converts a non-client mouse down message to a regular ChromeViews event - // and handle it. |point| is the mouse position of the message in screen - // coords. |flags| are flags that would be passed with a WM_L/M/RBUTTON* - // message and relate to things like which button was pressed. These are - // combined with flags relating to the current key state. - void ProcessNCMousePress(const CPoint& point, int flags); - - // True if this window is the active top level window. - bool is_active_; - - // True if updates to this window are currently locked. - bool lock_updates_; - - // The window styles of the window before updates were locked. - DWORD saved_window_style_; - - // Static resource initialization. - static void InitClass(); - enum ResizeCursor { - RC_NORMAL = 0, RC_VERTICAL, RC_HORIZONTAL, RC_NESW, RC_NWSE - }; - static HCURSOR resize_cursors_[6]; - - DISALLOW_EVIL_CONSTRUCTORS(CustomFrameWindow); -}; - -} // namespace views - -#endif // CHROME_VIEWS_CUSTOM_FRAME_WINDOW_H__ - diff --git a/chrome/views/default_non_client_view.cc b/chrome/views/default_non_client_view.cc deleted file mode 100644 index e3998a5..0000000 --- a/chrome/views/default_non_client_view.cc +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/views/default_non_client_view.h" - -#include "base/win_util.h" -#include "chrome/common/gfx/path.h" -#include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/gfx/chrome_font.h" -#include "chrome/common/resource_bundle.h" -#include "chrome/common/win_util.h" -#include "chrome/views/client_view.h" -#include "grit/theme_resources.h" - -namespace views { - -// An enumeration of bitmap resources used by this window. -enum { - FRAME_PART_BITMAP_FIRST = 0, // Must be first. - - // Window Controls. - FRAME_CLOSE_BUTTON_ICON, - FRAME_CLOSE_BUTTON_ICON_H, - FRAME_CLOSE_BUTTON_ICON_P, - FRAME_CLOSE_BUTTON_ICON_SA, - FRAME_CLOSE_BUTTON_ICON_SA_H, - FRAME_CLOSE_BUTTON_ICON_SA_P, - FRAME_RESTORE_BUTTON_ICON, - FRAME_RESTORE_BUTTON_ICON_H, - FRAME_RESTORE_BUTTON_ICON_P, - FRAME_MAXIMIZE_BUTTON_ICON, - FRAME_MAXIMIZE_BUTTON_ICON_H, - FRAME_MAXIMIZE_BUTTON_ICON_P, - FRAME_MINIMIZE_BUTTON_ICON, - FRAME_MINIMIZE_BUTTON_ICON_H, - FRAME_MINIMIZE_BUTTON_ICON_P, - - // Window Frame Border. - FRAME_BOTTOM_EDGE, - FRAME_BOTTOM_LEFT_CORNER, - FRAME_BOTTOM_RIGHT_CORNER, - FRAME_LEFT_EDGE, - FRAME_RIGHT_EDGE, - FRAME_TOP_EDGE, - FRAME_TOP_LEFT_CORNER, - FRAME_TOP_RIGHT_CORNER, - - // Client Edge Border. - FRAME_CLIENT_EDGE_TOP_LEFT, - FRAME_CLIENT_EDGE_TOP, - FRAME_CLIENT_EDGE_TOP_RIGHT, - FRAME_CLIENT_EDGE_RIGHT, - FRAME_CLIENT_EDGE_BOTTOM_RIGHT, - FRAME_CLIENT_EDGE_BOTTOM, - FRAME_CLIENT_EDGE_BOTTOM_LEFT, - FRAME_CLIENT_EDGE_LEFT, - - FRAME_PART_BITMAP_COUNT // Must be last. -}; - -class ActiveWindowResources : public WindowResources { - public: - ActiveWindowResources() { - InitClass(); - } - virtual ~ActiveWindowResources() { - } - - // WindowResources implementation: - virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - 0, - IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, - IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, - IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, - IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, - IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, - 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_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT, - IDR_CONTENT_RIGHT_SIDE, IDR_CONTENT_BOTTOM_RIGHT_CORNER, - IDR_CONTENT_BOTTOM_CENTER, IDR_CONTENT_BOTTOM_LEFT_CORNER, - IDR_CONTENT_LEFT_SIDE, - 0 - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) { - int id = kFramePartBitmapIds[i]; - if (id != 0) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(id); - } - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - static ChromeFont title_font_; - - DISALLOW_EVIL_CONSTRUCTORS(ActiveWindowResources); -}; - -class InactiveWindowResources : public WindowResources { - public: - InactiveWindowResources() { - InitClass(); - } - virtual ~InactiveWindowResources() { - } - - // WindowResources implementation: - virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const { - return standard_frame_bitmaps_[part]; - } - - private: - static void InitClass() { - static bool initialized = false; - if (!initialized) { - static const int kFramePartBitmapIds[] = { - 0, - IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P, - IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, - IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P, - IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P, - IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P, - 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, - IDR_CONTENT_RIGHT_SIDE, IDR_CONTENT_BOTTOM_RIGHT_CORNER, - IDR_CONTENT_BOTTOM_CENTER, IDR_CONTENT_BOTTOM_LEFT_CORNER, - IDR_CONTENT_LEFT_SIDE, - 0 - }; - - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) { - int id = kFramePartBitmapIds[i]; - if (id != 0) - standard_frame_bitmaps_[i] = rb.GetBitmapNamed(id); - } - initialized = true; - } - } - - static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT]; - - DISALLOW_EVIL_CONSTRUCTORS(InactiveWindowResources); -}; - -// static -SkBitmap* ActiveWindowResources::standard_frame_bitmaps_[]; -SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[]; - -// static -WindowResources* DefaultNonClientView::active_resources_ = NULL; -WindowResources* DefaultNonClientView::inactive_resources_ = NULL; -ChromeFont DefaultNonClientView::title_font_; - -namespace { -// The frame border is only visible in restored mode and is hardcoded to 4 px on -// each side regardless of the system window border size. -const int kFrameBorderThickness = 4; -// Various edges of the frame border have a 1 px shadow along their edges; in a -// few cases we shift elements based on this amount for visual appeal. -const int kFrameShadowThickness = 1; -// While resize areas on Windows are normally the same size as the window -// borders, our top area is shrunk by 1 px to make it easier to move the window -// around with our thinner top grabbable strip. (Incidentally, our side and -// bottom resize areas don't match the frame border thickness either -- they -// span the whole nonclient area, so there's no "dead zone" for the mouse.) -const int kTopResizeAdjust = 1; -// In the window corners, the resize areas don't actually expand bigger, but the -// 16 px at the end of each edge triggers diagonal resizing. -const int kResizeAreaCornerSize = 16; -// The titlebar never shrinks to less than 18 px tall, plus the height of the -// frame border and any bottom edge. -const int kTitlebarMinimumHeight = 18; -// The icon is inset 2 px from the left frame border. -const int kIconLeftSpacing = 2; -// The icon takes up 16/25th of the available titlebar height. (This is -// expressed as two ints to avoid precision losses leading to off-by-one pixel -// errors.) -const int kIconHeightFractionNumerator = 16; -const int kIconHeightFractionDenominator = 25; -// The icon never shrinks below 16 px on a side. -const int kIconMinimumSize = 16; -// Because our frame border has a different "3D look" than Windows', with a less -// cluttered top edge, we need to shift the icon up by 1 px in restored mode so -// it looks more centered. -const int kIconRestoredAdjust = 1; -// There is a 4 px gap between the icon and the title text. -const int kIconTitleSpacing = 4; -// The title text starts 2 px below the bottom of the top frame border. -const int kTitleTopSpacing = 2; -// There is a 5 px gap between the title text and the caption buttons. -const int kTitleCaptionSpacing = 5; -// The caption buttons are always drawn 1 px down from the visible top of the -// window (the true top in restored mode, or the top of the screen in maximized -// mode). -const int kCaptionTopSpacing = 1; -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultNonClientView, public: - -DefaultNonClientView::DefaultNonClientView( - CustomFrameWindow* container) - : NonClientView(), - client_view_(NULL), - close_button_(new Button), - restore_button_(new Button), - maximize_button_(new Button), - minimize_button_(new Button), - system_menu_button_(new Button), - should_show_minmax_buttons_(false), - container_(container) { - InitClass(); - WindowResources* resources = active_resources_; - - // Close button images will be set in LayoutWindowControls(). - close_button_->SetListener(this, -1); - AddChildView(close_button_); - - restore_button_->SetImage(Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON)); - restore_button_->SetImage(Button::BS_HOT, - resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_H)); - restore_button_->SetImage(Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_P)); - restore_button_->SetListener(this, -1); - AddChildView(restore_button_); - - maximize_button_->SetImage(Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON)); - maximize_button_->SetImage(Button::BS_HOT, - resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_H)); - maximize_button_->SetImage(Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_P)); - maximize_button_->SetListener(this, -1); - AddChildView(maximize_button_); - - minimize_button_->SetImage(Button::BS_NORMAL, - resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON)); - minimize_button_->SetImage(Button::BS_HOT, - resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_H)); - minimize_button_->SetImage(Button::BS_PUSHED, - resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_P)); - minimize_button_->SetListener(this, -1); - AddChildView(minimize_button_); - - should_show_minmax_buttons_ = container->window_delegate()->CanMaximize(); - - AddChildView(system_menu_button_); -} - -DefaultNonClientView::~DefaultNonClientView() { -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultNonClientView, CustomFrameWindow::NonClientView implementation: - -gfx::Rect DefaultNonClientView::CalculateClientAreaBounds(int width, - int height) const { - int top_height = NonClientTopBorderHeight(); - int border_thickness = NonClientBorderThickness(); - return gfx::Rect(border_thickness, top_height, - std::max(0, width - (2 * border_thickness)), - std::max(0, height - top_height - border_thickness)); -} - -gfx::Size DefaultNonClientView::CalculateWindowSizeForClientSize( - int width, - int height) const { - int border_thickness = NonClientBorderThickness(); - return gfx::Size(width + (2 * border_thickness), - height + NonClientTopBorderHeight() + border_thickness); -} - -gfx::Point DefaultNonClientView::GetSystemMenuPoint() const { - gfx::Point system_menu_point(FrameBorderThickness(), - NonClientTopBorderHeight() - BottomEdgeThicknessWithinNonClientHeight()); - ConvertPointToScreen(this, &system_menu_point); - return system_menu_point; -} - -int DefaultNonClientView::NonClientHitTest(const gfx::Point& point) { - if (!bounds().Contains(point)) - return HTNOWHERE; - - int frame_component = container_->client_view()->NonClientHitTest(point); - if (frame_component != HTNOWHERE) - return frame_component; - - // Then see if the point is within any of the window controls. - if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) - return HTCLOSE; - if (restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTMAXBUTTON; - if (maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTMAXBUTTON; - if (minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTMINBUTTON; - if (system_menu_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains( - point)) - return HTSYSMENU; - - int window_component = GetHTComponentForFrame(point, FrameBorderThickness(), - NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, - container_->window_delegate()->CanResize()); - // Fall back to the caption if no other component matches. - return (window_component == HTNOWHERE) ? HTCAPTION : window_component; -} - -void DefaultNonClientView::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) { - DCHECK(window_mask); - - // Redefine the window visible region for the new size. - window_mask->moveTo(0, 3); - window_mask->lineTo(1, 2); - window_mask->lineTo(1, 1); - window_mask->lineTo(2, 1); - window_mask->lineTo(3, 0); - - window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); - window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); - window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); - window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); - window_mask->lineTo(SkIntToScalar(size.width()), 3); - - window_mask->lineTo(SkIntToScalar(size.width()), - SkIntToScalar(size.height())); - window_mask->lineTo(0, SkIntToScalar(size.height())); - window_mask->close(); -} - -void DefaultNonClientView::EnableClose(bool enable) { - close_button_->SetEnabled(enable); -} - -void DefaultNonClientView::ResetWindowControls() { - restore_button_->SetState(Button::BS_NORMAL); - minimize_button_->SetState(Button::BS_NORMAL); - maximize_button_->SetState(Button::BS_NORMAL); - // The close button isn't affected by this constraint. -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultNonClientView, View overrides: - -void DefaultNonClientView::Paint(ChromeCanvas* canvas) { - if (container_->IsMaximized()) - PaintMaximizedFrameBorder(canvas); - else - PaintRestoredFrameBorder(canvas); - PaintTitleBar(canvas); - if (!container_->IsMaximized()) - PaintRestoredClientEdge(canvas); -} - -void DefaultNonClientView::Layout() { - LayoutWindowControls(); - LayoutTitleBar(); - LayoutClientView(); -} - -gfx::Size DefaultNonClientView::GetPreferredSize() { - gfx::Size pref = client_view_->GetPreferredSize(); - DCHECK(pref.width() > 0 && pref.height() > 0); - return CalculateWindowSizeForClientSize(pref.width(), pref.height()); -} - -void DefaultNonClientView::ViewHierarchyChanged(bool is_add, - View* parent, - View* child) { - // Add our Client View as we are added to the Widget so that if we are - // subsequently resized all the parent-child relationships are established. - if (is_add && GetWidget() && child == this) - AddChildView(container_->client_view()); -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultNonClientView, BaseButton::ButtonListener implementation: - -void DefaultNonClientView::ButtonPressed(BaseButton* sender) { - if (sender == close_button_) - container_->ExecuteSystemMenuCommand(SC_CLOSE); - else if (sender == minimize_button_) - container_->ExecuteSystemMenuCommand(SC_MINIMIZE); - else if (sender == maximize_button_) - container_->ExecuteSystemMenuCommand(SC_MAXIMIZE); - else if (sender == restore_button_) - container_->ExecuteSystemMenuCommand(SC_RESTORE); -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultNonClientView, private: - -int DefaultNonClientView::FrameBorderThickness() const { - return container_->IsMaximized() ? - GetSystemMetrics(SM_CXSIZEFRAME) : kFrameBorderThickness; -} - -int DefaultNonClientView::NonClientBorderThickness() const { - // In maximized mode, we don't show a client edge. - return FrameBorderThickness() + - (container_->IsMaximized() ? 0 : kClientEdgeThickness); -} - -int DefaultNonClientView::NonClientTopBorderHeight() const { - int title_top_spacing, title_thickness; - return TitleCoordinates(&title_top_spacing, &title_thickness); -} - -int DefaultNonClientView::BottomEdgeThicknessWithinNonClientHeight() const { - return kFrameShadowThickness + - (container_->IsMaximized() ? 0 : kClientEdgeThickness); -} - -int DefaultNonClientView::TitleCoordinates(int* title_top_spacing, - int* title_thickness) const { - int frame_thickness = FrameBorderThickness(); - int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; - *title_top_spacing = frame_thickness + kTitleTopSpacing; - // The bottom spacing should be the same apparent height as the top spacing. - // Because the actual top spacing height varies based on the system border - // thickness, we calculate this based on the restored top spacing and then - // adjust for maximized mode. We also don't include the frame shadow here, - // since while it's part of the bottom spacing it will be added in at the end. - int title_bottom_spacing = - kFrameBorderThickness + kTitleTopSpacing - kFrameShadowThickness; - if (container_->IsMaximized()) { - // When we maximize, the top border appears to be chopped off; shift the - // title down to stay centered within the remaining space. - int title_adjust = (kFrameBorderThickness / 2); - *title_top_spacing += title_adjust; - title_bottom_spacing -= title_adjust; - } - *title_thickness = std::max(title_font_.height(), - min_titlebar_height - *title_top_spacing - title_bottom_spacing); - return *title_top_spacing + *title_thickness + title_bottom_spacing + - BottomEdgeThicknessWithinNonClientHeight(); -} - -void DefaultNonClientView::PaintRestoredFrameBorder(ChromeCanvas* canvas) { - SkBitmap* top_left_corner = resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER); - SkBitmap* top_right_corner = - resources()->GetPartBitmap(FRAME_TOP_RIGHT_CORNER); - SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); - SkBitmap* right_edge = resources()->GetPartBitmap(FRAME_RIGHT_EDGE); - SkBitmap* left_edge = resources()->GetPartBitmap(FRAME_LEFT_EDGE); - SkBitmap* bottom_left_corner = - resources()->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER); - SkBitmap* bottom_right_corner = - resources()->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER); - SkBitmap* bottom_edge = resources()->GetPartBitmap(FRAME_BOTTOM_EDGE); - - // Top. - canvas->DrawBitmapInt(*top_left_corner, 0, 0); - canvas->TileImageInt(*top_edge, top_left_corner->width(), 0, - width() - top_right_corner->width(), top_edge->height()); - canvas->DrawBitmapInt(*top_right_corner, - width() - top_right_corner->width(), 0); - - // Right. - canvas->TileImageInt(*right_edge, width() - right_edge->width(), - top_right_corner->height(), right_edge->width(), - height() - top_right_corner->height() - - bottom_right_corner->height()); - - // Bottom. - canvas->DrawBitmapInt(*bottom_right_corner, - width() - bottom_right_corner->width(), - height() - bottom_right_corner->height()); - canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(), - height() - bottom_edge->height(), - width() - bottom_left_corner->width() - - bottom_right_corner->width(), - bottom_edge->height()); - canvas->DrawBitmapInt(*bottom_left_corner, 0, - height() - bottom_left_corner->height()); - - // Left. - canvas->TileImageInt(*left_edge, 0, top_left_corner->height(), - left_edge->width(), - height() - top_left_corner->height() - bottom_left_corner->height()); -} - -void DefaultNonClientView::PaintMaximizedFrameBorder( - ChromeCanvas* canvas) { - SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); - canvas->TileImageInt(*top_edge, 0, FrameBorderThickness(), width(), - top_edge->height()); - - // The bottom of the titlebar actually comes from the top of the Client Edge - // graphic, with the actual client edge clipped off the bottom. - SkBitmap* titlebar_bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); - int edge_height = titlebar_bottom->height() - kClientEdgeThickness; - canvas->TileImageInt(*titlebar_bottom, 0, - container_->client_view()->y() - edge_height, width(), edge_height); -} - -void DefaultNonClientView::PaintTitleBar(ChromeCanvas* canvas) { - WindowDelegate* d = container_->window_delegate(); - - // It seems like in some conditions we can be asked to paint after the window - // that contains us is WM_DESTROYed. At this point, our delegate is NULL. The - // correct long term fix may be to shut down the RootView in WM_DESTROY. - if (!d) - return; - - canvas->DrawStringInt(d->GetWindowTitle(), title_font_, SK_ColorWHITE, - MirroredLeftPointForRect(title_bounds_), title_bounds_.y(), - title_bounds_.width(), title_bounds_.height()); -} - -void DefaultNonClientView::PaintRestoredClientEdge(ChromeCanvas* canvas) { - gfx::Rect client_area_bounds = container_->client_view()->bounds(); - int client_area_top = client_area_bounds.y(); - - SkBitmap* top_left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT); - SkBitmap* top = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); - SkBitmap* top_right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT); - SkBitmap* right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT); - SkBitmap* bottom_right = - resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT); - SkBitmap* bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM); - SkBitmap* bottom_left = - resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT); - SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT); - - // Top. - // This next calculation is necessary because the top center bitmap is shorter - // than the top left and right bitmaps. We need their top edges to line up, - // and we need the left and right edges to start below the corners' bottoms. - int top_edge_y = client_area_top - top->height(); - client_area_top = top_edge_y + top_left->height(); - canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(), - top_edge_y); - canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y, - client_area_bounds.width(), top->height()); - canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y); - - // Right. - int client_area_bottom = - std::max(client_area_top, client_area_bounds.bottom()); - int client_area_height = client_area_bottom - client_area_top; - canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, - right->width(), client_area_height); - - // Bottom. - canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(), - client_area_bottom); - canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom, - client_area_bounds.width(), bottom_right->height()); - canvas->DrawBitmapInt(*bottom_left, - client_area_bounds.x() - bottom_left->width(), client_area_bottom); - - // Left. - canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), - client_area_top, left->width(), client_area_height); -} - -void DefaultNonClientView::LayoutWindowControls() { - close_button_->SetImageAlignment(Button::ALIGN_LEFT, Button::ALIGN_BOTTOM); - // Maximized buttons start at window top so that even if their images aren't - // drawn flush with the screen edge, they still obey Fitts' Law. - bool is_maximized = container_->IsMaximized(); - int frame_thickness = FrameBorderThickness(); - int caption_y = is_maximized ? frame_thickness : kCaptionTopSpacing; - int top_extra_height = is_maximized ? kCaptionTopSpacing : 0; - // There should always be the same number of non-shadow pixels visible to the - // side of the caption buttons. In maximized mode we extend the rightmost - // button to the screen corner to obey Fitts' Law. - int right_extra_width = is_maximized ? - (kFrameBorderThickness - kFrameShadowThickness) : 0; - int right_spacing = is_maximized ? - (GetSystemMetrics(SM_CXSIZEFRAME) + right_extra_width) : frame_thickness; - gfx::Size close_button_size = close_button_->GetPreferredSize(); - close_button_->SetBounds(width() - close_button_size.width() - right_spacing, - caption_y, - close_button_size.width() + right_extra_width, - close_button_size.height() + top_extra_height); - - // When the window is restored, we show a maximized button; otherwise, we show - // a restore button. - bool is_restored = !is_maximized && !container_->IsMinimized(); - views::Button* invisible_button = is_restored ? - restore_button_ : maximize_button_; - invisible_button->SetVisible(false); - - views::Button* visible_button = is_restored ? - maximize_button_ : restore_button_; - FramePartBitmap normal_part, hot_part, pushed_part; - if (should_show_minmax_buttons_) { - visible_button->SetVisible(true); - visible_button->SetImageAlignment(Button::ALIGN_LEFT, Button::ALIGN_BOTTOM); - gfx::Size visible_button_size = visible_button->GetPreferredSize(); - visible_button->SetBounds(close_button_->x() - visible_button_size.width(), - caption_y, visible_button_size.width(), - visible_button_size.height() + top_extra_height); - - minimize_button_->SetVisible(true); - minimize_button_->SetImageAlignment(Button::ALIGN_LEFT, - Button::ALIGN_BOTTOM); - gfx::Size minimize_button_size = minimize_button_->GetPreferredSize(); - minimize_button_->SetBounds( - visible_button->x() - minimize_button_size.width(), caption_y, - minimize_button_size.width(), - minimize_button_size.height() + top_extra_height); - - normal_part = FRAME_CLOSE_BUTTON_ICON; - hot_part = FRAME_CLOSE_BUTTON_ICON_H; - pushed_part = FRAME_CLOSE_BUTTON_ICON_P; - } else { - visible_button->SetVisible(false); - minimize_button_->SetVisible(false); - - normal_part = FRAME_CLOSE_BUTTON_ICON_SA; - hot_part = FRAME_CLOSE_BUTTON_ICON_SA_H; - pushed_part = FRAME_CLOSE_BUTTON_ICON_SA_P; - } - - close_button_->SetImage(Button::BS_NORMAL, - active_resources_->GetPartBitmap(normal_part)); - close_button_->SetImage(Button::BS_HOT, - active_resources_->GetPartBitmap(hot_part)); - close_button_->SetImage(Button::BS_PUSHED, - active_resources_->GetPartBitmap(pushed_part)); -} - -void DefaultNonClientView::LayoutTitleBar() { - // Always lay out the icon, even when it's not present, so we can lay out the - // window title based on its position. - int frame_thickness = FrameBorderThickness(); - int icon_x = frame_thickness + kIconLeftSpacing; - - // The usable height of the titlebar area is the total height minus the top - // resize border and any edge area we draw at its bottom. - int title_top_spacing, title_thickness; - int top_height = TitleCoordinates(&title_top_spacing, &title_thickness); - int available_height = top_height - frame_thickness - - BottomEdgeThicknessWithinNonClientHeight(); - - // The icon takes up a constant fraction of the available height, down to a - // minimum size, and is always an even number of pixels on a side (presumably - // to make scaled icons look better). It's centered within the usable height. - int icon_size = std::max((available_height * kIconHeightFractionNumerator / - kIconHeightFractionDenominator) / 2 * 2, kIconMinimumSize); - int icon_y = ((available_height - icon_size) / 2) + frame_thickness; - - // Hack: Our frame border has a different "3D look" than Windows'. Theirs has - // a more complex gradient on the top that they push their icon/title below; - // then the maximized window cuts this off and the icon/title are centered in - // the remaining space. Because the apparent shape of our border is simpler, - // using the same positioning makes things look slightly uncentered with - // restored windows, so we come up to compensate. - if (!container_->IsMaximized()) - icon_y -= kIconRestoredAdjust; - - views::WindowDelegate* d = container_->window_delegate(); - if (!d->ShouldShowWindowIcon()) - icon_size = 0; - system_menu_button_->SetBounds(icon_x, icon_y, icon_size, icon_size); - - // Size the title. - int icon_right = icon_x + icon_size; - int title_x = - icon_right + (d->ShouldShowWindowIcon() ? kIconTitleSpacing : 0); - int title_right = (should_show_minmax_buttons_ ? - minimize_button_->x() : close_button_->x()) - kTitleCaptionSpacing; - title_bounds_.SetRect(title_x, - title_top_spacing + ((title_thickness - title_font_.height()) / 2), - std::max(0, title_right - title_x), title_font_.height()); -} - -void DefaultNonClientView::LayoutClientView() { - container_->client_view()->SetBounds(CalculateClientAreaBounds(width(), - height())); -} - -// static -void DefaultNonClientView::InitClass() { - static bool initialized = false; - if (!initialized) { - active_resources_ = new ActiveWindowResources; - inactive_resources_ = new InactiveWindowResources; - - title_font_ = win_util::GetWindowTitleFont(); - - initialized = true; - } -} - -} // namespace views diff --git a/chrome/views/default_non_client_view.h b/chrome/views/default_non_client_view.h deleted file mode 100644 index 2c46fca..0000000 --- a/chrome/views/default_non_client_view.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_VIEWS_DEFAULT_NON_CLIENT_VIEW_H_ -#define CHROME_VIEWS_DEFAULT_NON_CLIENT_VIEW_H_ - -#include "base/basictypes.h" -#include "chrome/views/button.h" -#include "chrome/views/custom_frame_window.h" -#include "chrome/views/non_client_view.h" -#include "chrome/views/window_resources.h" - -namespace gfx{ -class Size; -class Path; -class Point; -} -class ChromeCanvas; -class ChromeFont; - -namespace views { - -class ClientView; - -/////////////////////////////////////////////////////////////////////////////// -// -// DefaultNonClientView -// -// A ChromeView that provides the "frame" for CustomFrameWindows. This means -// rendering the non-standard window caption, border, and controls. -// -//////////////////////////////////////////////////////////////////////////////// -class DefaultNonClientView : public NonClientView, - public BaseButton::ButtonListener { - public: - explicit DefaultNonClientView(CustomFrameWindow* container); - virtual ~DefaultNonClientView(); - - // Overridden from views::NonClientView: - virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; - virtual gfx::Size CalculateWindowSizeForClientSize(int width, - int height) const; - virtual gfx::Point GetSystemMenuPoint() const; - virtual int NonClientHitTest(const gfx::Point& point); - virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); - virtual void EnableClose(bool enable); - virtual void ResetWindowControls(); - - // View overrides: - virtual void Paint(ChromeCanvas* canvas); - virtual void Layout(); - virtual gfx::Size GetPreferredSize(); - virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); - - // BaseButton::ButtonListener implementation: - virtual void ButtonPressed(BaseButton* sender); - - private: - // Returns the thickness of the border that makes up the window frame edges. - // This does not include any client edge. - int FrameBorderThickness() const; - - // Returns the thickness of the entire nonclient left, right, and bottom - // borders, including both the window frame and any client edge. - int NonClientBorderThickness() const; - - // Returns the height of the entire nonclient top border, including the window - // frame, any title area, and any connected client edge. - int NonClientTopBorderHeight() const; - - // A bottom border, and, in restored mode, a client edge are drawn at the - // bottom of the titlebar. This returns the total height drawn. - int BottomEdgeThicknessWithinNonClientHeight() const; - - // Calculates multiple values related to title layout. Returns the height of - // the entire titlebar including any connected client edge. - int TitleCoordinates(int* title_top_spacing, - int* title_thickness) const; - - // Paint various sub-components of this view. - void PaintRestoredFrameBorder(ChromeCanvas* canvas); - void PaintMaximizedFrameBorder(ChromeCanvas* canvas); - void PaintTitleBar(ChromeCanvas* canvas); - void PaintRestoredClientEdge(ChromeCanvas* canvas); - - // Layout various sub-components of this view. - void LayoutWindowControls(); - void LayoutTitleBar(); - void LayoutClientView(); - - // Returns the resource collection to be used when rendering the window. - WindowResources* resources() const { - return container_->is_active() || paint_as_active() ? active_resources_ - : inactive_resources_; - } - - // The View that provides the background for the window, and optionally - // dialog buttons. Note: the non-client view does _not_ own this view, the - // container does. - ClientView* client_view_; - - // The layout rect of the title, if visible. - gfx::Rect title_bounds_; - - // Window controls. - Button* close_button_; - Button* restore_button_; - Button* maximize_button_; - Button* minimize_button_; - Button* system_menu_button_; // Uses the window icon if visible. - bool should_show_minmax_buttons_; - - // The window that owns this view. - CustomFrameWindow* container_; - - // Initialize various static resources. - static void InitClass(); - static WindowResources* active_resources_; - static WindowResources* inactive_resources_; - static ChromeFont title_font_; - - DISALLOW_COPY_AND_ASSIGN(DefaultNonClientView); -}; - -} // namespace views - -#endif // CHROME_VIEWS_DEFAULT_NON_CLIENT_VIEW_H_ diff --git a/chrome/views/native_frame_view.cc b/chrome/views/native_frame_view.cc new file mode 100644 index 0000000..04f3448 --- /dev/null +++ b/chrome/views/native_frame_view.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/views/native_frame_view.h" + +#include "chrome/views/window.h" + +namespace views { + +//////////////////////////////////////////////////////////////////////////////// +// NativeFrameView, public: + +NativeFrameView::NativeFrameView(Window* frame) + : NonClientFrameView(), + frame_(frame) { +} + +NativeFrameView::~NativeFrameView() { +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeFrameView, NonClientFrameView overrides: + +gfx::Rect NativeFrameView::GetBoundsForClientView() const { + return gfx::Rect(0, 0, width(), height()); +} + +gfx::Rect NativeFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + RECT rect = client_bounds.ToRECT(); + AdjustWindowRectEx(&rect, frame_->window_style(), FALSE, + frame_->window_ex_style()); + return gfx::Rect(rect); +} + +gfx::Point NativeFrameView::GetSystemMenuPoint() const { + POINT temp = {0, -kFrameShadowThickness }; + MapWindowPoints(frame_->GetHWND(), HWND_DESKTOP, &temp, 1); + return gfx::Point(temp); +} + +int NativeFrameView::NonClientHitTest(const gfx::Point& point) { + return HTNOWHERE; +} + +void NativeFrameView::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { + // Nothing to do, we use the default window mask. +} + +void NativeFrameView::EnableClose(bool enable) { + // Nothing to do, handled automatically by Window. +} + +void NativeFrameView::ResetWindowControls() { + // Nothing to do. +} + +} // namespace views + diff --git a/chrome/views/native_frame_view.h b/chrome/views/native_frame_view.h new file mode 100644 index 0000000..aa599ff --- /dev/null +++ b/chrome/views/native_frame_view.h @@ -0,0 +1,38 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_VIEWS_NATIVE_FRAME_VIEW_H_ +#define CHROME_VIEWS_NATIVE_FRAME_VIEW_H_ + +#include "chrome/views/non_client_view.h" + +namespace views { + +class NativeFrameView : public NonClientFrameView { + public: + explicit NativeFrameView(Window* frame); + virtual ~NativeFrameView(); + + // NonClientFrameView overrides: + virtual gfx::Rect GetBoundsForClientView() const; + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const; + virtual gfx::Point GetSystemMenuPoint() const; + virtual int NonClientHitTest(const gfx::Point& point); + virtual void GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask); + virtual void EnableClose(bool enable); + virtual void ResetWindowControls(); + + private: + // Our containing frame. + Window* frame_; + + DISALLOW_COPY_AND_ASSIGN(NativeFrameView); +}; + +} // namespace views + +#endif // #ifndef CHROME_VIEWS_NATIVE_FRAME_VIEW_H_ + diff --git a/chrome/views/non_client_view.cc b/chrome/views/non_client_view.cc index bb89cb5..166042d 100644 --- a/chrome/views/non_client_view.cc +++ b/chrome/views/non_client_view.cc @@ -3,20 +3,46 @@ // found in the LICENSE file. #include "chrome/views/non_client_view.h" -#include "chrome/views/widget.h" + +#include "chrome/common/win_util.h" +#include "chrome/views/root_view.h" +#include "chrome/views/window.h" namespace views { -const int NonClientView::kFrameShadowThickness = 1; -const int NonClientView::kClientEdgeThickness = 1; +const int NonClientFrameView::kFrameShadowThickness = 1; +const int NonClientFrameView::kClientEdgeThickness = 1; + +// The frame view and the client view are always at these specific indices, +// because the RootView message dispatch sends messages to items higher in the +// z-order first and we always want the client view to have first crack at +// handling mouse messages. +static const int kFrameViewIndex = 0; +static const int kClientViewIndex = 1; //////////////////////////////////////////////////////////////////////////////// // NonClientView, public: -NonClientView::NonClientView() : paint_as_active_(false) { +NonClientView::NonClientView(Window* frame) + : frame_(frame), + client_view_(NULL), + use_native_frame_(win_util::ShouldUseVistaFrame()) { } NonClientView::~NonClientView() { + // This value may have been reset before the window hierarchy shuts down, + // so we need to manually remove it. + RemoveChildView(frame_view_.get()); +} + +void NonClientView::SetFrameView(NonClientFrameView* frame_view) { + // See comment in header about ownership. + frame_view->SetParentOwned(false); + if (frame_view_.get()) + RemoveChildView(frame_view_.get()); + frame_view_.reset(frame_view); + if (GetParent()) + AddChildView(kFrameViewIndex, frame_view_.get()); } bool NonClientView::CanClose() const { @@ -27,41 +53,84 @@ void NonClientView::WindowClosing() { client_view_->WindowClosing(); } +void NonClientView::SystemThemeChanged() { + // The window may try to paint in SetUseNativeFrame, and as a result it can + // get into a state where it is very unhappy with itself - rendering black + // behind the entire client area. This is because for some reason the + // SkPorterDuff::kClear_mode erase done in the RootView thinks the window is + // still opaque. So, to work around this we hide the window as soon as we can + // (now), saving off its placement so it can be properly restored once + // everything has settled down. + WINDOWPLACEMENT saved_window_placement; + saved_window_placement.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(frame_->GetHWND(), &saved_window_placement); + frame_->Hide(); + + SetUseNativeFrame(win_util::ShouldUseVistaFrame()); + + // Now that we've updated the frame, we'll want to restore our saved placement + // since the display should have settled down and we can be properly rendered. + SetWindowPlacement(frame_->GetHWND(), &saved_window_placement); +} + +void NonClientView::SetUseNativeFrame(bool use_native_frame) { + use_native_frame_ = use_native_frame; + SetFrameView(frame_->CreateFrameViewForWindow()); + GetRootView()->ThemeChanged(); + Layout(); + SchedulePaint(); + frame_->UpdateFrameAfterFrameChange(); +} + bool NonClientView::UseNativeFrame() const { - return true; + // The frame view may always require a custom frame, e.g. Constrained Windows. + bool always_use_custom_frame = + frame_view_.get() && frame_view_->AlwaysUseCustomFrame(); + return !always_use_custom_frame && use_native_frame_; } -gfx::Rect NonClientView::CalculateClientAreaBounds(int width, - int height) const { - return gfx::Rect(); +void NonClientView::DisableInactiveRendering(bool disable) { + frame_view_->DisableInactiveRendering(disable); } -gfx::Size NonClientView::CalculateWindowSizeForClientSize(int width, - int height) const { - return gfx::Size(); +gfx::Rect NonClientView::GetWindowBoundsForClientBounds( + const gfx::Rect client_bounds) const { + return frame_view_->GetWindowBoundsForClientBounds(client_bounds); } gfx::Point NonClientView::GetSystemMenuPoint() const { - CPoint temp(0, -kFrameShadowThickness); - MapWindowPoints(GetWidget()->GetHWND(), HWND_DESKTOP, &temp, 1); - return gfx::Point(temp); + return frame_view_->GetSystemMenuPoint(); } int NonClientView::NonClientHitTest(const gfx::Point& point) { - return client_view_->NonClientHitTest(point); + // Sanity check. + if (!bounds().Contains(point)) + return HTNOWHERE; + + // The ClientView gets first crack, since it overlays the NonClientFrameView + // in the display stack. + int frame_component = client_view_->NonClientHitTest(point); + if (frame_component != HTNOWHERE) + return frame_component; + + // Finally ask the NonClientFrameView. It's at the back of the display stack + // so it gets asked last. + return frame_view_->NonClientHitTest(point); } void NonClientView::GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) { + frame_view_->GetWindowMask(size, window_mask); } void NonClientView::EnableClose(bool enable) { + frame_view_->EnableClose(enable); } void NonClientView::ResetWindowControls() { + frame_view_->ResetWindowControls(); } - //////////////////////////////////////////////////////////////////////////////// // NonClientView, View overrides: @@ -70,26 +139,34 @@ gfx::Size NonClientView::GetPreferredSize() { } void NonClientView::Layout() { - client_view_->SetBounds(0, 0, width(), height()); + // First layout the NonClientFrameView, which determines the size of the + // ClientView... + frame_view_->SetBounds(0, 0, width(), height()); + + // Then layout the ClientView, using those bounds. + client_view_->SetBounds(frame_view_->GetBoundsForClientView()); } void NonClientView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { - // Add our Client View as we are added to the Widget so that if we are - // subsequently resized all the parent-child relationships are established. - if (is_add && GetWidget() && child == this) - AddChildView(client_view_); + // Add our two child views here as we are added to the Widget so that if we + // are subsequently resized all the parent-child relationships are + // established. + if (is_add && GetWidget() && child == this) { + AddChildView(kFrameViewIndex, frame_view_.get()); + AddChildView(kClientViewIndex, client_view_); + } } //////////////////////////////////////////////////////////////////////////////// -// NonClientView, protected: - -int NonClientView::GetHTComponentForFrame(const gfx::Point& point, - int top_resize_border_height, - int resize_border_thickness, - int top_resize_corner_height, - int resize_corner_width, - bool can_resize) { +// NonClientFrameView, protected: + +int NonClientFrameView::GetHTComponentForFrame(const gfx::Point& point, + int top_resize_border_height, + int resize_border_thickness, + int top_resize_corner_height, + int resize_corner_width, + bool can_resize) { // Tricky: In XP, native behavior is to return HTTOPLEFT and HTTOPRIGHT for // a |resize_corner_size|-length strip of both the side and top borders, but // only to return HTBOTTOMLEFT/HTBOTTOMRIGHT along the bottom border + corner diff --git a/chrome/views/non_client_view.h b/chrome/views/non_client_view.h index 1887c2e..f801d6f 100644 --- a/chrome/views/non_client_view.h +++ b/chrome/views/non_client_view.h @@ -5,6 +5,7 @@ #ifndef CHROME_VIEWS_NON_CLIENT_VIEW_H_ #define CHROME_VIEWS_NON_CLIENT_VIEW_H_ +#include "base/task.h" #include "chrome/views/view.h" #include "chrome/views/client_view.h" @@ -14,21 +15,15 @@ class Path; namespace views { -/////////////////////////////////////////////////////////////////////////////// -// NonClientView -// -// An object implementing the NonClientView interface is a View that provides -// the "non-client" areas of a window. This is the area that typically -// encompasses the window frame - title bar, sizing borders and window -// controls. This interface provides methods that allow a specific -// presentation to define non-client areas for windows hit testing, the shape -// of the window, and other window-related information. +//////////////////////////////////////////////////////////////////////////////// +// NonClientFrameView // -class NonClientView : public View { +// An object that subclasses NonClientFrameView is a View that renders and +// responds to events within the frame portions of the non-client area of a +// window. This view does _not_ contain the ClientView, but rather is a sibling +// of it. +class NonClientFrameView : public views::View { public: - NonClientView(); - virtual ~NonClientView(); - // Various edges of the frame border have a 1 px shadow along their edges; in // a few cases we shift elements based on this amount for visual appeal. static const int kFrameShadowThickness; @@ -36,6 +31,99 @@ class NonClientView : public View { // frame border. static const int kClientEdgeThickness; + void DisableInactiveRendering(bool disable) { + paint_as_active_ = disable; + if (!paint_as_active_) + SchedulePaint(); + } + + // Returns the bounds (in this View's parent's coordinates) that the client + // view should be laid out within. + virtual gfx::Rect GetBoundsForClientView() const = 0; + + // Returns true if this FrameView should always use the custom frame, + // regardless of the system settings. An example is the Constrained Window, + // which is a child window and must always provide its own frame. + virtual bool AlwaysUseCustomFrame() const { return false; } + + virtual gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const = 0; + virtual gfx::Point GetSystemMenuPoint() const = 0; + virtual int NonClientHitTest(const gfx::Point& point) = 0; + virtual void GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) = 0; + virtual void EnableClose(bool enable) = 0; + virtual void ResetWindowControls() = 0; + + protected: + NonClientFrameView() : paint_as_active_(false) {} + + + // Helper for non-client view implementations to determine which area of the + // window border the specified |point| falls within. The other parameters are + // the size of the sizing edges, and whether or not the window can be + // resized. + int GetHTComponentForFrame(const gfx::Point& point, + int top_resize_border_height, + int resize_border_thickness, + int top_resize_corner_height, + int resize_corner_width, + bool can_resize); + + // Accessor for paint_as_active_. + bool paint_as_active() const { return paint_as_active_; } + + private: + // True when the non-client view should always be rendered as if the window + // were active, regardless of whether or not the top level window actually + // is active. + bool paint_as_active_; +}; + +//////////////////////////////////////////////////////////////////////////////// +// NonClientView +// +// The NonClientView is the logical root of all Views contained within a +// Window, except for the RootView which is its parent and of which it is the +// sole child. The NonClientView has two children, the NonClientFrameView which +// is responsible for painting and responding to events from the non-client +// portions of the window, and the ClientView, which is responsible for the +// same for the client area of the window: +// +// +- views::Window ------------------------------------+ +// | +- views::RootView ------------------------------+ | +// | | +- views::NonClientView ---------------------+ | | +// | | | +- views::NonClientFrameView subclass ---+ | | | +// | | | | | | | | +// | | | | << all painting and event receiving >> | | | | +// | | | | << of the non-client areas of a >> | | | | +// | | | | << views::Window. >> | | | | +// | | | | | | | | +// | | | +----------------------------------------+ | | | +// | | | +- views::ClientView or subclass --------+ | | | +// | | | | | | | | +// | | | | << all painting and event receiving >> | | | | +// | | | | << of the client areas of a >> | | | | +// | | | | << views::Window. >> | | | | +// | | | | | | | | +// | | | +----------------------------------------+ | | | +// | | +--------------------------------------------+ | | +// | +------------------------------------------------+ | +// +----------------------------------------------------+ +// +// The NonClientFrameView and ClientView are siblings because due to theme +// changes the NonClientFrameView may be replaced with different +// implementations (e.g. during the switch from DWM/Aero-Glass to Vista Basic/ +// Classic rendering). +// +class NonClientView : public View { + public: + explicit NonClientView(Window* frame); + virtual ~NonClientView(); + + // Replaces the current NonClientFrameView (if any) with the specified one. + void SetFrameView(NonClientFrameView* frame_view); + // Returns true if the ClientView determines that the containing window can be // closed, false otherwise. bool CanClose() const; @@ -43,48 +131,52 @@ class NonClientView : public View { // Called by the containing Window when it is closed. void WindowClosing(); + // Called by the window when it receives a theme changed notification. Changes + // the content of the NonClientView to match what is required for the current + // system theme. + void SystemThemeChanged(); + + // Changes the frame from native to custom depending on the value of + // |use_native_frame|. + void SetUseNativeFrame(bool use_native_frame); + // Returns true if the native window frame should be used, false if the // NonClientView provides its own frame implementation. bool UseNativeFrame() const; - // Calculates the bounds of the client area of the window assuming the - // window is sized to |width| and |height|. - virtual gfx::Rect CalculateClientAreaBounds(int width, int height) const; + // Prevents the window from being rendered as deactivated when |disable| is + // true, until called with |disable| false. Used when a sub-window is to be + // shown that shouldn't visually de-activate the window. + // Subclasses can override this to perform additional actions when this value + // changes. + void DisableInactiveRendering(bool disable); - // Calculates the size of window required to display a client area of the - // specified width and height. - virtual gfx::Size CalculateWindowSizeForClientSize(int width, - int height) const; + // Returns the bounds of the window required to display the content area at + // the specified bounds. + gfx::Rect GetWindowBoundsForClientBounds(const gfx::Rect client_bounds) const; // Returns the point, in screen coordinates, where the system menu should // be shown so it shows up anchored to the system menu icon. - virtual gfx::Point GetSystemMenuPoint() const; + gfx::Point GetSystemMenuPoint() const; // Determines the windows HT* code when the mouse cursor is at the // specified point, in window coordinates. - virtual int NonClientHitTest(const gfx::Point& point); + int NonClientHitTest(const gfx::Point& point); // Returns a mask to be used to clip the top level window for the given // size. This is used to create the non-rectangular window shape. - virtual void GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask); + void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); // Toggles the enable state for the Close button (and the Close menu item in // the system menu). - virtual void EnableClose(bool enable); + void EnableClose(bool enable); // Tells the window controls as rendered by the NonClientView to reset // themselves to a normal state. This happens in situations where the // containing window does not receive a normal sequences of messages that // would lead to the controls returning to this normal state naturally, e.g. // when the window is maximized, minimized or restored. - virtual void ResetWindowControls(); - - // Prevents the non-client view from rendering as inactive when called with - // |disable| true, until called with false. - void set_paint_as_active(bool paint_as_active) { - paint_as_active_ = paint_as_active; - } + void ResetWindowControls(); // Get/Set client_view property. ClientView* client_view() const { return client_view_; } @@ -100,30 +192,24 @@ class NonClientView : public View { // NonClientView, View overrides: virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); - // Helper for non-client view implementations to determine which area of the - // window border the specified |point| falls within. The other parameters are - // the size of the sizing edges, and whether or not the window can be - // resized. - int GetHTComponentForFrame(const gfx::Point& point, - int top_resize_border_height, - int resize_border_thickness, - int top_resize_corner_height, - int resize_corner_width, - bool can_resize); - - // Accessor for paint_as_active_. - bool paint_as_active() const { return paint_as_active_; } - private: + // The frame that hosts this NonClientView. + Window* frame_; + // A ClientView object or subclass, responsible for sizing the contents view // of the window, hit testing and perhaps other tasks depending on the // implementation. ClientView* client_view_; - // True when the non-client view should always be rendered as if the window - // were active, regardless of whether or not the top level window actually - // is active. - bool paint_as_active_; + // The NonClientFrameView that renders the non-client portions of the window. + // This object is not owned by the view hierarchy because it can be replaced + // dynamically as the system settings change. + scoped_ptr frame_view_; + + // Whether or not we should use the native frame. + bool use_native_frame_; + + DISALLOW_COPY_AND_ASSIGN(NonClientView); }; } // namespace views diff --git a/chrome/views/root_view.cc b/chrome/views/root_view.cc index dfff6e4..8955732 100644 --- a/chrome/views/root_view.cc +++ b/chrome/views/root_view.cc @@ -220,6 +220,10 @@ Widget* RootView::GetWidget() const { return widget_; } +void RootView::ThemeChanged() { + View::ThemeChanged(); +} + ///////////////////////////////////////////////////////////////////////////// // // RootView - event dispatch and propagation diff --git a/chrome/views/root_view.h b/chrome/views/root_view.h index 6538625..103b06d 100644 --- a/chrome/views/root_view.h +++ b/chrome/views/root_view.h @@ -83,6 +83,10 @@ class RootView : public View, // Get the Widget that hosts this View. virtual Widget* GetWidget() const; + // Public API for broadcasting theme change notifications to this View + // hierarchy. + virtual void ThemeChanged(); + // The following event methods are overridden to propagate event to the // control tree virtual bool OnMousePressed(const MouseEvent& e); diff --git a/chrome/views/view.cc b/chrome/views/view.cc index d435ddb..395eabc 100644 --- a/chrome/views/view.cc +++ b/chrome/views/view.cc @@ -626,6 +626,12 @@ void View::PropagateAddNotifications(View* parent, View* child) { ViewHierarchyChangedImpl(true, true, parent, child); } +void View::ThemeChanged() { + int c = GetChildViewCount(); + for (int i = c - 1; i >= 0; --i) + GetChildViewAt(i)->ThemeChanged(); +} + #ifndef NDEBUG bool View::IsProcessingPaint() const { return GetParent() && GetParent()->IsProcessingPaint(); diff --git a/chrome/views/view.h b/chrome/views/view.h index aee08a3..824eb3f 100644 --- a/chrome/views/view.h +++ b/chrome/views/view.h @@ -995,6 +995,14 @@ class View : public AcceleratorTarget { // to find other radio buttons. int group_; + // Called when the UI theme has changed, overriding allows individual Views to + // do special cleanup and processing (such as dropping resource caches). + // Subclasses that override this method must call the base class + // implementation to ensure child views are processed. + // Can only be called by subclasses. To dispatch a theme changed notification, + // call this method on the RootView. + virtual void ThemeChanged(); + #ifndef NDEBUG // Returns true if the View is currently processing a paint. virtual bool IsProcessingPaint() const; diff --git a/chrome/views/views.vcproj b/chrome/views/views.vcproj index e937b47..cbc6cd8 100644 --- a/chrome/views/views.vcproj +++ b/chrome/views/views.vcproj @@ -254,11 +254,11 @@ > - - - - @@ -418,6 +410,14 @@ > + + + + diff --git a/chrome/views/widget.h b/chrome/views/widget.h index d135860..0dab65f 100644 --- a/chrome/views/widget.h +++ b/chrome/views/widget.h @@ -16,9 +16,10 @@ class Rect; namespace views { +class Accelerator; class RootView; class TooltipManager; -class Accelerator; +class Window; //////////////////////////////////////////////////////////////////////////////// // @@ -77,6 +78,11 @@ class Widget { // no accelerator associated with a given id, which is a common condition. virtual bool GetAccelerator(int cmd_id, Accelerator* accelerator) = 0; + + // Returns the Widget as a Window, if such a conversion is possible, or NULL + // if it is not. + virtual Window* AsWindow() { return NULL; } + virtual const Window* AsWindow() const { return NULL; } }; } // namespace views diff --git a/chrome/views/widget_win.cc b/chrome/views/widget_win.cc index 9568a64..0d7edf4 100644 --- a/chrome/views/widget_win.cc +++ b/chrome/views/widget_win.cc @@ -566,7 +566,7 @@ void WidgetWin::OnMouseMove(UINT flags, const CPoint& point) { ProcessMouseMoved(point, flags, false); } -LRESULT WidgetWin::OnMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param) { +LRESULT WidgetWin::OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param) { tooltip_manager_->OnMouseLeave(); ProcessMouseExited(); return 0; diff --git a/chrome/views/widget_win.h b/chrome/views/widget_win.h index 97f9fe4..546e9f7 100644 --- a/chrome/views/widget_win.h +++ b/chrome/views/widget_win.h @@ -176,6 +176,9 @@ class WidgetWin : public Widget, MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption) MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame) + // Vista and newer + MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged) + // Non-atlcrack.h handlers MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject) MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnNCMouseLeave) @@ -183,6 +186,7 @@ class WidgetWin : public Widget, // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU. MSG_WM_ACTIVATE(OnActivate) + MSG_WM_ACTIVATEAPP(OnActivateApp) MSG_WM_APPCOMMAND(OnAppCommand) MSG_WM_CANCELMODE(OnCancelMode) MSG_WM_CAPTURECHANGED(OnCaptureChanged) @@ -347,7 +351,12 @@ class WidgetWin : public Widget, // handling to the appropriate Process* function. This is so that // subclasses can easily override these methods to do different things // and have a convenient function to call to get the default behavior. - virtual void OnActivate(UINT action, BOOL minimized, HWND window) { } + virtual void OnActivate(UINT action, BOOL minimized, HWND window) { + SetMsgHandled(FALSE); + } + virtual void OnActivateApp(BOOL active, DWORD thread_id) { + SetMsgHandled(FALSE); + } virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device, int keystate) { SetMsgHandled(FALSE); @@ -362,6 +371,12 @@ class WidgetWin : public Widget, // WARNING: If you override this be sure and invoke super, otherwise we'll // leak a few things. virtual void OnDestroy(); + virtual LRESULT OnDwmCompositionChanged(UINT msg, + WPARAM w_param, + LPARAM l_param) { + SetMsgHandled(FALSE); + return 0; + } virtual void OnEndSession(BOOL ending, UINT logoff) { SetMsgHandled(FALSE); } virtual void OnEnterSizeMove() { SetMsgHandled(FALSE); } virtual void OnExitMenuLoop(BOOL is_track_popup_menu) { SetMsgHandled(FALSE); } @@ -384,7 +399,7 @@ class WidgetWin : public Widget, virtual void OnMButtonUp(UINT flags, const CPoint& point); virtual LRESULT OnMouseActivate(HWND window, UINT hittest_code, UINT message); virtual void OnMouseMove(UINT flags, const CPoint& point); - virtual LRESULT OnMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param); + virtual LRESULT OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param); virtual void OnMove(const CPoint& point) { SetMsgHandled(FALSE); } virtual void OnMoving(UINT param, const LPRECT new_bounds) { } virtual LRESULT OnMouseWheel(UINT flags, short distance, const CPoint& point); diff --git a/chrome/views/window.cc b/chrome/views/window.cc index d4cb905..a879a99 100644 --- a/chrome/views/window.cc +++ b/chrome/views/window.cc @@ -16,8 +16,8 @@ #include "chrome/common/resource_bundle.h" #include "chrome/common/win_util.h" #include "chrome/views/client_view.h" -#include "chrome/views/custom_frame_window.h" -#include "chrome/views/default_non_client_view.h" +#include "chrome/views/custom_frame_view.h" +#include "chrome/views/native_frame_view.h" #include "chrome/views/non_client_view.h" #include "chrome/views/root_view.h" #include "chrome/views/window_delegate.h" @@ -82,12 +82,8 @@ Window::~Window() { Window* Window::CreateChromeWindow(HWND parent, const gfx::Rect& bounds, WindowDelegate* window_delegate) { - Window* window = NULL; - if (win_util::ShouldUseVistaFrame()) { - window = new Window(window_delegate); - } else { - window = new CustomFrameWindow(window_delegate); - } + Window* window = new Window(window_delegate); + window->non_client_view_->SetFrameView(window->CreateFrameViewForWindow()); window->Init(parent, bounds); return window; } @@ -205,18 +201,9 @@ void Window::EnableClose(bool enable) { SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER); } -void Window::DisableInactiveRendering(bool disable) { - disable_inactive_rendering_ = disable; - if (!disable_inactive_rendering_) - DefWindowProc(GetHWND(), WM_NCACTIVATE, FALSE, 0); - - if (!non_client_view_->UseNativeFrame()) { - // If the non-client view is rendering its own frame, we need to forcibly - // schedule a paint so it updates when we unset this mode. - non_client_view_->set_paint_as_active(disable); - if (!disable) - non_client_view_->SchedulePaint(); - } +void Window::DisableInactiveRendering() { + disable_inactive_rendering_ = true; + non_client_view_->DisableInactiveRendering(disable_inactive_rendering_); } void Window::UpdateWindowTitle() { @@ -262,6 +249,11 @@ void Window::ExecuteSystemMenuCommand(int command) { SendMessage(GetHWND(), WM_SYSCOMMAND, command, 0); } +gfx::Rect Window::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) { + return non_client_view_->GetWindowBoundsForClientBounds(client_bounds); +} + // static int Window::GetLocalizedContentsWidth(int col_resource_id) { double chars = _wtof(l10n_util::GetString(col_resource_id).c_str()); @@ -309,7 +301,7 @@ Window::Window(WindowDelegate* window_delegate) : WidgetWin(), focus_on_creation_(true), window_delegate_(window_delegate), - non_client_view_(new NonClientView), + non_client_view_(new NonClientView(this)), owning_hwnd_(NULL), minimum_size_(100, 100), is_modal_(false), @@ -349,13 +341,13 @@ void Window::Init(HWND parent, const gfx::Rect& bounds) { WidgetWin::Init(parent, bounds, true); win_util::SetWindowUserData(GetHWND(), this); - std::wstring window_title = window_delegate_->GetWindowTitle(); - std::wstring localized_text; - if (l10n_util::AdjustStringForLocaleDirection(window_title, &localized_text)) - window_title.assign(localized_text); - SetWindowText(GetHWND(), window_title.c_str()); + // Create the ClientView, add it to the NonClientView and add the + // NonClientView to the RootView. This will cause everything to be parented. + non_client_view_->set_client_view(window_delegate_->CreateClientView(this)); + WidgetWin::SetContentsView(non_client_view_); + + UpdateWindowTitle(); - SetClientView(window_delegate_->CreateClientView(this)); SetInitialBounds(bounds); InitAlwaysOnTopState(); @@ -366,7 +358,18 @@ void Window::Init(HWND parent, const gfx::Rect& bounds) { NotificationService::AllSources()); } - ResetWindowRegion(); + ResetWindowRegion(false); +} + +NonClientFrameView* Window::CreateFrameViewForWindow() { + if (non_client_view_->UseNativeFrame()) + return new NativeFrameView(this); + return new CustomFrameView(this); +} + +void Window::UpdateFrameAfterFrameChange() { + // We've either gained or lost a custom window region, so reset it now. + ResetWindowRegion(true); } void Window::SizeWindowToDefault() { @@ -398,6 +401,15 @@ void Window::OnActivate(UINT action, BOOL minimized, HWND window) { SaveWindowPosition(); } +void Window::OnActivateApp(BOOL active, DWORD thread_id) { + if (!active && thread_id != GetCurrentThreadId()) { + // Another application was activated, we should reset any state that + // disables inactive rendering now. + disable_inactive_rendering_ = false; + non_client_view_->DisableInactiveRendering(false); + } +} + LRESULT Window::OnAppCommand(HWND window, short app_command, WORD device, int keystate) { // We treat APPCOMMAND ids as an extension of our command namespace, and just @@ -426,6 +438,27 @@ void Window::OnDestroy() { } namespace { +static BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) { + SendMessage(window, WM_DWMCOMPOSITIONCHANGED, 0, 0); + return TRUE; +} +} // namespace + +LRESULT Window::OnDwmCompositionChanged(UINT msg, WPARAM w_param, + LPARAM l_param) { + // We respond to this in response to WM_DWMCOMPOSITIONCHANGED since that is + // the only thing we care about - we don't actually respond to WM_THEMECHANGED + // messages. + non_client_view_->SystemThemeChanged(); + + // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want + // to notify our children too, since we can have MDI child windows who need to + // update their appearance. + EnumChildWindows(GetHWND(), &SendDwmCompositionChanged, NULL); + return 0; +} + +namespace { static void EnableMenuItem(HMENU menu, UINT command, bool enabled) { UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED); EnableMenuItem(menu, command, flags); @@ -435,10 +468,8 @@ static void EnableMenuItem(HMENU menu, UINT command, bool enabled) { void Window::OnInitMenu(HMENU menu) { // We only need to manually enable the system menu if we're not using a native // frame. - if (non_client_view_->UseNativeFrame()) { - SetMsgHandled(FALSE); - return; - } + if (non_client_view_->UseNativeFrame()) + WidgetWin::OnInitMenu(menu); bool is_minimized = IsMinimized(); bool is_maximized = IsMaximized(); @@ -482,12 +513,12 @@ void Window::OnMouseLeave() { } LRESULT Window::OnNCActivate(BOOL active) { + is_active_ = !!active; + // If we're not using the native frame, we need to force a synchronous repaint // otherwise we'll be left in the wrong activation state until something else // causes a repaint later. if (!non_client_view_->UseNativeFrame()) { - is_active_ = !!active; - // We can get WM_NCACTIVATE before we're actually visible. If we're not // visible, no need to paint. if (IsWindowVisible(GetHWND())) { @@ -498,21 +529,26 @@ LRESULT Window::OnNCActivate(BOOL active) { } } + // If we're active again, we should be allowed to render as inactive, so + // tell the non-client view. This must be done independently of the check for + // disable_inactive_rendering_ since that check is valid even if the frame + // is not active, but this can only be done if we've become active. + if (is_active_) + non_client_view_->DisableInactiveRendering(false); + + // Reset the disable inactive rendering state since activation has changed. if (disable_inactive_rendering_) { disable_inactive_rendering_ = false; - return DefWindowProc(GetHWND(), WM_NCACTIVATE, TRUE, 0); + return CallDefaultNCActivateHandler(TRUE); } - // Otherwise just do the default thing. - return WidgetWin::OnNCActivate(active); + return CallDefaultNCActivateHandler(active); } LRESULT Window::OnNCCalcSize(BOOL mode, LPARAM l_param) { // We only need to adjust the client size/paint handling when we're not using // the native frame. - if (non_client_view_->UseNativeFrame()) { - SetMsgHandled(FALSE); - return 0; - } + if (non_client_view_->UseNativeFrame()) + return WidgetWin::OnNCCalcSize(mode, l_param); // We need to repaint all when the window bounds change. return WVR_REDRAW; @@ -529,8 +565,7 @@ LRESULT Window::OnNCHitTest(const CPoint& point) { // Otherwise, we let Windows do all the native frame non-client handling for // us. - SetMsgHandled(FALSE); - return 0; + return WidgetWin::OnNCHitTest(point); } namespace { @@ -564,10 +599,8 @@ static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) { void Window::OnNCPaint(HRGN rgn) { // We only do non-client painting if we're not using the native frame. - if (non_client_view_->UseNativeFrame()) { - SetMsgHandled(FALSE); - return; - } + if (non_client_view_->UseNativeFrame()) + return WidgetWin::OnNCPaint(rgn); // We have an NC region and need to paint it. We expand the NC region to // include the dirty region of the root view. This is done to minimize @@ -765,7 +798,7 @@ void Window::OnSize(UINT size_param, const CSize& new_size) { // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've // invoked OnSize we ensure the RootView has been laid out. - ResetWindowRegion(); + ResetWindowRegion(false); } void Window::OnSysCommand(UINT notification_code, CPoint click) { @@ -796,17 +829,17 @@ void Window::OnSysCommand(UINT notification_code, CPoint click) { is_always_on_top_ = !is_always_on_top_; // Change the menu check state. - HMENU system_menu = ::GetSystemMenu(GetHWND(), FALSE); + HMENU system_menu = GetSystemMenu(GetHWND(), FALSE); MENUITEMINFO menu_info; memset(&menu_info, 0, sizeof(MENUITEMINFO)); menu_info.cbSize = sizeof(MENUITEMINFO); - BOOL r = ::GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, - FALSE, &menu_info); + BOOL r = GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, + FALSE, &menu_info); DCHECK(r); menu_info.fMask = MIIM_STATE; if (is_always_on_top_) menu_info.fState = MFS_CHECKED; - r = ::SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info); + r = SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info); // Now change the actual window's behavior. AlwaysOnTopChanged(); @@ -823,13 +856,6 @@ void Window::OnSysCommand(UINT notification_code, CPoint click) { //////////////////////////////////////////////////////////////////////////////// // Window, private: -void Window::SetClientView(ClientView* client_view) { - DCHECK(client_view && GetHWND()); - non_client_view_->set_client_view(client_view); - // This will trigger the ClientView to be added by the non-client view. - WidgetWin::SetContentsView(non_client_view_); -} - void Window::BecomeModal() { // We implement modality by crawling up the hierarchy of windows starting // at the owner, disabling all of them so that they don't receive input @@ -1023,11 +1049,14 @@ void Window::UnlockUpdates() { lock_updates_ = false; } -void Window::ResetWindowRegion() { +void Window::ResetWindowRegion(bool force) { // A native frame uses the native window region, and we don't want to mess // with it. - if (non_client_view_->UseNativeFrame()) + if (non_client_view_->UseNativeFrame()) { + if (force) + SetWindowRgn(NULL, TRUE); return; + } // Changing the window region is going to force a paint. Only change the // window region if the region really differs. @@ -1075,6 +1104,14 @@ void Window::ProcessNCMousePress(const CPoint& point, int flags) { ProcessMousePressed(temp, message_flags, false, false); } +LRESULT Window::CallDefaultNCActivateHandler(BOOL active) { + // The DefWindowProc handling for WM_NCACTIVATE renders the classic-look + // window title bar directly, so we need to use a redraw lock here to prevent + // it from doing so. + ScopedRedrawLock lock(this); + return DefWindowProc(GetHWND(), WM_NCACTIVATE, active, 0); +} + void Window::InitClass() { static bool initialized = false; if (!initialized) { diff --git a/chrome/views/window.h b/chrome/views/window.h index b87f0e3..564cfab 100644 --- a/chrome/views/window.h +++ b/chrome/views/window.h @@ -68,7 +68,7 @@ class Window : public WidgetWin, void SetBounds(const gfx::Rect& bounds, HWND other_hwnd); // Closes the window, ultimately destroying it. - virtual void Close(); + void Close(); // Whether or not the window is maximized or minimized. bool IsMaximized() const; @@ -76,35 +76,46 @@ class Window : public WidgetWin, // Toggles the enable state for the Close button (and the Close menu item in // the system menu). - virtual void EnableClose(bool enable); + void EnableClose(bool enable); - // Prevents the window from being rendered as deactivated when |disable| is - // true, until called with |disable| false. Used when a sub-window is to be - // shown that shouldn't visually de-activate the window. - // Subclasses can override this to perform additional actions when this value - // changes. - virtual void DisableInactiveRendering(bool disable); - - WindowDelegate* window_delegate() const { return window_delegate_; } - - void set_focus_on_creation(bool focus_on_creation) { - focus_on_creation_ = focus_on_creation; - } + // Prevents the window from being rendered as deactivated the next time it is. + // This state is reset automatically as soon as the window becomes actiated + // again. There is no ability to control the state through this API as this + // leads to sync problems. + void DisableInactiveRendering(); // Tell the window to update its title from the delegate. - virtual void UpdateWindowTitle(); + void UpdateWindowTitle(); // Tell the window to update its icon from the delegate. - virtual void UpdateWindowIcon(); + void UpdateWindowIcon(); // Executes the specified SC_command. void ExecuteSystemMenuCommand(int command); - // The parent of this window. - HWND owning_window() const { return owning_hwnd_; } + // Shortcut to access the determination of whether or not we're using a + // native frame. This triggers different rendering modes in certain views and + // should be used in preference to calling win_util::ShouldUseVistaFrame. + bool UseNativeFrame() const { return non_client_view_->UseNativeFrame(); } + + // Returns the bounds of the window required to display the content area + // at the specified bounds. + gfx::Rect GetWindowBoundsForClientBounds(const gfx::Rect& client_bounds); + + // Creates an appropriate NonClientFrameView for this window. + virtual NonClientFrameView* CreateFrameViewForWindow(); - // Shortcut to access the ClientView associated with this window. + // Updates the frame after an event caused it to be changed. + virtual void UpdateFrameAfterFrameChange(); + + // Accessors and setters for various properties. + WindowDelegate* window_delegate() const { return window_delegate_; } + HWND owning_window() const { return owning_hwnd_; } ClientView* client_view() const { return non_client_view_->client_view(); } + bool is_active() const { return is_active_; } + void set_focus_on_creation(bool focus_on_creation) { + focus_on_creation_ = focus_on_creation; + } // Returns the preferred size of the contents view of this window based on // its localized size data. The width in cols is held in a localized string @@ -144,25 +155,30 @@ class Window : public WidgetWin, // Overridden from WidgetWin: virtual void OnActivate(UINT action, BOOL minimized, HWND window); + virtual void OnActivateApp(BOOL active, DWORD thread_id); virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device, int keystate); virtual void OnCommand(UINT notification_code, int command_id, HWND window); virtual void OnDestroy(); + virtual LRESULT OnDwmCompositionChanged(UINT msg, WPARAM w_param, + LPARAM l_param); virtual void OnInitMenu(HMENU menu); virtual void OnMouseLeave(); virtual LRESULT OnNCActivate(BOOL active); virtual LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param); virtual LRESULT OnNCHitTest(const CPoint& point); - virtual LRESULT OnNCUAHDrawCaption(UINT msg, WPARAM w_param, LPARAM l_param); - virtual LRESULT OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param); virtual void OnNCPaint(HRGN rgn); virtual void OnNCLButtonDown(UINT ht_component, const CPoint& point); virtual void OnNCRButtonDown(UINT ht_component, const CPoint& point); + virtual LRESULT OnNCUAHDrawCaption(UINT msg, WPARAM w_param, LPARAM l_param); + virtual LRESULT OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param); virtual LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT message); virtual LRESULT OnSetIcon(UINT size_type, HICON new_icon); virtual LRESULT OnSetText(const wchar_t* text); virtual void OnSize(UINT size_param, const CSize& new_size); virtual void OnSysCommand(UINT notification_code, CPoint click); + virtual Window* AsWindow() { return this; } + virtual const Window* AsWindow() const { return this; } // The View that provides the non-client area of the window (title bar, // window controls, sizing borders etc). To use an implementation other than @@ -176,15 +192,6 @@ class Window : public WidgetWin, } private: - // Sets the specified view as the ClientView of this Window. The ClientView - // is responsible for laying out the Window's contents view, as well as - // performing basic hit-testing, and perhaps other responsibilities depending - // on the implementation. The Window's view hierarchy takes ownership of the - // ClientView unless the ClientView specifies otherwise. This must be called - // only once, and after the native window has been created. - // This is called by Init. |client_view| cannot be NULL. - void SetClientView(ClientView* client_view); - // Set the window as modal (by disabling all the other windows). void BecomeModal(); @@ -224,7 +231,9 @@ class Window : public WidgetWin, void UnlockUpdates(); // Resets the window region for the current window bounds if necessary. - void ResetWindowRegion(); + // If |force| is true, the window region is reset to NULL even for native + // frame windows. + void ResetWindowRegion(bool force); // Converts a non-client mouse down message to a regular ChromeViews event // and handle it. |point| is the mouse position of the message in screen @@ -233,6 +242,11 @@ class Window : public WidgetWin, // combined with flags relating to the current key state. void ProcessNCMousePress(const CPoint& point, int flags); + // Calls the default WM_NCACTIVATE handler with the specified activation + // value, safely wrapping the call in a ScopedRedrawLock to prevent frame + // flicker. + LRESULT CallDefaultNCActivateHandler(BOOL active); + // Static resource initialization. static void InitClass(); enum ResizeCursor { -- cgit v1.1