| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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/views/constrained_window_impl.h" | |
| 6 | |
| 7 #include "app/gfx/canvas.h" | |
| 8 #include "app/gfx/font.h" | |
| 9 #include "app/gfx/path.h" | |
| 10 #include "app/gfx/text_elider.h" | |
| 11 #include "app/l10n_util.h" | |
| 12 #include "app/resource_bundle.h" | |
| 13 #include "app/win_util.h" | |
| 14 #include "base/gfx/rect.h" | |
| 15 #include "chrome/app/chrome_dll_resource.h" | |
| 16 #include "chrome/browser/browser_process.h" | |
| 17 #include "chrome/browser/profile.h" | |
| 18 #include "chrome/browser/tab_contents/tab_contents.h" | |
| 19 #include "chrome/browser/tab_contents/tab_contents.h" | |
| 20 #include "chrome/browser/tab_contents/tab_contents_view.h" | |
| 21 #include "chrome/browser/toolbar_model.h" | |
| 22 #include "chrome/browser/views/frame/browser_view.h" | |
| 23 #include "chrome/browser/window_sizer.h" | |
| 24 #include "chrome/common/chrome_constants.h" | |
| 25 #include "chrome/common/notification_service.h" | |
| 26 #include "chrome/common/pref_names.h" | |
| 27 #include "chrome/common/pref_service.h" | |
| 28 #include "grit/app_resources.h" | |
| 29 #include "grit/chromium_strings.h" | |
| 30 #include "grit/generated_resources.h" | |
| 31 #include "grit/theme_resources.h" | |
| 32 #include "net/base/net_util.h" | |
| 33 #include "views/controls/button/image_button.h" | |
| 34 #include "views/focus/focus_manager.h" | |
| 35 #include "views/window/client_view.h" | |
| 36 #include "views/window/non_client_view.h" | |
| 37 #include "views/window/window_resources.h" | |
| 38 | |
| 39 using base::TimeDelta; | |
| 40 | |
| 41 namespace views { | |
| 42 class ClientView; | |
| 43 } | |
| 44 | |
| 45 // An enumeration of bitmap resources used by this window. | |
| 46 enum { | |
| 47 FRAME_PART_BITMAP_FIRST = 0, // Must be first. | |
| 48 | |
| 49 // Window Controls. | |
| 50 FRAME_CLOSE_BUTTON_ICON, | |
| 51 FRAME_CLOSE_BUTTON_ICON_H, | |
| 52 FRAME_CLOSE_BUTTON_ICON_P, | |
| 53 | |
| 54 // Window Frame Border. | |
| 55 FRAME_BOTTOM_EDGE, | |
| 56 FRAME_BOTTOM_LEFT_CORNER, | |
| 57 FRAME_BOTTOM_RIGHT_CORNER, | |
| 58 FRAME_LEFT_EDGE, | |
| 59 FRAME_RIGHT_EDGE, | |
| 60 FRAME_TOP_EDGE, | |
| 61 FRAME_TOP_LEFT_CORNER, | |
| 62 FRAME_TOP_RIGHT_CORNER, | |
| 63 | |
| 64 FRAME_WINDOW, | |
| 65 FRAME_WINDOW_INACTIVE, | |
| 66 FRAME_WINDOW_INCOGNITO, | |
| 67 FRAME_WINDOW_INCOGNITO_INACTIVE, | |
| 68 | |
| 69 FRAME_PART_BITMAP_COUNT // Must be last. | |
| 70 }; | |
| 71 | |
| 72 static const int kXPFramePartIDs[] = { | |
| 73 0, | |
| 74 IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, | |
| 75 IDR_WINDOW_BOTTOM_CENTER, IDR_WINDOW_BOTTOM_LEFT_CORNER, | |
| 76 IDR_WINDOW_BOTTOM_RIGHT_CORNER, IDR_WINDOW_LEFT_SIDE, | |
| 77 IDR_WINDOW_RIGHT_SIDE, IDR_WINDOW_TOP_CENTER, | |
| 78 IDR_WINDOW_TOP_LEFT_CORNER, IDR_WINDOW_TOP_RIGHT_CORNER, | |
| 79 IDR_THEME_FRAME, IDR_THEME_FRAME_INACTIVE, IDR_THEME_FRAME_INCOGNITO, | |
| 80 IDR_THEME_FRAME_INCOGNITO_INACTIVE, | |
| 81 0 }; | |
| 82 static const int kVistaFramePartIDs[] = { | |
| 83 0, | |
| 84 IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P, | |
| 85 IDR_CONSTRAINED_BOTTOM_CENTER_V, IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V, | |
| 86 IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V, IDR_CONSTRAINED_LEFT_SIDE_V, | |
| 87 IDR_CONSTRAINED_RIGHT_SIDE_V, IDR_CONSTRAINED_TOP_CENTER_V, | |
| 88 IDR_CONSTRAINED_TOP_LEFT_CORNER_V, IDR_CONSTRAINED_TOP_RIGHT_CORNER_V, | |
| 89 IDR_THEME_FRAME, IDR_THEME_FRAME_INACTIVE, IDR_THEME_FRAME_INCOGNITO, | |
| 90 IDR_THEME_FRAME_INCOGNITO_INACTIVE, | |
| 91 0 }; | |
| 92 | |
| 93 class XPWindowResources : public views::WindowResources { | |
| 94 public: | |
| 95 XPWindowResources() { | |
| 96 InitClass(); | |
| 97 } | |
| 98 virtual ~XPWindowResources() {} | |
| 99 | |
| 100 virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part_id) const { | |
| 101 return bitmaps_[part_id]; | |
| 102 } | |
| 103 | |
| 104 private: | |
| 105 static void InitClass() { | |
| 106 static bool initialized = false; | |
| 107 if (!initialized) { | |
| 108 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 109 for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) { | |
| 110 int id = kXPFramePartIDs[i]; | |
| 111 if (id != 0) | |
| 112 bitmaps_[i] = rb.GetBitmapNamed(id); | |
| 113 } | |
| 114 initialized = true; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 static SkBitmap* bitmaps_[FRAME_PART_BITMAP_COUNT]; | |
| 119 | |
| 120 DISALLOW_EVIL_CONSTRUCTORS(XPWindowResources); | |
| 121 }; | |
| 122 | |
| 123 class VistaWindowResources : public views::WindowResources { | |
| 124 public: | |
| 125 VistaWindowResources() { | |
| 126 InitClass(); | |
| 127 } | |
| 128 virtual ~VistaWindowResources() {} | |
| 129 | |
| 130 virtual SkBitmap* GetPartBitmap(views::FramePartBitmap part_id) const { | |
| 131 return bitmaps_[part_id]; | |
| 132 } | |
| 133 | |
| 134 private: | |
| 135 static void InitClass() { | |
| 136 static bool initialized = false; | |
| 137 if (!initialized) { | |
| 138 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 139 for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) { | |
| 140 int id = kVistaFramePartIDs[i]; | |
| 141 if (id != 0) | |
| 142 bitmaps_[i] = rb.GetBitmapNamed(id); | |
| 143 } | |
| 144 initialized = true; | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 static SkBitmap* bitmaps_[FRAME_PART_BITMAP_COUNT]; | |
| 149 | |
| 150 DISALLOW_EVIL_CONSTRUCTORS(VistaWindowResources); | |
| 151 }; | |
| 152 | |
| 153 SkBitmap* XPWindowResources::bitmaps_[]; | |
| 154 SkBitmap* VistaWindowResources::bitmaps_[]; | |
| 155 | |
| 156 //////////////////////////////////////////////////////////////////////////////// | |
| 157 // ConstrainedWindowFrameView | |
| 158 | |
| 159 class ConstrainedWindowFrameView | |
| 160 : public views::NonClientFrameView, | |
| 161 public views::ButtonListener { | |
| 162 public: | |
| 163 explicit ConstrainedWindowFrameView(ConstrainedWindowImpl* container); | |
| 164 virtual ~ConstrainedWindowFrameView(); | |
| 165 | |
| 166 void UpdateWindowTitle(); | |
| 167 | |
| 168 // Overridden from views::NonClientFrameView: | |
| 169 virtual gfx::Rect GetBoundsForClientView() const; | |
| 170 virtual bool AlwaysUseCustomFrame() const; | |
| 171 virtual gfx::Rect GetWindowBoundsForClientBounds( | |
| 172 const gfx::Rect& client_bounds) const; | |
| 173 virtual gfx::Point GetSystemMenuPoint() const; | |
| 174 virtual int NonClientHitTest(const gfx::Point& point); | |
| 175 virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask); | |
| 176 virtual void EnableClose(bool enable); | |
| 177 virtual void ResetWindowControls() { } | |
| 178 | |
| 179 // Overridden from views::View: | |
| 180 virtual void Paint(gfx::Canvas* canvas); | |
| 181 virtual void Layout(); | |
| 182 virtual void ThemeChanged(); | |
| 183 | |
| 184 // Overridden from views::ButtonListener: | |
| 185 virtual void ButtonPressed(views::Button* sender); | |
| 186 | |
| 187 private: | |
| 188 // Returns the thickness of the border that makes up the window frame edges. | |
| 189 // This does not include any client edge. | |
| 190 int FrameBorderThickness() const; | |
| 191 | |
| 192 // Returns the thickness of the entire nonclient left, right, and bottom | |
| 193 // borders, including both the window frame and any client edge. | |
| 194 int NonClientBorderThickness() const; | |
| 195 | |
| 196 // Returns the height of the entire nonclient top border, including the window | |
| 197 // frame, any title area, and any connected client edge. | |
| 198 int NonClientTopBorderHeight() const; | |
| 199 | |
| 200 // Calculates multiple values related to title layout. Returns the height of | |
| 201 // the entire titlebar including any connected client edge. | |
| 202 int TitleCoordinates(int* title_top_spacing, | |
| 203 int* title_thickness) const; | |
| 204 | |
| 205 // Paints different parts of the window to the incoming canvas. | |
| 206 void PaintFrameBorder(gfx::Canvas* canvas); | |
| 207 void PaintTitleBar(gfx::Canvas* canvas); | |
| 208 void PaintClientEdge(gfx::Canvas* canvas); | |
| 209 | |
| 210 // Layout various sub-components of this view. | |
| 211 void LayoutWindowControls(); | |
| 212 void LayoutTitleBar(); | |
| 213 void LayoutClientView(); | |
| 214 | |
| 215 // Returns the bounds of the client area for the specified view size. | |
| 216 gfx::Rect CalculateClientAreaBounds(int width, int height) const; | |
| 217 | |
| 218 SkColor GetTitleColor() const { | |
| 219 return (container_->owner()->profile()->IsOffTheRecord() || | |
| 220 !win_util::ShouldUseVistaFrame()) ? SK_ColorWHITE : SK_ColorBLACK; | |
| 221 } | |
| 222 | |
| 223 // Loads the appropriate set of WindowResources for the frame view. | |
| 224 void InitWindowResources(); | |
| 225 | |
| 226 ConstrainedWindowImpl* container_; | |
| 227 | |
| 228 scoped_ptr<views::WindowResources> resources_; | |
| 229 | |
| 230 gfx::Rect title_bounds_; | |
| 231 | |
| 232 views::ImageButton* close_button_; | |
| 233 | |
| 234 // The bounds of the ClientView. | |
| 235 gfx::Rect client_view_bounds_; | |
| 236 | |
| 237 static void InitClass(); | |
| 238 | |
| 239 // The font to be used to render the titlebar text. | |
| 240 static gfx::Font* title_font_; | |
| 241 | |
| 242 DISALLOW_EVIL_CONSTRUCTORS(ConstrainedWindowFrameView); | |
| 243 }; | |
| 244 | |
| 245 gfx::Font* ConstrainedWindowFrameView::title_font_ = NULL; | |
| 246 | |
| 247 namespace { | |
| 248 // The frame border is only visible in restored mode and is hardcoded to 4 px on | |
| 249 // each side regardless of the system window border size. | |
| 250 const int kFrameBorderThickness = 4; | |
| 251 // Various edges of the frame border have a 1 px shadow along their edges; in a | |
| 252 // few cases we shift elements based on this amount for visual appeal. | |
| 253 const int kFrameShadowThickness = 1; | |
| 254 // In the window corners, the resize areas don't actually expand bigger, but the | |
| 255 // 16 px at the end of each edge triggers diagonal resizing. | |
| 256 const int kResizeAreaCornerSize = 16; | |
| 257 // The titlebar never shrinks to less than 20 px tall, including the height of | |
| 258 // the frame border and client edge. | |
| 259 const int kTitlebarMinimumHeight = 20; | |
| 260 // The icon is inset 2 px from the left frame border. | |
| 261 const int kIconLeftSpacing = 2; | |
| 262 // The title text starts 2 px below the bottom of the top frame border. | |
| 263 const int kTitleTopSpacing = 2; | |
| 264 // There is a 5 px gap between the title text and the caption buttons. | |
| 265 const int kTitleCaptionSpacing = 5; | |
| 266 // The caption buttons are always drawn 1 px down from the visible top of the | |
| 267 // window (the true top in restored mode, or the top of the screen in maximized | |
| 268 // mode). | |
| 269 const int kCaptionTopSpacing = 1; | |
| 270 | |
| 271 const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0); | |
| 272 } | |
| 273 | |
| 274 //////////////////////////////////////////////////////////////////////////////// | |
| 275 // ConstrainedWindowFrameView, public: | |
| 276 | |
| 277 ConstrainedWindowFrameView::ConstrainedWindowFrameView( | |
| 278 ConstrainedWindowImpl* container) | |
| 279 : NonClientFrameView(), | |
| 280 container_(container), | |
| 281 close_button_(new views::ImageButton(this)) { | |
| 282 InitClass(); | |
| 283 InitWindowResources(); | |
| 284 | |
| 285 close_button_->SetImage(views::CustomButton::BS_NORMAL, | |
| 286 resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON)); | |
| 287 close_button_->SetImage(views::CustomButton::BS_HOT, | |
| 288 resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_H)); | |
| 289 close_button_->SetImage(views::CustomButton::BS_PUSHED, | |
| 290 resources_->GetPartBitmap(FRAME_CLOSE_BUTTON_ICON_P)); | |
| 291 close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
| 292 views::ImageButton::ALIGN_MIDDLE); | |
| 293 AddChildView(close_button_); | |
| 294 } | |
| 295 | |
| 296 ConstrainedWindowFrameView::~ConstrainedWindowFrameView() { | |
| 297 } | |
| 298 | |
| 299 void ConstrainedWindowFrameView::UpdateWindowTitle() { | |
| 300 SchedulePaint(title_bounds_, false); | |
| 301 } | |
| 302 | |
| 303 //////////////////////////////////////////////////////////////////////////////// | |
| 304 // ConstrainedWindowFrameView, views::NonClientFrameView implementation: | |
| 305 | |
| 306 gfx::Rect ConstrainedWindowFrameView::GetBoundsForClientView() const { | |
| 307 return client_view_bounds_; | |
| 308 } | |
| 309 | |
| 310 bool ConstrainedWindowFrameView::AlwaysUseCustomFrame() const { | |
| 311 // Constrained windows always use the custom frame - they just have a | |
| 312 // different set of bitmaps. | |
| 313 return true; | |
| 314 } | |
| 315 | |
| 316 gfx::Rect ConstrainedWindowFrameView::GetWindowBoundsForClientBounds( | |
| 317 const gfx::Rect& client_bounds) const { | |
| 318 int top_height = NonClientTopBorderHeight(); | |
| 319 int border_thickness = NonClientBorderThickness(); | |
| 320 return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), | |
| 321 std::max(0, client_bounds.y() - top_height), | |
| 322 client_bounds.width() + (2 * border_thickness), | |
| 323 client_bounds.height() + top_height + border_thickness); | |
| 324 } | |
| 325 | |
| 326 gfx::Point ConstrainedWindowFrameView::GetSystemMenuPoint() const { | |
| 327 // Doesn't really matter, since we never show system menus on constrained | |
| 328 // windows... | |
| 329 gfx::Point system_menu_point(FrameBorderThickness(), | |
| 330 NonClientTopBorderHeight()); | |
| 331 ConvertPointToScreen(this, &system_menu_point); | |
| 332 return system_menu_point; | |
| 333 } | |
| 334 | |
| 335 int ConstrainedWindowFrameView::NonClientHitTest(const gfx::Point& point) { | |
| 336 if (!bounds().Contains(point)) | |
| 337 return HTNOWHERE; | |
| 338 | |
| 339 int frame_component = container_->GetClientView()->NonClientHitTest(point); | |
| 340 if (frame_component != HTNOWHERE) | |
| 341 return frame_component; | |
| 342 | |
| 343 // Then see if the point is within any of the window controls. | |
| 344 if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) | |
| 345 return HTCLOSE; | |
| 346 | |
| 347 int window_component = GetHTComponentForFrame(point, FrameBorderThickness(), | |
| 348 NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, | |
| 349 container_->GetDelegate()->CanResize()); | |
| 350 // Fall back to the caption if no other component matches. | |
| 351 return (window_component == HTNOWHERE) ? HTCAPTION : window_component; | |
| 352 } | |
| 353 | |
| 354 void ConstrainedWindowFrameView::GetWindowMask(const gfx::Size& size, | |
| 355 gfx::Path* window_mask) { | |
| 356 DCHECK(window_mask); | |
| 357 | |
| 358 // Redefine the window visible region for the new size. | |
| 359 window_mask->moveTo(0, 3); | |
| 360 window_mask->lineTo(1, 2); | |
| 361 window_mask->lineTo(1, 1); | |
| 362 window_mask->lineTo(2, 1); | |
| 363 window_mask->lineTo(3, 0); | |
| 364 | |
| 365 window_mask->lineTo(SkIntToScalar(size.width() - 3), 0); | |
| 366 window_mask->lineTo(SkIntToScalar(size.width() - 2), 1); | |
| 367 window_mask->lineTo(SkIntToScalar(size.width() - 1), 1); | |
| 368 window_mask->lineTo(SkIntToScalar(size.width() - 1), 2); | |
| 369 window_mask->lineTo(SkIntToScalar(size.width()), 3); | |
| 370 | |
| 371 window_mask->lineTo(SkIntToScalar(size.width()), | |
| 372 SkIntToScalar(size.height())); | |
| 373 window_mask->lineTo(0, SkIntToScalar(size.height())); | |
| 374 window_mask->close(); | |
| 375 } | |
| 376 | |
| 377 void ConstrainedWindowFrameView::EnableClose(bool enable) { | |
| 378 close_button_->SetEnabled(enable); | |
| 379 } | |
| 380 | |
| 381 //////////////////////////////////////////////////////////////////////////////// | |
| 382 // ConstrainedWindowFrameView, views::View implementation: | |
| 383 | |
| 384 void ConstrainedWindowFrameView::Paint(gfx::Canvas* canvas) { | |
| 385 PaintFrameBorder(canvas); | |
| 386 PaintTitleBar(canvas); | |
| 387 PaintClientEdge(canvas); | |
| 388 } | |
| 389 | |
| 390 void ConstrainedWindowFrameView::Layout() { | |
| 391 LayoutWindowControls(); | |
| 392 LayoutTitleBar(); | |
| 393 LayoutClientView(); | |
| 394 } | |
| 395 | |
| 396 void ConstrainedWindowFrameView::ThemeChanged() { | |
| 397 InitWindowResources(); | |
| 398 } | |
| 399 | |
| 400 //////////////////////////////////////////////////////////////////////////////// | |
| 401 // ConstrainedWindowFrameView, views::ButtonListener implementation: | |
| 402 | |
| 403 void ConstrainedWindowFrameView::ButtonPressed(views::Button* sender) { | |
| 404 if (sender == close_button_) | |
| 405 container_->ExecuteSystemMenuCommand(SC_CLOSE); | |
| 406 } | |
| 407 | |
| 408 //////////////////////////////////////////////////////////////////////////////// | |
| 409 // ConstrainedWindowFrameView, private: | |
| 410 | |
| 411 int ConstrainedWindowFrameView::FrameBorderThickness() const { | |
| 412 return kFrameBorderThickness; | |
| 413 } | |
| 414 | |
| 415 int ConstrainedWindowFrameView::NonClientBorderThickness() const { | |
| 416 return FrameBorderThickness() + kClientEdgeThickness; | |
| 417 } | |
| 418 | |
| 419 int ConstrainedWindowFrameView::NonClientTopBorderHeight() const { | |
| 420 int title_top_spacing, title_thickness; | |
| 421 return TitleCoordinates(&title_top_spacing, &title_thickness); | |
| 422 } | |
| 423 | |
| 424 int ConstrainedWindowFrameView::TitleCoordinates( | |
| 425 int* title_top_spacing, | |
| 426 int* title_thickness) const { | |
| 427 int frame_thickness = FrameBorderThickness(); | |
| 428 int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; | |
| 429 *title_top_spacing = frame_thickness + kTitleTopSpacing; | |
| 430 // The bottom spacing should be the same apparent height as the top spacing, | |
| 431 // plus have the client edge tacked on. | |
| 432 int title_bottom_spacing = *title_top_spacing + kClientEdgeThickness; | |
| 433 *title_thickness = std::max(title_font_->height(), | |
| 434 min_titlebar_height - *title_top_spacing - title_bottom_spacing); | |
| 435 return *title_top_spacing + *title_thickness + title_bottom_spacing; | |
| 436 } | |
| 437 | |
| 438 void ConstrainedWindowFrameView::PaintFrameBorder(gfx::Canvas* canvas) { | |
| 439 SkBitmap* top_left_corner = resources_->GetPartBitmap(FRAME_TOP_LEFT_CORNER); | |
| 440 SkBitmap* top_right_corner = | |
| 441 resources_->GetPartBitmap(FRAME_TOP_RIGHT_CORNER); | |
| 442 SkBitmap* top_edge = resources_->GetPartBitmap(FRAME_TOP_EDGE); | |
| 443 SkBitmap* right_edge = resources_->GetPartBitmap(FRAME_RIGHT_EDGE); | |
| 444 SkBitmap* left_edge = resources_->GetPartBitmap(FRAME_LEFT_EDGE); | |
| 445 SkBitmap* bottom_left_corner = | |
| 446 resources_->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER); | |
| 447 SkBitmap* bottom_right_corner = | |
| 448 resources_->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER); | |
| 449 SkBitmap* bottom_edge = resources_->GetPartBitmap(FRAME_BOTTOM_EDGE); | |
| 450 | |
| 451 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 452 SkBitmap* theme_frame = rb.GetBitmapNamed(IDR_THEME_FRAME); | |
| 453 SkColor frame_color = ResourceBundle::frame_color; | |
| 454 | |
| 455 // Fill with the frame color first so we have a constant background for | |
| 456 // areas not covered by the theme image. | |
| 457 canvas->FillRectInt(frame_color, 0, 0, width(), theme_frame->height()); | |
| 458 // Now fill down the sides | |
| 459 canvas->FillRectInt(frame_color, | |
| 460 0, theme_frame->height(), | |
| 461 left_edge->width(), height() - theme_frame->height()); | |
| 462 canvas->FillRectInt(frame_color, | |
| 463 width() - right_edge->width(), theme_frame->height(), | |
| 464 right_edge->width(), height() - theme_frame->height()); | |
| 465 // Now fill the bottom area. | |
| 466 canvas->FillRectInt(frame_color, | |
| 467 left_edge->width(), height() - bottom_edge->height(), | |
| 468 width() - left_edge->width() - right_edge->width(), | |
| 469 bottom_edge->height()); | |
| 470 | |
| 471 // Draw the theme frame. | |
| 472 canvas->TileImageInt(*theme_frame, 0, 0, width(), theme_frame->height()); | |
| 473 | |
| 474 // Top. | |
| 475 canvas->DrawBitmapInt(*top_left_corner, 0, 0); | |
| 476 canvas->TileImageInt(*top_edge, top_left_corner->width(), 0, | |
| 477 width() - top_right_corner->width(), top_edge->height()); | |
| 478 canvas->DrawBitmapInt(*top_right_corner, | |
| 479 width() - top_right_corner->width(), 0); | |
| 480 | |
| 481 // Right. | |
| 482 canvas->TileImageInt(*right_edge, width() - right_edge->width(), | |
| 483 top_right_corner->height(), right_edge->width(), | |
| 484 height() - top_right_corner->height() - | |
| 485 bottom_right_corner->height()); | |
| 486 | |
| 487 // Bottom. | |
| 488 canvas->DrawBitmapInt(*bottom_right_corner, | |
| 489 width() - bottom_right_corner->width(), | |
| 490 height() - bottom_right_corner->height()); | |
| 491 canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(), | |
| 492 height() - bottom_edge->height(), | |
| 493 width() - bottom_left_corner->width() - | |
| 494 bottom_right_corner->width(), | |
| 495 bottom_edge->height()); | |
| 496 canvas->DrawBitmapInt(*bottom_left_corner, 0, | |
| 497 height() - bottom_left_corner->height()); | |
| 498 | |
| 499 // Left. | |
| 500 canvas->TileImageInt(*left_edge, 0, top_left_corner->height(), | |
| 501 left_edge->width(), | |
| 502 height() - top_left_corner->height() - bottom_left_corner->height()); | |
| 503 } | |
| 504 | |
| 505 void ConstrainedWindowFrameView::PaintTitleBar(gfx::Canvas* canvas) { | |
| 506 canvas->DrawStringInt(container_->GetWindowTitle(), *title_font_, | |
| 507 GetTitleColor(), MirroredLeftPointForRect(title_bounds_), | |
| 508 title_bounds_.y(), title_bounds_.width(), title_bounds_.height()); | |
| 509 } | |
| 510 | |
| 511 void ConstrainedWindowFrameView::PaintClientEdge(gfx::Canvas* canvas) { | |
| 512 gfx::Rect client_edge_bounds(CalculateClientAreaBounds(width(), height())); | |
| 513 client_edge_bounds.Inset(-kClientEdgeThickness, -kClientEdgeThickness); | |
| 514 gfx::Rect frame_shadow_bounds(client_edge_bounds); | |
| 515 frame_shadow_bounds.Inset(-kFrameShadowThickness, -kFrameShadowThickness); | |
| 516 | |
| 517 canvas->FillRectInt(kContentsBorderShadow, frame_shadow_bounds.x(), | |
| 518 frame_shadow_bounds.y(), frame_shadow_bounds.width(), | |
| 519 frame_shadow_bounds.height()); | |
| 520 | |
| 521 canvas->FillRectInt(ResourceBundle::toolbar_color, client_edge_bounds.x(), | |
| 522 client_edge_bounds.y(), client_edge_bounds.width(), | |
| 523 client_edge_bounds.height()); | |
| 524 } | |
| 525 | |
| 526 void ConstrainedWindowFrameView::LayoutWindowControls() { | |
| 527 gfx::Size close_button_size = close_button_->GetPreferredSize(); | |
| 528 close_button_->SetBounds( | |
| 529 width() - close_button_size.width() - FrameBorderThickness(), | |
| 530 kCaptionTopSpacing, close_button_size.width(), | |
| 531 close_button_size.height()); | |
| 532 } | |
| 533 | |
| 534 void ConstrainedWindowFrameView::LayoutTitleBar() { | |
| 535 // Size the title. | |
| 536 int title_x = FrameBorderThickness() + kIconLeftSpacing; | |
| 537 int title_top_spacing, title_thickness; | |
| 538 TitleCoordinates(&title_top_spacing, &title_thickness); | |
| 539 title_bounds_.SetRect(title_x, | |
| 540 title_top_spacing + ((title_thickness - title_font_->height()) / 2), | |
| 541 std::max(0, close_button_->x() - kTitleCaptionSpacing - title_x), | |
| 542 title_font_->height()); | |
| 543 } | |
| 544 | |
| 545 void ConstrainedWindowFrameView::LayoutClientView() { | |
| 546 client_view_bounds_ = CalculateClientAreaBounds(width(), height()); | |
| 547 } | |
| 548 | |
| 549 gfx::Rect ConstrainedWindowFrameView::CalculateClientAreaBounds( | |
| 550 int width, | |
| 551 int height) const { | |
| 552 int top_height = NonClientTopBorderHeight(); | |
| 553 int border_thickness = NonClientBorderThickness(); | |
| 554 return gfx::Rect(border_thickness, top_height, | |
| 555 std::max(0, width - (2 * border_thickness)), | |
| 556 std::max(0, height - top_height - border_thickness)); | |
| 557 } | |
| 558 | |
| 559 void ConstrainedWindowFrameView::InitWindowResources() { | |
| 560 if (win_util::ShouldUseVistaFrame()) { | |
| 561 resources_.reset(new VistaWindowResources); | |
| 562 } else { | |
| 563 resources_.reset(new XPWindowResources); | |
| 564 } | |
| 565 } | |
| 566 | |
| 567 // static | |
| 568 void ConstrainedWindowFrameView::InitClass() { | |
| 569 static bool initialized = false; | |
| 570 if (!initialized) { | |
| 571 title_font_ = new gfx::Font(win_util::GetWindowTitleFont()); | |
| 572 | |
| 573 initialized = true; | |
| 574 } | |
| 575 } | |
| 576 | |
| 577 //////////////////////////////////////////////////////////////////////////////// | |
| 578 // ConstrainedWindowImpl, public: | |
| 579 | |
| 580 // The space (in pixels) between minimized pop-ups stacked horizontally and | |
| 581 // vertically. | |
| 582 static const int kPopupRepositionOffset = 5; | |
| 583 static const int kConstrainedWindowEdgePadding = 10; | |
| 584 | |
| 585 ConstrainedWindowImpl::~ConstrainedWindowImpl() { | |
| 586 } | |
| 587 | |
| 588 //////////////////////////////////////////////////////////////////////////////// | |
| 589 // ConstrainedWindowImpl, ConstrainedWindow implementation: | |
| 590 | |
| 591 views::NonClientFrameView* ConstrainedWindowImpl::CreateFrameViewForWindow() { | |
| 592 return new ConstrainedWindowFrameView(this); | |
| 593 } | |
| 594 | |
| 595 void ConstrainedWindowImpl::CloseConstrainedWindow() { | |
| 596 // Broadcast to all observers of NOTIFY_CWINDOW_CLOSED. | |
| 597 // One example of such an observer is AutomationCWindowTracker in the | |
| 598 // automation component. | |
| 599 NotificationService::current()->Notify(NotificationType::CWINDOW_CLOSED, | |
| 600 Source<ConstrainedWindow>(this), | |
| 601 NotificationService::NoDetails()); | |
| 602 | |
| 603 Close(); | |
| 604 } | |
| 605 | |
| 606 std::wstring ConstrainedWindowImpl::GetWindowTitle() const { | |
| 607 std::wstring display_title; | |
| 608 if (GetDelegate()) | |
| 609 display_title = GetDelegate()->GetWindowTitle(); | |
| 610 else | |
| 611 display_title = L"Untitled"; | |
| 612 | |
| 613 return display_title; | |
| 614 } | |
| 615 | |
| 616 const gfx::Rect& ConstrainedWindowImpl::GetCurrentBounds() const { | |
| 617 return current_bounds_; | |
| 618 } | |
| 619 | |
| 620 //////////////////////////////////////////////////////////////////////////////// | |
| 621 // ConstrainedWindowImpl, private: | |
| 622 | |
| 623 ConstrainedWindowImpl::ConstrainedWindowImpl( | |
| 624 TabContents* owner, | |
| 625 views::WindowDelegate* window_delegate) | |
| 626 : WindowWin(window_delegate), | |
| 627 owner_(owner) { | |
| 628 GetNonClientView()->SetFrameView(CreateFrameViewForWindow()); | |
| 629 | |
| 630 focus_restoration_disabled_ = false; | |
| 631 set_window_style(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | | |
| 632 WS_THICKFRAME | WS_SYSMENU); | |
| 633 set_focus_on_creation(false); | |
| 634 | |
| 635 WindowWin::Init(owner_->GetNativeView(), gfx::Rect()); | |
| 636 ActivateConstrainedWindow(); | |
| 637 } | |
| 638 | |
| 639 void ConstrainedWindowImpl::ActivateConstrainedWindow() { | |
| 640 // Other pop-ups are simply moved to the front of the z-order. | |
| 641 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); | |
| 642 | |
| 643 // Store the focus of our parent focus manager so we can restore it when we | |
| 644 // close. | |
| 645 views::FocusManager* focus_manager = | |
| 646 views::FocusManager::GetFocusManager(GetNativeView()); | |
| 647 DCHECK(focus_manager); | |
| 648 focus_manager = focus_manager->GetParentFocusManager(); | |
| 649 if (focus_manager) { | |
| 650 // We could not have a parent focus manager if the ConstrainedWindow is | |
| 651 // displayed in a tab that is not currently selected. | |
| 652 // TODO(jcampan): we should store the ConstrainedWindow active events in | |
| 653 // that case and replay them when the TabContents becomes selected. | |
| 654 focus_manager->StoreFocusedView(); | |
| 655 | |
| 656 // Give our window the focus so we get keyboard messages. | |
| 657 ::SetFocus(GetNativeView()); | |
| 658 } | |
| 659 } | |
| 660 | |
| 661 //////////////////////////////////////////////////////////////////////////////// | |
| 662 // ConstrainedWindowImpl, views::WidgetWin overrides: | |
| 663 | |
| 664 void ConstrainedWindowImpl::OnDestroy() { | |
| 665 // We do this here, rather than |Close|, since the window may be destroyed in | |
| 666 // a way other than by some other component calling Close, e.g. by the native | |
| 667 // window hierarchy closing. We are guaranteed to receive a WM_DESTROY | |
| 668 // message regardless of how the window is closed. | |
| 669 // Note that when we get this message, the focus manager of the | |
| 670 // ConstrainedWindow has already been destroyed (by the processing of | |
| 671 // WM_DESTROY in FocusManager). So the FocusManager we retrieve here is the | |
| 672 // parent one (the one from the top window). | |
| 673 views::FocusManager* focus_manager = | |
| 674 views::FocusManager::GetFocusManager(GetNativeView()); | |
| 675 if (focus_manager) { | |
| 676 // We may not have a focus manager if: | |
| 677 // - we are hidden when closed (the TabContent would be detached). | |
| 678 // - the tab has been closed and we are closed as a result. | |
| 679 // TODO(jcampan): when hidden, we should modify the stored focus of the tab | |
| 680 // so when it becomes visible again we retrieve the focus appropriately. | |
| 681 if (!focus_restoration_disabled_) | |
| 682 focus_manager->RestoreFocusedView(); | |
| 683 } | |
| 684 | |
| 685 // Make sure we call super so that it can do its cleanup. | |
| 686 WindowWin::OnDestroy(); | |
| 687 } | |
| 688 | |
| 689 void ConstrainedWindowImpl::OnFinalMessage(HWND window) { | |
| 690 // Tell our constraining TabContents that we've gone so it can update its | |
| 691 // list. | |
| 692 owner_->WillClose(this); | |
| 693 | |
| 694 WindowWin::OnFinalMessage(window); | |
| 695 } | |
| 696 | |
| 697 LRESULT ConstrainedWindowImpl::OnMouseActivate(HWND window, | |
| 698 UINT hittest_code, | |
| 699 UINT message) { | |
| 700 // We only detach the window if the user clicked on the title bar. That | |
| 701 // way, users can click inside the contents of legitimate popups obtained | |
| 702 // with a mouse gesture. | |
| 703 if (hittest_code != HTCLIENT && hittest_code != HTNOWHERE && | |
| 704 hittest_code != HTCLOSE) { | |
| 705 ActivateConstrainedWindow(); | |
| 706 } | |
| 707 | |
| 708 return MA_ACTIVATE; | |
| 709 } | |
| 710 | |
| 711 void ConstrainedWindowImpl::OnWindowPosChanged(WINDOWPOS* window_pos) { | |
| 712 // If the window was moved or sized, tell the owner. | |
| 713 if (!(window_pos->flags & SWP_NOMOVE) || !(window_pos->flags & SWP_NOSIZE)) | |
| 714 owner_->DidMoveOrResize(this); | |
| 715 SetMsgHandled(FALSE); | |
| 716 } | |
| 717 | |
| 718 | |
| 719 // static | |
| 720 ConstrainedWindow* ConstrainedWindow::CreateConstrainedDialog( | |
| 721 TabContents* parent, | |
| 722 views::WindowDelegate* window_delegate) { | |
| 723 ConstrainedWindowImpl* window = new ConstrainedWindowImpl(parent, | |
| 724 window_delegate); | |
| 725 return window; | |
| 726 } | |
| OLD | NEW |