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