Reland "Enable SysInfo::AmountOfPhysicalMemory to be called from within the Linux...
[chromium-blink-merge.git] / ash / wm / header_painter_unittest.cc
blob55f0ff7be50f5c22447535cb3f03599a644ba7a2
1 // Copyright 2013 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/header_painter.h"
7 #include "ash/ash_constants.h"
8 #include "ash/root_window_settings.h"
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/test/ash_test_base.h"
12 #include "ash/wm/caption_buttons/frame_caption_button_container_view.h"
13 #include "ash/wm/window_state.h"
14 #include "ash/wm/window_util.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "grit/ash_resources.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "ui/aura/client/aura_constants.h"
20 #include "ui/aura/client/window_tree_client.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/aura/window_observer.h"
23 #include "ui/base/hit_test.h"
24 #include "ui/gfx/font.h"
25 #include "ui/gfx/screen.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/views/widget/widget_delegate.h"
28 #include "ui/views/widget/widget_observer.h"
29 #include "ui/views/window/non_client_view.h"
31 using ash::HeaderPainter;
32 using views::NonClientFrameView;
33 using views::Widget;
35 namespace {
37 class ResizableWidgetDelegate : public views::WidgetDelegate {
38 public:
39 ResizableWidgetDelegate(views::Widget* widget) {
40 widget_ = widget;
43 virtual bool CanResize() const OVERRIDE { return true; }
44 // Implementations of the widget class.
45 virtual views::Widget* GetWidget() OVERRIDE { return widget_; }
46 virtual const views::Widget* GetWidget() const OVERRIDE { return widget_; }
47 virtual void DeleteDelegate() OVERRIDE {
48 delete this;
51 private:
52 views::Widget* widget_;
54 DISALLOW_COPY_AND_ASSIGN(ResizableWidgetDelegate);
57 class WindowRepaintChecker : public aura::WindowObserver {
58 public:
59 explicit WindowRepaintChecker(aura::Window* window)
60 : is_paint_scheduled_(false) {
61 window->AddObserver(this);
63 virtual ~WindowRepaintChecker() {
66 bool IsPaintScheduledAndReset() {
67 bool result = is_paint_scheduled_;
68 is_paint_scheduled_ = false;
69 return result;
72 private:
73 // aura::WindowObserver overrides:
74 virtual void OnWindowPaintScheduled(aura::Window* window,
75 const gfx::Rect& region) OVERRIDE {
76 is_paint_scheduled_ = true;
78 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
79 window->RemoveObserver(this);
82 bool is_paint_scheduled_;
84 DISALLOW_COPY_AND_ASSIGN(WindowRepaintChecker);
87 // Modifies the values of kInactiveWindowOpacity, kActiveWindowOpacity, and
88 // kSoloWindowOpacity for the lifetime of the class. This is useful so that
89 // the constants each have different values.
90 class ScopedOpacityConstantModifier {
91 public:
92 ScopedOpacityConstantModifier()
93 : initial_active_window_opacity_(
94 ash::HeaderPainter::kActiveWindowOpacity),
95 initial_inactive_window_opacity_(
96 ash::HeaderPainter::kInactiveWindowOpacity),
97 initial_solo_window_opacity_(ash::HeaderPainter::kSoloWindowOpacity) {
98 ash::HeaderPainter::kActiveWindowOpacity = 100;
99 ash::HeaderPainter::kInactiveWindowOpacity = 120;
100 ash::HeaderPainter::kSoloWindowOpacity = 140;
102 ~ScopedOpacityConstantModifier() {
103 ash::HeaderPainter::kActiveWindowOpacity = initial_active_window_opacity_;
104 ash::HeaderPainter::kInactiveWindowOpacity =
105 initial_inactive_window_opacity_;
106 ash::HeaderPainter::kSoloWindowOpacity = initial_solo_window_opacity_;
109 private:
110 int initial_active_window_opacity_;
111 int initial_inactive_window_opacity_;
112 int initial_solo_window_opacity_;
114 DISALLOW_COPY_AND_ASSIGN(ScopedOpacityConstantModifier);
117 // Creates a new HeaderPainter with empty buttons. Caller owns the memory.
118 HeaderPainter* CreateTestPainter(Widget* widget) {
119 HeaderPainter* painter = new HeaderPainter();
120 NonClientFrameView* frame_view = widget->non_client_view()->frame_view();
121 ash::FrameCaptionButtonContainerView* container =
122 new ash::FrameCaptionButtonContainerView(
123 widget,
124 ash::FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
125 // Add the container to the widget's non-client frame view so that it will be
126 // deleted when the widget is destroyed.
127 frame_view->AddChildView(container);
128 painter->Init(widget, frame_view, NULL, container);
129 return painter;
132 // Self-owned manager of the frame painter which deletes the painter and itself
133 // when its widget is closed.
134 class HeaderPainterOwner : views::WidgetObserver {
135 public:
136 explicit HeaderPainterOwner(Widget* widget)
137 : header_painter_(CreateTestPainter(widget)) {
138 widget->AddObserver(this);
141 virtual ~HeaderPainterOwner() {}
143 HeaderPainter* header_painter() { return header_painter_.get(); }
145 private:
146 virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
147 widget->RemoveObserver(this);
148 // Do not delete directly here, since the task of HeaderPainter causing
149 // the crash of crbug.com/273310 may run after this class handles this
150 // event.
151 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
154 scoped_ptr<HeaderPainter> header_painter_;
156 DISALLOW_COPY_AND_ASSIGN(HeaderPainterOwner);
159 } // namespace
161 namespace ash {
163 class HeaderPainterTest : public ash::test::AshTestBase {
164 public:
165 // Creates a test widget that owns its native widget.
166 Widget* CreateTestWidget() {
167 Widget* widget = new Widget;
168 Widget::InitParams params;
169 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
170 params.context = CurrentContext();
171 widget->Init(params);
172 return widget;
175 Widget* CreateAlwaysOnTopWidget() {
176 Widget* widget = new Widget;
177 Widget::InitParams params;
178 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
179 params.context = CurrentContext();
180 params.keep_on_top = true;
181 widget->Init(params);
182 return widget;
185 Widget* CreatePanelWidget() {
186 Widget* widget = new Widget;
187 Widget::InitParams params;
188 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
189 params.context = CurrentContext();
190 params.type = Widget::InitParams::TYPE_PANEL;
191 widget->Init(params);
192 return widget;
195 Widget* CreateResizableWidget() {
196 Widget* widget = new Widget;
197 Widget::InitParams params;
198 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
199 params.context = CurrentContext();
200 params.keep_on_top = true;
201 params.delegate = new ResizableWidgetDelegate(widget);
202 params.type = Widget::InitParams::TYPE_WINDOW;
203 widget->Init(params);
204 return widget;
208 TEST_F(HeaderPainterTest, CreateAndDeleteSingleWindow) {
209 // Ensure that creating/deleting a window works well and doesn't cause
210 // crashes. See crbug.com/155634
211 aura::Window* root = Shell::GetTargetRootWindow();
213 scoped_ptr<Widget> widget(CreateTestWidget());
214 scoped_ptr<HeaderPainter> painter(CreateTestPainter(widget.get()));
215 widget->Show();
217 // We only have one window, so it should use a solo header.
218 EXPECT_TRUE(painter->UseSoloWindowHeader());
219 EXPECT_TRUE(internal::GetRootWindowSettings(root)->solo_window_header);
221 // Close the window.
222 widget.reset();
223 EXPECT_FALSE(internal::GetRootWindowSettings(root)->solo_window_header);
225 // Recreate another window again.
226 widget.reset(CreateTestWidget());
227 painter.reset(CreateTestPainter(widget.get()));
228 widget->Show();
229 EXPECT_TRUE(painter->UseSoloWindowHeader());
230 EXPECT_TRUE(internal::GetRootWindowSettings(root)->solo_window_header);
233 TEST_F(HeaderPainterTest, UseSoloWindowHeader) {
234 // Create a widget and a painter for it.
235 scoped_ptr<Widget> w1(CreateTestWidget());
236 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
237 w1->Show();
239 // We only have one window, so it should use a solo header.
240 EXPECT_TRUE(p1->UseSoloWindowHeader());
242 // Create a second widget and painter.
243 scoped_ptr<Widget> w2(CreateTestWidget());
244 scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
245 w2->Show();
247 // Now there are two windows, so we should not use solo headers. This only
248 // needs to test |p1| because "solo window headers" are a per-root-window
249 // property.
250 EXPECT_FALSE(p1->UseSoloWindowHeader());
252 // Hide one window. Solo should be enabled.
253 w2->Hide();
254 EXPECT_TRUE(p1->UseSoloWindowHeader());
256 // Show that window. Solo should be disabled.
257 w2->Show();
258 EXPECT_FALSE(p1->UseSoloWindowHeader());
260 // Minimize the second window. Solo should be enabled.
261 w2->Minimize();
262 EXPECT_TRUE(p1->UseSoloWindowHeader());
264 // Close the minimized window.
265 w2.reset();
266 EXPECT_TRUE(p1->UseSoloWindowHeader());
268 // Open an always-on-top widget (which lives in a different container).
269 scoped_ptr<Widget> w3(CreateAlwaysOnTopWidget());
270 scoped_ptr<HeaderPainter> p3(CreateTestPainter(w3.get()));
271 w3->Show();
272 EXPECT_FALSE(p3->UseSoloWindowHeader());
274 // Close the always-on-top widget.
275 w3.reset();
276 EXPECT_TRUE(p1->UseSoloWindowHeader());
279 // An open V2 app window should cause browser windows not to use the
280 // solo window header.
281 TEST_F(HeaderPainterTest, UseSoloWindowHeaderWithApp) {
282 // Create a widget and a painter for it.
283 scoped_ptr<Widget> w1(CreateTestWidget());
284 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
285 w1->Show();
287 // We only have one window, so it should use a solo header.
288 EXPECT_TRUE(p1->UseSoloWindowHeader());
290 // Simulate a V2 app window, which is part of the active workspace but does
291 // not have a frame painter.
292 scoped_ptr<Widget> w2(CreateTestWidget());
293 w2->Show();
295 // Now there are two windows, so we should not use solo headers.
296 EXPECT_FALSE(p1->UseSoloWindowHeader());
298 // Minimize the app window. The first window should go solo again.
299 w2->Minimize();
300 EXPECT_TRUE(p1->UseSoloWindowHeader());
302 // Restoring the app window turns off solo headers.
303 w2->Restore();
304 EXPECT_FALSE(p1->UseSoloWindowHeader());
307 // Panels should not "count" for computing solo window headers, and the panel
308 // itself should always have an opaque header.
309 TEST_F(HeaderPainterTest, UseSoloWindowHeaderWithPanel) {
310 // Create a widget and a painter for it.
311 scoped_ptr<Widget> w1(CreateTestWidget());
312 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
313 w1->Show();
315 // We only have one window, so it should use a solo header.
316 EXPECT_TRUE(p1->UseSoloWindowHeader());
318 // Create a panel and a painter for it.
319 scoped_ptr<Widget> w2(CreatePanelWidget());
320 scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
321 w2->Show();
323 // Despite two windows, the first window should still be considered "solo"
324 // because panels aren't included in the computation.
325 EXPECT_TRUE(p1->UseSoloWindowHeader());
327 // The panel itself is not considered solo.
328 EXPECT_FALSE(p2->UseSoloWindowHeader());
330 // Even after closing the first window, the panel is still not considered
331 // solo.
332 w1.reset();
333 EXPECT_FALSE(p2->UseSoloWindowHeader());
336 // Modal dialogs should not use solo headers.
337 TEST_F(HeaderPainterTest, UseSoloWindowHeaderModal) {
338 // Create a widget and a painter for it.
339 scoped_ptr<Widget> w1(CreateTestWidget());
340 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
341 w1->Show();
343 // We only have one window, so it should use a solo header.
344 EXPECT_TRUE(p1->UseSoloWindowHeader());
346 // Create a fake modal window.
347 scoped_ptr<Widget> w2(CreateTestWidget());
348 scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
349 w2->GetNativeWindow()->SetProperty(aura::client::kModalKey,
350 ui::MODAL_TYPE_WINDOW);
351 w2->Show();
353 // Despite two windows, the first window should still be considered "solo"
354 // because modal windows aren't included in the computation.
355 EXPECT_TRUE(p1->UseSoloWindowHeader());
357 // The modal window itself is not considered solo.
358 EXPECT_FALSE(p2->UseSoloWindowHeader());
361 // Constrained windows should not use solo headers.
362 TEST_F(HeaderPainterTest, UseSoloWindowHeaderConstrained) {
363 // Create a widget and a painter for it.
364 scoped_ptr<Widget> w1(CreateTestWidget());
365 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
366 w1->Show();
368 // We only have one window, so it should use a solo header.
369 EXPECT_TRUE(p1->UseSoloWindowHeader());
371 // Create a fake constrained window.
372 scoped_ptr<Widget> w2(CreateTestWidget());
373 scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
374 w2->GetNativeWindow()->SetProperty(ash::kConstrainedWindowKey, true);
375 w2->Show();
377 // Despite two windows, the first window should still be considered "solo"
378 // because constrained windows aren't included in the computation.
379 EXPECT_TRUE(p1->UseSoloWindowHeader());
381 // The constrained window itself is not considered solo.
382 EXPECT_FALSE(p2->UseSoloWindowHeader());
385 // Non-drawing windows should not affect the solo computation.
386 TEST_F(HeaderPainterTest, UseSoloWindowHeaderNotDrawn) {
387 // Create a widget and a painter for it.
388 scoped_ptr<Widget> widget(CreateTestWidget());
389 scoped_ptr<HeaderPainter> painter(CreateTestPainter(widget.get()));
390 widget->Show();
392 // We only have one window, so it should use a solo header.
393 EXPECT_TRUE(painter->UseSoloWindowHeader());
395 // Create non-drawing window similar to DragDropTracker.
396 scoped_ptr<aura::Window> window(new aura::Window(NULL));
397 window->SetType(aura::client::WINDOW_TYPE_NORMAL);
398 window->Init(ui::LAYER_NOT_DRAWN);
399 aura::client::ParentWindowWithContext(window.get(), widget->GetNativeWindow(),
400 gfx::Rect());
401 window->Show();
403 // Despite two windows, the first window should still be considered "solo"
404 // because non-drawing windows aren't included in the computation.
405 EXPECT_TRUE(painter->UseSoloWindowHeader());
408 #if defined(OS_WIN)
409 // Multiple displays are not supported on Windows Ash. http://crbug.com/165962
410 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
411 DISABLED_UseSoloWindowHeaderMultiDisplay
412 #else
413 #define MAYBE_UseSoloWindowHeaderMultiDisplay \
414 UseSoloWindowHeaderMultiDisplay
415 #endif
417 TEST_F(HeaderPainterTest, MAYBE_UseSoloWindowHeaderMultiDisplay) {
418 if (!SupportsMultipleDisplays())
419 return;
421 UpdateDisplay("1000x600,600x400");
423 // Create two widgets and painters for them.
424 scoped_ptr<Widget> w1(CreateTestWidget());
425 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
426 w1->SetBounds(gfx::Rect(0, 0, 100, 100));
427 w1->Show();
428 WindowRepaintChecker checker1(w1->GetNativeWindow());
429 scoped_ptr<Widget> w2(CreateTestWidget());
430 scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
431 w2->SetBounds(gfx::Rect(0, 0, 100, 100));
432 w2->Show();
433 WindowRepaintChecker checker2(w2->GetNativeWindow());
435 // Now there are two windows in the same display, so we should not use solo
436 // headers.
437 EXPECT_FALSE(p1->UseSoloWindowHeader());
438 EXPECT_FALSE(p2->UseSoloWindowHeader());
439 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
441 // Moves the second window to the secondary display. Both w1/w2 should be
442 // solo.
443 w2->SetBounds(gfx::Rect(1200, 0, 100, 100));
444 EXPECT_TRUE(p1->UseSoloWindowHeader());
445 EXPECT_TRUE(p2->UseSoloWindowHeader());
446 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
447 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
449 // Open two more windows in the primary display.
450 scoped_ptr<Widget> w3(CreateTestWidget());
451 scoped_ptr<HeaderPainter> p3(CreateTestPainter(w3.get()));
452 w3->SetBounds(gfx::Rect(0, 0, 100, 100));
453 w3->Show();
454 scoped_ptr<Widget> w4(CreateTestWidget());
455 scoped_ptr<HeaderPainter> p4(CreateTestPainter(w4.get()));
456 w4->SetBounds(gfx::Rect(0, 0, 100, 100));
457 w4->Show();
459 // Because the primary display has two windows w1 and w3, they shouldn't be
460 // solo. w2 should be solo.
461 EXPECT_FALSE(p1->UseSoloWindowHeader());
462 EXPECT_TRUE(p2->UseSoloWindowHeader());
463 EXPECT_FALSE(p3->UseSoloWindowHeader());
464 EXPECT_FALSE(p4->UseSoloWindowHeader());
465 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
467 // Moves the w4 to the secondary display. Now the w2 shouldn't be solo
468 // anymore.
469 w4->SetBounds(gfx::Rect(1200, 0, 100, 100));
470 EXPECT_FALSE(p1->UseSoloWindowHeader());
471 EXPECT_FALSE(p2->UseSoloWindowHeader());
472 EXPECT_FALSE(p3->UseSoloWindowHeader());
473 EXPECT_FALSE(p4->UseSoloWindowHeader());
474 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
476 // Moves the w3 to the secondary display too. Now w1 should be solo again.
477 w3->SetBounds(gfx::Rect(1200, 0, 100, 100));
478 EXPECT_TRUE(p1->UseSoloWindowHeader());
479 EXPECT_FALSE(p2->UseSoloWindowHeader());
480 EXPECT_FALSE(p3->UseSoloWindowHeader());
481 EXPECT_FALSE(p4->UseSoloWindowHeader());
482 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
484 // Change the w3 state to maximize. Doesn't affect to w1.
485 wm::GetWindowState(w3->GetNativeWindow())->Maximize();
486 EXPECT_TRUE(p1->UseSoloWindowHeader());
487 EXPECT_FALSE(p2->UseSoloWindowHeader());
488 EXPECT_FALSE(p3->UseSoloWindowHeader());
489 EXPECT_FALSE(p4->UseSoloWindowHeader());
491 // Close the w3 and w4.
492 w3.reset();
493 w4.reset();
494 EXPECT_TRUE(p1->UseSoloWindowHeader());
495 EXPECT_TRUE(p2->UseSoloWindowHeader());
496 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
498 // Move w2 back to the primary display.
499 w2->SetBounds(gfx::Rect(0, 0, 100, 100));
500 EXPECT_FALSE(p1->UseSoloWindowHeader());
501 EXPECT_FALSE(p2->UseSoloWindowHeader());
502 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
503 EXPECT_TRUE(checker2.IsPaintScheduledAndReset());
505 // Close w2.
506 w2.reset();
507 EXPECT_TRUE(p1->UseSoloWindowHeader());
508 EXPECT_TRUE(checker1.IsPaintScheduledAndReset());
511 TEST_F(HeaderPainterTest, GetHeaderOpacity) {
512 // Create a widget and a painter for it.
513 scoped_ptr<Widget> w1(CreateTestWidget());
514 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
515 w1->Show();
517 // Modify the values of the opacity constants so that they each have a
518 // different value.
519 ScopedOpacityConstantModifier opacity_constant_modifier;
521 // Solo active window has solo window opacity.
522 EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
523 p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
524 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
525 0));
527 // Create a second widget and painter.
528 scoped_ptr<Widget> w2(CreateTestWidget());
529 scoped_ptr<HeaderPainter> p2(CreateTestPainter(w2.get()));
530 w2->Show();
532 // Active window has active window opacity.
533 EXPECT_EQ(HeaderPainter::kActiveWindowOpacity,
534 p2->GetHeaderOpacity(HeaderPainter::ACTIVE,
535 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
536 0));
538 // Inactive window has inactive window opacity.
539 EXPECT_EQ(HeaderPainter::kInactiveWindowOpacity,
540 p2->GetHeaderOpacity(HeaderPainter::INACTIVE,
541 IDR_AURA_WINDOW_HEADER_BASE_INACTIVE,
542 0));
544 // Regular maximized windows are fully opaque.
545 wm::GetWindowState(w1->GetNativeWindow())->Maximize();
546 EXPECT_EQ(255,
547 p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
548 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
549 0));
552 // Test that the minimal header style is used in the proper situations.
553 TEST_F(HeaderPainterTest, MinimalHeaderStyle) {
554 // Create a widget and a painter for it.
555 scoped_ptr<Widget> w(CreateTestWidget());
556 scoped_ptr<HeaderPainter> p(CreateTestPainter(w.get()));
557 w->Show();
559 // Regular non-maximized windows should not use the minimal header style.
560 EXPECT_FALSE(p->ShouldUseMinimalHeaderStyle(HeaderPainter::THEMED_NO));
562 // Regular maximized windows should use the minimal header style.
563 w->Maximize();
564 EXPECT_TRUE(p->ShouldUseMinimalHeaderStyle(HeaderPainter::THEMED_NO));
566 // Test cases where the maximized window should not use the minimal header
567 // style.
568 EXPECT_FALSE(p->ShouldUseMinimalHeaderStyle(HeaderPainter::THEMED_YES));
570 wm::GetWindowState(w->GetNativeWindow())->SetTrackedByWorkspace(false);
571 EXPECT_FALSE(p->ShouldUseMinimalHeaderStyle(HeaderPainter::THEMED_NO));
572 wm::GetWindowState(w->GetNativeWindow())->SetTrackedByWorkspace(true);
575 // Ensure the title text is vertically aligned with the window icon.
576 TEST_F(HeaderPainterTest, TitleIconAlignment) {
577 scoped_ptr<Widget> w(CreateTestWidget());
578 HeaderPainter p;
579 ash::FrameCaptionButtonContainerView container(w.get(),
580 ash::FrameCaptionButtonContainerView::MINIMIZE_ALLOWED);
581 views::View window_icon;
582 window_icon.SetBounds(0, 0, 16, 16);
583 p.Init(w.get(),
584 w->non_client_view()->frame_view(),
585 &window_icon,
586 &container);
587 w->SetBounds(gfx::Rect(0, 0, 500, 500));
588 w->Show();
590 // Title and icon are aligned when shorter_header is false.
591 p.LayoutHeader(false);
592 gfx::Font default_font;
593 gfx::Rect large_header_title_bounds = p.GetTitleBounds(default_font);
594 EXPECT_EQ(window_icon.bounds().CenterPoint().y(),
595 large_header_title_bounds.CenterPoint().y());
597 // Title and icon are aligned when shorter_header is true.
598 p.LayoutHeader(true);
599 gfx::Rect short_header_title_bounds = p.GetTitleBounds(default_font);
600 EXPECT_EQ(window_icon.bounds().CenterPoint().y(),
601 short_header_title_bounds.CenterPoint().y());
604 TEST_F(HeaderPainterTest, ChildWindowVisibility) {
605 scoped_ptr<Widget> w1(CreateTestWidget());
606 scoped_ptr<HeaderPainter> p1(CreateTestPainter(w1.get()));
607 w1->Show();
609 // Solo active window has solo window opacity.
610 EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
611 p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
612 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
613 0));
615 // Create a child window which doesn't affect the solo header.
616 scoped_ptr<Widget> w2(new Widget);
617 Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
618 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
619 params.parent = w1->GetNativeView();
620 w2->Init(params);
621 w2->Show();
623 // Still has solo header if child window is added.
624 EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
625 p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
626 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
627 0));
629 // Change the visibility of w2 and verifies w1 still has solo header.
630 w2->Hide();
631 EXPECT_EQ(HeaderPainter::kSoloWindowOpacity,
632 p1->GetHeaderOpacity(HeaderPainter::ACTIVE,
633 IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
634 0));
637 TEST_F(HeaderPainterTest, NoCrashShutdownWithAlwaysOnTopWindow) {
638 // Create normal window and an always-on-top window, and leave it as is
639 // and finish the test, then verify it doesn't cause a crash. See
640 // crbug.com/273310. Note that those widgets will be deleted at
641 // RootWindowController::CloseChildWindows(), so this code is memory-safe.
642 Widget* w1 = new Widget;
643 Widget::InitParams params1;
644 params1.context = CurrentContext();
645 w1->Init(params1);
646 HeaderPainterOwner* o1 = new HeaderPainterOwner(w1);
647 HeaderPainter* p1 = o1->header_painter();
648 w1->SetBounds(gfx::Rect(0, 0, 100, 100));
649 w1->Show();
650 EXPECT_TRUE(p1->UseSoloWindowHeader());
652 Widget* w2 = new Widget;
653 Widget::InitParams params2;
654 params2.context = CurrentContext();
655 params2.keep_on_top = true;
656 w2->Init(params2);
657 HeaderPainterOwner* o2 = new HeaderPainterOwner(w2);
658 HeaderPainter* p2 = o2->header_painter();
659 w2->Show();
660 EXPECT_FALSE(p1->UseSoloWindowHeader());
661 EXPECT_FALSE(p2->UseSoloWindowHeader());
663 // Exit with no resource release. They'll be released at shutdown.
666 } // namespace ash