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/screen.h"
23 #include "ui/views/controls/button/button.h"
24 #include "ui/views/controls/button/image_button.h"
25 #include "ui/views/widget/widget.h"
26 #include "ui/views/widget/widget_delegate.h"
27 #include "ui/views/window/non_client_view.h"
29 using ui::ThemeProvider
;
31 using views::ImageButton
;
32 using views::NonClientFrameView
;
33 using views::ToggleImageButton
;
38 bool ImagesMatch(ImageButton
* button
,
41 int pressed_image_id
) {
42 ThemeProvider
* theme
= button
->GetWidget()->GetThemeProvider();
43 gfx::ImageSkia
* normal
= theme
->GetImageSkiaNamed(normal_image_id
);
44 gfx::ImageSkia
* hovered
= theme
->GetImageSkiaNamed(hovered_image_id
);
45 gfx::ImageSkia
* pressed
= theme
->GetImageSkiaNamed(pressed_image_id
);
46 return button
->GetImage(Button::STATE_NORMAL
).BackedBySameObjectAs(*normal
) &&
47 button
->GetImage(Button::STATE_HOVERED
).BackedBySameObjectAs(*hovered
) &&
48 button
->GetImage(Button::STATE_PRESSED
).BackedBySameObjectAs(*pressed
);
51 class ResizableWidgetDelegate
: public views::WidgetDelegate
{
53 ResizableWidgetDelegate(views::Widget
* widget
) {
57 virtual bool CanResize() const OVERRIDE
{ return true; }
58 // Implementations of the widget class.
59 virtual views::Widget
* GetWidget() OVERRIDE
{ return widget_
; }
60 virtual const views::Widget
* GetWidget() const OVERRIDE
{ return widget_
; }
61 virtual void DeleteDelegate() OVERRIDE
{
66 views::Widget
* widget_
;
68 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate
);
71 class WindowRepaintChecker
: public aura::WindowObserver
{
73 explicit WindowRepaintChecker(aura::Window
* window
)
74 : is_paint_scheduled_(false) {
75 window
->AddObserver(this);
77 virtual ~WindowRepaintChecker() {
80 bool IsPaintScheduledAndReset() {
81 bool result
= is_paint_scheduled_
;
82 is_paint_scheduled_
= false;
87 // aura::WindowObserver overrides:
88 virtual void OnWindowPaintScheduled(aura::Window
* window
,
89 const gfx::Rect
& region
) OVERRIDE
{
90 is_paint_scheduled_
= true;
92 virtual void OnWindowDestroying(aura::Window
* window
) OVERRIDE
{
93 window
->RemoveObserver(this);
96 bool is_paint_scheduled_
;
98 DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker
);
101 // Modifies the values of kInactiveWindowOpacity, kActiveWindowOpacity, and
102 // kSoloWindowOpacity for the lifetime of the class. This is useful so that
103 // the constants each have different values.
104 class ScopedOpacityConstantModifier
{
106 ScopedOpacityConstantModifier()
107 : initial_active_window_opacity_(
108 ash::FramePainter::kActiveWindowOpacity
),
109 initial_inactive_window_opacity_(
110 ash::FramePainter::kInactiveWindowOpacity
),
111 initial_solo_window_opacity_(ash::FramePainter::kSoloWindowOpacity
) {
112 ash::FramePainter::kActiveWindowOpacity
= 100;
113 ash::FramePainter::kInactiveWindowOpacity
= 120;
114 ash::FramePainter::kSoloWindowOpacity
= 140;
116 ~ScopedOpacityConstantModifier() {
117 ash::FramePainter::kActiveWindowOpacity
= initial_active_window_opacity_
;
118 ash::FramePainter::kInactiveWindowOpacity
=
119 initial_inactive_window_opacity_
;
120 ash::FramePainter::kSoloWindowOpacity
= initial_solo_window_opacity_
;
124 int initial_active_window_opacity_
;
125 int initial_inactive_window_opacity_
;
126 int initial_solo_window_opacity_
;
128 DISALLOW_COPY_AND_ASSIGN(ScopedOpacityConstantModifier
);
135 class FramePainterTest
: public ash::test::AshTestBase
{
137 // Creates a test widget that owns its native widget.
138 Widget
* CreateTestWidget() {
139 Widget
* widget
= new Widget
;
140 Widget::InitParams params
;
141 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
142 params
.context
= CurrentContext();
143 widget
->Init(params
);
147 Widget
* CreateAlwaysOnTopWidget() {
148 Widget
* widget
= new Widget
;
149 Widget::InitParams params
;
150 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
151 params
.context
= CurrentContext();
152 params
.keep_on_top
= true;
153 widget
->Init(params
);
157 Widget
* CreatePanelWidget() {
158 Widget
* widget
= new Widget
;
159 Widget::InitParams params
;
160 params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
161 params
.context
= CurrentContext();
162 params
.type
= Widget::InitParams::TYPE_PANEL
;
163 widget
->Init(params
);
167 Widget
* CreateResizableWidget() {
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 params
.delegate
= new ResizableWidgetDelegate(widget
);
174 params
.type
= Widget::InitParams::TYPE_WINDOW
;
175 widget
->Init(params
);
180 TEST_F(FramePainterTest
, CreateAndDeleteSingleWindow
) {
181 // Ensure that creating/deleting a window works well and doesn't cause
182 // crashes. See crbug.com/155634
183 aura::RootWindow
* root
= Shell::GetActiveRootWindow();
185 scoped_ptr
<Widget
> widget(CreateTestWidget());
186 scoped_ptr
<FramePainter
> painter(new FramePainter
);
187 ImageButton
size(NULL
);
188 ImageButton
close(NULL
);
190 widget
.get(), NULL
, &size
, &close
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
193 // We only have one window, so it should use a solo header.
194 EXPECT_TRUE(painter
->UseSoloWindowHeader());
195 EXPECT_TRUE(root
->GetProperty(internal::kSoloWindowHeaderKey
));
199 EXPECT_FALSE(root
->GetProperty(internal::kSoloWindowHeaderKey
));
201 // Recreate another window again.
202 painter
.reset(new FramePainter
);
203 widget
.reset(CreateTestWidget());
206 widget
.get(), NULL
, &size
, &close
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
208 EXPECT_TRUE(painter
->UseSoloWindowHeader());
209 EXPECT_TRUE(root
->GetProperty(internal::kSoloWindowHeaderKey
));
212 TEST_F(FramePainterTest
, LayoutHeader
) {
213 scoped_ptr
<Widget
> widget(CreateTestWidget());
214 ImageButton
size_button(NULL
);
215 ImageButton
close_button(NULL
);
216 NonClientFrameView
* frame_view
= widget
->non_client_view()->frame_view();
217 frame_view
->AddChildView(&size_button
);
218 frame_view
->AddChildView(&close_button
);
219 scoped_ptr
<FramePainter
> painter(new FramePainter
);
220 painter
->Init(widget
.get(),
224 FramePainter::SIZE_BUTTON_MAXIMIZES
);
228 painter
->LayoutHeader(frame_view
, false);
229 EXPECT_TRUE(ImagesMatch(&close_button
,
230 IDR_AURA_WINDOW_CLOSE
,
231 IDR_AURA_WINDOW_CLOSE_H
,
232 IDR_AURA_WINDOW_CLOSE_P
));
233 EXPECT_TRUE(ImagesMatch(&size_button
,
234 IDR_AURA_WINDOW_MAXIMIZE
,
235 IDR_AURA_WINDOW_MAXIMIZE_H
,
236 IDR_AURA_WINDOW_MAXIMIZE_P
));
239 painter
->LayoutHeader(frame_view
, true);
240 EXPECT_TRUE(ImagesMatch(&close_button
,
241 IDR_AURA_WINDOW_MAXIMIZED_CLOSE
,
242 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_H
,
243 IDR_AURA_WINDOW_MAXIMIZED_CLOSE_P
));
244 EXPECT_TRUE(ImagesMatch(&size_button
,
245 IDR_AURA_WINDOW_MAXIMIZED_RESTORE
,
246 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_H
,
247 IDR_AURA_WINDOW_MAXIMIZED_RESTORE_P
));
249 // Maximized shorter layout.
251 painter
->LayoutHeader(frame_view
, true);
252 EXPECT_TRUE(ImagesMatch(&close_button
,
253 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2
,
254 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_H
,
255 IDR_AURA_WINDOW_MAXIMIZED_CLOSE2_P
));
256 EXPECT_TRUE(ImagesMatch(&size_button
,
257 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2
,
258 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_H
,
259 IDR_AURA_WINDOW_MAXIMIZED_RESTORE2_P
));
261 // Fullscreen can show the buttons during an immersive reveal, so it should
262 // use the same images as maximized.
263 widget
->SetFullscreen(true);
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
));
275 TEST_F(FramePainterTest
, UseSoloWindowHeader
) {
276 // Create a widget and a painter for it.
277 scoped_ptr
<Widget
> w1(CreateTestWidget());
279 ImageButton
size1(NULL
);
280 ImageButton
close1(NULL
);
281 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
284 // We only have one window, so it should use a solo header.
285 EXPECT_TRUE(p1
.UseSoloWindowHeader());
287 // Create a second widget and painter.
288 scoped_ptr
<Widget
> w2(CreateTestWidget());
290 ImageButton
size2(NULL
);
291 ImageButton
close2(NULL
);
292 p2
.Init(w2
.get(), NULL
, &size2
, &close2
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
295 // Now there are two windows, so we should not use solo headers. This only
296 // needs to test |p1| because "solo window headers" are a per-root-window
298 EXPECT_FALSE(p1
.UseSoloWindowHeader());
300 // Hide one window. Solo should be enabled.
302 EXPECT_TRUE(p1
.UseSoloWindowHeader());
304 // Show that window. Solo should be disabled.
306 EXPECT_FALSE(p1
.UseSoloWindowHeader());
308 // Maximize the window, then activate the first window. The second window
309 // is in its own workspace, so solo should be active for the first one.
312 EXPECT_TRUE(p1
.UseSoloWindowHeader());
314 // Switch to the second window and restore it. Solo should be disabled.
317 EXPECT_FALSE(p2
.UseSoloWindowHeader());
319 // Minimize the second window. Solo should be enabled.
321 EXPECT_TRUE(p1
.UseSoloWindowHeader());
323 // Close the minimized window.
325 EXPECT_TRUE(p1
.UseSoloWindowHeader());
327 // Open an always-on-top widget (which lives in a different container).
328 scoped_ptr
<Widget
> w3(CreateAlwaysOnTopWidget());
330 ImageButton
size3(NULL
);
331 ImageButton
close3(NULL
);
332 p3
.Init(w3
.get(), NULL
, &size3
, &close3
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
334 EXPECT_FALSE(p3
.UseSoloWindowHeader());
336 // Close the always-on-top widget.
338 EXPECT_TRUE(p1
.UseSoloWindowHeader());
341 // An open V2 app window should cause browser windows not to use the
342 // solo window header.
343 TEST_F(FramePainterTest
, UseSoloWindowHeaderWithApp
) {
344 // Create a widget and a painter for it.
345 scoped_ptr
<Widget
> w1(CreateTestWidget());
347 ImageButton
size1(NULL
);
348 ImageButton
close1(NULL
);
349 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
352 // We only have one window, so it should use a solo header.
353 EXPECT_TRUE(p1
.UseSoloWindowHeader());
355 // Simulate a V2 app window, which is part of the active workspace but does
356 // not have a frame painter.
357 scoped_ptr
<Widget
> w2(CreateTestWidget());
360 // Now there are two windows, so we should not use solo headers.
361 EXPECT_FALSE(p1
.UseSoloWindowHeader());
363 // Minimize the app window. The first window should go solo again.
365 EXPECT_TRUE(p1
.UseSoloWindowHeader());
367 // Restoring the app window turns off solo headers.
369 EXPECT_FALSE(p1
.UseSoloWindowHeader());
372 // Panels should not "count" for computing solo window headers, and the panel
373 // itself should always have an opaque header.
374 TEST_F(FramePainterTest
, UseSoloWindowHeaderWithPanel
) {
375 // Create a widget and a painter for it.
376 scoped_ptr
<Widget
> w1(CreateTestWidget());
378 ImageButton
size1(NULL
);
379 ImageButton
close1(NULL
);
380 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
383 // We only have one window, so it should use a solo header.
384 EXPECT_TRUE(p1
.UseSoloWindowHeader());
386 // Create a panel and a painter for it.
387 scoped_ptr
<Widget
> w2(CreatePanelWidget());
389 ImageButton
size2(NULL
);
390 ImageButton
close2(NULL
);
391 p2
.Init(w2
.get(), NULL
, &size2
, &close2
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
394 // Despite two windows, the first window should still be considered "solo"
395 // because panels aren't included in the computation.
396 EXPECT_TRUE(p1
.UseSoloWindowHeader());
398 // The panel itself is not considered solo.
399 EXPECT_FALSE(p2
.UseSoloWindowHeader());
401 // Even after closing the first window, the panel is still not considered
404 EXPECT_FALSE(p2
.UseSoloWindowHeader());
407 // Modal dialogs should not use solo headers.
408 TEST_F(FramePainterTest
, UseSoloWindowHeaderModal
) {
409 // Create a widget and a painter for it.
410 scoped_ptr
<Widget
> w1(CreateTestWidget());
412 ImageButton
size1(NULL
);
413 ImageButton
close1(NULL
);
414 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
417 // We only have one window, so it should use a solo header.
418 EXPECT_TRUE(p1
.UseSoloWindowHeader());
420 // Create a fake modal window.
421 scoped_ptr
<Widget
> w2(CreateTestWidget());
422 w2
->GetNativeWindow()->SetProperty(aura::client::kModalKey
,
423 ui::MODAL_TYPE_WINDOW
);
425 ImageButton
size2(NULL
);
426 ImageButton
close2(NULL
);
427 p2
.Init(w2
.get(), NULL
, &size2
, &close2
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
430 // Despite two windows, the first window should still be considered "solo"
431 // because modal windows aren't included in the computation.
432 EXPECT_TRUE(p1
.UseSoloWindowHeader());
434 // The modal window itself is not considered solo.
435 EXPECT_FALSE(p2
.UseSoloWindowHeader());
438 // Constrained windows should not use solo headers.
439 TEST_F(FramePainterTest
, UseSoloWindowHeaderConstrained
) {
440 // Create a widget and a painter for it.
441 scoped_ptr
<Widget
> w1(CreateTestWidget());
443 ImageButton
size1(NULL
);
444 ImageButton
close1(NULL
);
445 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
448 // We only have one window, so it should use a solo header.
449 EXPECT_TRUE(p1
.UseSoloWindowHeader());
451 // Create a fake constrained window.
452 scoped_ptr
<Widget
> w2(CreateTestWidget());
453 w2
->GetNativeWindow()->SetProperty(ash::kConstrainedWindowKey
, true);
455 ImageButton
size2(NULL
);
456 ImageButton
close2(NULL
);
457 p2
.Init(w2
.get(), NULL
, &size2
, &close2
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
460 // Despite two windows, the first window should still be considered "solo"
461 // because constrained windows aren't included in the computation.
462 EXPECT_TRUE(p1
.UseSoloWindowHeader());
464 // The constrained window itself is not considered solo.
465 EXPECT_FALSE(p2
.UseSoloWindowHeader());
469 // Multiple displays are not supported on Windows Ash. http://crbug.com/165962
470 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
471 DISABLED_UseSoloWindowHeaderMultiDisplay
473 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
474 UseSoloWindowHeaderMultiDisplay
477 TEST_F(FramePainterTest
, MAYBE_UseSoloWindowHeaderMultiDisplay
) {
478 UpdateDisplay("1000x600,600x400");
480 // Create two widgets and painters for them.
481 scoped_ptr
<Widget
> w1(CreateTestWidget());
483 ImageButton
size1(NULL
);
484 ImageButton
close1(NULL
);
485 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
486 w1
->SetBounds(gfx::Rect(0, 0, 100, 100));
488 WindowRepaintChecker
checker1(w1
->GetNativeWindow());
489 scoped_ptr
<Widget
> w2(CreateTestWidget());
491 ImageButton
size2(NULL
);
492 ImageButton
close2(NULL
);
493 p2
.Init(w2
.get(), NULL
, &size2
, &close2
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
494 w2
->SetBounds(gfx::Rect(0, 0, 100, 100));
496 WindowRepaintChecker
checker2(w2
->GetNativeWindow());
498 // Now there are two windows in the same display, so we should not use solo
500 EXPECT_FALSE(p1
.UseSoloWindowHeader());
501 EXPECT_FALSE(p2
.UseSoloWindowHeader());
502 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
504 // Moves the second window to the secondary display. Both w1/w2 should be
506 w2
->SetBounds(gfx::Rect(1200, 0, 100, 100));
507 EXPECT_TRUE(p1
.UseSoloWindowHeader());
508 EXPECT_TRUE(p2
.UseSoloWindowHeader());
509 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
510 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
512 // Open two more windows in the primary display.
513 scoped_ptr
<Widget
> w3(CreateTestWidget());
515 ImageButton
size3(NULL
);
516 ImageButton
close3(NULL
);
517 p3
.Init(w3
.get(), NULL
, &size3
, &close3
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
518 w3
->SetBounds(gfx::Rect(0, 0, 100, 100));
520 scoped_ptr
<Widget
> w4(CreateTestWidget());
522 ImageButton
size4(NULL
);
523 ImageButton
close4(NULL
);
524 p4
.Init(w4
.get(), NULL
, &size4
, &close4
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
525 w4
->SetBounds(gfx::Rect(0, 0, 100, 100));
528 // Because the primary display has two windows w1 and w3, they shouldn't be
529 // solo. w2 should be solo.
530 EXPECT_FALSE(p1
.UseSoloWindowHeader());
531 EXPECT_TRUE(p2
.UseSoloWindowHeader());
532 EXPECT_FALSE(p3
.UseSoloWindowHeader());
533 EXPECT_FALSE(p4
.UseSoloWindowHeader());
534 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
536 // Moves the w4 to the secondary display. Now the w2 shouldn't be solo
538 w4
->SetBounds(gfx::Rect(1200, 0, 100, 100));
539 EXPECT_FALSE(p1
.UseSoloWindowHeader());
540 EXPECT_FALSE(p2
.UseSoloWindowHeader());
541 EXPECT_FALSE(p3
.UseSoloWindowHeader());
542 EXPECT_FALSE(p4
.UseSoloWindowHeader());
543 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
545 // Moves the w3 to the secondary display too. Now w1 should be solo again.
546 w3
->SetBounds(gfx::Rect(1200, 0, 100, 100));
547 EXPECT_TRUE(p1
.UseSoloWindowHeader());
548 EXPECT_FALSE(p2
.UseSoloWindowHeader());
549 EXPECT_FALSE(p3
.UseSoloWindowHeader());
550 EXPECT_FALSE(p4
.UseSoloWindowHeader());
551 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
553 // Change the w3 state to maximize. Doesn't affect to w1.
554 wm::MaximizeWindow(w3
->GetNativeWindow());
555 EXPECT_TRUE(p1
.UseSoloWindowHeader());
556 EXPECT_FALSE(p2
.UseSoloWindowHeader());
557 EXPECT_FALSE(p3
.UseSoloWindowHeader());
558 EXPECT_FALSE(p4
.UseSoloWindowHeader());
560 // Close the w3 and w4.
563 EXPECT_TRUE(p1
.UseSoloWindowHeader());
564 EXPECT_TRUE(p2
.UseSoloWindowHeader());
565 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
567 // Move w2 back to the primary display.
568 w2
->SetBounds(gfx::Rect(0, 0, 100, 100));
569 EXPECT_FALSE(p1
.UseSoloWindowHeader());
570 EXPECT_FALSE(p2
.UseSoloWindowHeader());
571 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
572 EXPECT_TRUE(checker2
.IsPaintScheduledAndReset());
576 EXPECT_TRUE(p1
.UseSoloWindowHeader());
577 EXPECT_TRUE(checker1
.IsPaintScheduledAndReset());
580 TEST_F(FramePainterTest
, GetHeaderOpacity
) {
581 // Create a widget and a painter for it.
582 scoped_ptr
<Widget
> w1(CreateTestWidget());
584 ImageButton
size1(NULL
);
585 ImageButton
close1(NULL
);
586 p1
.Init(w1
.get(), NULL
, &size1
, &close1
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
589 // Modify the values of the opacity constants so that they each have a
591 ScopedOpacityConstantModifier opacity_constant_modifier
;
593 // Solo active window has solo window opacity.
594 EXPECT_EQ(FramePainter::kSoloWindowOpacity
,
595 p1
.GetHeaderOpacity(FramePainter::ACTIVE
,
596 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
599 // Create a second widget and painter.
600 scoped_ptr
<Widget
> w2(CreateTestWidget());
602 ImageButton
size2(NULL
);
603 ImageButton
close2(NULL
);
604 p2
.Init(w2
.get(), NULL
, &size2
, &close2
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
607 // Active window has active window opacity.
608 EXPECT_EQ(FramePainter::kActiveWindowOpacity
,
609 p2
.GetHeaderOpacity(FramePainter::ACTIVE
,
610 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
613 // Inactive window has inactive window opacity.
614 EXPECT_EQ(FramePainter::kInactiveWindowOpacity
,
615 p2
.GetHeaderOpacity(FramePainter::INACTIVE
,
616 IDR_AURA_WINDOW_HEADER_BASE_INACTIVE
,
619 // Regular maximized windows are fully opaque.
620 ash::wm::MaximizeWindow(w1
->GetNativeWindow());
622 p1
.GetHeaderOpacity(FramePainter::ACTIVE
,
623 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE
,
627 // Test that the minimal header style is used in the proper situations.
628 TEST_F(FramePainterTest
, MinimalHeaderStyle
) {
629 // Create a widget and a painter for it.
630 scoped_ptr
<Widget
> w(CreateTestWidget());
632 ImageButton
size(NULL
);
633 ImageButton
close(NULL
);
634 p
.Init(w
.get(), NULL
, &size
, &close
, FramePainter::SIZE_BUTTON_MAXIMIZES
);
637 // Regular non-maximized windows should not use the minimal header style.
638 EXPECT_FALSE(p
.ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));
640 // Regular maximized windows should use the minimal header style.
642 EXPECT_TRUE(p
.ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));
644 // Test cases where the maximized window should not use the minimal header
646 EXPECT_FALSE(p
.ShouldUseMinimalHeaderStyle(FramePainter::THEMED_YES
));
648 SetTrackedByWorkspace(w
->GetNativeWindow(), false);
649 EXPECT_FALSE(p
.ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));
650 SetTrackedByWorkspace(w
->GetNativeWindow(), true);
652 w
->GetNativeWindow()->GetRootWindow()->SetProperty(
653 ash::internal::kCyclingThroughWorkspacesKey
, true);
654 EXPECT_FALSE(p
.ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO
));