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 |