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.
4
5#include "ash/scoped_target_root_window.h"
6#include "ash/screen_util.h"
7#include "ash/shell.h"
8#include "ash/test/ash_test_base.h"
9#include "ash/test/test_shell_delegate.h"
10#include "ash/wm/window_positioner.h"
11#include "ash/wm/window_resizer.h"
12#include "ash/wm/window_state.h"
13#include "base/compiler_specific.h"
14#include "chrome/browser/ui/ash/ash_init.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/window_sizer/window_sizer_common_unittest.h"
17#include "chrome/common/chrome_switches.h"
18#include "chrome/test/base/testing_profile.h"
19#include "content/public/test/render_view_test.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "ui/aura/client/aura_constants.h"
22#include "ui/aura/env.h"
23#include "ui/aura/test/test_windows.h"
24#include "ui/aura/window_event_dispatcher.h"
25#include "ui/gfx/screen.h"
26#include "ui/wm/public/activation_client.h"
27
28typedef ash::test::AshTestBase WindowSizerAshTest;
29
30namespace {
31
32// A browser window proxy which is able to associate an aura native window with
33// it.
34class TestBrowserWindowAura : public TestBrowserWindow {
35 public:
36  // |native_window| will still be owned by the caller after the constructor
37  // was called.
38  explicit TestBrowserWindowAura(aura::Window* native_window)
39      : native_window_(native_window) {
40  }
41  virtual ~TestBrowserWindowAura() {}
42
43  // TestBrowserWindow overrides:
44  virtual void Show() OVERRIDE {
45    native_window_->Show();
46    Activate();
47  }
48  virtual void Hide() OVERRIDE {
49    native_window_->Hide();
50  }
51  virtual void Activate() OVERRIDE {
52    aura::client::GetActivationClient(
53        native_window_->GetRootWindow())->ActivateWindow(native_window_.get());
54  }
55  virtual gfx::NativeWindow GetNativeWindow() OVERRIDE {
56    return native_window_.get();
57  }
58  virtual gfx::Rect GetBounds() const OVERRIDE {
59    return native_window_->bounds();
60  }
61
62  Browser* browser() { return browser_.get(); }
63
64  void CreateBrowser(const Browser::CreateParams& params) {
65    Browser::CreateParams create_params = params;
66    create_params.window = this;
67    browser_.reset(new Browser(create_params));
68    if (browser_->is_type_tabbed() || browser_->is_app()) {
69      ash::wm::GetWindowState(native_window_.get())->
70          set_window_position_managed(true);
71    }
72  }
73
74 private:
75  scoped_ptr<Browser> browser_;
76  scoped_ptr<aura::Window> native_window_;
77
78  DISALLOW_COPY_AND_ASSIGN(TestBrowserWindowAura);
79};
80
81scoped_ptr<TestBrowserWindowAura> CreateTestBrowserWindow(
82    aura::Window* window,
83    const gfx::Rect& bounds,
84    const Browser::CreateParams& params) {
85  if (!bounds.IsEmpty())
86    window->SetBounds(bounds);
87  scoped_ptr<TestBrowserWindowAura> browser_window(
88      new TestBrowserWindowAura(window));
89  browser_window->CreateBrowser(params);
90  return browser_window.Pass();
91}
92
93}  // namespace
94
95// On desktop linux aura, we currently don't use the ash frame, breaking some
96// tests which expect ash sizes: http://crbug.com/303862
97#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
98#define MAYBE_DefaultSizeCase DISABLED_DefaultSizeCase
99#else
100#define MAYBE_DefaultSizeCase DefaultSizeCase
101#endif
102
103// Test that the window is sized appropriately for the first run experience
104// where the default window bounds calculation is invoked.
105TEST_F(WindowSizerAshTest, MAYBE_DefaultSizeCase) {
106#if defined(OS_WIN)
107  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kOpenAsh);
108#endif
109  { // 4:3 monitor case, 1024x768, no taskbar
110    gfx::Rect window_bounds;
111    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
112                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
113    EXPECT_EQ(gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
114                        ash::WindowPositioner::kDesktopBorderSize,
115                        1024 - ash::WindowPositioner::kDesktopBorderSize * 2,
116                        768 - ash::WindowPositioner::kDesktopBorderSize),
117              window_bounds);
118  }
119
120  { // 4:3 monitor case, 1024x768, taskbar on bottom
121    gfx::Rect window_bounds;
122    GetWindowBounds(p1024x768, taskbar_bottom_work_area, gfx::Rect(),
123                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
124                    &window_bounds);
125    EXPECT_EQ(gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
126                        ash::WindowPositioner::kDesktopBorderSize,
127                        1024 - ash::WindowPositioner::kDesktopBorderSize * 2,
128                        taskbar_bottom_work_area.height() -
129                          ash::WindowPositioner::kDesktopBorderSize),
130              window_bounds);
131  }
132
133  { // 4:3 monitor case, 1024x768, taskbar on right
134    gfx::Rect window_bounds;
135    GetWindowBounds(p1024x768, taskbar_right_work_area, gfx::Rect(),
136                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
137                    &window_bounds);
138    EXPECT_EQ(gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
139                        ash::WindowPositioner::kDesktopBorderSize,
140                        taskbar_right_work_area.width() -
141                          ash::WindowPositioner::kDesktopBorderSize * 2,
142                        768 - ash::WindowPositioner::kDesktopBorderSize),
143              window_bounds);
144  }
145
146  { // 4:3 monitor case, 1024x768, taskbar on left
147    gfx::Rect window_bounds;
148    GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
149                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
150                    &window_bounds);
151    EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x() +
152                          ash::WindowPositioner::kDesktopBorderSize,
153                        ash::WindowPositioner::kDesktopBorderSize,
154                        taskbar_left_work_area.width() -
155                          ash::WindowPositioner::kDesktopBorderSize * 2,
156                        taskbar_left_work_area.height() -
157                          ash::WindowPositioner::kDesktopBorderSize),
158              window_bounds);
159  }
160
161  { // 4:3 monitor case, 1024x768, taskbar on top
162    gfx::Rect window_bounds;
163    GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
164                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
165                    &window_bounds);
166    EXPECT_EQ(gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
167                        taskbar_top_work_area.y() +
168                          ash::WindowPositioner::kDesktopBorderSize,
169                        1024 - ash::WindowPositioner::kDesktopBorderSize * 2,
170                        taskbar_top_work_area.height() -
171                            ash::WindowPositioner::kDesktopBorderSize),
172              window_bounds);
173  }
174
175  { // 4:3 monitor case, 1280x1024
176    gfx::Rect window_bounds;
177    GetWindowBounds(p1280x1024, p1280x1024, gfx::Rect(), gfx::Rect(),
178                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
179    EXPECT_EQ(gfx::Rect((1280 - ash::WindowPositioner::kMaximumWindowWidth) / 2,
180                        ash::WindowPositioner::kDesktopBorderSize,
181                        ash::WindowPositioner::kMaximumWindowWidth,
182                        1024 - ash::WindowPositioner::kDesktopBorderSize),
183              window_bounds);
184  }
185
186  { // 4:3 monitor case, 1600x1200
187    gfx::Rect window_bounds;
188    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(),
189                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
190    EXPECT_EQ(gfx::Rect((1600 - ash::WindowPositioner::kMaximumWindowWidth) / 2,
191                        ash::WindowPositioner::kDesktopBorderSize,
192                        ash::WindowPositioner::kMaximumWindowWidth,
193                        1200 - ash::WindowPositioner::kDesktopBorderSize),
194              window_bounds);
195  }
196
197  { // 16:10 monitor case, 1680x1050
198    gfx::Rect window_bounds;
199    GetWindowBounds(p1680x1050, p1680x1050, gfx::Rect(), gfx::Rect(),
200                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
201    EXPECT_EQ(gfx::Rect((1680 - ash::WindowPositioner::kMaximumWindowWidth) / 2,
202                        ash::WindowPositioner::kDesktopBorderSize,
203                        ash::WindowPositioner::kMaximumWindowWidth,
204                        1050 - ash::WindowPositioner::kDesktopBorderSize),
205              window_bounds);
206  }
207
208  { // 16:10 monitor case, 1920x1200
209    gfx::Rect window_bounds;
210    GetWindowBounds(p1920x1200, p1920x1200, gfx::Rect(), gfx::Rect(),
211                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
212    EXPECT_EQ(gfx::Rect((1920 - ash::WindowPositioner::kMaximumWindowWidth) / 2,
213                        ash::WindowPositioner::kDesktopBorderSize,
214                        ash::WindowPositioner::kMaximumWindowWidth,
215                        1200 - ash::WindowPositioner::kDesktopBorderSize),
216              window_bounds);
217  }
218}
219
220// Test that the next opened window is positioned appropriately given the
221// bounds of an existing window of the same type.
222TEST_F(WindowSizerAshTest, LastWindowBoundsCase) {
223  { // normal, in the middle of the screen somewhere.
224    gfx::Rect window_bounds;
225    GetWindowBounds(
226        p1024x768, p1024x768, gfx::Rect(),
227        gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
228                  ash::WindowPositioner::kDesktopBorderSize, 500, 400),
229        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
230        &window_bounds);
231    EXPECT_EQ(
232        gfx::Rect(kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
233                  kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
234                  500, 400).ToString(),
235        window_bounds.ToString());
236  }
237
238  { // taskbar on top.
239    gfx::Rect window_bounds;
240    GetWindowBounds(
241        p1024x768, taskbar_top_work_area, gfx::Rect(),
242        gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
243                  ash::WindowPositioner::kDesktopBorderSize, 500, 400),
244        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
245        &window_bounds);
246    EXPECT_EQ(
247        gfx::Rect(kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
248                  std::max(kWindowTilePixels +
249                           ash::WindowPositioner::kDesktopBorderSize,
250                           34 /* toolbar height */),
251                  500, 400).ToString(),
252        window_bounds.ToString());
253  }
254
255  { // Too small to satisify the minimum visibility condition.
256    gfx::Rect window_bounds;
257    GetWindowBounds(
258        p1024x768, p1024x768, gfx::Rect(),
259        gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
260                  ash::WindowPositioner::kDesktopBorderSize, 29, 29),
261        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
262        &window_bounds);
263    EXPECT_EQ(
264        gfx::Rect(kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
265                  kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
266                  30 /* not 29 */,
267                  30 /* not 29 */).ToString(),
268        window_bounds.ToString());
269  }
270
271
272  { // Normal.
273    gfx::Rect window_bounds;
274    GetWindowBounds(
275        p1024x768, p1024x768, gfx::Rect(),
276        gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
277                  ash::WindowPositioner::kDesktopBorderSize, 500, 400),
278        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
279        &window_bounds);
280    EXPECT_EQ(
281        gfx::Rect(kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
282                  kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
283                  500, 400).ToString(),
284        window_bounds.ToString());
285  }
286}
287
288// Test that the window opened is sized appropriately given persisted sizes.
289TEST_F(WindowSizerAshTest, PersistedBoundsCase) {
290  { // normal, in the middle of the screen somewhere.
291    gfx::Rect initial_bounds(
292        ash::WindowPositioner::kDesktopBorderSize,
293        ash::WindowPositioner::kDesktopBorderSize, 500, 400);
294
295    gfx::Rect window_bounds;
296    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
297                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
298    EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
299  }
300
301  { // Normal.
302    gfx::Rect initial_bounds(0, 0, 1024, 768);
303
304    gfx::Rect window_bounds;
305    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
306                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
307    EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
308  }
309
310  { // normal, on non-primary monitor in negative coords.
311    gfx::Rect initial_bounds(-600, 10, 500, 400);
312
313    gfx::Rect window_bounds;
314    GetWindowBounds(p1024x768, p1024x768, left_s1024x768,
315                    initial_bounds, gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
316                    &window_bounds);
317    EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
318  }
319
320  { // normal, on non-primary monitor in negative coords.
321    gfx::Rect initial_bounds(-1024, 0, 1024, 768);
322
323    gfx::Rect window_bounds;
324    GetWindowBounds(p1024x768, p1024x768, left_s1024x768,
325                    initial_bounds, gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
326                    &window_bounds);
327    EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
328  }
329
330  { // Non-primary monitor resoultion has changed, but the monitor still
331    // completely contains the window.
332
333    gfx::Rect initial_bounds(1074, 50, 600, 500);
334
335    gfx::Rect window_bounds;
336    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
337                    initial_bounds, right_s1024x768, PERSISTED, NULL,
338                    gfx::Rect(), &window_bounds);
339    EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
340  }
341
342  { // Non-primary monitor resoultion has changed, and the window is partially
343    // off-screen.
344
345    gfx::Rect initial_bounds(1274, 50, 600, 500);
346
347    gfx::Rect window_bounds;
348    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
349                    initial_bounds, right_s1024x768, PERSISTED,
350                    NULL, gfx::Rect(), &window_bounds);
351    EXPECT_EQ("1224,50 600x500", window_bounds.ToString());
352  }
353
354  { // Non-primary monitor resoultion has changed, and the window is now too
355    // large for the monitor.
356
357    gfx::Rect initial_bounds(1274, 50, 900, 700);
358
359    gfx::Rect window_bounds;
360    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
361                    initial_bounds, right_s1024x768, PERSISTED,
362                    NULL, gfx::Rect(), &window_bounds);
363    EXPECT_EQ("1024,0 800x600", window_bounds.ToString());
364  }
365
366  { // width and height too small
367    gfx::Rect window_bounds;
368    GetWindowBounds(
369        p1024x768, p1024x768, gfx::Rect(),
370        gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
371                  ash::WindowPositioner::kDesktopBorderSize, 29, 29),
372        gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
373    EXPECT_EQ(gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
374                        ash::WindowPositioner::kDesktopBorderSize,
375                        30 /* not 29 */, 30 /* not 29 */).ToString(),
376              window_bounds.ToString());
377  }
378}
379
380//////////////////////////////////////////////////////////////////////////////
381// The following unittests have different results on Mac/non-Mac because we
382// reposition windows aggressively on Mac.  The *WithAggressiveReposition tests
383// are run on Mac, and the *WithNonAggressiveRepositioning tests are run on
384// other platforms.
385
386TEST_F(WindowSizerAshTest, LastWindowOffscreenWithNonAggressiveRepositioning) {
387  { // taskbar on left.
388    gfx::Rect window_bounds;
389    GetWindowBounds(
390        p1024x768, taskbar_left_work_area, gfx::Rect(),
391        gfx::Rect(ash::WindowPositioner::kDesktopBorderSize,
392                  ash::WindowPositioner::kDesktopBorderSize, 500, 400),
393        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
394        &window_bounds);
395    EXPECT_EQ(
396        gfx::Rect(kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
397                  kWindowTilePixels + ash::WindowPositioner::kDesktopBorderSize,
398                  500, 400).ToString(),
399        window_bounds.ToString());
400  }
401
402  { // offset would put the new window offscreen at the bottom but the minimum
403    // visibility condition is barely satisfied without relocation.
404    gfx::Rect window_bounds;
405    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
406                    gfx::Rect(10, 728, 500, 400), gfx::Rect(), LAST_ACTIVE,
407                    NULL, gfx::Rect(), &window_bounds);
408    EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738, 500, 400).ToString(),
409              window_bounds.ToString());
410  }
411
412  { // offset would put the new window offscreen at the bottom and the minimum
413    // visibility condition is satisified by relocation.
414    gfx::Rect window_bounds;
415    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
416                    gfx::Rect(10, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
417                    NULL, gfx::Rect(), &window_bounds);
418    EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels,
419                        738 /* not 739 */,
420                        500,
421                        400).ToString(),
422              window_bounds.ToString());
423  }
424
425  { // offset would put the new window offscreen at the right but the minimum
426    // visibility condition is barely satisfied without relocation.
427    gfx::Rect window_bounds;
428    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
429                    gfx::Rect(984, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
430                    NULL, gfx::Rect(), &window_bounds);
431    EXPECT_EQ(gfx::Rect(994, 10 + kWindowTilePixels, 500, 400).ToString(),
432              window_bounds.ToString());
433  }
434
435  { // offset would put the new window offscreen at the right and the minimum
436    // visibility condition is satisified by relocation.
437    gfx::Rect window_bounds;
438    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
439                    gfx::Rect(985, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
440                    NULL, gfx::Rect(), &window_bounds);
441    EXPECT_EQ(gfx::Rect(994 /* not 995 */,
442                        10 + kWindowTilePixels,
443                        500,
444                        400).ToString(),
445              window_bounds.ToString());
446  }
447
448  { // offset would put the new window offscreen at the bottom right and the
449    // minimum visibility condition is satisified by relocation.
450    gfx::Rect window_bounds;
451    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
452                    gfx::Rect(985, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
453                    NULL, gfx::Rect(), &window_bounds);
454    EXPECT_EQ(gfx::Rect(994 /* not 995 */,
455                        738 /* not 739 */,
456                        500,
457                        400).ToString(),
458              window_bounds.ToString());
459  }
460}
461
462// On desktop linux aura, we currently don't use the ash frame, breaking some
463// tests which expect ash sizes: http://crbug.com/303862
464#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
465#define MAYBE_PlaceNewWindows DISABLED_PlaceNewWindows
466#else
467#define MAYBE_PlaceNewWindows PlaceNewWindows
468#endif
469
470// Test the placement of newly created windows.
471TEST_F(WindowSizerAshTest, MAYBE_PlaceNewWindows) {
472  // Create a browser to pass into the GetWindowBounds function.
473  scoped_ptr<TestingProfile> profile(new TestingProfile());
474  // Creating a popup handler here to make sure it does not interfere with the
475  // existing windows.
476  Browser::CreateParams native_params(profile.get(),
477                                      chrome::HOST_DESKTOP_TYPE_ASH);
478  scoped_ptr<Browser> browser(
479      chrome::CreateBrowserWithTestWindowForParams(&native_params));
480
481  // Creating a popup handler here to make sure it does not interfere with the
482  // existing windows.
483  scoped_ptr<BrowserWindow> browser_window(CreateTestBrowserWindow(
484      CreateTestWindowInShellWithId(0),
485      gfx::Rect(16, 32, 640, 320),
486      Browser::CreateParams(profile.get(), chrome::HOST_DESKTOP_TYPE_ASH)));
487
488  // Creating a popup to make sure it does not interfere with the positioning.
489  scoped_ptr<TestBrowserWindowAura> browser_popup(CreateTestBrowserWindow(
490      CreateTestWindowInShellWithId(1),
491      gfx::Rect(16, 32, 128, 256),
492      Browser::CreateParams(Browser::TYPE_POPUP, profile.get(),
493                            chrome::HOST_DESKTOP_TYPE_ASH)));
494
495  // Creating a panel to make sure it does not interfere with the positioning.
496  scoped_ptr<BrowserWindow> browser_panel(CreateTestBrowserWindow(
497      CreateTestWindowInShellWithId(2),
498      gfx::Rect(32, 48, 256, 512),
499      Browser::CreateParams(Browser::TYPE_POPUP, profile.get(),
500                            chrome::HOST_DESKTOP_TYPE_ASH)));
501  browser_window->Show();
502  { // Make sure that popups do not get changed.
503    gfx::Rect window_bounds;
504    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
505                    gfx::Rect(50, 100, 300, 150), bottom_s1600x1200,
506                    PERSISTED, browser_popup->browser(),
507                    gfx::Rect(), &window_bounds);
508    EXPECT_EQ("50,100 300x150", window_bounds.ToString());
509  }
510
511  browser_window->Hide();
512  { // If a window is there but not shown the persisted default should be used.
513    gfx::Rect window_bounds;
514    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
515                    gfx::Rect(50, 100, 300, 150), bottom_s1600x1200,
516                    PERSISTED, browser.get(), gfx::Rect(), &window_bounds);
517    EXPECT_EQ("50,100 300x150", window_bounds.ToString());
518  }
519
520  { // If a window is there but not shown the default should be returned.
521    gfx::Rect window_bounds;
522    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
523                    gfx::Rect(), bottom_s1600x1200,
524                    DEFAULT, browser.get(), gfx::Rect(), &window_bounds);
525    // Note: We need to also take the defaults maximum width into account here
526    // since that might get used if the resolution is too big.
527    EXPECT_EQ(
528        gfx::Rect(
529            std::max(ash::WindowPositioner::kDesktopBorderSize,
530                     (1600 - ash::WindowPositioner::kMaximumWindowWidth) / 2),
531            ash::WindowPositioner::kDesktopBorderSize,
532            std::min(ash::WindowPositioner::kMaximumWindowWidth,
533                     1600 - 2 * ash::WindowPositioner::kDesktopBorderSize),
534            1200 - ash::WindowPositioner::kDesktopBorderSize).ToString(),
535        window_bounds.ToString());
536  }
537}
538
539// On desktop linux aura, we currently don't use the ash frame, breaking some
540// tests which expect ash sizes: http://crbug.com/303862
541#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
542#define MAYBE_PlaceNewBrowserWindowOnEmptyDesktop DISABLED_PlaceNewBrowserWindowOnEmptyDesktop
543#else
544#define MAYBE_PlaceNewBrowserWindowOnEmptyDesktop PlaceNewBrowserWindowOnEmptyDesktop
545#endif
546
547// Test the placement of newly created windows on an empty desktop.
548// This test supplements "PlaceNewWindows" by testing the creation of a newly
549// created browser window on an empty desktop.
550TEST_F(WindowSizerAshTest, MAYBE_PlaceNewBrowserWindowOnEmptyDesktop) {
551  // Create a browser to pass into the GetWindowBoundsAndShowState function.
552  scoped_ptr<TestingProfile> profile(new TestingProfile());
553  Browser::CreateParams native_params(profile.get(),
554                                      chrome::HOST_DESKTOP_TYPE_ASH);
555  scoped_ptr<Browser> browser(
556      chrome::CreateBrowserWithTestWindowForParams(&native_params));
557
558  // A common screen size for Chrome OS devices where this behavior is
559  // desirable.
560  const gfx::Rect p1366x768(0, 0, 1366, 768);
561
562  // If there is no previous state the window should get maximized if the
563  // screen is less than or equal to our limit (1366 pixels width).
564  gfx::Rect window_bounds;
565  ui::WindowShowState out_show_state1 = ui::SHOW_STATE_DEFAULT;
566  GetWindowBoundsAndShowState(
567      p1366x768,                    // The screen resolution.
568      p1366x768,                    // The monitor work area.
569      gfx::Rect(),                  // The second monitor.
570      gfx::Rect(),                  // The (persisted) bounds.
571      p1366x768,                    // The overall work area.
572      ui::SHOW_STATE_NORMAL,        // The persisted show state.
573      ui::SHOW_STATE_DEFAULT,       // The last show state.
574      DEFAULT,                      // No persisted values.
575      browser.get(),                // Use this browser.
576      gfx::Rect(),                  // Don't request valid bounds.
577      &window_bounds,
578      &out_show_state1);
579  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, out_show_state1);
580
581  // If there is a stored coordinate however, that should be taken instead.
582  ui::WindowShowState out_show_state2 = ui::SHOW_STATE_DEFAULT;
583  GetWindowBoundsAndShowState(
584      p1366x768,                    // The screen resolution.
585      p1366x768,                    // The monitor work area.
586      gfx::Rect(),                  // The second monitor.
587      gfx::Rect(50, 100, 300, 150), // The (persisted) bounds.
588      p1366x768,                    // The overall work area.
589      ui::SHOW_STATE_NORMAL,        // The persisted show state.
590      ui::SHOW_STATE_DEFAULT,       // The last show state.
591      PERSISTED,                    // Set the persisted values.
592      browser.get(),                // Use this browser.
593      gfx::Rect(),                  // Don't request valid bounds.
594      &window_bounds,
595      &out_show_state2);
596  EXPECT_EQ(ui::SHOW_STATE_NORMAL, out_show_state2);
597  EXPECT_EQ("50,100 300x150", window_bounds.ToString());
598
599  // A larger monitor should not trigger auto-maximize.
600  ui::WindowShowState out_show_state3 = ui::SHOW_STATE_DEFAULT;
601  GetWindowBoundsAndShowState(
602      p1600x1200,                   // The screen resolution.
603      p1600x1200,                   // The monitor work area.
604      gfx::Rect(),                  // The second monitor.
605      gfx::Rect(),                  // The (persisted) bounds.
606      p1600x1200,                   // The overall work area.
607      ui::SHOW_STATE_NORMAL,        // The persisted show state.
608      ui::SHOW_STATE_DEFAULT,       // The last show state.
609      DEFAULT,                      // No persisted values.
610      browser.get(),                // Use this browser.
611      gfx::Rect(),                  // Don't request valid bounds.
612      &window_bounds,
613      &out_show_state3);
614#if defined(OS_WIN)
615  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, out_show_state3);
616#else
617  EXPECT_EQ(ui::SHOW_STATE_DEFAULT, out_show_state3);
618#endif
619}
620
621#if defined(OS_CHROMEOS)
622#define MAYBE_PlaceNewWindowsOnMultipleDisplays PlaceNewWindowsOnMultipleDisplays
623#else
624// No multiple displays on windows ash.
625#define MAYBE_PlaceNewWindowsOnMultipleDisplays DISABLED_PlaceNewWindowsOnMultipleDisplays
626#endif
627
628// Test the placement of newly created windows on multiple dislays.
629TEST_F(WindowSizerAshTest, MAYBE_PlaceNewWindowsOnMultipleDisplays) {
630  UpdateDisplay("1600x1200,1600x1200");
631  gfx::Rect primary_bounds = ash::Shell::GetInstance()->GetScreen()->
632      GetPrimaryDisplay().bounds();
633  gfx::Rect secondary_bounds = ash::ScreenUtil::GetSecondaryDisplay().bounds();
634
635  ash::Shell::GetInstance()->set_target_root_window(
636      ash::Shell::GetPrimaryRootWindow());
637
638  scoped_ptr<TestingProfile> profile(new TestingProfile());
639
640  // Create browser windows that are used as reference.
641  scoped_ptr<BrowserWindow> browser_window(CreateTestBrowserWindow(
642      CreateTestWindowInShellWithId(0),
643      gfx::Rect(10, 10, 200, 200),
644      Browser::CreateParams(profile.get(), chrome::HOST_DESKTOP_TYPE_ASH)));
645  browser_window->Show();
646  EXPECT_EQ(browser_window->GetNativeWindow()->GetRootWindow(),
647            ash::Shell::GetTargetRootWindow());
648
649  scoped_ptr<BrowserWindow> another_browser_window(CreateTestBrowserWindow(
650      CreateTestWindowInShellWithId(1),
651      gfx::Rect(400, 10, 300, 300),
652      Browser::CreateParams(profile.get(), chrome::HOST_DESKTOP_TYPE_ASH)));
653  another_browser_window->Show();
654
655  // Creating a new window to verify the new placement.
656  scoped_ptr<TestBrowserWindowAura> new_browser_window(CreateTestBrowserWindow(
657      CreateTestWindowInShellWithId(0),
658      gfx::Rect(),
659      Browser::CreateParams(profile.get(),
660                            chrome::HOST_DESKTOP_TYPE_ASH)));
661
662  // Make sure the primary root is active.
663  ASSERT_EQ(ash::Shell::GetPrimaryRootWindow(),
664            ash::Shell::GetTargetRootWindow());
665
666  // First new window should be in the primary.
667  {
668    gfx::Rect window_bounds;
669    GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds,
670                    gfx::Rect(), secondary_bounds,
671                    PERSISTED, new_browser_window->browser(),
672                    gfx::Rect(), &window_bounds);
673    // TODO(oshima): Use exact bounds when the window_sizer_ash is
674    // moved to ash and changed to include the result from
675    // RearrangeVisibleWindowOnShow.
676    EXPECT_TRUE(primary_bounds.Contains(window_bounds));
677  }
678
679  // Move the window to the right side of the secondary display and create a new
680  // window. It should be opened then on the secondary display.
681  {
682    gfx::Display second_display = ash::Shell::GetScreen()->
683        GetDisplayNearestPoint(gfx::Point(1600 + 100,10));
684    browser_window->GetNativeWindow()->SetBoundsInScreen(
685        gfx::Rect(secondary_bounds.CenterPoint().x() - 100, 10, 200, 200),
686        second_display);
687    browser_window->Activate();
688    EXPECT_NE(ash::Shell::GetPrimaryRootWindow(),
689              ash::Shell::GetTargetRootWindow());
690    gfx::Rect window_bounds;
691    GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds,
692                    gfx::Rect(), secondary_bounds,
693                    PERSISTED, new_browser_window->browser(),
694                    gfx::Rect(), &window_bounds);
695    // TODO(oshima): Use exact bounds when the window_sizer_ash is
696    // moved to ash and changed to include the result from
697    // RearrangeVisibleWindowOnShow.
698    EXPECT_TRUE(secondary_bounds.Contains(window_bounds));
699  }
700
701  // Activate another window in the primary display and create a new window.
702  // It should be created in the primary display.
703  {
704    another_browser_window->Activate();
705    EXPECT_EQ(ash::Shell::GetPrimaryRootWindow(),
706              ash::Shell::GetTargetRootWindow());
707
708    gfx::Rect window_bounds;
709    GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds,
710                    gfx::Rect(), secondary_bounds,
711                    PERSISTED, new_browser_window->browser(),
712                    gfx::Rect(), &window_bounds);
713    // TODO(oshima): Use exact bounds when the window_sizer_ash is
714    // moved to ash and changed to include the result from
715    // RearrangeVisibleWindowOnShow.
716    EXPECT_TRUE(primary_bounds.Contains(window_bounds));
717  }
718}
719
720// On desktop linux aura, we currently don't use the ash frame, breaking some
721// tests which expect ash sizes: http://crbug.com/303862
722#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
723#define MAYBE_TestShowState DISABLED_TestShowState
724#else
725#define MAYBE_TestShowState TestShowState
726#endif
727
728// Test that the show state is properly returned for non default cases.
729TEST_F(WindowSizerAshTest, MAYBE_TestShowState) {
730  scoped_ptr<TestingProfile> profile(new TestingProfile());
731
732  // Creating a browser & window to play with.
733  scoped_ptr<TestBrowserWindowAura> browser_window(CreateTestBrowserWindow(
734      CreateTestWindowInShellWithId(0),
735      gfx::Rect(16, 32, 640, 320),
736      Browser::CreateParams(Browser::TYPE_TABBED, profile.get(),
737                            chrome::HOST_DESKTOP_TYPE_ASH)));
738
739  // Create also a popup browser since that behaves different.
740  scoped_ptr<TestBrowserWindowAura> browser_popup(CreateTestBrowserWindow(
741      CreateTestWindowInShellWithId(1),
742      gfx::Rect(16, 32, 640, 320),
743      Browser::CreateParams(Browser::TYPE_POPUP, profile.get(),
744                            chrome::HOST_DESKTOP_TYPE_ASH)));
745
746  // Tabbed windows should retrieve the saved window state - since there is a
747  // top window.
748  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
749            GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
750                               ui::SHOW_STATE_NORMAL,
751                               BOTH,
752                               browser_window->browser(),
753                               p1600x1200,
754                               p1600x1200));
755  // A window that is smaller than the whole work area is set to default state.
756  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
757            GetWindowShowState(ui::SHOW_STATE_DEFAULT,
758                               ui::SHOW_STATE_NORMAL,
759                               BOTH,
760                               browser_window->browser(),
761                               p1280x1024,
762                               p1600x1200));
763  // A window that is sized to occupy the whole work area is maximized.
764  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
765            GetWindowShowState(ui::SHOW_STATE_DEFAULT,
766                               ui::SHOW_STATE_NORMAL,
767                               BOTH,
768                               browser_window->browser(),
769                               p1600x1200,
770                               p1600x1200));
771  // Non tabbed windows should always follow the window saved visibility state.
772  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
773            GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
774                               ui::SHOW_STATE_NORMAL,
775                               BOTH,
776                               browser_popup->browser(),
777                               p1600x1200,
778                               p1600x1200));
779  // The non tabbed window will take the status of the last active of its kind.
780  EXPECT_EQ(ui::SHOW_STATE_NORMAL,
781            GetWindowShowState(ui::SHOW_STATE_DEFAULT,
782                               ui::SHOW_STATE_NORMAL,
783                               BOTH,
784                               browser_popup->browser(),
785                               p1600x1200,
786                               p1600x1200));
787
788  // Now create a top level window and check again for both. Only the tabbed
789  // window should follow the top level window's state.
790  // Creating a browser & window to play with.
791  scoped_ptr<TestBrowserWindowAura> browser_window2(CreateTestBrowserWindow(
792      CreateTestWindowInShellWithId(3),
793      gfx::Rect(16, 32, 640, 320),
794      Browser::CreateParams(Browser::TYPE_TABBED, profile.get(),
795                            chrome::HOST_DESKTOP_TYPE_ASH)));
796
797  // A tabbed window should now take the top level window state.
798  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
799            GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
800                               ui::SHOW_STATE_DEFAULT,
801                               BOTH,
802                               browser_window->browser(),
803                               p1600x1200,
804                               p1600x1200));
805  // Non tabbed windows should always follow the window saved visibility state.
806  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
807            GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
808                               ui::SHOW_STATE_MINIMIZED,
809                               BOTH,
810                               browser_popup->browser(),
811                               p1600x1200,
812                               p1600x1200));
813
814  // In smaller screen resolutions we default to maximized if there is no other
815  // window visible.
816  int min_size = ash::WindowPositioner::GetForceMaximizedWidthLimit() / 2;
817  if (min_size > 0) {
818    const gfx::Rect tiny_screen(0, 0, min_size, min_size);
819    EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
820              GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
821                                 ui::SHOW_STATE_DEFAULT,
822                                 BOTH,
823                                 browser_window->browser(),
824                                 tiny_screen,
825                                 tiny_screen));
826    browser_window->Hide();
827    EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
828              GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
829                                 ui::SHOW_STATE_DEFAULT,
830                                 BOTH,
831                                 browser_window2->browser(),
832                                 tiny_screen,
833                                 tiny_screen));
834
835  }
836}
837
838// Test that the default show state override behavior is properly handled.
839TEST_F(WindowSizerAshTest, TestShowStateDefaults) {
840  // Creating a browser & window to play with.
841  scoped_ptr<TestingProfile> profile(new TestingProfile());
842
843  scoped_ptr<TestBrowserWindowAura> browser_window(CreateTestBrowserWindow(
844      CreateTestWindowInShellWithId(0),
845      gfx::Rect(16, 32, 640, 320),
846      Browser::CreateParams(Browser::TYPE_TABBED, profile.get(),
847                            chrome::HOST_DESKTOP_TYPE_ASH)));
848
849  // Create also a popup browser since that behaves slightly different for
850  // defaults.
851  scoped_ptr<TestBrowserWindowAura> browser_popup(CreateTestBrowserWindow(
852      CreateTestWindowInShellWithId(1),
853      gfx::Rect(16, 32, 128, 256),
854      Browser::CreateParams(Browser::TYPE_POPUP, profile.get(),
855                            chrome::HOST_DESKTOP_TYPE_ASH)));
856
857  // Check that a browser creation state always get used if not given as
858  // SHOW_STATE_DEFAULT. On Windows ASH it should be SHOW_STATE_MAXIMIZED.
859  ui::WindowShowState window_show_state =
860      GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
861                         ui::SHOW_STATE_MAXIMIZED,
862                         DEFAULT,
863                         browser_window->browser(),
864                         p1600x1200,
865                         p1600x1200);
866#if defined(OS_WIN)
867  EXPECT_EQ(window_show_state, ui::SHOW_STATE_MAXIMIZED);
868#else
869  EXPECT_EQ(window_show_state, ui::SHOW_STATE_DEFAULT);
870#endif
871
872  browser_window->browser()->set_initial_show_state(ui::SHOW_STATE_MINIMIZED);
873  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
874                               ui::SHOW_STATE_MAXIMIZED,
875                               BOTH,
876                               browser_window->browser(),
877                               p1600x1200,
878                               p1600x1200), ui::SHOW_STATE_MINIMIZED);
879  browser_window->browser()->set_initial_show_state(ui::SHOW_STATE_NORMAL);
880  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
881                               ui::SHOW_STATE_MAXIMIZED,
882                               BOTH,
883                               browser_window->browser(),
884                               p1600x1200,
885                               p1600x1200), ui::SHOW_STATE_NORMAL);
886  browser_window->browser()->set_initial_show_state(ui::SHOW_STATE_MAXIMIZED);
887  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_NORMAL,
888                               ui::SHOW_STATE_NORMAL,
889                               BOTH,
890                               browser_window->browser(),
891                               p1600x1200,
892                               p1600x1200), ui::SHOW_STATE_MAXIMIZED);
893
894  // Check that setting the maximized command line option is forcing the
895  // maximized state.
896  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kStartMaximized);
897
898  browser_window->browser()->set_initial_show_state(ui::SHOW_STATE_NORMAL);
899  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_NORMAL,
900                               ui::SHOW_STATE_NORMAL,
901                               BOTH,
902                               browser_window->browser(),
903                               p1600x1200,
904                               p1600x1200), ui::SHOW_STATE_MAXIMIZED);
905
906  // The popup should favor the initial show state over the command line.
907  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_NORMAL,
908                               ui::SHOW_STATE_NORMAL,
909                               BOTH,
910                               browser_popup->browser(),
911                               p1600x1200,
912                               p1600x1200), ui::SHOW_STATE_NORMAL);
913}
914
915TEST_F(WindowSizerAshTest, DefaultStateBecomesMaximized) {
916  // Create a browser to pass into the GetWindowBounds function.
917  scoped_ptr<TestingProfile> profile(new TestingProfile());
918  Browser::CreateParams native_params(profile.get(),
919                                      chrome::HOST_DESKTOP_TYPE_ASH);
920  scoped_ptr<Browser> browser(
921      chrome::CreateBrowserWithTestWindowForParams(&native_params));
922
923  gfx::Rect display_bounds = ash::Shell::GetInstance()->GetScreen()->
924      GetPrimaryDisplay().bounds();
925  gfx::Rect specified_bounds = display_bounds;
926
927  // Make a window bigger than the display work area.
928  specified_bounds.Inset(-20, -20);
929  ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;
930  gfx::Rect bounds;
931  WindowSizer::GetBrowserWindowBoundsAndShowState(
932      std::string(), specified_bounds, browser.get(), &bounds, &show_state);
933  // The window should start maximized with its restore bounds shrunken.
934  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, show_state);
935  EXPECT_NE(display_bounds.ToString(), bounds.ToString());
936  EXPECT_TRUE(display_bounds.Contains(bounds));
937
938  // Make a window smaller than the display work area.
939  specified_bounds.Inset(100, 100);
940  show_state = ui::SHOW_STATE_DEFAULT;
941  WindowSizer::GetBrowserWindowBoundsAndShowState(
942      std::string(), specified_bounds, browser.get(), &bounds, &show_state);
943  // The window should start in default state.
944  EXPECT_EQ(ui::SHOW_STATE_DEFAULT, show_state);
945  EXPECT_EQ(specified_bounds.ToString(), bounds.ToString());
946}
947
948// Test that the target root window is used as the destination of
949// the non browser window. This differ from PersistedBoundsCase
950// in that this uses real ash shell implementations + StateProvider
951// TargetDisplayProvider, rather than mocks.
952TEST_F(WindowSizerAshTest, DefaultBoundsInTargetDisplay) {
953  if (!SupportsMultipleDisplays() || !chrome::ShouldOpenAshOnStartup())
954    return;
955  UpdateDisplay("500x500,600x600");
956  {
957    aura::Window* first_root =
958        ash::Shell::GetAllRootWindows()[0];
959    ash::ScopedTargetRootWindow tmp(first_root);
960    gfx::Rect bounds;
961    ui::WindowShowState show_state;
962    WindowSizer::GetBrowserWindowBoundsAndShowState(
963        std::string(),
964        gfx::Rect(),
965        NULL,
966        &bounds,
967        &show_state);
968    EXPECT_TRUE(first_root->GetBoundsInScreen().Contains(bounds));
969  }
970  {
971    aura::Window* second_root =
972        ash::Shell::GetAllRootWindows()[1];
973    ash::ScopedTargetRootWindow tmp(second_root);
974    gfx::Rect bounds;
975    ui::WindowShowState show_state;
976    WindowSizer::GetBrowserWindowBoundsAndShowState(
977        std::string(),
978        gfx::Rect(),
979        NULL,
980        &bounds,
981        &show_state);
982    EXPECT_TRUE(second_root->GetBoundsInScreen().Contains(bounds));
983  }
984}
985
986TEST_F(WindowSizerAshTest, TrustedPopupBehavior) {
987  scoped_ptr<TestingProfile> profile(new TestingProfile());
988  Browser::CreateParams trusted_popup_create_params(
989      Browser::TYPE_POPUP, profile.get(), chrome::HOST_DESKTOP_TYPE_ASH);
990  trusted_popup_create_params.trusted_source = true;
991
992  scoped_ptr<TestBrowserWindowAura> trusted_popup(CreateTestBrowserWindow(
993      CreateTestWindowInShellWithId(1),
994      gfx::Rect(16, 32, 640, 320),
995      trusted_popup_create_params));
996  // Trusted popup windows should follow the saved show state and ignore the
997  // last show state.
998  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
999            GetWindowShowState(ui::SHOW_STATE_DEFAULT,
1000                               ui::SHOW_STATE_NORMAL,
1001                               BOTH,
1002                               trusted_popup->browser(),
1003                               p1280x1024,
1004                               p1600x1200));
1005  // A popup that is sized to occupy the whole work area has default state.
1006  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
1007            GetWindowShowState(ui::SHOW_STATE_DEFAULT,
1008                               ui::SHOW_STATE_NORMAL,
1009                               BOTH,
1010                               trusted_popup->browser(),
1011                               p1600x1200,
1012                               p1600x1200));
1013}
1014