| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/constrained_window_views.h" | 5 #include "chrome/browser/ui/views/constrained_window_views.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "chrome/browser/themes/theme_properties.h" | |
| 10 #include "chrome/browser/ui/browser_finder.h" | 9 #include "chrome/browser/ui/browser_finder.h" |
| 11 #include "chrome/browser/ui/views/theme_image_mapper.h" | |
| 12 #include "components/web_modal/web_contents_modal_dialog_host.h" | 10 #include "components/web_modal/web_contents_modal_dialog_host.h" |
| 13 #include "grit/theme_resources.h" | |
| 14 #include "grit/ui_resources.h" | |
| 15 #include "ui/base/hit_test.h" | |
| 16 #include "ui/base/resource/resource_bundle.h" | |
| 17 #include "ui/gfx/canvas.h" | |
| 18 #include "ui/gfx/font.h" | |
| 19 #include "ui/views/border.h" | 11 #include "ui/views/border.h" |
| 20 #include "ui/views/color_constants.h" | |
| 21 #include "ui/views/controls/button/image_button.h" | |
| 22 #include "ui/views/widget/widget.h" | 12 #include "ui/views/widget/widget.h" |
| 23 #include "ui/views/widget/widget_observer.h" | 13 #include "ui/views/widget/widget_observer.h" |
| 24 #include "ui/views/window/dialog_delegate.h" | 14 #include "ui/views/window/dialog_delegate.h" |
| 25 #include "ui/views/window/frame_background.h" | |
| 26 #include "ui/views/window/window_resources.h" | |
| 27 #include "ui/views/window/window_shape.h" | |
| 28 | |
| 29 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 30 #include "ui/base/win/shell.h" | |
| 31 #include "ui/views/widget/native_widget_win.h" | |
| 32 #endif | |
| 33 | |
| 34 #if defined(USE_AURA) | |
| 35 #include "ui/aura/window.h" | |
| 36 #endif | |
| 37 | |
| 38 #if defined(USE_ASH) | |
| 39 #include "ash/wm/custom_frame_view_ash.h" | |
| 40 #endif | |
| 41 | 15 |
| 42 using web_modal::ModalDialogHost; | 16 using web_modal::ModalDialogHost; |
| 43 using web_modal::ModalDialogHostObserver; | 17 using web_modal::ModalDialogHostObserver; |
| 44 | 18 |
| 45 namespace { | 19 namespace { |
| 46 // The name of a key to store on the window handle to associate | 20 // The name of a key to store on the window handle to associate |
| 47 // BrowserModalDialogHostObserverViews with the Widget. | 21 // BrowserModalDialogHostObserverViews with the Widget. |
| 48 const char* const kBrowserModalDialogHostObserverViewsKey = | 22 const char* const kBrowserModalDialogHostObserverViewsKey = |
| 49 "__BROWSER_MODAL_DIALOG_HOST_OBSERVER_VIEWS__"; | 23 "__BROWSER_MODAL_DIALOG_HOST_OBSERVER_VIEWS__"; |
| 50 | 24 |
| 51 // Applies positioning changes from the ModalDialogHost to the Widget. | 25 // Applies positioning changes from the ModalDialogHost to the Widget. |
| 52 class BrowserModalDialogHostObserverViews | 26 class BrowserModalDialogHostObserverViews |
| 53 : public views::WidgetObserver, | 27 : public views::WidgetObserver, |
| 54 public ModalDialogHostObserver { | 28 public ModalDialogHostObserver { |
| 55 public: | 29 public: |
| 56 BrowserModalDialogHostObserverViews( | 30 BrowserModalDialogHostObserverViews(ModalDialogHost* host, |
| 57 ModalDialogHost* host, | 31 views::Widget* target_widget, |
| 58 views::Widget* target_widget, | 32 const char *const native_window_property) |
| 59 const char *const native_window_property) | |
| 60 : host_(host), | 33 : host_(host), |
| 61 target_widget_(target_widget), | 34 target_widget_(target_widget), |
| 62 native_window_property_(native_window_property) { | 35 native_window_property_(native_window_property) { |
| 63 DCHECK(host_); | 36 DCHECK(host_); |
| 64 DCHECK(target_widget_); | 37 DCHECK(target_widget_); |
| 65 host_->AddObserver(this); | 38 host_->AddObserver(this); |
| 66 target_widget_->AddObserver(this); | 39 target_widget_->AddObserver(this); |
| 67 } | 40 } |
| 68 | 41 |
| 69 virtual ~BrowserModalDialogHostObserverViews() { | 42 virtual ~BrowserModalDialogHostObserverViews() { |
| 70 if (host_) | 43 if (host_) |
| 71 host_->RemoveObserver(this); | 44 host_->RemoveObserver(this); |
| 72 target_widget_->RemoveObserver(this); | 45 target_widget_->RemoveObserver(this); |
| 73 target_widget_->SetNativeWindowProperty(native_window_property_, | 46 target_widget_->SetNativeWindowProperty(native_window_property_, NULL); |
| 74 NULL); | |
| 75 } | 47 } |
| 76 | 48 |
| 77 // WidgetObserver overrides | 49 // WidgetObserver overrides |
| 78 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE { | 50 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE { |
| 79 delete this; | 51 delete this; |
| 80 } | 52 } |
| 81 | 53 |
| 82 // WebContentsModalDialogHostObserver overrides | 54 // WebContentsModalDialogHostObserver overrides |
| 83 virtual void OnPositionRequiresUpdate() OVERRIDE { | 55 virtual void OnPositionRequiresUpdate() OVERRIDE { |
| 84 UpdateBrowserModalDialogPosition(target_widget_, host_); | 56 UpdateBrowserModalDialogPosition(target_widget_, host_); |
| 85 } | 57 } |
| 86 | 58 |
| 87 virtual void OnHostDestroying() OVERRIDE { | 59 virtual void OnHostDestroying() OVERRIDE { |
| 88 host_->RemoveObserver(this); | 60 host_->RemoveObserver(this); |
| 89 host_ = NULL; | 61 host_ = NULL; |
| 90 } | 62 } |
| 91 | 63 |
| 92 private: | 64 private: |
| 93 ModalDialogHost* host_; | 65 ModalDialogHost* host_; |
| 94 views::Widget* target_widget_; | 66 views::Widget* target_widget_; |
| 95 const char* const native_window_property_; | 67 const char* const native_window_property_; |
| 96 | 68 |
| 97 DISALLOW_COPY_AND_ASSIGN(BrowserModalDialogHostObserverViews); | 69 DISALLOW_COPY_AND_ASSIGN(BrowserModalDialogHostObserverViews); |
| 98 }; | 70 }; |
| 99 | 71 |
| 100 void UpdateModalDialogPosition( | 72 void UpdateModalDialogPosition(views::Widget* widget, |
| 101 views::Widget* widget, | 73 web_modal::ModalDialogHost* dialog_host, |
| 102 web_modal::ModalDialogHost* dialog_host, | 74 const gfx::Size& size) { |
| 103 const gfx::Size& size) { | |
| 104 // Do not forcibly update the dialog widget position if it is being dragged. | 75 // Do not forcibly update the dialog widget position if it is being dragged. |
| 105 if (widget->HasCapture()) | 76 if (widget->HasCapture()) |
| 106 return; | 77 return; |
| 107 | 78 |
| 108 gfx::Point position = dialog_host->GetDialogPosition(size); | 79 gfx::Point position = dialog_host->GetDialogPosition(size); |
| 109 views::Border* border = | 80 views::Border* border = widget->non_client_view()->frame_view()->border(); |
| 110 widget->non_client_view()->frame_view()->border(); | |
| 111 // Border may be null during widget initialization. | 81 // Border may be null during widget initialization. |
| 112 if (border) { | 82 if (border) { |
| 113 // Align the first row of pixels inside the border. This is the apparent | 83 // Align the first row of pixels inside the border. This is the apparent |
| 114 // top of the dialog. | 84 // top of the dialog. |
| 115 position.set_y(position.y() - border->GetInsets().top()); | 85 position.set_y(position.y() - border->GetInsets().top()); |
| 116 } | 86 } |
| 117 | 87 |
| 118 if (widget->is_top_level()) { | 88 if (widget->is_top_level()) { |
| 119 position += | 89 position += |
| 120 views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())-> | 90 views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())-> |
| 121 GetClientAreaBoundsInScreen().OffsetFromOrigin(); | 91 GetClientAreaBoundsInScreen().OffsetFromOrigin(); |
| 122 } | 92 } |
| 123 | 93 |
| 124 widget->SetBounds(gfx::Rect(position, size)); | 94 widget->SetBounds(gfx::Rect(position, size)); |
| 125 } | 95 } |
| 126 | 96 |
| 127 } // namespace | 97 } // namespace |
| 128 | 98 |
| 129 // An enumeration of image resources used by this window. | |
| 130 enum { | |
| 131 FRAME_PART_IMAGE_FIRST = 0, // Must be first. | |
| 132 | |
| 133 // Window Frame Border. | |
| 134 FRAME_BOTTOM_EDGE, | |
| 135 FRAME_BOTTOM_LEFT_CORNER, | |
| 136 FRAME_BOTTOM_RIGHT_CORNER, | |
| 137 FRAME_LEFT_EDGE, | |
| 138 FRAME_RIGHT_EDGE, | |
| 139 FRAME_TOP_EDGE, | |
| 140 FRAME_TOP_LEFT_CORNER, | |
| 141 FRAME_TOP_RIGHT_CORNER, | |
| 142 | |
| 143 FRAME_PART_IMAGE_COUNT // Must be last. | |
| 144 }; | |
| 145 | |
| 146 static const int kXPFramePartIDs[] = { | |
| 147 0, | |
| 148 IDR_WINDOW_BOTTOM_CENTER, IDR_WINDOW_BOTTOM_LEFT_CORNER, | |
| 149 IDR_WINDOW_BOTTOM_RIGHT_CORNER, IDR_WINDOW_LEFT_SIDE, | |
| 150 IDR_WINDOW_RIGHT_SIDE, IDR_WINDOW_TOP_CENTER, | |
| 151 IDR_WINDOW_TOP_LEFT_CORNER, IDR_WINDOW_TOP_RIGHT_CORNER, | |
| 152 0 }; | |
| 153 static const int kVistaFramePartIDs[] = { | |
| 154 0, | |
| 155 IDR_CONSTRAINED_BOTTOM_CENTER_V, IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V, | |
| 156 IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V, IDR_CONSTRAINED_LEFT_SIDE_V, | |
| 157 IDR_CONSTRAINED_RIGHT_SIDE_V, IDR_CONSTRAINED_TOP_CENTER_V, | |
| 158 IDR_CONSTRAINED_TOP_LEFT_CORNER_V, IDR_CONSTRAINED_TOP_RIGHT_CORNER_V, | |
| 159 0 }; | |
| 160 | |
| 161 class XPWindowResources : public views::WindowResources { | |
| 162 public: | |
| 163 XPWindowResources() { | |
| 164 InitClass(); | |
| 165 } | |
| 166 virtual ~XPWindowResources() {} | |
| 167 | |
| 168 virtual gfx::ImageSkia* GetPartImage( | |
| 169 views::FramePartImage part_id) const OVERRIDE { | |
| 170 return images_[part_id]; | |
| 171 } | |
| 172 | |
| 173 private: | |
| 174 static void InitClass() { | |
| 175 static bool initialized = false; | |
| 176 if (!initialized) { | |
| 177 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 178 for (int i = 0; i < FRAME_PART_IMAGE_COUNT; ++i) { | |
| 179 int id = kXPFramePartIDs[i]; | |
| 180 if (id != 0) | |
| 181 images_[i] = rb.GetImageSkiaNamed(id); | |
| 182 } | |
| 183 initialized = true; | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 static gfx::ImageSkia* images_[FRAME_PART_IMAGE_COUNT]; | |
| 188 | |
| 189 DISALLOW_COPY_AND_ASSIGN(XPWindowResources); | |
| 190 }; | |
| 191 | |
| 192 class VistaWindowResources : public views::WindowResources { | |
| 193 public: | |
| 194 VistaWindowResources() { | |
| 195 InitClass(); | |
| 196 } | |
| 197 virtual ~VistaWindowResources() {} | |
| 198 | |
| 199 virtual gfx::ImageSkia* GetPartImage( | |
| 200 views::FramePartImage part_id) const OVERRIDE { | |
| 201 return images_[part_id]; | |
| 202 } | |
| 203 | |
| 204 private: | |
| 205 static void InitClass() { | |
| 206 static bool initialized = false; | |
| 207 if (!initialized) { | |
| 208 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 209 for (int i = 0; i < FRAME_PART_IMAGE_COUNT; ++i) { | |
| 210 int id = kVistaFramePartIDs[i]; | |
| 211 if (id != 0) | |
| 212 images_[i] = rb.GetImageSkiaNamed(id); | |
| 213 } | |
| 214 initialized = true; | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 static gfx::ImageSkia* images_[FRAME_PART_IMAGE_COUNT]; | |
| 219 | |
| 220 DISALLOW_COPY_AND_ASSIGN(VistaWindowResources); | |
| 221 }; | |
| 222 | |
| 223 gfx::ImageSkia* XPWindowResources::images_[]; | |
| 224 gfx::ImageSkia* VistaWindowResources::images_[]; | |
| 225 | |
| 226 class ConstrainedWindowFrameView : public views::NonClientFrameView, | |
| 227 public views::ButtonListener { | |
| 228 public: | |
| 229 ConstrainedWindowFrameView(views::Widget* container, | |
| 230 bool browser_is_off_the_record); | |
| 231 virtual ~ConstrainedWindowFrameView(); | |
| 232 | |
| 233 virtual void UpdateWindowTitle() OVERRIDE; | |
| 234 | |
| 235 // Overridden from views::NonClientFrameView: | |
| 236 virtual gfx::Rect GetBoundsForClientView() const OVERRIDE; | |
| 237 virtual gfx::Rect GetWindowBoundsForClientBounds( | |
| 238 const gfx::Rect& client_bounds) const OVERRIDE; | |
| 239 virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE; | |
| 240 virtual void GetWindowMask(const gfx::Size& size, | |
| 241 gfx::Path* window_mask) OVERRIDE; | |
| 242 virtual void ResetWindowControls() OVERRIDE {} | |
| 243 virtual void UpdateWindowIcon() OVERRIDE {} | |
| 244 | |
| 245 // Overridden from views::View: | |
| 246 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; | |
| 247 virtual void Layout() OVERRIDE; | |
| 248 virtual void OnThemeChanged() OVERRIDE; | |
| 249 | |
| 250 // Overridden from views::ButtonListener: | |
| 251 virtual void ButtonPressed(views::Button* sender, | |
| 252 const ui::Event& event) OVERRIDE; | |
| 253 | |
| 254 private: | |
| 255 // Returns the thickness of the entire nonclient left, right, and bottom | |
| 256 // borders, including both the window frame and any client edge. | |
| 257 int NonClientBorderThickness() const; | |
| 258 | |
| 259 // Returns the height of the entire nonclient top border, including the window | |
| 260 // frame, any title area, and any connected client edge. | |
| 261 int NonClientTopBorderHeight() const; | |
| 262 | |
| 263 // Returns the thickness of the nonclient portion of the 3D edge along the | |
| 264 // bottom of the titlebar. | |
| 265 int TitlebarBottomThickness() const; | |
| 266 | |
| 267 // Returns what the size of the titlebar icon would be if there was one. | |
| 268 int IconSize() const; | |
| 269 | |
| 270 // Returns what the titlebar icon's bounds would be if there was one. | |
| 271 gfx::Rect IconBounds() const; | |
| 272 | |
| 273 // Paints different parts of the window to the incoming canvas. | |
| 274 void PaintFrameBorder(gfx::Canvas* canvas); | |
| 275 void PaintTitleBar(gfx::Canvas* canvas); | |
| 276 void PaintClientEdge(gfx::Canvas* canvas); | |
| 277 | |
| 278 // Layout various sub-components of this view. | |
| 279 void LayoutWindowControls(); | |
| 280 void LayoutTitleBar(); | |
| 281 | |
| 282 // Returns the bounds of the client area for the specified view size. | |
| 283 gfx::Rect CalculateClientAreaBounds(int width, int height) const; | |
| 284 | |
| 285 SkColor GetTitleColor() const { | |
| 286 return browser_is_off_the_record_ | |
| 287 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 288 || !ui::win::IsAeroGlassEnabled() | |
| 289 #endif | |
| 290 ? SK_ColorWHITE : SK_ColorBLACK; | |
| 291 } | |
| 292 | |
| 293 // Loads the appropriate set of WindowResources for the frame view. | |
| 294 void InitWindowResources(); | |
| 295 | |
| 296 views::Widget* container_; | |
| 297 | |
| 298 bool browser_is_off_the_record_; | |
| 299 | |
| 300 scoped_ptr<views::WindowResources> resources_; | |
| 301 | |
| 302 gfx::Rect title_bounds_; | |
| 303 | |
| 304 views::ImageButton* close_button_; | |
| 305 | |
| 306 // The bounds of the ClientView. | |
| 307 gfx::Rect client_view_bounds_; | |
| 308 | |
| 309 // Background painter for the frame. | |
| 310 scoped_ptr<views::FrameBackground> frame_background_; | |
| 311 | |
| 312 static void InitClass(); | |
| 313 | |
| 314 // The font to be used to render the titlebar text. | |
| 315 static const gfx::Font* title_font_; | |
| 316 | |
| 317 DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowFrameView); | |
| 318 }; | |
| 319 | |
| 320 const gfx::Font* ConstrainedWindowFrameView::title_font_ = NULL; | |
| 321 | |
| 322 namespace { | |
| 323 // The frame border is only visible in restored mode and is hardcoded to 4 px on | |
| 324 // each side regardless of the system window border size. | |
| 325 const int kFrameBorderThickness = 4; | |
| 326 // In the window corners, the resize areas don't actually expand bigger, but the | |
| 327 // 16 px at the end of each edge triggers diagonal resizing. | |
| 328 const int kResizeAreaCornerSize = 16; | |
| 329 // The titlebar never shrinks too short to show the caption button plus some | |
| 330 // padding below it. | |
| 331 const int kCaptionButtonHeightWithPadding = 19; | |
| 332 // The titlebar has a 2 px 3D edge along the top and bottom. | |
| 333 const int kTitlebarTopAndBottomEdgeThickness = 2; | |
| 334 // The icon would never shrink below 16 px on a side, if there was one. | |
| 335 const int kIconMinimumSize = 16; | |
| 336 // The title text starts 2 px from the right edge of the left frame border. | |
| 337 const int kTitleLeftSpacing = 2; | |
| 338 // There is a 5 px gap between the title text and the caption buttons. | |
| 339 const int kTitleCaptionSpacing = 5; | |
| 340 | |
| 341 const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0); | |
| 342 | |
| 343 } // namespace | |
| 344 | |
| 345 ConstrainedWindowFrameView::ConstrainedWindowFrameView( | |
| 346 views::Widget* container, bool browser_is_off_the_record) | |
| 347 : NonClientFrameView(), | |
| 348 container_(container), | |
| 349 browser_is_off_the_record_(browser_is_off_the_record), | |
| 350 close_button_(new views::ImageButton(this)), | |
| 351 frame_background_(new views::FrameBackground()) { | |
| 352 InitClass(); | |
| 353 InitWindowResources(); | |
| 354 | |
| 355 // Constrained windows always use the custom frame - they just have a | |
| 356 // different set of images. | |
| 357 container->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM); | |
| 358 | |
| 359 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 360 close_button_->SetImage(views::CustomButton::STATE_NORMAL, | |
| 361 rb.GetImageSkiaNamed(IDR_CLOSE_SA)); | |
| 362 close_button_->SetImage(views::CustomButton::STATE_HOVERED, | |
| 363 rb.GetImageSkiaNamed(IDR_CLOSE_SA_H)); | |
| 364 close_button_->SetImage(views::CustomButton::STATE_PRESSED, | |
| 365 rb.GetImageSkiaNamed(IDR_CLOSE_SA_P)); | |
| 366 close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
| 367 views::ImageButton::ALIGN_MIDDLE); | |
| 368 AddChildView(close_button_); | |
| 369 } | |
| 370 | |
| 371 ConstrainedWindowFrameView::~ConstrainedWindowFrameView() { | |
| 372 } | |
| 373 | |
| 374 void ConstrainedWindowFrameView::UpdateWindowTitle() { | |
| 375 SchedulePaintInRect(title_bounds_); | |
| 376 } | |
| 377 | |
| 378 gfx::Rect ConstrainedWindowFrameView::GetBoundsForClientView() const { | |
| 379 return client_view_bounds_; | |
| 380 } | |
| 381 | |
| 382 gfx::Rect ConstrainedWindowFrameView::GetWindowBoundsForClientBounds( | |
| 383 const gfx::Rect& client_bounds) const { | |
| 384 int top_height = NonClientTopBorderHeight(); | |
| 385 int border_thickness = NonClientBorderThickness(); | |
| 386 return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), | |
| 387 std::max(0, client_bounds.y() - top_height), | |
| 388 client_bounds.width() + (2 * border_thickness), | |
| 389 client_bounds.height() + top_height + border_thickness); | |
| 390 } | |
| 391 | |
| 392 int ConstrainedWindowFrameView::NonClientHitTest(const gfx::Point& point) { | |
| 393 if (!bounds().Contains(point)) | |
| 394 return HTNOWHERE; | |
| 395 | |
| 396 int frame_component = | |
| 397 container_->client_view()->NonClientHitTest(point); | |
| 398 | |
| 399 // See if we're in the sysmenu region. (We check the ClientView first to be | |
| 400 // consistent with OpaqueBrowserFrameView; it's not really necessary here.) | |
| 401 gfx::Rect sysmenu_rect(IconBounds()); | |
| 402 sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect)); | |
| 403 if (sysmenu_rect.Contains(point)) | |
| 404 return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU; | |
| 405 | |
| 406 if (frame_component != HTNOWHERE) | |
| 407 return frame_component; | |
| 408 | |
| 409 // Then see if the point is within any of the window controls. | |
| 410 if (close_button_->GetMirroredBounds().Contains(point)) | |
| 411 return HTCLOSE; | |
| 412 | |
| 413 int window_component = GetHTComponentForFrame(point, kFrameBorderThickness, | |
| 414 NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, | |
| 415 container_->widget_delegate()->CanResize()); | |
| 416 // Fall back to the caption if no other component matches. | |
| 417 return (window_component == HTNOWHERE) ? HTCAPTION : window_component; | |
| 418 } | |
| 419 | |
| 420 void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size, | |
| 421 gfx::Path* window_mask) { | |
| 422 DCHECK(window_mask); | |
| 423 views::GetDefaultWindowMask(size, window_mask); | |
| 424 } | |
| 425 | |
| 426 void ConstrainedWindowFrameView::OnPaint(gfx::Canvas* canvas) { | |
| 427 PaintFrameBorder(canvas); | |
| 428 PaintTitleBar(canvas); | |
| 429 PaintClientEdge(canvas); | |
| 430 } | |
| 431 | |
| 432 void ConstrainedWindowFrameView::Layout() { | |
| 433 LayoutWindowControls(); | |
| 434 LayoutTitleBar(); | |
| 435 client_view_bounds_ = CalculateClientAreaBounds(width(), height()); | |
| 436 } | |
| 437 | |
| 438 void ConstrainedWindowFrameView::OnThemeChanged() { | |
| 439 InitWindowResources(); | |
| 440 } | |
| 441 | |
| 442 void ConstrainedWindowFrameView::ButtonPressed( | |
| 443 views::Button* sender, const ui::Event& event) { | |
| 444 if (sender == close_button_) | |
| 445 container_->Close(); | |
| 446 } | |
| 447 | |
| 448 int ConstrainedWindowFrameView::NonClientBorderThickness() const { | |
| 449 return kFrameBorderThickness + kClientEdgeThickness; | |
| 450 } | |
| 451 | |
| 452 int ConstrainedWindowFrameView::NonClientTopBorderHeight() const { | |
| 453 return std::max(kFrameBorderThickness + IconSize(), | |
| 454 kFrameShadowThickness + kCaptionButtonHeightWithPadding) + | |
| 455 TitlebarBottomThickness(); | |
| 456 } | |
| 457 | |
| 458 int ConstrainedWindowFrameView::TitlebarBottomThickness() const { | |
| 459 return kTitlebarTopAndBottomEdgeThickness + kClientEdgeThickness; | |
| 460 } | |
| 461 | |
| 462 int ConstrainedWindowFrameView::IconSize() const { | |
| 463 #if defined(OS_WIN) | |
| 464 // This metric scales up if either the titlebar height or the titlebar font | |
| 465 // size are increased. | |
| 466 return GetSystemMetrics(SM_CYSMICON); | |
| 467 #else | |
| 468 return std::max(title_font_->GetHeight(), kIconMinimumSize); | |
| 469 #endif | |
| 470 } | |
| 471 | |
| 472 gfx::Rect ConstrainedWindowFrameView::IconBounds() const { | |
| 473 int size = IconSize(); | |
| 474 // Our frame border has a different "3D look" than Windows'. Theirs has a | |
| 475 // more complex gradient on the top that they push their icon/title below; | |
| 476 // then the maximized window cuts this off and the icon/title are centered | |
| 477 // in the remaining space. Because the apparent shape of our border is | |
| 478 // simpler, using the same positioning makes things look slightly uncentered | |
| 479 // with restored windows, so instead of calculating the remaining space from | |
| 480 // below the frame border, we calculate from below the 3D edge. | |
| 481 int unavailable_px_at_top = kTitlebarTopAndBottomEdgeThickness; | |
| 482 // When the icon is shorter than the minimum space we reserve for the caption | |
| 483 // button, we vertically center it. We want to bias rounding to put extra | |
| 484 // space above the icon, since the 3D edge + client edge below looks (to the | |
| 485 // eye) more like additional space than does the 3D edge above; hence the +1. | |
| 486 int y = unavailable_px_at_top + (NonClientTopBorderHeight() - | |
| 487 unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2; | |
| 488 return gfx::Rect(kFrameBorderThickness + kTitleLeftSpacing, y, size, size); | |
| 489 } | |
| 490 | |
| 491 void ConstrainedWindowFrameView::PaintFrameBorder(gfx::Canvas* canvas) { | |
| 492 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 493 frame_background_->set_frame_color(ThemeProperties::GetDefaultColor( | |
| 494 ThemeProperties::COLOR_FRAME)); | |
| 495 chrome::HostDesktopType desktop_type = | |
| 496 chrome::GetHostDesktopTypeForNativeView(GetWidget()->GetNativeView()); | |
| 497 gfx::ImageSkia* theme_frame = rb.GetImageSkiaNamed( | |
| 498 chrome::MapThemeImage(desktop_type, IDR_THEME_FRAME)); | |
| 499 frame_background_->set_theme_image(theme_frame); | |
| 500 frame_background_->set_theme_overlay_image(NULL); | |
| 501 frame_background_->set_top_area_height(theme_frame->height()); | |
| 502 | |
| 503 frame_background_->SetCornerImages( | |
| 504 resources_->GetPartImage(FRAME_TOP_LEFT_CORNER), | |
| 505 resources_->GetPartImage(FRAME_TOP_RIGHT_CORNER), | |
| 506 resources_->GetPartImage(FRAME_BOTTOM_LEFT_CORNER), | |
| 507 resources_->GetPartImage(FRAME_BOTTOM_RIGHT_CORNER)); | |
| 508 frame_background_->SetSideImages( | |
| 509 resources_->GetPartImage(FRAME_LEFT_EDGE), | |
| 510 resources_->GetPartImage(FRAME_TOP_EDGE), | |
| 511 resources_->GetPartImage(FRAME_RIGHT_EDGE), | |
| 512 resources_->GetPartImage(FRAME_BOTTOM_EDGE)); | |
| 513 frame_background_->PaintRestored(canvas, this); | |
| 514 } | |
| 515 | |
| 516 void ConstrainedWindowFrameView::PaintTitleBar(gfx::Canvas* canvas) { | |
| 517 canvas->DrawStringInt( | |
| 518 container_->widget_delegate()->GetWindowTitle(), | |
| 519 *title_font_, GetTitleColor(), GetMirroredXForRect(title_bounds_), | |
| 520 title_bounds_.y(), title_bounds_.width(), title_bounds_.height()); | |
| 521 } | |
| 522 | |
| 523 void ConstrainedWindowFrameView::PaintClientEdge(gfx::Canvas* canvas) { | |
| 524 gfx::Rect client_edge_bounds(CalculateClientAreaBounds(width(), height())); | |
| 525 client_edge_bounds.Inset(-kClientEdgeThickness, -kClientEdgeThickness); | |
| 526 gfx::Rect frame_shadow_bounds(client_edge_bounds); | |
| 527 frame_shadow_bounds.Inset(-kFrameShadowThickness, -kFrameShadowThickness); | |
| 528 | |
| 529 canvas->FillRect(frame_shadow_bounds, kContentsBorderShadow); | |
| 530 canvas->FillRect(client_edge_bounds, views::kClientEdgeColor); | |
| 531 } | |
| 532 | |
| 533 void ConstrainedWindowFrameView::LayoutWindowControls() { | |
| 534 gfx::Size close_button_size = close_button_->GetPreferredSize(); | |
| 535 close_button_->SetBounds( | |
| 536 width() - kFrameBorderThickness - close_button_size.width(), | |
| 537 kFrameShadowThickness, close_button_size.width(), | |
| 538 close_button_size.height()); | |
| 539 } | |
| 540 | |
| 541 void ConstrainedWindowFrameView::LayoutTitleBar() { | |
| 542 // The window title is based on the calculated icon position, even though' | |
| 543 // there is no icon in constrained windows. | |
| 544 gfx::Rect icon_bounds(IconBounds()); | |
| 545 int title_x = icon_bounds.x(); | |
| 546 int title_height = title_font_->GetHeight(); | |
| 547 // We bias the title position so that when the difference between the icon and | |
| 548 // title heights is odd, the extra pixel of the title is above the vertical | |
| 549 // midline rather than below. This compensates for how the icon is already | |
| 550 // biased downwards (see IconBounds()) and helps prevent descenders on the | |
| 551 // title from overlapping the 3D edge at the bottom of the titlebar. | |
| 552 title_bounds_.SetRect(title_x, | |
| 553 icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2), | |
| 554 std::max(0, close_button_->x() - kTitleCaptionSpacing - title_x), | |
| 555 title_height); | |
| 556 } | |
| 557 | |
| 558 gfx::Rect ConstrainedWindowFrameView::CalculateClientAreaBounds( | |
| 559 int width, | |
| 560 int height) const { | |
| 561 int top_height = NonClientTopBorderHeight(); | |
| 562 int border_thickness = NonClientBorderThickness(); | |
| 563 return gfx::Rect(border_thickness, top_height, | |
| 564 std::max(0, width - (2 * border_thickness)), | |
| 565 std::max(0, height - top_height - border_thickness)); | |
| 566 } | |
| 567 | |
| 568 void ConstrainedWindowFrameView::InitWindowResources() { | |
| 569 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 570 resources_.reset(ui::win::IsAeroGlassEnabled() ? | |
| 571 static_cast<views::WindowResources*>(new VistaWindowResources) : | |
| 572 new XPWindowResources); | |
| 573 #else | |
| 574 // TODO(oshima): Use aura frame decoration. | |
| 575 resources_.reset(new XPWindowResources); | |
| 576 #endif | |
| 577 } | |
| 578 | |
| 579 // static | |
| 580 void ConstrainedWindowFrameView::InitClass() { | |
| 581 static bool initialized = false; | |
| 582 if (!initialized) { | |
| 583 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 584 title_font_ = new gfx::Font(views::NativeWidgetWin::GetWindowTitleFont()); | |
| 585 #else | |
| 586 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 587 title_font_ = &rb.GetFont(ui::ResourceBundle::MediumFont); | |
| 588 #endif | |
| 589 initialized = true; | |
| 590 } | |
| 591 } | |
| 592 | |
| 593 void UpdateWebContentsModalDialogPosition( | 99 void UpdateWebContentsModalDialogPosition( |
| 594 views::Widget* widget, | 100 views::Widget* widget, |
| 595 web_modal::WebContentsModalDialogHost* dialog_host) { | 101 web_modal::WebContentsModalDialogHost* dialog_host) { |
| 596 gfx::Size size = widget->GetRootView()->GetPreferredSize(); | 102 gfx::Size size = widget->GetRootView()->GetPreferredSize(); |
| 597 gfx::Size max_size = dialog_host->GetMaximumDialogSize(); | 103 gfx::Size max_size = dialog_host->GetMaximumDialogSize(); |
| 598 // Enlarge the max size by the top border, as the dialog will be shifted | 104 // Enlarge the max size by the top border, as the dialog will be shifted |
| 599 // outside the area specified by the dialog host by this amount later. | 105 // outside the area specified by the dialog host by this amount later. |
| 600 views::Border* border = | 106 views::Border* border = |
| 601 widget->non_client_view()->frame_view()->border(); | 107 widget->non_client_view()->frame_view()->border(); |
| 602 // Border may be null during widget initialization. | 108 // Border may be null during widget initialization. |
| 603 if (border) | 109 if (border) |
| 604 max_size.Enlarge(0, border->GetInsets().top()); | 110 max_size.Enlarge(0, border->GetInsets().top()); |
| 605 size.SetToMin(max_size); | 111 size.SetToMin(max_size); |
| 606 UpdateModalDialogPosition(widget, dialog_host, size); | 112 UpdateModalDialogPosition(widget, dialog_host, size); |
| 607 } | 113 } |
| 608 | 114 |
| 609 void UpdateBrowserModalDialogPosition( | 115 void UpdateBrowserModalDialogPosition(views::Widget* widget, |
| 610 views::Widget* widget, | 116 web_modal::ModalDialogHost* dialog_host) { |
| 611 web_modal::ModalDialogHost* dialog_host) { | 117 UpdateModalDialogPosition(widget, dialog_host, |
| 612 UpdateModalDialogPosition(widget, | |
| 613 dialog_host, | |
| 614 widget->GetRootView()->GetPreferredSize()); | 118 widget->GetRootView()->GetPreferredSize()); |
| 615 } | 119 } |
| 616 | 120 |
| 617 views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, | 121 views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, |
| 618 gfx::NativeWindow parent) { | 122 gfx::NativeWindow parent) { |
| 619 views::Widget* widget = | 123 views::Widget* widget = |
| 620 views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent); | 124 views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent); |
| 621 if (!dialog->UseNewStyleForThisDialog()) | 125 if (!dialog->UseNewStyleForThisDialog()) |
| 622 return widget; | 126 return widget; |
| 623 | 127 |
| 624 // Get the browser dialog management and hosting components from |parent|. | 128 // Get the browser dialog management and hosting components from |parent|. |
| 625 Browser* browser = chrome::FindBrowserWithWindow(parent); | 129 Browser* browser = chrome::FindBrowserWithWindow(parent); |
| 626 if (browser) { | 130 if (browser) { |
| 627 ChromeWebModalDialogManagerDelegate* manager = browser; | 131 ChromeWebModalDialogManagerDelegate* manager = browser; |
| 628 ModalDialogHost* host = manager->GetWebContentsModalDialogHost(); | 132 ModalDialogHost* host = manager->GetWebContentsModalDialogHost(); |
| 629 DCHECK_EQ(parent, host->GetHostView()); | 133 DCHECK_EQ(parent, host->GetHostView()); |
| 630 ModalDialogHostObserver* dialog_host_observer = | 134 ModalDialogHostObserver* dialog_host_observer = |
| 631 new BrowserModalDialogHostObserverViews( | 135 new BrowserModalDialogHostObserverViews( |
| 632 host, widget, kBrowserModalDialogHostObserverViewsKey); | 136 host, widget, kBrowserModalDialogHostObserverViewsKey); |
| 633 dialog_host_observer->OnPositionRequiresUpdate(); | 137 dialog_host_observer->OnPositionRequiresUpdate(); |
| 634 } | 138 } |
| 635 return widget; | 139 return widget; |
| 636 } | 140 } |
| 637 | 141 |
| 638 views::NonClientFrameView* CreateConstrainedStyleNonClientFrameView( | 142 views::NonClientFrameView* CreateConstrainedStyleNonClientFrameView( |
| 639 views::Widget* widget, | 143 views::Widget* widget, |
| 640 content::BrowserContext* browser_context) { | 144 content::BrowserContext* browser_context) { |
| 641 if (views::DialogDelegate::UseNewStyle()) { | 145 bool force_opaque = true; |
| 642 #if defined(USE_AURA) | 146 #if defined(USE_AURA) |
| 643 const bool force_opaque_border = false; | 147 force_opaque = false; |
| 644 #else | |
| 645 const bool force_opaque_border = true; | |
| 646 #endif | 148 #endif |
| 647 return views::DialogDelegate::CreateNewStyleFrameView(widget, | 149 return views::DialogDelegate::CreateDialogFrameView(widget, force_opaque); |
| 648 force_opaque_border); | |
| 649 } | |
| 650 #if defined(USE_ASH) | |
| 651 ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh(widget); | |
| 652 // Always use "active" look. | |
| 653 frame->SetInactiveRenderingDisabled(true); | |
| 654 return frame; | |
| 655 #endif | |
| 656 return new ConstrainedWindowFrameView(widget, | |
| 657 browser_context->IsOffTheRecord()); | |
| 658 } | 150 } |
| OLD | NEW |