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