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.
5 #include "ash/wm/frame_painter.h"
7 #include "ash/ash_constants.h"
9 #include "ash/shell_window_ids.h"
10 #include "ash/test/ash_test_base.h"
11 #include "ash/wm/property_util.h"
12 #include "ash/wm/window_properties.h"
13 #include "ash/wm/window_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "grit/ash_resources.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/aura/client/aura_constants.h"
18 #include "ui/aura/root_window.h"
19 #include "ui/aura/window_observer.h"
20 #include "ui/base/hit_test.h"
21 #include "ui/base/theme_provider.h"
22 #include "ui/gfx/font.h"
23 #include "ui/gfx/screen.h"
24 #include "ui/views/controls/button/button.h"
25 #include "ui/views/controls/button/image_button.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/views/widget/widget_delegate.h"
28 #include "ui/views/window/non_client_view.h"
30 using ash::FramePainter
;
31 using ui::ThemeProvider
;
33 using views::ImageButton
;
34 using views::NonClientFrameView
;
35 using views::ToggleImageButton
;
40 bool ImagesMatch(ImageButton
* button
,
43 int pressed_image_id
) {
44 ThemeProvider
* theme
= button
->GetWidget()->GetThemeProvider();
45 gfx::ImageSkia
* normal
= theme
->GetImageSkiaNamed(normal_image_id
);
46 gfx::ImageSkia
* hovered
= theme
->GetImageSkiaNamed(hovered_image_id
);
47 gfx::ImageSkia
* pressed
= theme
->GetImageSkiaNamed(pressed_image_id
);
48 return button
->GetImage(Button::STATE_NORMAL
).BackedBySameObjectAs(*normal
) &&
49 button
->GetImage(Button::STATE_HOVERED
).BackedBySameObjectAs(*hovered
) &&
50 button
->GetImage(Button::STATE_PRESSED
).BackedBySameObjectAs(*pressed
);
53 class ResizableWidgetDelegate
: public views::WidgetDelegate
{
55 ResizableWidgetDelegate(views::Widget
* widget
) {
59 virtual bool CanResize() const OVERRIDE
{ return true; }
60 // Implementations of the widget class.
61 virtual views::Widget
* GetWidget() OVERRIDE
{ return widget_
; }
62 virtual const views::Widget
* GetWidget() const OVERRIDE
{ return widget_
; }
63 virtual void DeleteDelegate() OVERRIDE
{
68 views::Widget
* widget_
;
70 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate
);
73 class WindowRepaintChecker
: public aura::WindowObserver
{
75 explicit WindowRepaintChecker(aura::Window
* window
)
76 : is_paint_scheduled_(false) {
77 window
->AddObserver(this);
79 virtual ~WindowRepaintChecker() {
82 bool IsPaintScheduledAndReset() {
83 bool result
= is_paint_scheduled_
;
84 is_paint_scheduled_
= false;
89 // aura::WindowObserver overrides:
90 virtual void OnWindowPaintScheduled(aura::Window
* window
,
91 const gfx::Rect
& region
) OVERRIDE
{
92 is_paint_scheduled_
= true;
94 virtual void OnWindowDestroying(aura::Window
* window
) OVERRIDE
{
95 window
->RemoveObserver(this);
98 bool is_paint_scheduled_
;
100 DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker
);
103 // Modifies the values of kInactiveWindowOpacity, kActiveWindowOpacity, and
104 // kSoloWindowOpacity for the lifetime of the class. This is useful so that
105 // the constants each have different values.
106 class ScopedOpacityConstantModifier
{
108 ScopedOpacityConstantModifier()
109 : initial_active_window_opacity_(
110 ash::FramePainter::kActiveWindowOpacity
),
111 initial_inactive_window_opacity_(
112 ash::FramePainter::kInactiveWindowOpacity
),
113 initial_solo_window_opacity_(ash::FramePainter::kSoloWindowOpacity
) {
114 ash::FramePainter::kActiveWindowOpacity
= 100;
115 ash::FramePainter::kInactiveWindowOpacity
= 120;
116 ash::FramePainter::kSoloWindowOpacity
= 140;
118 ~ScopedOpacityConstantModifier() {
119 ash::FramePainter::kActiveWindowOpacity
= initial_active_window_opacity_
;
120 ash::FramePainter::kInactiveWindowOpacity
=
121 initial_inactive_window_opacity_
;
122 ash::FramePainter::kSoloWindowOpacity
= initial_solo_window_opacity_
;
126 int initial_active_window_opacity_
;
127 int initial_inactive_window_opacity_
;
128 int initial_solo_window_opacity_
;
130 DISALLOW_COPY_AND_ASSIGN(ScopedOpacityConstantModifier
);
133 // Creates a new FramePainter with empty buttons. Caller owns the memory.
134 FramePainter
* CreateTestPainter(Widget
* widget
) {
135 FramePainter
* painter
= new FramePainter();
136 ImageButton
* size_button
= new ImageButton(NULL
);
137 ImageButton
* close_button
= new ImageButton(NULL
);
138 // Add the buttons to the widget's non-client frame view so they will be
139 // deleted when the widget is destroyed.
140 NonClientFrameView
* frame_view
= widget
->non_client_view()->frame_view();
141 frame_view
->AddChildView(size_button
);
142 frame_view
->AddChildView(close_button
);
143 painter
->Init(widget
,
147 FramePainter::SIZE_BUTTON_MAXIMIZES
);
155 class FramePainterTest
: public ash::test::AshTestBase
{
157 // Creates a test widget that owns its native widget.
158 Widget
* CreateTestWidget() {
159 Widget
* widget
= new Widget
;
160 Widget::InitParams params
;
161 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
162 params
.context
= CurrentContext();
163 widget
->Init(params
);
167 Widget
* CreateAlwaysOnTopWidget() {
168 Widget
* widget
= new Widget
;
169 Widget::InitParams params
;
170 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
171 params
.context
= CurrentContext();
172 params
.keep_on_top
= true;
173 widget
->Init(params
);
177 Widget
* CreatePanelWidget() {
178 Widget
* widget
= new Widget
;
179 Widget::InitParams params
;
180 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
181 params
.context
= CurrentContext();
182 params
.type
= Widget::InitParams::TYPE_PANEL
;
183 widget
->Init(params
);
187 Widget
* CreateResizableWidget() {
188 Widget
* widget
= new Widget
;
189 Widget::InitParams params
;
190 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
191 params
.context
= CurrentContext();
192 params
.keep_on_top
= true;
193 params
.delegate
= new ResizableWidgetDelegate(widget
);
194 params
.type
= Widget::InitParams::TYPE_WINDOW
;
195 widget
->Init(params
);
200 TEST_F(FramePainterTest
, CreateAndDeleteSingleWindow
) {
201 // Ensure that creating/deleting a window works well and doesn't cause
202 // crashes. See crbug.com/155634
203 aura::RootWindow
* root
= Shell::GetActiveRootWindow();
205 scoped_ptr
<Widget
> widget(CreateTestWidget());
206 scoped_ptr
<FramePainter
> painter(CreateTestPainter(widget
.get()));
209 // We only have one window, so it should use a solo header.
210 EXPECT_TRUE(painter
->UseSoloWindowHeader());
211 EXPECT_TRUE(root
->GetProperty(internal::kSoloWindowHeaderKey
));
215 EXPECT_FALSE(root
->GetProperty(internal::kSoloWindowHeaderKey
));
217 // Recreate another window again.
218 widget
.reset(CreateTestWidget());
219 painter
.reset(CreateTestPainter(widget
.get()));
221 EXPECT_TRUE(painter
->UseSoloWindowHeader());
222 EXPECT_TRUE(root
->GetProperty(internal::kSoloWindowHeaderKey
));
225 TEST_F(FramePainterTest
, LayoutHeader
) {
226 scoped_ptr
<Widget
> widget(CreateTestWidget());
227 ImageButton
size_button(NULL
);
228 ImageButton
close_button(NULL
);
229 NonClientFrameView
* frame_view
= widget
->non_client_view()->frame_view();
230 frame_view
->AddChildView(&size_button
);
231 frame_view
->AddChildView(&close_button
);
232 scoped_ptr
<FramePainter
> painter(new FramePainter
);
233 painter
->Init(widget
.get(),
237 FramePainter::SIZE_BUTTON_MAXIMIZES
);
241 painter
->LayoutHeader(frame_view
, false);
242 EXPECT_TRUE(ImagesMatch(&close_button
,
243 IDR_AURA_WINDOW_CLOSE
,
244 IDR_AURA_WINDOW_CLOSE_H
,
245 IDR_AURA_WINDOW_CLOSE_P
));
246 EXPECT_TRUE(ImagesMatch(&size_button
,
247 IDR_AURA_WINDOW_MAXIMIZE
,
248 IDR_AURA_WINDOW_MAXIMIZE_H
,
249 IDR_AURA_WINDOW_MAXIMIZE_P
));
252 painter
->LayoutHeader(frame_view
, true);
253 EXPECT_TRUE(ImagesMatch(&close_button
,
254 IDR_AURA_WINDOW_MAXIMIZED_CLOSE
,
255 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H
,
256 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P
));
257 EXPECT_TRUE(ImagesMatch(&size_button
,
258 IDR_AURA_WINDOW_MAXIMIZED_RESTORE
,
259 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H
,
260 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P
));
262 // Maximized shorter layout.
264 painter
->LayoutHeader(frame_view
, true);
265 EXPECT_TRUE(ImagesMatch(&close_button
,
266 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2
,
267 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H
,
268 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P
));
269 EXPECT_TRUE(ImagesMatch(&size_button
,
270 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2
,
271 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H
,
272 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P
));
274 // Fullscreen can show the buttons during an immersive reveal, so it should
275 // use the same images as maximized.
276 widget
->SetFullscreen(true);
277 painter
->LayoutHeader(frame_view
, true);
278 EXPECT_TRUE(ImagesMatch(&close_button
,
279 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2
,
280 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H
,
281 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P
));
282 EXPECT_TRUE(ImagesMatch(&size_button
,
283 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2
,
284 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H
,
285 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P
));
288 TEST_F(FramePainterTest
, UseSoloWindowHeader
) {
289 // Create a widget and a painter for it.
290 scoped_ptr
<Widget
> w1(CreateTestWidget());
291 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
294 // We only have one window, so it should use a solo header.
295 EXPECT_TRUE(p1
->UseSoloWindowHeader());
297 // Create a second widget and painter.
298 scoped_ptr
<Widget
> w2(CreateTestWidget());
299 scoped_ptr
<FramePainter
> p2(CreateTestPainter(w2
.get()));
302 // Now there are two windows, so we should not use solo headers. This only
303 // needs to test |p1| because "solo window headers" are a per-root-window
305 EXPECT_FALSE(p1
->UseSoloWindowHeader());
307 // Hide one window. Solo should be enabled.
309 EXPECT_TRUE(p1
->UseSoloWindowHeader());
311 // Show that window. Solo should be disabled.
313 EXPECT_FALSE(p1
->UseSoloWindowHeader());
315 // Minimize the second window. Solo should be enabled.
317 EXPECT_TRUE(p1
->UseSoloWindowHeader());
319 // Close the minimized window.
321 EXPECT_TRUE(p1
->UseSoloWindowHeader());
323 // Open an always-on-top widget (which lives in a different container).
324 scoped_ptr
<Widget
> w3(CreateAlwaysOnTopWidget());
325 scoped_ptr
<FramePainter
> p3(CreateTestPainter(w3
.get()));
327 EXPECT_FALSE(p3
->UseSoloWindowHeader());
329 // Close the always-on-top widget.
331 EXPECT_TRUE(p1
->UseSoloWindowHeader());
334 // An open V2 app window should cause browser windows not to use the
335 // solo window header.
336 TEST_F(FramePainterTest
, UseSoloWindowHeaderWithApp
) {
337 // Create a widget and a painter for it.
338 scoped_ptr
<Widget
> w1(CreateTestWidget());
339 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
342 // We only have one window, so it should use a solo header.
343 EXPECT_TRUE(p1
->UseSoloWindowHeader());
345 // Simulate a V2 app window, which is part of the active workspace but does
346 // not have a frame painter.
347 scoped_ptr
<Widget
> w2(CreateTestWidget());
350 // Now there are two windows, so we should not use solo headers.
351 EXPECT_FALSE(p1
->UseSoloWindowHeader());
353 // Minimize the app window. The first window should go solo again.
355 EXPECT_TRUE(p1
->UseSoloWindowHeader());
357 // Restoring the app window turns off solo headers.
359 EXPECT_FALSE(p1
->UseSoloWindowHeader());
362 // Panels should not "count" for computing solo window headers, and the panel
363 // itself should always have an opaque header.
364 TEST_F(FramePainterTest
, UseSoloWindowHeaderWithPanel
) {
365 // Create a widget and a painter for it.
366 scoped_ptr
<Widget
> w1(CreateTestWidget());
367 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
370 // We only have one window, so it should use a solo header.
371 EXPECT_TRUE(p1
->UseSoloWindowHeader());
373 // Create a panel and a painter for it.
374 scoped_ptr
<Widget
> w2(CreatePanelWidget());
375 scoped_ptr
<FramePainter
> p2(CreateTestPainter(w2
.get()));
378 // Despite two windows, the first window should still be considered "solo"
379 // because panels aren't included in the computation.
380 EXPECT_TRUE(p1
->UseSoloWindowHeader());
382 // The panel itself is not considered solo.
383 EXPECT_FALSE(p2
->UseSoloWindowHeader());
385 // Even after closing the first window, the panel is still not considered
388 EXPECT_FALSE(p2
->UseSoloWindowHeader());
391 // Modal dialogs should not use solo headers.
392 TEST_F(FramePainterTest
, UseSoloWindowHeaderModal
) {
393 // Create a widget and a painter for it.
394 scoped_ptr
<Widget
> w1(CreateTestWidget());
395 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
398 // We only have one window, so it should use a solo header.
399 EXPECT_TRUE(p1
->UseSoloWindowHeader());
401 // Create a fake modal window.
402 scoped_ptr
<Widget
> w2(CreateTestWidget());
403 scoped_ptr
<FramePainter
> p2(CreateTestPainter(w2
.get()));
404 w2
->GetNativeWindow()->SetProperty(aura::client::kModalKey
,
405 ui::MODAL_TYPE_WINDOW
);
408 // Despite two windows, the first window should still be considered "solo"
409 // because modal windows aren't included in the computation.
410 EXPECT_TRUE(p1
->UseSoloWindowHeader());
412 // The modal window itself is not considered solo.
413 EXPECT_FALSE(p2
->UseSoloWindowHeader());
416 // Constrained windows should not use solo headers.
417 TEST_F(FramePainterTest
, UseSoloWindowHeaderConstrained
) {
418 // Create a widget and a painter for it.
419 scoped_ptr
<Widget
> w1(CreateTestWidget());
420 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
423 // We only have one window, so it should use a solo header.
424 EXPECT_TRUE(p1
->UseSoloWindowHeader());
426 // Create a fake constrained window.
427 scoped_ptr
<Widget
> w2(CreateTestWidget());
428 scoped_ptr
<FramePainter
> p2(CreateTestPainter(w2
.get()));
429 w2
->GetNativeWindow()->SetProperty(ash::kConstrainedWindowKey
, true);
432 // Despite two windows, the first window should still be considered "solo"
433 // because constrained windows aren't included in the computation.
434 EXPECT_TRUE(p1
->UseSoloWindowHeader());
436 // The constrained window itself is not considered solo.
437 EXPECT_FALSE(p2
->UseSoloWindowHeader());
440 // Non-drawing windows should not affect the solo computation.
441 TEST_F(FramePainterTest
, UseSoloWindowHeaderNotDrawn
) {
442 // Create a widget and a painter for it.
443 scoped_ptr
<Widget
> widget(CreateTestWidget());
444 scoped_ptr
<FramePainter
> painter(CreateTestPainter(widget
.get()));
447 // We only have one window, so it should use a solo header.
448 EXPECT_TRUE(painter
->UseSoloWindowHeader());
450 // Create non-drawing window similar to DragDropTracker.
451 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
452 window
->SetType(aura::client::WINDOW_TYPE_NORMAL
);
453 window
->Init(ui::LAYER_NOT_DRAWN
);
454 window
->SetDefaultParentByRootWindow(
455 widget
->GetNativeWindow()->GetRootWindow(), gfx::Rect());
458 // Despite two windows, the first window should still be considered "solo"
459 // because non-drawing windows aren't included in the computation.
460 EXPECT_TRUE(painter
->UseSoloWindowHeader());
464 // Multiple displays are not supported on Windows Ash. http://crbug.com/165962
465 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
466 DISABLED_UseSoloWindowHeaderMultiDisplay
468 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
469 UseSoloWindowHeaderMultiDisplay
472 TEST_F(FramePainterTest
, MAYBE_UseSoloWindowHeaderMultiDisplay
) {
473 if (!SupportsMultipleDisplays())
476 UpdateDisplay("1000x600,600x400");
478 // Create two widgets and painters for them.
479 scoped_ptr
<Widget
> w1(CreateTestWidget());
480 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
481 w1
->SetBounds(gfx::Rect(0, 0, 100, 100));
483 WindowRepaintChecker
checker1(w1
->GetNativeWindow());
484 scoped_ptr
<Widget
> w2(CreateTestWidget());
485 scoped_ptr
<FramePainter
> p2(CreateTestPainter(w2
.get()));
486 w2
->SetBounds(gfx::Rect(0, 0, 100, 100));
488 WindowRepaintChecker
checker2(w2
->GetNativeWindow());
490 // Now there are two windows in the same display, so we should not use solo
492 EXPECT_FALSE(p1
->UseSoloWindowHeader());
493 EXPECT_FALSE(p2
->UseSoloWindowHeader());
494 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
496 // Moves the second window to the secondary display. Both w1/w2 should be
498 w2
->SetBounds(gfx::Rect(1200, 0, 100, 100));
499 EXPECT_TRUE(p1
->UseSoloWindowHeader());
500 EXPECT_TRUE(p2
->UseSoloWindowHeader());
501 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
502 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
504 // Open two more windows in the primary display.
505 scoped_ptr
<Widget
> w3(CreateTestWidget());
506 scoped_ptr
<FramePainter
> p3(CreateTestPainter(w3
.get()));
507 w3
->SetBounds(gfx::Rect(0, 0, 100, 100));
509 scoped_ptr
<Widget
> w4(CreateTestWidget());
510 scoped_ptr
<FramePainter
> p4(CreateTestPainter(w4
.get()));
511 w4
->SetBounds(gfx::Rect(0, 0, 100, 100));
514 // Because the primary display has two windows w1 and w3, they shouldn't be
515 // solo. w2 should be solo.
516 EXPECT_FALSE(p1
->UseSoloWindowHeader());
517 EXPECT_TRUE(p2
->UseSoloWindowHeader());
518 EXPECT_FALSE(p3
->UseSoloWindowHeader());
519 EXPECT_FALSE(p4
->UseSoloWindowHeader());
520 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
522 // Moves the w4 to the secondary display. Now the w2 shouldn't be solo
524 w4
->SetBounds(gfx::Rect(1200, 0, 100, 100));
525 EXPECT_FALSE(p1
->UseSoloWindowHeader());
526 EXPECT_FALSE(p2
->UseSoloWindowHeader());
527 EXPECT_FALSE(p3
->UseSoloWindowHeader());
528 EXPECT_FALSE(p4
->UseSoloWindowHeader());
529 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
531 // Moves the w3 to the secondary display too. Now w1 should be solo again.
532 w3
->SetBounds(gfx::Rect(1200, 0, 100, 100));
533 EXPECT_TRUE(p1
->UseSoloWindowHeader());
534 EXPECT_FALSE(p2
->UseSoloWindowHeader());
535 EXPECT_FALSE(p3
->UseSoloWindowHeader());
536 EXPECT_FALSE(p4
->UseSoloWindowHeader());
537 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
539 // Change the w3 state to maximize. Doesn't affect to w1.
540 wm::MaximizeWindow(w3
->GetNativeWindow());
541 EXPECT_TRUE(p1
->UseSoloWindowHeader());
542 EXPECT_FALSE(p2
->UseSoloWindowHeader());
543 EXPECT_FALSE(p3
->UseSoloWindowHeader());
544 EXPECT_FALSE(p4
->UseSoloWindowHeader());
546 // Close the w3 and w4.
549 EXPECT_TRUE(p1
->UseSoloWindowHeader());
550 EXPECT_TRUE(p2
->UseSoloWindowHeader());
551 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
553 // Move w2 back to the primary display.
554 w2
->SetBounds(gfx::Rect(0, 0, 100, 100));
555 EXPECT_FALSE(p1
->UseSoloWindowHeader());
556 EXPECT_FALSE(p2
->UseSoloWindowHeader());
557 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
558 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
562 EXPECT_TRUE(p1
->UseSoloWindowHeader());
563 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
566 TEST_F(FramePainterTest
, GetHeaderOpacity
) {
567 // Create a widget and a painter for it.
568 scoped_ptr
<Widget
> w1(CreateTestWidget());
569 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
572 // Modify the values of the opacity constants so that they each have a
574 ScopedOpacityConstantModifier opacity_constant_modifier
;
576 // Solo active window has solo window opacity.
577 EXPECT_EQ(FramePainter::kSoloWindowOpacity
,
578 p1
->GetHeaderOpacity(FramePainter::ACTIVE
,
579 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
582 // Create a second widget and painter.
583 scoped_ptr
<Widget
> w2(CreateTestWidget());
584 scoped_ptr
<FramePainter
> p2(CreateTestPainter(w2
.get()));
587 // Active window has active window opacity.
588 EXPECT_EQ(FramePainter::kActiveWindowOpacity
,
589 p2
->GetHeaderOpacity(FramePainter::ACTIVE
,
590 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
593 // Inactive window has inactive window opacity.
594 EXPECT_EQ(FramePainter::kInactiveWindowOpacity
,
595 p2
->GetHeaderOpacity(FramePainter::INACTIVE
,
596 IDR_AURA_WINDOW_HEADER_BASE_INACTIVE
,
599 // Regular maximized windows are fully opaque.
600 ash::wm::MaximizeWindow(w1
->GetNativeWindow());
602 p1
->GetHeaderOpacity(FramePainter::ACTIVE
,
603 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
607 // Test that the minimal header style is used in the proper situations.
608 TEST_F(FramePainterTest
, MinimalHeaderStyle
) {
609 // Create a widget and a painter for it.
610 scoped_ptr
<Widget
> w(CreateTestWidget());
611 scoped_ptr
<FramePainter
> p(CreateTestPainter(w
.get()));
614 // Regular non-maximized windows should not use the minimal header style.
615 EXPECT_FALSE(p
->ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));
617 // Regular maximized windows should use the minimal header style.
619 EXPECT_TRUE(p
->ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));
621 // Test cases where the maximized window should not use the minimal header
623 EXPECT_FALSE(p
->ShouldUseMinimalHeaderStyle(FramePainter::THEMED_YES
));
625 SetTrackedByWorkspace(w
->GetNativeWindow(), false);
626 EXPECT_FALSE(p
->ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));
627 SetTrackedByWorkspace(w
->GetNativeWindow(), true);
630 // Ensure the title text is vertically aligned with the window icon.
631 TEST_F(FramePainterTest
, TitleIconAlignment
) {
632 scoped_ptr
<Widget
> w(CreateTestWidget());
634 ImageButton
size(NULL
);
635 ImageButton
close(NULL
);
636 views::View window_icon
;
637 window_icon
.SetBounds(0, 0, 16, 16);
642 FramePainter::SIZE_BUTTON_MAXIMIZES
);
643 w
->SetBounds(gfx::Rect(0, 0, 500, 500));
646 // Title and icon are aligned when shorter_header is false.
647 p
.LayoutHeader(w
->non_client_view()->frame_view(), false);
648 gfx::Font default_font
;
649 gfx::Rect large_header_title_bounds
= p
.GetTitleBounds(default_font
);
650 EXPECT_EQ(window_icon
.bounds().CenterPoint().y(),
651 large_header_title_bounds
.CenterPoint().y());
653 // Title and icon are aligned when shorter_header is true.
654 p
.LayoutHeader(w
->non_client_view()->frame_view(), true);
655 gfx::Rect short_header_title_bounds
= p
.GetTitleBounds(default_font
);
656 EXPECT_EQ(window_icon
.bounds().CenterPoint().y(),
657 short_header_title_bounds
.CenterPoint().y());
660 TEST_F(FramePainterTest
, ChildWindowVisibility
) {
661 scoped_ptr
<Widget
> w1(CreateTestWidget());
662 scoped_ptr
<FramePainter
> p1(CreateTestPainter(w1
.get()));
665 // Solo active window has solo window opacity.
666 EXPECT_EQ(FramePainter::kSoloWindowOpacity
,
667 p1
->GetHeaderOpacity(FramePainter::ACTIVE
,
668 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
671 // Create a child window which doesn't affect the solo header.
672 scoped_ptr
<Widget
> w2(new Widget
);
673 Widget::InitParams
params(Widget::InitParams::TYPE_CONTROL
);
674 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
675 params
.parent
= w1
->GetNativeView();
679 // Still has solo header if child window is added.
680 EXPECT_EQ(FramePainter::kSoloWindowOpacity
,
681 p1
->GetHeaderOpacity(FramePainter::ACTIVE
,
682 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
685 // Change the visibility of w2 and verifies w1 still has solo header.
687 EXPECT_EQ(FramePainter::kSoloWindowOpacity
,
688 p1
->GetHeaderOpacity(FramePainter::ACTIVE
,
689 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,