Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / ash / wm / frame_painter_unittest.cc
blobee9313fcf105b60fe1856a088378fae2f5632854
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"
8 #include "ash/shell.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;
32 using views::Button;
33 using views::ImageButton;
34 using views::NonClientFrameView;
35 using views::ToggleImageButton;
36 using views::Widget;
38 namespace {
40 bool ImagesMatch(ImageButton* button,
41 int normal_image_id,
42 int hovered_image_id,
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 {
54 public:
55 ResizableWidgetDelegate(views::Widget* widget) {
56 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 {
64 delete this;
67 private:
68 views::Widget* widget_;
70 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
73 class WindowRepaintChecker : public aura::WindowObserver {
74 public:
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;
85 return result;
88 private:
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 {
107 public:
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_;
125 private:
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,
144 NULL,
145 size_button,
146 close_button,
147 FramePainter::SIZE_BUTTON_MAXIMIZES);
148 return painter;
151 } // namespace
153 namespace ash {
155 class FramePainterTest : public ash::test::AshTestBase {
156 public:
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);
164 return widget;
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);
174 return widget;
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);
184 return widget;
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);
196 return widget;
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()));
207 widget->Show();
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));
213 // Close the window.
214 widget.reset();
215 EXPECT_FALSE(root->GetProperty(internal::kSoloWindowHeaderKey));
217 // Recreate another window again.
218 widget.reset(CreateTestWidget());
219 painter.reset(CreateTestPainter(widget.get()));
220 widget->Show();
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(),
234 NULL,
235 &size_button,
236 &close_button,
237 FramePainter::SIZE_BUTTON_MAXIMIZES);
238 widget->Show();
240 // Basic layout.
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));
251 // Shorter layout.
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.
263 widget->Maximize();
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()));
292 w1->Show();
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()));
300 w2->Show();
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
304 // property.
305 EXPECT_FALSE(p1->UseSoloWindowHeader());
307 // Hide one window. Solo should be enabled.
308 w2->Hide();
309 EXPECT_TRUE(p1->UseSoloWindowHeader());
311 // Show that window. Solo should be disabled.
312 w2->Show();
313 EXPECT_FALSE(p1->UseSoloWindowHeader());
315 // Minimize the second window. Solo should be enabled.
316 w2->Minimize();
317 EXPECT_TRUE(p1->UseSoloWindowHeader());
319 // Close the minimized window.
320 w2.reset();
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()));
326 w3->Show();
327 EXPECT_FALSE(p3->UseSoloWindowHeader());
329 // Close the always-on-top widget.
330 w3.reset();
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()));
340 w1->Show();
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());
348 w2->Show();
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.
354 w2->Minimize();
355 EXPECT_TRUE(p1->UseSoloWindowHeader());
357 // Restoring the app window turns off solo headers.
358 w2->Restore();
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()));
368 w1->Show();
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()));
376 w2->Show();
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
386 // solo.
387 w1.reset();
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()));
396 w1->Show();
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);
406 w2->Show();
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()));
421 w1->Show();
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);
430 w2->Show();
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()));
445 widget->Show();
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());
456 window->Show();
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());
463 #if defined(OS_WIN)
464 // Multiple displays are not supported on Windows Ash. http://crbug.com/165962
465 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
466 DISABLED_UseSoloWindowHeaderMultiDisplay
467 #else
468 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
469 UseSoloWindowHeaderMultiDisplay
470 #endif
472 TEST_F(FramePainterTest, MAYBE_UseSoloWindowHeaderMultiDisplay) {
473 if (!SupportsMultipleDisplays())
474 return;
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));
482 w1->Show();
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));
487 w2->Show();
488 WindowRepaintChecker checker2(w2->GetNativeWindow());
490 // Now there are two windows in the same display, so we should not use solo
491 // headers.
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
497 // solo.
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));
508 w3->Show();
509 scoped_ptr<Widget> w4(CreateTestWidget());
510 scoped_ptr<FramePainter> p4(CreateTestPainter(w4.get()));
511 w4->SetBounds(gfx::Rect(0, 0, 100, 100));
512 w4->Show();
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
523 // anymore.
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.
547 w3.reset();
548 w4.reset();
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());
560 // Close w2.
561 w2.reset();
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()));
570 w1->Show();
572 // Modify the values of the opacity constants so that they each have a
573 // different value.
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,
580 0));
582 // Create a second widget and painter.
583 scoped_ptr<Widget> w2(CreateTestWidget());
584 scoped_ptr<FramePainter> p2(CreateTestPainter(w2.get()));
585 w2->Show();
587 // Active window has active window opacity.
588 EXPECT_EQ(FramePainter::kActiveWindowOpacity,
589 p2->GetHeaderOpacity(FramePainter::ACTIVE,
590 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
591 0));
593 // Inactive window has inactive window opacity.
594 EXPECT_EQ(FramePainter::kInactiveWindowOpacity,
595 p2->GetHeaderOpacity(FramePainter::INACTIVE,
596 IDR_AURA_WINDOW_HEADER_BASE_INACTIVE,
597 0));
599 // Regular maximized windows are fully opaque.
600 ash::wm::MaximizeWindow(w1->GetNativeWindow());
601 EXPECT_EQ(255,
602 p1->GetHeaderOpacity(FramePainter::ACTIVE,
603 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
604 0));
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()));
612 w->Show();
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.
618 w->Maximize();
619 EXPECT_TRUE(p->ShouldUseMinimalHeaderStyle(FramePainter::THEMED_NO));
621 // Test cases where the maximized window should not use the minimal header
622 // style.
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());
633 FramePainter p;
634 ImageButton size(NULL);
635 ImageButton close(NULL);
636 views::View window_icon;
637 window_icon.SetBounds(0, 0, 16, 16);
638 p.Init(w.get(),
639 &window_icon,
640 &size,
641 &close,
642 FramePainter::SIZE_BUTTON_MAXIMIZES);
643 w->SetBounds(gfx::Rect(0, 0, 500, 500));
644 w->Show();
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()));
663 w1->Show();
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,
669 0));
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();
676 w2->Init(params);
677 w2->Show();
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,
683 0));
685 // Change the visibility of w2 and verifies w1 still has solo header.
686 w2->Hide();
687 EXPECT_EQ(FramePainter::kSoloWindowOpacity,
688 p1->GetHeaderOpacity(FramePainter::ACTIVE,
689 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
690 0));
693 } // namespace ash