1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ash/wm/custom_frame_view_ash.h" 6 7 #include "ash/shell_delegate.h" 8 #include "ash/wm/frame_painter.h" 9 #include "ash/wm/workspace/frame_maximize_button.h" 10 #include "grit/ash_resources.h" 11 #include "grit/ui_strings.h" // Accessibility names 12 #include "ui/base/l10n/l10n_util.h" 13 #include "ui/base/resource/resource_bundle.h" 14 #include "ui/compositor/layer_animator.h" 15 #include "ui/compositor/scoped_animation_duration_scale_mode.h" 16 #include "ui/gfx/canvas.h" 17 #include "ui/gfx/font.h" 18 #include "ui/gfx/image/image.h" 19 #include "ui/gfx/rect.h" 20 #include "ui/gfx/size.h" 21 #include "ui/views/controls/button/image_button.h" 22 #include "ui/views/widget/native_widget_aura.h" 23 #include "ui/views/widget/widget.h" 24 #include "ui/views/widget/widget_delegate.h" 25 26 namespace { 27 28 const gfx::Font& GetTitleFont() { 29 static gfx::Font* title_font = NULL; 30 if (!title_font) 31 title_font = new gfx::Font(views::NativeWidgetAura::GetWindowTitleFont()); 32 return *title_font; 33 } 34 35 } // namespace 36 37 namespace ash { 38 39 // static 40 const char CustomFrameViewAsh::kViewClassName[] = "CustomFrameViewAsh"; 41 42 //////////////////////////////////////////////////////////////////////////////// 43 // CustomFrameViewAsh, public: 44 CustomFrameViewAsh::CustomFrameViewAsh() 45 : frame_(NULL), 46 maximize_button_(NULL), 47 close_button_(NULL), 48 window_icon_(NULL), 49 frame_painter_(new ash::FramePainter) { 50 } 51 52 CustomFrameViewAsh::~CustomFrameViewAsh() { 53 } 54 55 void CustomFrameViewAsh::Init(views::Widget* frame) { 56 frame_ = frame; 57 58 maximize_button_ = new FrameMaximizeButton(this, this); 59 maximize_button_->SetAccessibleName( 60 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); 61 AddChildView(maximize_button_); 62 close_button_ = new views::ImageButton(this); 63 close_button_->SetAccessibleName( 64 l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); 65 AddChildView(close_button_); 66 67 maximize_button_->SetVisible(frame_->widget_delegate()->CanMaximize()); 68 69 if (frame_->widget_delegate()->ShouldShowWindowIcon()) { 70 window_icon_ = new views::ImageButton(this); 71 AddChildView(window_icon_); 72 } 73 74 frame_painter_->Init(frame_, window_icon_, maximize_button_, close_button_, 75 FramePainter::SIZE_BUTTON_MAXIMIZES); 76 } 77 78 //////////////////////////////////////////////////////////////////////////////// 79 // CustomFrameViewAsh, views::NonClientFrameView overrides: 80 gfx::Rect CustomFrameViewAsh::GetBoundsForClientView() const { 81 int top_height = NonClientTopBorderHeight(); 82 return frame_painter_->GetBoundsForClientView(top_height, 83 bounds()); 84 } 85 86 gfx::Rect CustomFrameViewAsh::GetWindowBoundsForClientBounds( 87 const gfx::Rect& client_bounds) const { 88 int top_height = NonClientTopBorderHeight(); 89 return frame_painter_->GetWindowBoundsForClientBounds(top_height, 90 client_bounds); 91 } 92 93 int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) { 94 return frame_painter_->NonClientHitTest(this, point); 95 } 96 97 void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size, 98 gfx::Path* window_mask) { 99 // No window masks in Aura. 100 } 101 102 void CustomFrameViewAsh::ResetWindowControls() { 103 maximize_button_->SetState(views::CustomButton::STATE_NORMAL); 104 } 105 106 void CustomFrameViewAsh::UpdateWindowIcon() { 107 if (window_icon_) 108 window_icon_->SchedulePaint(); 109 } 110 111 void CustomFrameViewAsh::UpdateWindowTitle() { 112 frame_painter_->SchedulePaintForTitle(GetTitleFont()); 113 } 114 115 //////////////////////////////////////////////////////////////////////////////// 116 // CustomFrameViewAsh, views::View overrides: 117 118 gfx::Size CustomFrameViewAsh::GetPreferredSize() { 119 gfx::Size pref = frame_->client_view()->GetPreferredSize(); 120 gfx::Rect bounds(0, 0, pref.width(), pref.height()); 121 return frame_->non_client_view()->GetWindowBoundsForClientBounds( 122 bounds).size(); 123 } 124 125 void CustomFrameViewAsh::Layout() { 126 // Use the shorter maximized layout headers. 127 frame_painter_->LayoutHeader(this, true); 128 } 129 130 void CustomFrameViewAsh::OnPaint(gfx::Canvas* canvas) { 131 if (frame_->IsFullscreen()) 132 return; 133 134 // Prevent bleeding paint onto the client area below the window frame, which 135 // may become visible when the WebContent is transparent. 136 canvas->Save(); 137 canvas->ClipRect(gfx::Rect(0, 0, width(), NonClientTopBorderHeight())); 138 139 bool paint_as_active = ShouldPaintAsActive(); 140 int theme_image_id = 0; 141 if (frame_painter_->ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO)) 142 theme_image_id = IDR_AURA_WINDOW_HEADER_BASE_MINIMAL; 143 else if (paint_as_active) 144 theme_image_id = IDR_AURA_WINDOW_HEADER_BASE_ACTIVE; 145 else 146 theme_image_id = IDR_AURA_WINDOW_HEADER_BASE_INACTIVE; 147 148 frame_painter_->PaintHeader( 149 this, 150 canvas, 151 paint_as_active ? FramePainter::ACTIVE : FramePainter::INACTIVE, 152 theme_image_id, 153 0); 154 frame_painter_->PaintTitleBar(this, canvas, GetTitleFont()); 155 frame_painter_->PaintHeaderContentSeparator(this, canvas); 156 canvas->Restore(); 157 } 158 159 const char* CustomFrameViewAsh::GetClassName() const { 160 return kViewClassName; 161 } 162 163 gfx::Size CustomFrameViewAsh::GetMinimumSize() { 164 return frame_painter_->GetMinimumSize(this); 165 } 166 167 gfx::Size CustomFrameViewAsh::GetMaximumSize() { 168 return frame_painter_->GetMaximumSize(this); 169 } 170 171 //////////////////////////////////////////////////////////////////////////////// 172 // views::ButtonListener overrides: 173 void CustomFrameViewAsh::ButtonPressed(views::Button* sender, 174 const ui::Event& event) { 175 scoped_ptr<ui::ScopedAnimationDurationScaleMode> slow_duration_mode; 176 if (event.IsShiftDown()) { 177 slow_duration_mode.reset(new ui::ScopedAnimationDurationScaleMode( 178 ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); 179 } 180 181 ash::UserMetricsAction action = 182 ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE; 183 184 if (sender == maximize_button_) { 185 // The maximize button may move out from under the cursor. 186 ResetWindowControls(); 187 if (frame_->IsMaximized()) { 188 action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE; 189 frame_->Restore(); 190 } else { 191 frame_->Maximize(); 192 } 193 // |this| may be deleted - some windows delete their frames on maximize. 194 } else if (sender == close_button_) { 195 action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK; 196 frame_->Close(); 197 } else { 198 return; 199 } 200 201 ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction(action); 202 } 203 204 //////////////////////////////////////////////////////////////////////////////// 205 // CustomFrameViewAsh, private: 206 207 int CustomFrameViewAsh::NonClientTopBorderHeight() const { 208 if (frame_->IsFullscreen()) 209 return 0; 210 211 // Reserve enough space to see the buttons, including any offset from top and 212 // reserving space for the separator line. 213 return close_button_->bounds().bottom() + 214 frame_painter_->HeaderContentSeparatorSize(); 215 } 216 217 } // namespace ash 218