1 // Copyright 2016 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 "ui/ozone/platform/wayland/host/wayland_window.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include <cursor-shapes-unstable-v1-client-protocol.h>
11 #include <linux/input.h>
12 #include <wayland-server-core.h>
13 #include <xdg-shell-server-protocol.h>
14 #include <xdg-shell-unstable-v6-server-protocol.h>
15 
16 #include "base/files/file_util.h"
17 #include "base/memory/scoped_refptr.h"
18 #include "base/run_loop.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
23 #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
24 #include "ui/base/hit_test.h"
25 #include "ui/events/base_event_utils.h"
26 #include "ui/events/event.h"
27 #include "ui/gfx/native_widget_types.h"
28 #include "ui/gfx/overlay_transform.h"
29 #include "ui/ozone/platform/wayland/common/wayland_util.h"
30 #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
31 #include "ui/ozone/platform/wayland/host/wayland_connection_test_api.h"
32 #include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
33 #include "ui/ozone/platform/wayland/host/wayland_zcr_cursor_shapes.h"
34 #include "ui/ozone/platform/wayland/test/mock_pointer.h"
35 #include "ui/ozone/platform/wayland/test/mock_surface.h"
36 #include "ui/ozone/platform/wayland/test/test_keyboard.h"
37 #include "ui/ozone/platform/wayland/test/test_region.h"
38 #include "ui/ozone/platform/wayland/test/test_touch.h"
39 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
40 #include "ui/ozone/platform/wayland/test/wayland_test.h"
41 #include "ui/ozone/test/mock_platform_window_delegate.h"
42 #include "ui/platform_window/platform_window.h"
43 #include "ui/platform_window/platform_window_init_properties.h"
44 #include "ui/platform_window/wm/wm_move_resize_handler.h"
45 
46 using ::testing::_;
47 using ::testing::Eq;
48 using ::testing::Mock;
49 using ::testing::Return;
50 using ::testing::SaveArg;
51 using ::testing::StrEq;
52 
53 namespace ui {
54 
55 namespace {
56 
57 struct PopupPosition {
58   gfx::Rect anchor_rect;
59   gfx::Size size;
60   uint32_t anchor = 0;
61   uint32_t gravity = 0;
62   uint32_t constraint_adjustment = 0;
63 };
64 
65 class ScopedWlArray {
66  public:
ScopedWlArray()67   ScopedWlArray() { wl_array_init(&array_); }
68 
ScopedWlArray(ScopedWlArray && rhs)69   ScopedWlArray(ScopedWlArray&& rhs) {
70     array_ = rhs.array_;
71     // wl_array_init sets rhs.array_'s fields to nullptr, so that
72     // the free() in wl_array_release() is a no-op.
73     wl_array_init(&rhs.array_);
74   }
75 
~ScopedWlArray()76   ~ScopedWlArray() { wl_array_release(&array_); }
77 
operator =(ScopedWlArray && rhs)78   ScopedWlArray& operator=(ScopedWlArray&& rhs) {
79     wl_array_release(&array_);
80     array_ = rhs.array_;
81     // wl_array_init sets rhs.array_'s fields to nullptr, so that
82     // the free() in wl_array_release() is a no-op.
83     wl_array_init(&rhs.array_);
84     return *this;
85   }
86 
get()87   wl_array* get() { return &array_; }
88 
89  private:
90   wl_array array_;
91 };
92 
MakeFD()93 base::ScopedFD MakeFD() {
94   base::FilePath temp_path;
95   EXPECT_TRUE(base::CreateTemporaryFile(&temp_path));
96   auto file =
97       base::File(temp_path, base::File::FLAG_READ | base::File::FLAG_WRITE |
98                                 base::File::FLAG_CREATE_ALWAYS);
99   return base::ScopedFD(file.TakePlatformFile());
100 }
101 
102 class MockZcrCursorShapes : public WaylandZcrCursorShapes {
103  public:
MockZcrCursorShapes()104   MockZcrCursorShapes() : WaylandZcrCursorShapes(nullptr, nullptr) {}
105   MockZcrCursorShapes(const MockZcrCursorShapes&) = delete;
106   MockZcrCursorShapes& operator=(const MockZcrCursorShapes&) = delete;
107   ~MockZcrCursorShapes() override = default;
108 
109   MOCK_METHOD(void, SetCursorShape, (int32_t), (override));
110 };
111 
112 }  // namespace
113 
114 class WaylandWindowTest : public WaylandTest {
115  public:
WaylandWindowTest()116   WaylandWindowTest()
117       : test_mouse_event_(ET_MOUSE_PRESSED,
118                           gfx::Point(10, 15),
119                           gfx::Point(10, 15),
120                           ui::EventTimeStampFromSeconds(123456),
121                           EF_LEFT_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON,
122                           EF_LEFT_MOUSE_BUTTON) {}
123 
SetUp()124   void SetUp() override {
125     WaylandTest::SetUp();
126 
127     xdg_surface_ = surface_->xdg_surface();
128     ASSERT_TRUE(xdg_surface_);
129   }
130 
131  protected:
SendConfigureEventPopup(WaylandWindow * menu_window,const gfx::Rect bounds)132   void SendConfigureEventPopup(WaylandWindow* menu_window,
133                                const gfx::Rect bounds) {
134     auto* popup = GetPopupByWindow(menu_window);
135     ASSERT_TRUE(popup);
136     if (GetParam() == kXdgShellV6) {
137       zxdg_popup_v6_send_configure(popup->resource(), bounds.x(), bounds.y(),
138                                    bounds.width(), bounds.height());
139     } else {
140       xdg_popup_send_configure(popup->resource(), bounds.x(), bounds.y(),
141                                bounds.width(), bounds.height());
142     }
143   }
144 
GetXdgToplevel()145   wl::MockXdgTopLevel* GetXdgToplevel() { return xdg_surface_->xdg_toplevel(); }
146 
AddStateToWlArray(uint32_t state,wl_array * states)147   void AddStateToWlArray(uint32_t state, wl_array* states) {
148     *static_cast<uint32_t*>(wl_array_add(states, sizeof state)) = state;
149   }
150 
InitializeWlArrayWithActivatedState()151   ScopedWlArray InitializeWlArrayWithActivatedState() {
152     ScopedWlArray states;
153     AddStateToWlArray(XDG_TOPLEVEL_STATE_ACTIVATED, states.get());
154     return states;
155   }
156 
MakeStateArray(const std::vector<int32_t> states)157   ScopedWlArray MakeStateArray(const std::vector<int32_t> states) {
158     ScopedWlArray result;
159     for (const auto state : states)
160       AddStateToWlArray(state, result.get());
161     return result;
162   }
163 
CreateWaylandWindowWithParams(PlatformWindowType type,gfx::AcceleratedWidget parent_widget,const gfx::Rect bounds,MockPlatformWindowDelegate * delegate)164   std::unique_ptr<WaylandWindow> CreateWaylandWindowWithParams(
165       PlatformWindowType type,
166       gfx::AcceleratedWidget parent_widget,
167       const gfx::Rect bounds,
168       MockPlatformWindowDelegate* delegate) {
169     PlatformWindowInitProperties properties;
170     // TODO(msisov): use a fancy method to calculate position of a popup window.
171     properties.bounds = bounds;
172     properties.type = type;
173     properties.parent_widget = parent_widget;
174 
175     auto window = WaylandWindow::Create(delegate, connection_.get(),
176                                         std::move(properties));
177     if (window)
178       window->Show(false);
179     return window;
180   }
181 
InitializeWithSupportedHitTestValues(std::vector<int> * hit_tests)182   void InitializeWithSupportedHitTestValues(std::vector<int>* hit_tests) {
183     hit_tests->push_back(static_cast<int>(HTBOTTOM));
184     hit_tests->push_back(static_cast<int>(HTBOTTOMLEFT));
185     hit_tests->push_back(static_cast<int>(HTBOTTOMRIGHT));
186     hit_tests->push_back(static_cast<int>(HTLEFT));
187     hit_tests->push_back(static_cast<int>(HTRIGHT));
188     hit_tests->push_back(static_cast<int>(HTTOP));
189     hit_tests->push_back(static_cast<int>(HTTOPLEFT));
190     hit_tests->push_back(static_cast<int>(HTTOPRIGHT));
191   }
192 
InstallMockZcrCursorShapes()193   MockZcrCursorShapes* InstallMockZcrCursorShapes() {
194     auto zcr_cursor_shapes = std::make_unique<MockZcrCursorShapes>();
195     MockZcrCursorShapes* mock_cursor_shapes = zcr_cursor_shapes.get();
196     WaylandConnectionTestApi test_api(connection_.get());
197     test_api.SetZcrCursorShapes(std::move(zcr_cursor_shapes));
198     return mock_cursor_shapes;
199   }
200 
VerifyAndClearExpectations()201   void VerifyAndClearExpectations() {
202     Mock::VerifyAndClearExpectations(xdg_surface_);
203     Mock::VerifyAndClearExpectations(&delegate_);
204   }
205 
VerifyXdgPopupPosition(WaylandWindow * menu_window,const PopupPosition & position)206   void VerifyXdgPopupPosition(WaylandWindow* menu_window,
207                               const PopupPosition& position) {
208     auto* popup = GetPopupByWindow(menu_window);
209     ASSERT_TRUE(popup);
210 
211     EXPECT_EQ(popup->anchor_rect(), position.anchor_rect);
212     EXPECT_EQ(popup->size(), position.size);
213     EXPECT_EQ(popup->anchor(), position.anchor);
214     EXPECT_EQ(popup->gravity(), position.gravity);
215     EXPECT_EQ(popup->constraint_adjustment(), position.constraint_adjustment);
216   }
217 
VerifyCanDispatchMouseEvents(const std::vector<WaylandWindow * > & dispatching_windows,const std::vector<WaylandWindow * > & non_dispatching_windows)218   void VerifyCanDispatchMouseEvents(
219       const std::vector<WaylandWindow*>& dispatching_windows,
220       const std::vector<WaylandWindow*>& non_dispatching_windows) {
221     for (auto* window : dispatching_windows)
222       EXPECT_TRUE(window->CanDispatchEvent(&test_mouse_event_));
223     for (auto* window : non_dispatching_windows)
224       EXPECT_FALSE(window->CanDispatchEvent(&test_mouse_event_));
225   }
226 
VerifyCanDispatchTouchEvents(const std::vector<WaylandWindow * > & dispatching_windows,const std::vector<WaylandWindow * > & non_dispatching_windows)227   void VerifyCanDispatchTouchEvents(
228       const std::vector<WaylandWindow*>& dispatching_windows,
229       const std::vector<WaylandWindow*>& non_dispatching_windows) {
230     PointerDetails pointer_details(EventPointerType::kTouch, 1);
231     TouchEvent test_touch_event(ET_TOUCH_PRESSED, {1, 1}, base::TimeTicks(),
232                                 pointer_details);
233     for (auto* window : dispatching_windows)
234       EXPECT_TRUE(window->CanDispatchEvent(&test_touch_event));
235     for (auto* window : non_dispatching_windows)
236       EXPECT_FALSE(window->CanDispatchEvent(&test_touch_event));
237   }
238 
VerifyCanDispatchKeyEvents(const std::vector<WaylandWindow * > & dispatching_windows,const std::vector<WaylandWindow * > & non_dispatching_windows)239   void VerifyCanDispatchKeyEvents(
240       const std::vector<WaylandWindow*>& dispatching_windows,
241       const std::vector<WaylandWindow*>& non_dispatching_windows) {
242     KeyEvent test_key_event(ET_KEY_PRESSED, VKEY_0, 0);
243     for (auto* window : dispatching_windows)
244       EXPECT_TRUE(window->CanDispatchEvent(&test_key_event));
245     for (auto* window : non_dispatching_windows)
246       EXPECT_FALSE(window->CanDispatchEvent(&test_key_event));
247   }
248 
GetPopupByWindow(WaylandWindow * window)249   wl::TestXdgPopup* GetPopupByWindow(WaylandWindow* window) {
250     wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(
251         window->root_surface()->GetSurfaceId());
252     if (mock_surface) {
253       auto* mock_xdg_surface = mock_surface->xdg_surface();
254       if (mock_xdg_surface)
255         return mock_xdg_surface->xdg_popup();
256     }
257     return nullptr;
258   }
259 
260   wl::MockXdgSurface* xdg_surface_;
261 
262   MouseEvent test_mouse_event_;
263 
264  private:
265   DISALLOW_COPY_AND_ASSIGN(WaylandWindowTest);
266 };
267 
TEST_P(WaylandWindowTest,SetTitle)268 TEST_P(WaylandWindowTest, SetTitle) {
269   EXPECT_CALL(*GetXdgToplevel(), SetTitle(StrEq("hello")));
270   window_->SetTitle(base::ASCIIToUTF16("hello"));
271 }
272 
TEST_P(WaylandWindowTest,MaximizeAndRestore)273 TEST_P(WaylandWindowTest, MaximizeAndRestore) {
274   const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
275   const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600};
276 
277   uint32_t serial = 0;
278 
279   // Make sure the window has normal state initially.
280   EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
281   window_->SetBounds(kNormalBounds);
282   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
283   VerifyAndClearExpectations();
284 
285   // Deactivate the surface.
286   auto empty_state = MakeStateArray({});
287   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
288 
289   Sync();
290 
291   auto active_maximized = MakeStateArray(
292       {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
293   EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
294   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
295                                                kMaximizedBounds.height()));
296   EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
297   EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
298   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
299   window_->Maximize();
300   SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
301                      kMaximizedBounds.height(), ++serial,
302                      active_maximized.get());
303   Sync();
304   VerifyAndClearExpectations();
305 
306   auto inactive_maximized = MakeStateArray({XDG_TOPLEVEL_STATE_MAXIMIZED});
307   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
308                                                kMaximizedBounds.height()));
309   EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
310   EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
311   SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
312                      kMaximizedBounds.height(), ++serial,
313                      inactive_maximized.get());
314   Sync();
315   VerifyAndClearExpectations();
316 
317   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
318                                                kMaximizedBounds.height()));
319   EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
320   EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
321   SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
322                      kMaximizedBounds.height(), ++serial,
323                      active_maximized.get());
324   Sync();
325   VerifyAndClearExpectations();
326 
327   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
328                                                kNormalBounds.height()));
329   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
330   EXPECT_CALL(delegate_, OnActivationChanged(_)).Times(0);
331   EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
332   EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
333   window_->Restore();
334   // Reinitialize wl_array, which removes previous old states.
335   auto active = InitializeWlArrayWithActivatedState();
336   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, active.get());
337   Sync();
338 }
339 
TEST_P(WaylandWindowTest,Minimize)340 TEST_P(WaylandWindowTest, Minimize) {
341   ScopedWlArray states;
342 
343   // Make sure the window is initialized to normal state from the beginning.
344   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
345   SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
346   Sync();
347 
348   EXPECT_CALL(*GetXdgToplevel(), SetMinimized());
349   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
350   window_->Minimize();
351   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
352 
353   // Reinitialize wl_array, which removes previous old states.
354   states = ScopedWlArray();
355   SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
356   Sync();
357 
358   // Wayland compositor doesn't notify clients about minimized state, but rather
359   // if a window is not activated. Thus, a WaylandToplevelWindow marks itself as
360   // being minimized and and sets state to minimized. Thus, the state mustn't
361   // change after the configuration event is sent.
362   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMinimized);
363 
364   // Send one additional empty configuration event (which means the surface is
365   // not maximized, fullscreen or activated) to ensure, WaylandWindow stays in
366   // the same minimized state and doesn't notify its delegate.
367   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
368   SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
369   Sync();
370 
371   // And one last time to ensure the behaviour.
372   SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
373   Sync();
374 }
375 
TEST_P(WaylandWindowTest,SetFullscreenAndRestore)376 TEST_P(WaylandWindowTest, SetFullscreenAndRestore) {
377   // Make sure the window is initialized to normal state from the beginning.
378   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
379 
380   ScopedWlArray states = InitializeWlArrayWithActivatedState();
381   SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
382   Sync();
383 
384   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
385 
386   EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
387   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
388   window_->ToggleFullscreen();
389   // Make sure than WaylandWindow manually handles fullscreen states. Check the
390   // comment in the WaylandWindow::ToggleFullscreen.
391   EXPECT_EQ(window_->GetPlatformWindowState(),
392             PlatformWindowState::kFullScreen);
393   SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
394   Sync();
395 
396   EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
397   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
398   window_->Restore();
399   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
400   // Reinitialize wl_array, which removes previous old states.
401   states = InitializeWlArrayWithActivatedState();
402   SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
403   Sync();
404   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
405 }
406 
TEST_P(WaylandWindowTest,StartWithFullscreen)407 TEST_P(WaylandWindowTest, StartWithFullscreen) {
408   MockPlatformWindowDelegate delegate;
409   PlatformWindowInitProperties properties;
410   properties.bounds = gfx::Rect(0, 0, 100, 100);
411   properties.type = PlatformWindowType::kWindow;
412   // We need to create a window avoid calling Show() on it as it is what upper
413   // views layer does - when Widget initialize DesktopWindowTreeHost, the Show()
414   // is called later down the road, but Maximize may be called earlier. We
415   // cannot process them and set a pending state instead, because ShellSurface
416   // is not created by that moment.
417   auto window = WaylandWindow::Create(&delegate, connection_.get(),
418                                       std::move(properties));
419 
420   Sync();
421 
422   // Make sure the window is initialized to normal state from the beginning.
423   EXPECT_EQ(PlatformWindowState::kNormal, window->GetPlatformWindowState());
424 
425   // The state must not be changed to the fullscreen before the surface is
426   // activated.
427   auto* mock_surface = server_.GetObject<wl::MockSurface>(
428       window->root_surface()->GetSurfaceId());
429   EXPECT_FALSE(mock_surface->xdg_surface());
430   EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
431   window->ToggleFullscreen();
432   // The state of the window must already be fullscreen one.
433   EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen);
434 
435   Sync();
436 
437   // We mustn't receive any state changes if that does not differ from the last
438   // state.
439   EXPECT_CALL(delegate, OnWindowStateChanged(_)).Times(0);
440 
441   // Activate the surface.
442   ScopedWlArray states = InitializeWlArrayWithActivatedState();
443   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
444   SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
445 
446   Sync();
447 
448   // It must be still the same state.
449   EXPECT_EQ(window->GetPlatformWindowState(), PlatformWindowState::kFullScreen);
450 }
451 
TEST_P(WaylandWindowTest,StartMaximized)452 TEST_P(WaylandWindowTest, StartMaximized) {
453   MockPlatformWindowDelegate delegate;
454   PlatformWindowInitProperties properties;
455   properties.bounds = gfx::Rect(0, 0, 100, 100);
456   properties.type = PlatformWindowType::kWindow;
457   // We need to create a window avoid calling Show() on it as it is what upper
458   // views layer does - when Widget initialize DesktopWindowTreeHost, the Show()
459   // is called later down the road, but Maximize may be called earlier. We
460   // cannot process them and set a pending state instead, because ShellSurface
461   // is not created by that moment.
462   auto window = WaylandWindow::Create(&delegate, connection_.get(),
463                                       std::move(properties));
464 
465   Sync();
466 
467   // Make sure the window is initialized to normal state from the beginning.
468   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
469 
470   // The state must not be changed to the fullscreen before the surface is
471   // activated.
472   auto* mock_surface = server_.GetObject<wl::MockSurface>(
473       window->root_surface()->GetSurfaceId());
474   EXPECT_FALSE(mock_surface->xdg_surface());
475   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
476 
477   window_->Maximize();
478   // The state of the window must already be fullscreen one.
479   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
480 
481   Sync();
482 
483   // Once the surface will be activated, the window state mustn't be changed
484   // and retain the same.
485   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
486   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
487 
488   // Activate the surface.
489   ScopedWlArray states = InitializeWlArrayWithActivatedState();
490   AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
491   SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
492 
493   Sync();
494 
495   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
496 }
497 
TEST_P(WaylandWindowTest,CompositorSideStateChanges)498 TEST_P(WaylandWindowTest, CompositorSideStateChanges) {
499   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kNormal);
500   auto normal_bounds = window_->GetBounds();
501 
502   ScopedWlArray states = InitializeWlArrayWithActivatedState();
503   AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
504   SendConfigureEvent(xdg_surface_, 2000, 2000, 1, states.get());
505 
506   EXPECT_CALL(delegate_,
507               OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)))
508       .Times(1);
509   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000));
510 
511   Sync();
512 
513   EXPECT_EQ(window_->GetPlatformWindowState(), PlatformWindowState::kMaximized);
514 
515   // Unmaximize
516   states = InitializeWlArrayWithActivatedState();
517   SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
518 
519   EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
520       .Times(1);
521   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
522                                                normal_bounds.height()));
523 
524   // Now, set to fullscreen.
525   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
526   SendConfigureEvent(xdg_surface_, 2005, 2005, 3, states.get());
527   EXPECT_CALL(delegate_,
528               OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)))
529       .Times(1);
530   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005));
531 
532   Sync();
533 
534   // Unfullscreen
535   states = InitializeWlArrayWithActivatedState();
536   SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
537 
538   EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
539       .Times(1);
540   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
541                                                normal_bounds.height()));
542 
543   Sync();
544 
545   // Now, maximize, fullscreen and restore.
546   states = InitializeWlArrayWithActivatedState();
547   AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
548   SendConfigureEvent(xdg_surface_, 2000, 2000, 1, states.get());
549 
550   EXPECT_CALL(delegate_,
551               OnWindowStateChanged(Eq(PlatformWindowState::kMaximized)))
552       .Times(1);
553   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2000, 2000));
554 
555   Sync();
556 
557   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
558   SendConfigureEvent(xdg_surface_, 2005, 2005, 1, states.get());
559 
560   EXPECT_CALL(delegate_,
561               OnWindowStateChanged(Eq(PlatformWindowState::kFullScreen)))
562       .Times(1);
563   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 2005, 2005));
564 
565   // Restore
566   states = InitializeWlArrayWithActivatedState();
567   SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
568 
569   EXPECT_CALL(delegate_, OnWindowStateChanged(Eq(PlatformWindowState::kNormal)))
570       .Times(1);
571   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, normal_bounds.width(),
572                                                normal_bounds.height()));
573 
574   Sync();
575 }
576 
TEST_P(WaylandWindowTest,SetMaximizedFullscreenAndRestore)577 TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) {
578   const auto kNormalBounds = gfx::Rect{0, 0, 500, 300};
579   const auto kMaximizedBounds = gfx::Rect{0, 0, 800, 600};
580 
581   uint32_t serial = 0;
582 
583   // Make sure the window has normal state initially.
584   EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
585   window_->SetBounds(kNormalBounds);
586   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
587   VerifyAndClearExpectations();
588 
589   // Deactivate the surface.
590   ScopedWlArray empty_state;
591   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
592   Sync();
593 
594   auto active_maximized = MakeStateArray(
595       {XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_MAXIMIZED});
596   EXPECT_CALL(*GetXdgToplevel(), SetMaximized());
597   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
598                                                kMaximizedBounds.height()));
599   EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
600   EXPECT_CALL(delegate_, OnBoundsChanged(kMaximizedBounds));
601   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
602   window_->Maximize();
603   // State changes are synchronous.
604   EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
605   SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
606                      kMaximizedBounds.height(), ++serial,
607                      active_maximized.get());
608   Sync();
609   // Verify that the state has not been changed.
610   EXPECT_EQ(PlatformWindowState::kMaximized, window_->GetPlatformWindowState());
611   VerifyAndClearExpectations();
612 
613   EXPECT_CALL(*GetXdgToplevel(), SetFullscreen());
614   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kMaximizedBounds.width(),
615                                                kMaximizedBounds.height()));
616   EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
617   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
618   window_->ToggleFullscreen();
619   // State changes are synchronous.
620   EXPECT_EQ(PlatformWindowState::kFullScreen,
621             window_->GetPlatformWindowState());
622   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, active_maximized.get());
623   SendConfigureEvent(xdg_surface_, kMaximizedBounds.width(),
624                      kMaximizedBounds.height(), ++serial,
625                      active_maximized.get());
626   Sync();
627   // Verify that the state has not been changed.
628   EXPECT_EQ(PlatformWindowState::kFullScreen,
629             window_->GetPlatformWindowState());
630   VerifyAndClearExpectations();
631 
632   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, kNormalBounds.width(),
633                                                kNormalBounds.height()));
634   EXPECT_CALL(*GetXdgToplevel(), UnsetFullscreen());
635   EXPECT_CALL(*GetXdgToplevel(), UnsetMaximized());
636   EXPECT_CALL(delegate_, OnBoundsChanged(kNormalBounds));
637   EXPECT_CALL(delegate_, OnWindowStateChanged(_)).Times(0);
638   window_->Restore();
639   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
640   // Reinitialize wl_array, which removes previous old states.
641   auto active = InitializeWlArrayWithActivatedState();
642   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, active.get());
643   Sync();
644   EXPECT_EQ(PlatformWindowState::kNormal, window_->GetPlatformWindowState());
645 }
646 
TEST_P(WaylandWindowTest,RestoreBoundsAfterMaximize)647 TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximize) {
648   const gfx::Rect current_bounds = window_->GetBounds();
649 
650   ScopedWlArray states = InitializeWlArrayWithActivatedState();
651 
652   gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
653   EXPECT_TRUE(restored_bounds.IsEmpty());
654   gfx::Rect bounds = window_->GetBounds();
655 
656   const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
657   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
658   window_->Maximize();
659   AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
660   SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
661                      maximized_bounds.height(), 1, states.get());
662   Sync();
663   restored_bounds = window_->GetRestoredBoundsInPixels();
664   EXPECT_EQ(bounds, restored_bounds);
665 
666   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds)));
667   // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
668   // Thus, using a toplevel object in XdgV6 case is not right thing. Use a
669   // surface here instead.
670   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(),
671                                                current_bounds.height()));
672   window_->Restore();
673   // Reinitialize wl_array, which removes previous old states.
674   states = InitializeWlArrayWithActivatedState();
675   SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
676   Sync();
677   bounds = window_->GetBounds();
678   EXPECT_EQ(bounds, restored_bounds);
679   restored_bounds = window_->GetRestoredBoundsInPixels();
680   EXPECT_EQ(restored_bounds, gfx::Rect());
681 }
682 
TEST_P(WaylandWindowTest,RestoreBoundsAfterFullscreen)683 TEST_P(WaylandWindowTest, RestoreBoundsAfterFullscreen) {
684   const gfx::Rect current_bounds = window_->GetBounds();
685 
686   ScopedWlArray states = InitializeWlArrayWithActivatedState();
687   SendConfigureEvent(xdg_surface_, 0, 0, 1, states.get());
688   Sync();
689 
690   gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
691   EXPECT_EQ(restored_bounds, gfx::Rect());
692   gfx::Rect bounds = window_->GetBounds();
693 
694   const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720);
695   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
696   window_->ToggleFullscreen();
697   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
698   SendConfigureEvent(xdg_surface_, fullscreen_bounds.width(),
699                      fullscreen_bounds.height(), 2, states.get());
700   Sync();
701   restored_bounds = window_->GetRestoredBoundsInPixels();
702   EXPECT_EQ(bounds, restored_bounds);
703 
704   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds)));
705   // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
706   // Thus, using a toplevel object in XdgV6 case is not right thing. Use a
707   // surface here instead.
708   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(),
709                                                current_bounds.height()));
710   window_->Restore();
711   // Reinitialize wl_array, which removes previous old states.
712   states = InitializeWlArrayWithActivatedState();
713   SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
714   Sync();
715   bounds = window_->GetBounds();
716   EXPECT_EQ(bounds, restored_bounds);
717   restored_bounds = window_->GetRestoredBoundsInPixels();
718   EXPECT_EQ(restored_bounds, gfx::Rect());
719 }
720 
TEST_P(WaylandWindowTest,RestoreBoundsAfterMaximizeAndFullscreen)721 TEST_P(WaylandWindowTest, RestoreBoundsAfterMaximizeAndFullscreen) {
722   const gfx::Rect current_bounds = window_->GetBounds();
723 
724   ScopedWlArray states = InitializeWlArrayWithActivatedState();
725 
726   gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
727   EXPECT_EQ(restored_bounds, gfx::Rect());
728   gfx::Rect bounds = window_->GetBounds();
729 
730   const gfx::Rect maximized_bounds = gfx::Rect(0, 0, 1024, 768);
731   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
732   window_->Maximize();
733   AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
734   SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
735                      maximized_bounds.height(), 1, states.get());
736   Sync();
737   restored_bounds = window_->GetRestoredBoundsInPixels();
738   EXPECT_EQ(bounds, restored_bounds);
739 
740   const gfx::Rect fullscreen_bounds = gfx::Rect(0, 0, 1280, 720);
741   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(fullscreen_bounds)));
742   window_->ToggleFullscreen();
743   AddStateToWlArray(XDG_TOPLEVEL_STATE_FULLSCREEN, states.get());
744   SendConfigureEvent(xdg_surface_, fullscreen_bounds.width(),
745                      fullscreen_bounds.height(), 2, states.get());
746   Sync();
747   gfx::Rect fullscreen_restore_bounds = window_->GetRestoredBoundsInPixels();
748   EXPECT_EQ(restored_bounds, fullscreen_restore_bounds);
749 
750   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(maximized_bounds)));
751   window_->Maximize();
752   // Reinitialize wl_array, which removes previous old states.
753   states = InitializeWlArrayWithActivatedState();
754   AddStateToWlArray(XDG_TOPLEVEL_STATE_MAXIMIZED, states.get());
755   SendConfigureEvent(xdg_surface_, maximized_bounds.width(),
756                      maximized_bounds.height(), 3, states.get());
757   Sync();
758   restored_bounds = window_->GetRestoredBoundsInPixels();
759   EXPECT_EQ(restored_bounds, fullscreen_restore_bounds);
760 
761   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(current_bounds)));
762   // Both in XdgV5 and XdgV6, surfaces implement SetWindowGeometry method.
763   // Thus, using a toplevel object in XdgV6 case is not right thing. Use a
764   // surface here instead.
765   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, current_bounds.width(),
766                                                current_bounds.height()));
767   window_->Restore();
768   // Reinitialize wl_array, which removes previous old states.
769   states = InitializeWlArrayWithActivatedState();
770   SendConfigureEvent(xdg_surface_, 0, 0, 4, states.get());
771   Sync();
772   bounds = window_->GetBounds();
773   EXPECT_EQ(bounds, restored_bounds);
774   restored_bounds = window_->GetRestoredBoundsInPixels();
775   EXPECT_EQ(restored_bounds, gfx::Rect());
776 }
777 
TEST_P(WaylandWindowTest,SendsBoundsOnRequest)778 TEST_P(WaylandWindowTest, SendsBoundsOnRequest) {
779   const gfx::Rect initial_bounds = window_->GetBounds();
780 
781   const gfx::Rect new_bounds = gfx::Rect(0, 0, initial_bounds.width() + 10,
782                                          initial_bounds.height() + 10);
783   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(new_bounds)));
784   window_->SetBounds(new_bounds);
785 
786   ScopedWlArray states = InitializeWlArrayWithActivatedState();
787 
788   // First case is when Wayland sends a configure event with 0,0 height and
789   // width.
790   EXPECT_CALL(*xdg_surface_,
791               SetWindowGeometry(0, 0, new_bounds.width(), new_bounds.height()))
792       .Times(2);
793   SendConfigureEvent(xdg_surface_, 0, 0, 2, states.get());
794   Sync();
795 
796   // Restored bounds should keep empty value.
797   gfx::Rect restored_bounds = window_->GetRestoredBoundsInPixels();
798   EXPECT_EQ(restored_bounds, gfx::Rect());
799 
800   // Second case is when Wayland sends a configure event with 1, 1 height and
801   // width. It looks more like a bug in Gnome Shell with Wayland as long as the
802   // documentation says it must be set to 0, 0, when wayland requests bounds.
803   SendConfigureEvent(xdg_surface_, 0, 0, 3, states.get());
804   Sync();
805 
806   // Restored bounds should keep empty value.
807   restored_bounds = window_->GetRestoredBoundsInPixels();
808   EXPECT_EQ(restored_bounds, gfx::Rect());
809 }
810 
TEST_P(WaylandWindowTest,CanDispatchMouseEventDefault)811 TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) {
812   EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
813 }
814 
TEST_P(WaylandWindowTest,CanDispatchMouseEventFocus)815 TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) {
816   // SetPointerFocus(true) requires a WaylandPointer.
817   wl_seat_send_capabilities(server_.seat()->resource(),
818                             WL_SEAT_CAPABILITY_POINTER);
819   Sync();
820   ASSERT_TRUE(connection_->pointer());
821   window_->SetPointerFocus(true);
822   EXPECT_TRUE(window_->CanDispatchEvent(&test_mouse_event_));
823 }
824 
TEST_P(WaylandWindowTest,CanDispatchMouseEventUnfocus)825 TEST_P(WaylandWindowTest, CanDispatchMouseEventUnfocus) {
826   EXPECT_FALSE(window_->has_pointer_focus());
827   EXPECT_FALSE(window_->CanDispatchEvent(&test_mouse_event_));
828 }
829 
TEST_P(WaylandWindowTest,SetCursorUsesZcrCursorShapesForCommonTypes)830 TEST_P(WaylandWindowTest, SetCursorUsesZcrCursorShapesForCommonTypes) {
831   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
832 
833   // Verify some commonly-used cursors.
834   EXPECT_CALL(*mock_cursor_shapes,
835               SetCursorShape(ZCR_CURSOR_SHAPES_V1_CURSOR_SHAPE_TYPE_POINTER));
836   auto pointer_cursor =
837       base::MakeRefCounted<BitmapCursorOzone>(mojom::CursorType::kPointer);
838   window_->SetCursor(pointer_cursor.get());
839 
840   EXPECT_CALL(*mock_cursor_shapes,
841               SetCursorShape(ZCR_CURSOR_SHAPES_V1_CURSOR_SHAPE_TYPE_HAND));
842   auto hand_cursor =
843       base::MakeRefCounted<BitmapCursorOzone>(mojom::CursorType::kHand);
844   window_->SetCursor(hand_cursor.get());
845 
846   EXPECT_CALL(*mock_cursor_shapes,
847               SetCursorShape(ZCR_CURSOR_SHAPES_V1_CURSOR_SHAPE_TYPE_IBEAM));
848   auto ibeam_cursor =
849       base::MakeRefCounted<BitmapCursorOzone>(mojom::CursorType::kIBeam);
850   window_->SetCursor(ibeam_cursor.get());
851 }
852 
TEST_P(WaylandWindowTest,SetCursorCallsZcrCursorShapesOncePerCursor)853 TEST_P(WaylandWindowTest, SetCursorCallsZcrCursorShapesOncePerCursor) {
854   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
855   auto hand_cursor =
856       base::MakeRefCounted<BitmapCursorOzone>(mojom::CursorType::kHand);
857   // Setting the same cursor twice on the client only calls the server once.
858   EXPECT_CALL(*mock_cursor_shapes, SetCursorShape(_)).Times(1);
859   window_->SetCursor(hand_cursor.get());
860   window_->SetCursor(hand_cursor.get());
861 }
862 
TEST_P(WaylandWindowTest,SetCursorDoesNotUseZcrCursorShapesForNoneCursor)863 TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForNoneCursor) {
864   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
865   EXPECT_CALL(*mock_cursor_shapes, SetCursorShape(_)).Times(0);
866   // The "none" cursor is represented by nullptr.
867   window_->SetCursor(nullptr);
868 }
869 
TEST_P(WaylandWindowTest,SetCursorDoesNotUseZcrCursorShapesForCustomCursors)870 TEST_P(WaylandWindowTest, SetCursorDoesNotUseZcrCursorShapesForCustomCursors) {
871   MockZcrCursorShapes* mock_cursor_shapes = InstallMockZcrCursorShapes();
872 
873   // Custom cursors require bitmaps, so they do not use server-side cursors.
874   EXPECT_CALL(*mock_cursor_shapes, SetCursorShape(_)).Times(0);
875   auto custom_cursor = base::MakeRefCounted<BitmapCursorOzone>(
876       mojom::CursorType::kCustom, SkBitmap(), gfx::Point());
877   window_->SetCursor(custom_cursor.get());
878 }
879 
ACTION_P(CloneEvent,ptr)880 ACTION_P(CloneEvent, ptr) {
881   *ptr = Event::Clone(*arg0);
882 }
883 
TEST_P(WaylandWindowTest,DispatchEvent)884 TEST_P(WaylandWindowTest, DispatchEvent) {
885   std::unique_ptr<Event> event;
886   EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
887   window_->DispatchEvent(&test_mouse_event_);
888   ASSERT_TRUE(event);
889   ASSERT_TRUE(event->IsMouseEvent());
890   auto* mouse_event = event->AsMouseEvent();
891   EXPECT_EQ(mouse_event->location_f(), test_mouse_event_.location_f());
892   EXPECT_EQ(mouse_event->root_location_f(),
893             test_mouse_event_.root_location_f());
894   EXPECT_EQ(mouse_event->time_stamp(), test_mouse_event_.time_stamp());
895   EXPECT_EQ(mouse_event->button_flags(), test_mouse_event_.button_flags());
896   EXPECT_EQ(mouse_event->changed_button_flags(),
897             test_mouse_event_.changed_button_flags());
898 }
899 
TEST_P(WaylandWindowTest,ConfigureEvent)900 TEST_P(WaylandWindowTest, ConfigureEvent) {
901   ScopedWlArray states;
902 
903   // The surface must react on each configure event and send bounds to its
904   // delegate.
905 
906   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1000, 1000))));
907   // Responding to a configure event, the window geometry in here must respect
908   // the sizing negotiations specified by the configure event.
909   // |xdg_surface_| must receive the following calls in both xdg_shell_v5 and
910   // xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by
911   // xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5.
912   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1000, 1000)).Times(1);
913   EXPECT_CALL(*xdg_surface_, AckConfigure(12));
914   SendConfigureEvent(xdg_surface_, 1000, 1000, 12, states.get());
915 
916   Sync();
917 
918   EXPECT_CALL(delegate_, OnBoundsChanged(Eq(gfx::Rect(0, 0, 1500, 1000))));
919   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 1500, 1000)).Times(1);
920   EXPECT_CALL(*xdg_surface_, AckConfigure(13));
921   SendConfigureEvent(xdg_surface_, 1500, 1000, 13, states.get());
922 }
923 
TEST_P(WaylandWindowTest,ConfigureEventWithNulledSize)924 TEST_P(WaylandWindowTest, ConfigureEventWithNulledSize) {
925   ScopedWlArray states;
926 
927   // If Wayland sends configure event with 0 width and 0 size, client should
928   // call back with desired sizes. In this case, that's the actual size of
929   // the window.
930   SendConfigureEvent(xdg_surface_, 0, 0, 14, states.get());
931   // |xdg_surface_| must receive the following calls in both xdg_shell_v5 and
932   // xdg_shell_v6. Other calls like SetTitle or SetMaximized are recieved by
933   // xdg_toplevel in xdg_shell_v6 and by xdg_surface_ in xdg_shell_v5.
934   EXPECT_CALL(*xdg_surface_, SetWindowGeometry(0, 0, 800, 600));
935   EXPECT_CALL(*xdg_surface_, AckConfigure(14));
936 }
937 
TEST_P(WaylandWindowTest,OnActivationChanged)938 TEST_P(WaylandWindowTest, OnActivationChanged) {
939   uint32_t serial = 0;
940 
941   // Deactivate the surface.
942   ScopedWlArray empty_state;
943   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
944   Sync();
945 
946   {
947     ScopedWlArray states = InitializeWlArrayWithActivatedState();
948     EXPECT_CALL(delegate_, OnActivationChanged(Eq(true)));
949     SendConfigureEvent(xdg_surface_, 0, 0, ++serial, states.get());
950     Sync();
951   }
952 
953   ScopedWlArray states;
954   EXPECT_CALL(delegate_, OnActivationChanged(Eq(false)));
955   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, states.get());
956   Sync();
957 }
958 
TEST_P(WaylandWindowTest,OnAcceleratedWidgetDestroy)959 TEST_P(WaylandWindowTest, OnAcceleratedWidgetDestroy) {
960   window_.reset();
961 }
962 
TEST_P(WaylandWindowTest,CanCreateMenuWindow)963 TEST_P(WaylandWindowTest, CanCreateMenuWindow) {
964   MockPlatformWindowDelegate menu_window_delegate;
965 
966   // SetPointerFocus(true) requires a WaylandPointer.
967   wl_seat_send_capabilities(
968       server_.seat()->resource(),
969       WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH);
970   Sync();
971   ASSERT_TRUE(connection_->pointer() && connection_->touch());
972   window_->SetPointerFocus(true);
973 
974   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
975       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
976       gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
977   EXPECT_TRUE(menu_window);
978 
979   Sync();
980 
981   window_->SetPointerFocus(false);
982   window_->set_touch_focus(false);
983 
984   // Given that there is no parent passed and we don't have any focused windows,
985   // Wayland must still create a window.
986   menu_window = CreateWaylandWindowWithParams(
987       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
988       gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
989   EXPECT_TRUE(menu_window);
990 
991   Sync();
992 
993   window_->set_touch_focus(true);
994 
995   menu_window = CreateWaylandWindowWithParams(
996       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
997       gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
998   EXPECT_TRUE(menu_window);
999 
1000   Sync();
1001 }
1002 
TEST_P(WaylandWindowTest,CreateAndDestroyNestedMenuWindow)1003 TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) {
1004   MockPlatformWindowDelegate menu_window_delegate;
1005   gfx::AcceleratedWidget menu_window_widget;
1006   EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_))
1007       .WillOnce(SaveArg<0>(&menu_window_widget));
1008 
1009   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1010       PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10),
1011       &menu_window_delegate);
1012   EXPECT_TRUE(menu_window);
1013   ASSERT_NE(menu_window_widget, gfx::kNullAcceleratedWidget);
1014 
1015   Sync();
1016 
1017   MockPlatformWindowDelegate nested_menu_window_delegate;
1018   std::unique_ptr<WaylandWindow> nested_menu_window =
1019       CreateWaylandWindowWithParams(
1020           PlatformWindowType::kMenu, menu_window_widget,
1021           gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate);
1022   EXPECT_TRUE(nested_menu_window);
1023 
1024   Sync();
1025 }
1026 
TEST_P(WaylandWindowTest,DispatchesLocatedEventsToCapturedWindow)1027 TEST_P(WaylandWindowTest, DispatchesLocatedEventsToCapturedWindow) {
1028   MockPlatformWindowDelegate menu_window_delegate;
1029   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1030       PlatformWindowType::kMenu, widget_, gfx::Rect(10, 10, 10, 10),
1031       &menu_window_delegate);
1032   EXPECT_TRUE(menu_window);
1033 
1034   wl_seat_send_capabilities(server_.seat()->resource(),
1035                             WL_SEAT_CAPABILITY_POINTER);
1036   Sync();
1037   ASSERT_TRUE(connection_->pointer());
1038   window_->SetPointerFocus(true);
1039 
1040   // Make sure the events are handled by the window that has the pointer focus.
1041   VerifyCanDispatchMouseEvents({window_.get()}, {menu_window.get()});
1042 
1043   // The |window_| that has the pointer focus must receive the event.
1044   EXPECT_CALL(menu_window_delegate, DispatchEvent(_)).Times(0);
1045   std::unique_ptr<Event> event;
1046   EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
1047 
1048   // The event is send in local surface coordinates of the |window|.
1049   wl_pointer_send_motion(server_.seat()->pointer()->resource(), 1002,
1050                          wl_fixed_from_double(10.75),
1051                          wl_fixed_from_double(20.375));
1052 
1053   Sync();
1054 
1055   ASSERT_TRUE(event->IsLocatedEvent());
1056   EXPECT_EQ(event->AsLocatedEvent()->location(), gfx::Point(10, 20));
1057 
1058   // Set capture to menu window now.
1059   menu_window->SetCapture();
1060 
1061   // It's still the |window_| that can dispatch the events, but it will reroute
1062   // the event to correct window and fix the location.
1063   VerifyCanDispatchMouseEvents({window_.get()}, {menu_window.get()});
1064 
1065   // The |window_| that has the pointer focus must receive the event.
1066   EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
1067   std::unique_ptr<Event> event2;
1068   EXPECT_CALL(menu_window_delegate, DispatchEvent(_))
1069       .WillOnce(CloneEvent(&event2));
1070 
1071   // The event is send in local surface coordinates of the |window|.
1072   wl_pointer_send_motion(server_.seat()->pointer()->resource(), 1002,
1073                          wl_fixed_from_double(10.75),
1074                          wl_fixed_from_double(20.375));
1075 
1076   Sync();
1077 
1078   ASSERT_TRUE(event2->IsLocatedEvent());
1079   EXPECT_EQ(event2->AsLocatedEvent()->location(), gfx::Point(0, 10));
1080 
1081   // The event is send in local surface coordinates of the |window|.
1082   wl_pointer_send_motion(server_.seat()->pointer()->resource(), 1002,
1083                          wl_fixed_from_double(2.75),
1084                          wl_fixed_from_double(8.375));
1085 
1086   EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
1087   std::unique_ptr<Event> event3;
1088   EXPECT_CALL(menu_window_delegate, DispatchEvent(_))
1089       .WillOnce(CloneEvent(&event3));
1090 
1091   Sync();
1092 
1093   ASSERT_TRUE(event3->IsLocatedEvent());
1094   EXPECT_EQ(event3->AsLocatedEvent()->location(), gfx::Point(-8, -2));
1095 
1096   // If nested menu window is added, the events are still correctly translated
1097   // to the captured window.
1098   MockPlatformWindowDelegate nested_menu_window_delegate;
1099   std::unique_ptr<WaylandWindow> nested_menu_window =
1100       CreateWaylandWindowWithParams(
1101           PlatformWindowType::kMenu, menu_window->GetWidget(),
1102           gfx::Rect(15, 18, 10, 10), &nested_menu_window_delegate);
1103   EXPECT_TRUE(nested_menu_window);
1104 
1105   Sync();
1106 
1107   window_->SetPointerFocus(false);
1108   nested_menu_window->SetPointerFocus(true);
1109 
1110   // The event is processed by the window that has the pointer focus, but
1111   // dispatched by the window that has the capture.
1112   VerifyCanDispatchMouseEvents({nested_menu_window.get()},
1113                                {window_.get(), menu_window.get()});
1114   EXPECT_TRUE(menu_window->HasCapture());
1115 
1116   EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
1117   EXPECT_CALL(nested_menu_window_delegate, DispatchEvent(_)).Times(0);
1118   std::unique_ptr<Event> event4;
1119   EXPECT_CALL(menu_window_delegate, DispatchEvent(_))
1120       .WillOnce(CloneEvent(&event4));
1121 
1122   // The event is send in local surface coordinates of the |nested_menu_window|.
1123   wl_pointer_send_motion(server_.seat()->pointer()->resource(), 1002,
1124                          wl_fixed_from_double(2.75),
1125                          wl_fixed_from_double(8.375));
1126 
1127   Sync();
1128 
1129   ASSERT_TRUE(event4->IsLocatedEvent());
1130   EXPECT_EQ(event4->AsLocatedEvent()->location(), gfx::Point(7, 16));
1131 
1132   menu_window.reset();
1133 }
1134 
1135 // Tests that the event grabber gets the events processed by its toplevel parent
1136 // window iff they belong to the same "family". Otherwise, events mustn't be
1137 // rerouted from another toplevel window to the event grabber.
TEST_P(WaylandWindowTest,DispatchesLocatedEventsToCapturedWindowInTheSameStack)1138 TEST_P(WaylandWindowTest,
1139        DispatchesLocatedEventsToCapturedWindowInTheSameStack) {
1140   MockPlatformWindowDelegate menu_window_delegate;
1141   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1142       PlatformWindowType::kMenu, widget_, gfx::Rect(30, 40, 20, 50),
1143       &menu_window_delegate);
1144   EXPECT_TRUE(menu_window);
1145 
1146   // Second toplevel window has the same bounds as the |window_|.
1147   MockPlatformWindowDelegate toplevel_window2_delegate;
1148   std::unique_ptr<WaylandWindow> toplevel_window2 =
1149       CreateWaylandWindowWithParams(
1150           PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
1151           window_->GetBounds(), &toplevel_window2_delegate);
1152   EXPECT_TRUE(toplevel_window2);
1153 
1154   wl_seat_send_capabilities(server_.seat()->resource(),
1155                             WL_SEAT_CAPABILITY_POINTER);
1156   Sync();
1157   ASSERT_TRUE(connection_->pointer());
1158   window_->SetPointerFocus(true);
1159 
1160   // Make sure the events are handled by the window that has the pointer focus.
1161   VerifyCanDispatchMouseEvents({window_.get()},
1162                                {menu_window.get(), toplevel_window2.get()});
1163 
1164   menu_window->SetCapture();
1165 
1166   // The |menu_window| that has capture must receive the event.
1167   EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
1168   EXPECT_CALL(toplevel_window2_delegate, DispatchEvent(_)).Times(0);
1169   std::unique_ptr<Event> event;
1170   EXPECT_CALL(menu_window_delegate, DispatchEvent(_))
1171       .WillOnce(CloneEvent(&event));
1172 
1173   // The event is send in local surface coordinates of the |window|.
1174   wl_pointer_send_motion(server_.seat()->pointer()->resource(), 1002,
1175                          wl_fixed_from_double(10.75),
1176                          wl_fixed_from_double(20.375));
1177 
1178   Sync();
1179 
1180   ASSERT_TRUE(event->IsLocatedEvent());
1181   EXPECT_EQ(event->AsLocatedEvent()->location(), gfx::Point(-20, -20));
1182 
1183   // Now, pretend that the second toplevel window gets the pointer focus - the
1184   // event grabber must be disragerder now.
1185   window_->SetPointerFocus(false);
1186   toplevel_window2->SetPointerFocus(true);
1187 
1188   VerifyCanDispatchMouseEvents({toplevel_window2.get()},
1189                                {menu_window.get(), window_.get()});
1190 
1191   // The |toplevel_window2| that has capture and must receive the event.
1192   EXPECT_CALL(delegate_, DispatchEvent(_)).Times(0);
1193   EXPECT_CALL(menu_window_delegate, DispatchEvent(_)).Times(0);
1194   event.reset();
1195   EXPECT_CALL(toplevel_window2_delegate, DispatchEvent(_))
1196       .WillOnce(CloneEvent(&event));
1197 
1198   // The event is send in local surface coordinates of the |toplevel_window2|
1199   // (they're basically the same as the |window| has.)
1200   wl_pointer_send_motion(server_.seat()->pointer()->resource(), 1002,
1201                          wl_fixed_from_double(10.75),
1202                          wl_fixed_from_double(20.375));
1203 
1204   Sync();
1205 
1206   ASSERT_TRUE(event->IsLocatedEvent());
1207   EXPECT_EQ(event->AsLocatedEvent()->location(), gfx::Point(10, 20));
1208 }
1209 
TEST_P(WaylandWindowTest,DispatchesKeyboardEventToToplevelWindow)1210 TEST_P(WaylandWindowTest, DispatchesKeyboardEventToToplevelWindow) {
1211   MockPlatformWindowDelegate menu_window_delegate;
1212   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1213       PlatformWindowType::kMenu, widget_, gfx::Rect(10, 10, 10, 10),
1214       &menu_window_delegate);
1215   EXPECT_TRUE(menu_window);
1216 
1217   wl_seat_send_capabilities(server_.seat()->resource(),
1218                             WL_SEAT_CAPABILITY_KEYBOARD);
1219   Sync();
1220   ASSERT_TRUE(connection_->keyboard());
1221   menu_window->set_keyboard_focus(true);
1222 
1223   // Even though the menu window has the keyboard focus, the keyboard events are
1224   // dispatched by the root parent wayland window in the end.
1225   VerifyCanDispatchKeyEvents({menu_window.get()}, {window_.get()});
1226   EXPECT_CALL(menu_window_delegate, DispatchEvent(_)).Times(0);
1227   std::unique_ptr<Event> event;
1228   EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
1229 
1230   wl_keyboard_send_key(server_.seat()->keyboard()->resource(), 2, 0, 30 /* a */,
1231                        WL_KEYBOARD_KEY_STATE_PRESSED);
1232 
1233   Sync();
1234 
1235   ASSERT_TRUE(event->IsKeyEvent());
1236 
1237   // Setting capture doesn't affect the kbd events.
1238   menu_window->SetCapture();
1239   VerifyCanDispatchKeyEvents({menu_window.get()}, {window_.get()});
1240 
1241   wl_keyboard_send_key(server_.seat()->keyboard()->resource(), 2, 0, 30 /* a */,
1242                        WL_KEYBOARD_KEY_STATE_PRESSED);
1243 
1244   EXPECT_CALL(menu_window_delegate, DispatchEvent(_)).Times(0);
1245   event.reset();
1246   EXPECT_CALL(delegate_, DispatchEvent(_)).WillOnce(CloneEvent(&event));
1247 
1248   Sync();
1249 
1250   ASSERT_TRUE(event->IsKeyEvent());
1251 
1252   menu_window.reset();
1253 }
1254 
1255 // Tests that event is processed by the surface that has the focus. More
1256 // extensive tests are located in wayland touch/keyboard/pointer unittests.
TEST_P(WaylandWindowTest,CanDispatchEvent)1257 TEST_P(WaylandWindowTest, CanDispatchEvent) {
1258   MockPlatformWindowDelegate menu_window_delegate;
1259   gfx::AcceleratedWidget menu_window_widget;
1260   EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetAvailable(_))
1261       .WillOnce(SaveArg<0>(&menu_window_widget));
1262 
1263   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1264       PlatformWindowType::kMenu, widget_, gfx::Rect(0, 0, 10, 10),
1265       &menu_window_delegate);
1266   EXPECT_TRUE(menu_window);
1267 
1268   Sync();
1269 
1270   MockPlatformWindowDelegate nested_menu_window_delegate;
1271   std::unique_ptr<WaylandWindow> nested_menu_window =
1272       CreateWaylandWindowWithParams(
1273           PlatformWindowType::kMenu, menu_window_widget,
1274           gfx::Rect(20, 0, 10, 10), &nested_menu_window_delegate);
1275   EXPECT_TRUE(nested_menu_window);
1276 
1277   Sync();
1278 
1279   wl_seat_send_capabilities(server_.seat()->resource(),
1280                             WL_SEAT_CAPABILITY_POINTER |
1281                                 WL_SEAT_CAPABILITY_KEYBOARD |
1282                                 WL_SEAT_CAPABILITY_TOUCH);
1283   Sync();
1284   ASSERT_TRUE(connection_->pointer());
1285   ASSERT_TRUE(connection_->touch());
1286   ASSERT_TRUE(connection_->keyboard());
1287 
1288   uint32_t serial = 0;
1289 
1290   // Test that CanDispatchEvent is set correctly.
1291   wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>(
1292       window_->root_surface()->GetSurfaceId());
1293   wl_pointer_send_enter(server_.seat()->pointer()->resource(), ++serial,
1294                         toplevel_surface->resource(), 0, 0);
1295 
1296   Sync();
1297 
1298   // Only |window_| can dispatch MouseEvents.
1299   VerifyCanDispatchMouseEvents({window_.get()},
1300                                {menu_window.get(), nested_menu_window.get()});
1301   VerifyCanDispatchTouchEvents(
1302       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1303   VerifyCanDispatchKeyEvents(
1304       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1305 
1306   struct wl_array empty;
1307   wl_array_init(&empty);
1308   wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), ++serial,
1309                          toplevel_surface->resource(), &empty);
1310 
1311   Sync();
1312 
1313   // Only |window_| can dispatch MouseEvents and KeyEvents.
1314   VerifyCanDispatchMouseEvents({window_.get()},
1315                                {menu_window.get(), nested_menu_window.get()});
1316   VerifyCanDispatchTouchEvents(
1317       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1318   VerifyCanDispatchKeyEvents({window_.get()},
1319                              {menu_window.get(), nested_menu_window.get()});
1320 
1321   wl_touch_send_down(server_.seat()->touch()->resource(), ++serial, 0,
1322                      toplevel_surface->resource(), 0 /* id */,
1323                      wl_fixed_from_int(50), wl_fixed_from_int(100));
1324 
1325   Sync();
1326 
1327   // Only |window_| can dispatch MouseEvents and KeyEvents.
1328   VerifyCanDispatchMouseEvents({window_.get()},
1329                                {menu_window.get(), nested_menu_window.get()});
1330   VerifyCanDispatchTouchEvents({window_.get()},
1331                                {menu_window.get(), nested_menu_window.get()});
1332   VerifyCanDispatchKeyEvents({window_.get()},
1333                              {menu_window.get(), nested_menu_window.get()});
1334 
1335   wl::MockSurface* menu_window_surface = server_.GetObject<wl::MockSurface>(
1336       menu_window->root_surface()->GetSurfaceId());
1337 
1338   wl_pointer_send_leave(server_.seat()->pointer()->resource(), ++serial,
1339                         toplevel_surface->resource());
1340   wl_pointer_send_enter(server_.seat()->pointer()->resource(), ++serial,
1341                         menu_window_surface->resource(), 0, 0);
1342   wl_touch_send_up(server_.seat()->touch()->resource(), ++serial, 1000,
1343                    0 /* id */);
1344   wl_keyboard_send_leave(server_.seat()->keyboard()->resource(), ++serial,
1345                          toplevel_surface->resource());
1346 
1347   Sync();
1348 
1349   // Only |menu_window| can dispatch MouseEvents.
1350   VerifyCanDispatchMouseEvents({menu_window.get()},
1351                                {window_.get(), nested_menu_window.get()});
1352   VerifyCanDispatchTouchEvents(
1353       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1354   VerifyCanDispatchKeyEvents(
1355       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1356 
1357   wl::MockSurface* nested_menu_window_surface =
1358       server_.GetObject<wl::MockSurface>(
1359           nested_menu_window->root_surface()->GetSurfaceId());
1360 
1361   wl_pointer_send_leave(server_.seat()->pointer()->resource(), ++serial,
1362                         menu_window_surface->resource());
1363   wl_pointer_send_enter(server_.seat()->pointer()->resource(), ++serial,
1364                         nested_menu_window_surface->resource(), 0, 0);
1365 
1366   Sync();
1367 
1368   // Only |nested_menu_window| can dispatch MouseEvents.
1369   VerifyCanDispatchMouseEvents({nested_menu_window.get()},
1370                                {window_.get(), menu_window.get()});
1371   VerifyCanDispatchTouchEvents(
1372       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1373   VerifyCanDispatchKeyEvents(
1374       {}, {window_.get(), menu_window.get(), nested_menu_window.get()});
1375 }
1376 
TEST_P(WaylandWindowTest,DispatchWindowMove)1377 TEST_P(WaylandWindowTest, DispatchWindowMove) {
1378   EXPECT_CALL(*GetXdgToplevel(), Move(_));
1379   ui::GetWmMoveResizeHandler(*window_)->DispatchHostWindowDragMovement(
1380       HTCAPTION, gfx::Point());
1381 }
1382 
1383 // Makes sure hit tests are converted into right edges.
TEST_P(WaylandWindowTest,DispatchWindowResize)1384 TEST_P(WaylandWindowTest, DispatchWindowResize) {
1385   std::vector<int> hit_test_values;
1386   InitializeWithSupportedHitTestValues(&hit_test_values);
1387 
1388   auto* wm_move_resize_handler = ui::GetWmMoveResizeHandler(*window_);
1389 
1390   for (const int value : hit_test_values) {
1391     {
1392       uint32_t direction = wl::IdentifyDirection(*(connection_.get()), value);
1393       EXPECT_CALL(*GetXdgToplevel(), Resize(_, Eq(direction)));
1394       wm_move_resize_handler->DispatchHostWindowDragMovement(value,
1395                                                              gfx::Point());
1396     }
1397   }
1398 }
1399 
1400 // Tests WaylandWindow repositions menu windows to be relative to parent window
1401 // in a right way.
TEST_P(WaylandWindowTest,AdjustPopupBounds)1402 TEST_P(WaylandWindowTest, AdjustPopupBounds) {
1403   PopupPosition menu_window_positioner, nested_menu_window_positioner;
1404 
1405   if (GetParam() == kXdgShellV6) {
1406     menu_window_positioner = {
1407         gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409),
1408         ZXDG_POSITIONER_V6_ANCHOR_BOTTOM | ZXDG_POSITIONER_V6_ANCHOR_RIGHT,
1409         ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT,
1410         ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X |
1411             ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y};
1412 
1413     nested_menu_window_positioner = {
1414         gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99),
1415         ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_RIGHT,
1416         ZXDG_POSITIONER_V6_GRAVITY_BOTTOM | ZXDG_POSITIONER_V6_GRAVITY_RIGHT,
1417         ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X |
1418             ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y};
1419   } else {
1420     menu_window_positioner = {gfx::Rect(439, 46, 1, 30), gfx::Size(287, 409),
1421                               XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT,
1422                               XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
1423                               XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
1424                                   XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y};
1425 
1426     nested_menu_window_positioner = {
1427         gfx::Rect(4, 80, 279, 1), gfx::Size(305, 99),
1428         XDG_POSITIONER_ANCHOR_TOP_RIGHT, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
1429         XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X |
1430             XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y};
1431   }
1432 
1433   auto* toplevel_window = window_.get();
1434   toplevel_window->SetBounds(gfx::Rect(0, 0, 739, 574));
1435 
1436   // Case 1: the top menu window is positioned normally.
1437   MockPlatformWindowDelegate menu_window_delegate;
1438   gfx::Rect menu_window_bounds(gfx::Point(440, 76),
1439                                menu_window_positioner.size);
1440   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1441       PlatformWindowType::kMenu, toplevel_window->GetWidget(),
1442       menu_window_bounds, &menu_window_delegate);
1443   EXPECT_TRUE(menu_window);
1444 
1445   Sync();
1446 
1447   VerifyXdgPopupPosition(menu_window.get(), menu_window_positioner);
1448 
1449   EXPECT_CALL(menu_window_delegate, OnBoundsChanged(_)).Times(0);
1450   SendConfigureEventPopup(menu_window.get(), menu_window_bounds);
1451 
1452   Sync();
1453 
1454   EXPECT_EQ(menu_window->GetBounds(), menu_window_bounds);
1455 
1456   // Case 2: the nested menu window is positioned normally.
1457   MockPlatformWindowDelegate nested_menu_window_delegate;
1458   gfx::Rect nested_menu_window_bounds(gfx::Point(723, 156),
1459                                       nested_menu_window_positioner.size);
1460   std::unique_ptr<WaylandWindow> nested_menu_window =
1461       CreateWaylandWindowWithParams(
1462           PlatformWindowType::kMenu, menu_window->GetWidget(),
1463           nested_menu_window_bounds, &nested_menu_window_delegate);
1464   EXPECT_TRUE(nested_menu_window);
1465 
1466   Sync();
1467 
1468   VerifyXdgPopupPosition(nested_menu_window.get(),
1469                          nested_menu_window_positioner);
1470 
1471   EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0);
1472   const gfx::Point origin(nested_menu_window_positioner.anchor_rect.x() +
1473                               nested_menu_window_positioner.anchor_rect.width(),
1474                           nested_menu_window_positioner.anchor_rect.y());
1475   gfx::Rect calculated_nested_bounds = nested_menu_window_bounds;
1476   calculated_nested_bounds.set_origin(origin);
1477   SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
1478 
1479   Sync();
1480 
1481   EXPECT_EQ(nested_menu_window->GetBounds(), nested_menu_window_bounds);
1482 
1483   // Case 3: imagine the menu window was positioned near to the right edge of a
1484   // display. Nothing changes in the way how WaylandWindow calculates bounds,
1485   // because the Wayland compositor does not provide global location of windows.
1486   // Though, the compositor can reposition the window (flip along x or y axis or
1487   // slide along those axis). WaylandWindow just needs to correctly translate
1488   // bounds from relative to parent to be relative to screen. The Wayland
1489   // compositor does not reposition the menu, because it fits the screen, but
1490   // the nested menu window is repositioned to the left.
1491   EXPECT_CALL(
1492       nested_menu_window_delegate,
1493       OnBoundsChanged(gfx::Rect({139, 156}, nested_menu_window_bounds.size())));
1494   calculated_nested_bounds.set_origin({-301, 80});
1495   SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
1496 
1497   Sync();
1498 
1499   // Case 4: imagine the top level window was moved down to the bottom edge of a
1500   // display and only tab strip with 3-dot menu buttons left visible. In this
1501   // case, Chromium also does not know about that and positions the window
1502   // normally (normal bounds are sent), but the Wayland compositor flips the top
1503   // menu window along y-axis and fixes bounds of a top level window so that it
1504   // is located (from the Chromium point of view) below origin of the menu
1505   // window.
1506   EXPECT_CALL(delegate_, OnBoundsChanged(
1507                              gfx::Rect({0, 363}, window_->GetBounds().size())));
1508   EXPECT_CALL(menu_window_delegate,
1509               OnBoundsChanged(gfx::Rect({440, 0}, menu_window_bounds.size())));
1510   SendConfigureEventPopup(menu_window.get(),
1511                           gfx::Rect({440, -363}, menu_window_bounds.size()));
1512 
1513   Sync();
1514 
1515   // The nested menu window is also repositioned accordingly, but it's not
1516   // Wayland compositor reposition, but rather reposition from the Chromium
1517   // side. Thus, we have to check that anchor rect is correct.
1518   nested_menu_window.reset();
1519   nested_menu_window_bounds.set_origin({723, 258});
1520   nested_menu_window = CreateWaylandWindowWithParams(
1521       PlatformWindowType::kMenu, menu_window->GetWidget(),
1522       nested_menu_window_bounds, &nested_menu_window_delegate);
1523   EXPECT_TRUE(nested_menu_window);
1524 
1525   Sync();
1526 
1527   // We must get the anchor on gfx::Point(4, 258).
1528   nested_menu_window_positioner.anchor_rect.set_origin({4, 258});
1529   VerifyXdgPopupPosition(nested_menu_window.get(),
1530                          nested_menu_window_positioner);
1531 
1532   Sync();
1533 
1534   EXPECT_CALL(nested_menu_window_delegate, OnBoundsChanged(_)).Times(0);
1535   calculated_nested_bounds.set_origin({283, 258});
1536   SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
1537 
1538   Sync();
1539 
1540   // Case 5: this case involves case 4. Thus, it concerns only the nested menu
1541   // window. imagine that the top menu window is flipped along y-axis and
1542   // positioned near to the right side of a display. The nested menu window is
1543   // flipped along x-axis by the compositor and WaylandWindow must calculate
1544   // bounds back to be relative to display correctly. If the window is near to
1545   // the left edge of a display, nothing is going to change, and the origin will
1546   // be the same as in the previous case.
1547   EXPECT_CALL(
1548       nested_menu_window_delegate,
1549       OnBoundsChanged(gfx::Rect({149, 258}, nested_menu_window_bounds.size())));
1550   calculated_nested_bounds.set_origin({-291, 258});
1551   SendConfigureEventPopup(nested_menu_window.get(), calculated_nested_bounds);
1552 
1553   Sync();
1554 
1555   // Case 6: imagine the top level window was moved back to normal position. In
1556   // this case, the Wayland compositor positions the menu window normally and
1557   // the WaylandWindow repositions the top level window back to 0,0 (which had
1558   // an offset to compensate the position of the menu window fliped along
1559   // y-axis. It just has had negative y value, which is wrong for Chromium.
1560   EXPECT_CALL(delegate_,
1561               OnBoundsChanged(gfx::Rect({0, 0}, window_->GetBounds().size())));
1562   EXPECT_CALL(menu_window_delegate,
1563               OnBoundsChanged(gfx::Rect({440, 76}, menu_window_bounds.size())));
1564   SendConfigureEventPopup(menu_window.get(),
1565                           gfx::Rect({440, 76}, menu_window_bounds.size()));
1566 
1567   Sync();
1568 
1569   VerifyAndClearExpectations();
1570 }
1571 
ACTION_P(VerifyRegion,ptr)1572 ACTION_P(VerifyRegion, ptr) {
1573   wl::TestRegion* region = wl::GetUserDataAs<wl::TestRegion>(arg0);
1574   EXPECT_EQ(*ptr, region->getBounds());
1575 }
1576 
TEST_P(WaylandWindowTest,SetOpaqueRegion)1577 TEST_P(WaylandWindowTest, SetOpaqueRegion) {
1578   wl::MockSurface* mock_surface = server_.GetObject<wl::MockSurface>(
1579       window_->root_surface()->GetSurfaceId());
1580 
1581   gfx::Rect new_bounds(0, 0, 500, 600);
1582   auto state_array = MakeStateArray({XDG_TOPLEVEL_STATE_ACTIVATED});
1583   SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 1,
1584                      state_array.get());
1585 
1586   SkIRect rect =
1587       SkIRect::MakeXYWH(0, 0, new_bounds.width(), new_bounds.height());
1588   EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).WillOnce(VerifyRegion(&rect));
1589 
1590   Sync();
1591 
1592   VerifyAndClearExpectations();
1593 
1594   new_bounds.set_size(gfx::Size(1000, 534));
1595   SendConfigureEvent(xdg_surface_, new_bounds.width(), new_bounds.height(), 2,
1596                      state_array.get());
1597 
1598   rect = SkIRect::MakeXYWH(0, 0, new_bounds.width(), new_bounds.height());
1599   EXPECT_CALL(*mock_surface, SetOpaqueRegion(_)).WillOnce(VerifyRegion(&rect));
1600 
1601   Sync();
1602 
1603   VerifyAndClearExpectations();
1604 }
1605 
TEST_P(WaylandWindowTest,OnCloseRequest)1606 TEST_P(WaylandWindowTest, OnCloseRequest) {
1607   EXPECT_CALL(delegate_, OnCloseRequest());
1608 
1609   if (GetParam() == kXdgShellV6)
1610     zxdg_toplevel_v6_send_close(xdg_surface_->xdg_toplevel()->resource());
1611   else
1612     xdg_toplevel_send_close(xdg_surface_->xdg_toplevel()->resource());
1613 
1614   Sync();
1615 }
1616 
TEST_P(WaylandWindowTest,AuxiliaryWindowSimpleParent)1617 TEST_P(WaylandWindowTest, AuxiliaryWindowSimpleParent) {
1618   VerifyAndClearExpectations();
1619 
1620   std::unique_ptr<WaylandWindow> second_window = CreateWaylandWindowWithParams(
1621       PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
1622       gfx::Rect(0, 0, 640, 480), &delegate_);
1623   EXPECT_TRUE(second_window);
1624 
1625   // Test case 1: if the subsurface is provided with a parent widget, it must
1626   // always use that as a parent.
1627   gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
1628   std::unique_ptr<WaylandWindow> auxiliary_window =
1629       CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
1630                                     window_->GetWidget(), subsurface_bounds,
1631                                     &delegate_);
1632   EXPECT_TRUE(auxiliary_window);
1633 
1634   // The subsurface mustn't take the focused window as a parent, but use the
1635   // provided one.
1636   second_window->SetPointerFocus(true);
1637   auxiliary_window->Show(false);
1638 
1639   Sync();
1640 
1641   auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
1642       auxiliary_window->root_surface()->GetSurfaceId());
1643   auto* test_subsurface = mock_surface_subsurface->sub_surface();
1644 
1645   EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin());
1646   EXPECT_FALSE(test_subsurface->sync());
1647 
1648   auto* parent_resource =
1649       server_
1650           .GetObject<wl::MockSurface>(window_->root_surface()->GetSurfaceId())
1651           ->resource();
1652   EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
1653 
1654   // Test case 2: the subsurface must use the focused window as its parent.
1655   auxiliary_window = CreateWaylandWindowWithParams(
1656       PlatformWindowType::kTooltip, gfx::kNullAcceleratedWidget,
1657       subsurface_bounds, &delegate_);
1658   EXPECT_TRUE(auxiliary_window);
1659 
1660   // The tooltip must take the focused window.
1661   second_window->SetPointerFocus(true);
1662   auxiliary_window->Show(false);
1663 
1664   Sync();
1665 
1666   // Get new surface after recreating the WaylandAuxiliaryWindow.
1667   mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
1668       auxiliary_window->root_surface()->GetSurfaceId());
1669   test_subsurface = mock_surface_subsurface->sub_surface();
1670 
1671   auto* second_parent_resource =
1672       server_
1673           .GetObject<wl::MockSurface>(
1674               second_window->root_surface()->GetSurfaceId())
1675           ->resource();
1676   EXPECT_EQ(second_parent_resource, test_subsurface->parent_resource());
1677 
1678   auxiliary_window->Hide();
1679 
1680   Sync();
1681 
1682   // The subsurface must take the focused window.
1683   second_window->SetPointerFocus(false);
1684   window_->SetPointerFocus(true);
1685   auxiliary_window->Show(false);
1686 
1687   Sync();
1688 
1689   // The subsurface is invalidated on each Hide call.
1690   test_subsurface = mock_surface_subsurface->sub_surface();
1691 
1692   // The |window_|'s resource must be the parent resource.
1693   EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
1694 
1695   window_->SetPointerFocus(false);
1696 }
1697 
1698 // Case 1: When the menu bounds are positive and there is a positive,
1699 // non-zero anchor width
TEST_P(WaylandWindowTest,NestedPopupMenu)1700 TEST_P(WaylandWindowTest, NestedPopupMenu) {
1701   VerifyAndClearExpectations();
1702 
1703   gfx::Rect menu_window_bounds(gfx::Rect(4, 20, 8, 20));
1704   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1705       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
1706       &delegate_);
1707   EXPECT_TRUE(menu_window);
1708 
1709   VerifyAndClearExpectations();
1710 
1711   gfx::Rect nestedPopup_bounds(gfx::Rect(10, 30, 40, 20));
1712   std::unique_ptr<WaylandWindow> nested_popup_window =
1713       CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
1714                                     menu_window->GetWidget(),
1715                                     nestedPopup_bounds, &delegate_);
1716   EXPECT_TRUE(nested_popup_window);
1717 
1718   VerifyAndClearExpectations();
1719 
1720   nested_popup_window->SetPointerFocus(true);
1721 
1722   Sync();
1723 
1724   auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
1725 
1726   ASSERT_TRUE(mock_surface_nested_popup);
1727 
1728   auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
1729   EXPECT_EQ(4, anchor_width);
1730 
1731   nested_popup_window->SetPointerFocus(false);
1732 }
1733 
1734 // Case 2: When the menu bounds are positive and there is a negative or
1735 // zero anchor width
TEST_P(WaylandWindowTest,NestedPopupMenu1)1736 TEST_P(WaylandWindowTest, NestedPopupMenu1) {
1737   VerifyAndClearExpectations();
1738 
1739   gfx::Rect menu_window_bounds(gfx::Rect(6, 20, 8, 20));
1740   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1741       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
1742       &delegate_);
1743   EXPECT_TRUE(menu_window);
1744 
1745   VerifyAndClearExpectations();
1746 
1747   gfx::Rect nestedPopup_bounds(gfx::Rect(10, 30, 10, 20));
1748   std::unique_ptr<WaylandWindow> nested_popup_window =
1749       CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
1750                                     menu_window->GetWidget(),
1751                                     nestedPopup_bounds, &delegate_);
1752   EXPECT_TRUE(nested_popup_window);
1753 
1754   VerifyAndClearExpectations();
1755 
1756   nested_popup_window->SetPointerFocus(true);
1757 
1758   Sync();
1759 
1760   auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
1761 
1762   ASSERT_TRUE(mock_surface_nested_popup);
1763 
1764   auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
1765   EXPECT_EQ(1, anchor_width);
1766 
1767   nested_popup_window->SetPointerFocus(false);
1768 }
1769 
1770 // Case 3: When the menu bounds are negative and there is a positive,
1771 // non-zero anchor width
TEST_P(WaylandWindowTest,NestedPopupMenu2)1772 TEST_P(WaylandWindowTest, NestedPopupMenu2) {
1773   VerifyAndClearExpectations();
1774 
1775   gfx::Rect menu_window_bounds(gfx::Rect(10, 20, 40, 20));
1776   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1777       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
1778       &delegate_);
1779   EXPECT_TRUE(menu_window);
1780 
1781   VerifyAndClearExpectations();
1782 
1783   gfx::Rect nestedPopup_bounds(gfx::Rect(5, 30, 21, 20));
1784   std::unique_ptr<WaylandWindow> nested_popup_window =
1785       CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
1786                                     menu_window->GetWidget(),
1787                                     nestedPopup_bounds, &delegate_);
1788   EXPECT_TRUE(nested_popup_window);
1789 
1790   VerifyAndClearExpectations();
1791 
1792   nested_popup_window->SetPointerFocus(true);
1793 
1794   Sync();
1795 
1796   auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
1797 
1798   ASSERT_TRUE(mock_surface_nested_popup);
1799 
1800   auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
1801   EXPECT_EQ(8, anchor_width);
1802 
1803   nested_popup_window->SetPointerFocus(false);
1804 }
1805 
1806 // Case 4: When the menu bounds are negative and there is a negative,
1807 // zero anchor width
TEST_P(WaylandWindowTest,NestedPopupMenu3)1808 TEST_P(WaylandWindowTest, NestedPopupMenu3) {
1809   VerifyAndClearExpectations();
1810 
1811   gfx::Rect menu_window_bounds(gfx::Rect(10, 20, 20, 20));
1812   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1813       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
1814       &delegate_);
1815   EXPECT_TRUE(menu_window);
1816 
1817   VerifyAndClearExpectations();
1818 
1819   gfx::Rect nestedPopup_bounds(gfx::Rect(5, 30, 21, 20));
1820   std::unique_ptr<WaylandWindow> nested_popup_window =
1821       CreateWaylandWindowWithParams(PlatformWindowType::kPopup,
1822                                     menu_window->GetWidget(),
1823                                     nestedPopup_bounds, &delegate_);
1824   EXPECT_TRUE(nested_popup_window);
1825 
1826   VerifyAndClearExpectations();
1827 
1828   nested_popup_window->SetPointerFocus(true);
1829 
1830   Sync();
1831 
1832   auto* mock_surface_nested_popup = GetPopupByWindow(nested_popup_window.get());
1833 
1834   ASSERT_TRUE(mock_surface_nested_popup);
1835 
1836   auto anchor_width = (mock_surface_nested_popup->anchor_rect()).width();
1837 
1838   EXPECT_EQ(1, anchor_width);
1839 
1840   nested_popup_window->SetPointerFocus(false);
1841 }
1842 
TEST_P(WaylandWindowTest,AuxiliaryWindowNestedParent)1843 TEST_P(WaylandWindowTest, AuxiliaryWindowNestedParent) {
1844   VerifyAndClearExpectations();
1845 
1846   gfx::Rect menu_window_bounds(gfx::Point(10, 10), gfx::Size(100, 100));
1847   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
1848       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
1849       &delegate_);
1850   EXPECT_TRUE(menu_window);
1851 
1852   VerifyAndClearExpectations();
1853 
1854   gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
1855   std::unique_ptr<WaylandWindow> auxiliary_window =
1856       CreateWaylandWindowWithParams(PlatformWindowType::kTooltip,
1857                                     menu_window->GetWidget(), subsurface_bounds,
1858                                     &delegate_);
1859   EXPECT_TRUE(auxiliary_window);
1860 
1861   VerifyAndClearExpectations();
1862 
1863   menu_window->SetPointerFocus(true);
1864 
1865   auxiliary_window->Show(false);
1866 
1867   Sync();
1868 
1869   auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
1870       auxiliary_window->root_surface()->GetSurfaceId());
1871   auto* test_subsurface = mock_surface_subsurface->sub_surface();
1872 
1873   auto new_origin = subsurface_bounds.origin() -
1874                     menu_window_bounds.origin().OffsetFromOrigin();
1875   EXPECT_EQ(test_subsurface->position(), new_origin);
1876 
1877   menu_window->SetPointerFocus(false);
1878 }
1879 
TEST_P(WaylandWindowTest,OnSizeConstraintsChanged)1880 TEST_P(WaylandWindowTest, OnSizeConstraintsChanged) {
1881   const bool kBooleans[] = {false, true};
1882   for (bool has_min_size : kBooleans) {
1883     for (bool has_max_size : kBooleans) {
1884       base::Optional<gfx::Size> min_size =
1885           has_min_size ? base::Optional<gfx::Size>(gfx::Size(100, 200))
1886                        : base::nullopt;
1887       base::Optional<gfx::Size> max_size =
1888           has_max_size ? base::Optional<gfx::Size>(gfx::Size(300, 400))
1889                        : base::nullopt;
1890       EXPECT_CALL(delegate_, GetMinimumSizeForWindow())
1891           .WillOnce(Return(min_size));
1892       EXPECT_CALL(delegate_, GetMaximumSizeForWindow())
1893           .WillOnce(Return(max_size));
1894 
1895       EXPECT_CALL(*GetXdgToplevel(), SetMinSize(100, 200))
1896           .Times(has_min_size ? 1 : 0);
1897       EXPECT_CALL(*GetXdgToplevel(), SetMaxSize(300, 400))
1898           .Times(has_max_size ? 1 : 0);
1899 
1900       window_->SizeConstraintsChanged();
1901       Sync();
1902 
1903       VerifyAndClearExpectations();
1904     }
1905   }
1906 }
1907 
TEST_P(WaylandWindowTest,DestroysCreatesSurfaceOnHideShow)1908 TEST_P(WaylandWindowTest, DestroysCreatesSurfaceOnHideShow) {
1909   MockPlatformWindowDelegate delegate;
1910   auto window = CreateWaylandWindowWithParams(
1911       PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
1912       gfx::Rect(0, 0, 100, 100), &delegate);
1913   ASSERT_TRUE(window);
1914 
1915   Sync();
1916 
1917   auto* mock_surface = server_.GetObject<wl::MockSurface>(
1918       window->root_surface()->GetSurfaceId());
1919   EXPECT_TRUE(mock_surface->xdg_surface());
1920   EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel());
1921 
1922   Sync();
1923 
1924   window->Hide();
1925 
1926   Sync();
1927 
1928   EXPECT_FALSE(mock_surface->xdg_surface());
1929 
1930   window->Show(false);
1931 
1932   Sync();
1933 
1934   EXPECT_TRUE(mock_surface->xdg_surface());
1935   EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel());
1936 }
1937 
TEST_P(WaylandWindowTest,DestroysCreatesPopupsOnHideShow)1938 TEST_P(WaylandWindowTest, DestroysCreatesPopupsOnHideShow) {
1939   MockPlatformWindowDelegate delegate;
1940   auto window = CreateWaylandWindowWithParams(
1941       PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50),
1942       &delegate);
1943   ASSERT_TRUE(window);
1944 
1945   Sync();
1946 
1947   auto* mock_surface = server_.GetObject<wl::MockSurface>(
1948       window->root_surface()->GetSurfaceId());
1949   EXPECT_TRUE(mock_surface->xdg_surface());
1950   EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup());
1951 
1952   Sync();
1953 
1954   window->Hide();
1955 
1956   Sync();
1957 
1958   EXPECT_FALSE(mock_surface->xdg_surface());
1959 
1960   window->Show(false);
1961 
1962   Sync();
1963 
1964   EXPECT_TRUE(mock_surface->xdg_surface());
1965   EXPECT_TRUE(mock_surface->xdg_surface()->xdg_popup());
1966 }
1967 
TEST_P(WaylandWindowTest,RemovesReattachesBackgroundOnHideShow)1968 TEST_P(WaylandWindowTest, RemovesReattachesBackgroundOnHideShow) {
1969   EXPECT_TRUE(connection_->buffer_manager_host());
1970 
1971   auto interface_ptr = connection_->buffer_manager_host()->BindInterface();
1972   buffer_manager_gpu_->Initialize(std::move(interface_ptr), {}, false);
1973 
1974   // Setup wl_buffers.
1975   constexpr uint32_t buffer_id1 = 1;
1976   constexpr uint32_t buffer_id2 = 2;
1977   gfx::Size buffer_size(1024, 768);
1978   auto length = 1024 * 768 * 4;
1979   buffer_manager_gpu_->CreateShmBasedBuffer(MakeFD(), length, buffer_size,
1980                                             buffer_id1);
1981   buffer_manager_gpu_->CreateShmBasedBuffer(MakeFD(), length, buffer_size,
1982                                             buffer_id2);
1983 
1984   Sync();
1985 
1986   // Create window.
1987   MockPlatformWindowDelegate delegate;
1988   auto window = CreateWaylandWindowWithParams(
1989       PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
1990       gfx::Rect(0, 0, 100, 100), &delegate);
1991   ASSERT_TRUE(window);
1992   auto states = InitializeWlArrayWithActivatedState();
1993 
1994   Sync();
1995 
1996   // Configure window to be ready to attach wl_buffers.
1997   auto* mock_surface = server_.GetObject<wl::MockSurface>(
1998       window->root_surface()->GetSurfaceId());
1999   EXPECT_TRUE(mock_surface->xdg_surface());
2000   EXPECT_TRUE(mock_surface->xdg_surface()->xdg_toplevel());
2001   SendConfigureEvent(mock_surface->xdg_surface(), 100, 100, 1, states.get());
2002 
2003   // Commit a frame with only background.
2004   std::vector<ui::ozone::mojom::WaylandOverlayConfigPtr> overlays;
2005   ui::ozone::mojom::WaylandOverlayConfigPtr background{
2006       ui::ozone::mojom::WaylandOverlayConfig::New()};
2007   background->z_order = INT32_MIN;
2008   background->transform = gfx::OVERLAY_TRANSFORM_NONE;
2009   background->buffer_id = buffer_id1;
2010   overlays.push_back(std::move(background));
2011   buffer_manager_gpu_->CommitOverlays(window->GetWidget(), std::move(overlays));
2012   mock_surface->SendFrameCallback();
2013 
2014   Sync();
2015 
2016   EXPECT_NE(mock_surface->attached_buffer(), nullptr);
2017 
2018   // Hiding window attaches a nil wl_buffer as background.
2019   window->Hide();
2020   mock_surface->SendFrameCallback();
2021 
2022   Sync();
2023 
2024   EXPECT_EQ(mock_surface->attached_buffer(), nullptr);
2025 
2026   mock_surface->ReleaseBuffer(mock_surface->prev_attached_buffer());
2027   window->Show(false);
2028 
2029   Sync();
2030 
2031   SendConfigureEvent(mock_surface->xdg_surface(), 100, 100, 2, states.get());
2032 
2033   // Commit a frame with only the primary_plane.
2034   overlays.clear();
2035   ui::ozone::mojom::WaylandOverlayConfigPtr primary{
2036       ui::ozone::mojom::WaylandOverlayConfig::New()};
2037   primary->z_order = 0;
2038   primary->transform = gfx::OVERLAY_TRANSFORM_NONE;
2039   primary->buffer_id = buffer_id2;
2040   overlays.push_back(std::move(primary));
2041   buffer_manager_gpu_->CommitOverlays(window->GetWidget(), std::move(overlays));
2042 
2043   Sync();
2044 
2045   // WaylandWindow should automatically reattach the background.
2046   EXPECT_NE(mock_surface->attached_buffer(), nullptr);
2047 }
2048 
2049 // Tests that if the window gets hidden and shown again, the title, app id and
2050 // size constraints remain the same.
TEST_P(WaylandWindowTest,SetsPropertiesOnShow)2051 TEST_P(WaylandWindowTest, SetsPropertiesOnShow) {
2052   constexpr char kAppId[] = "wayland_test";
2053   const base::string16 kTitle(base::UTF8ToUTF16("WaylandWindowTest"));
2054 
2055   PlatformWindowInitProperties properties;
2056   properties.bounds = gfx::Rect(0, 0, 100, 100);
2057   properties.type = PlatformWindowType::kWindow;
2058   properties.wm_class_class = kAppId;
2059 
2060   MockPlatformWindowDelegate delegate;
2061   auto window = WaylandWindow::Create(&delegate, connection_.get(),
2062                                       std::move(properties));
2063   DCHECK(window);
2064   window->Show(false);
2065 
2066   Sync();
2067 
2068   auto* mock_surface = server_.GetObject<wl::MockSurface>(
2069       window->root_surface()->GetSurfaceId());
2070   auto* mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel();
2071 
2072   // Only app id must be set now.
2073   EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
2074   EXPECT_TRUE(mock_xdg_toplevel->title().empty());
2075   EXPECT_TRUE(mock_xdg_toplevel->min_size().IsEmpty());
2076   EXPECT_TRUE(mock_xdg_toplevel->max_size().IsEmpty());
2077 
2078   // Now, propagate size constraints and title.
2079   base::Optional<gfx::Size> min_size(gfx::Size(1, 1));
2080   base::Optional<gfx::Size> max_size(gfx::Size(100, 100));
2081   EXPECT_CALL(delegate, GetMinimumSizeForWindow()).WillOnce(Return(min_size));
2082   EXPECT_CALL(delegate, GetMaximumSizeForWindow()).WillOnce(Return(max_size));
2083 
2084   EXPECT_CALL(*mock_xdg_toplevel,
2085               SetMinSize(min_size.value().width(), min_size.value().height()));
2086   EXPECT_CALL(*mock_xdg_toplevel,
2087               SetMaxSize(max_size.value().width(), max_size.value().height()));
2088   EXPECT_CALL(*mock_xdg_toplevel, SetTitle(base::UTF16ToUTF8(kTitle)));
2089 
2090   window->SetTitle(kTitle);
2091   window->SizeConstraintsChanged();
2092 
2093   Sync();
2094 
2095   window->Hide();
2096 
2097   Sync();
2098 
2099   window->Show(false);
2100 
2101   Sync();
2102 
2103   mock_xdg_toplevel = mock_surface->xdg_surface()->xdg_toplevel();
2104 
2105   // We can't mock all those methods above as long as the xdg_toplevel is
2106   // created and destroyed on each show and hide call. However, it is the same
2107   // WaylandToplevelWindow object that cached the values we set and must restore
2108   // them on Show().
2109   EXPECT_EQ(mock_xdg_toplevel->min_size(), min_size.value());
2110   EXPECT_EQ(mock_xdg_toplevel->max_size(), max_size.value());
2111   EXPECT_EQ(std::string(kAppId), mock_xdg_toplevel->app_id());
2112   EXPECT_EQ(mock_xdg_toplevel->title(), base::UTF16ToUTF8(kTitle));
2113 }
2114 
2115 // Tests that a popup window is created using the serial of button press events
2116 // as required by the Wayland protocol spec.
TEST_P(WaylandWindowTest,CreatesPopupOnButtonPressSerial)2117 TEST_P(WaylandWindowTest, CreatesPopupOnButtonPressSerial) {
2118   wl_seat_send_capabilities(
2119       server_.seat()->resource(),
2120       WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD);
2121 
2122   Sync();
2123 
2124   constexpr uint32_t enter_serial = 1;
2125   constexpr uint32_t button_press_serial = 2;
2126   constexpr uint32_t button_release_serial = 3;
2127 
2128   wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>(
2129       window_->root_surface()->GetSurfaceId());
2130   struct wl_array empty;
2131   wl_array_init(&empty);
2132   wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), enter_serial,
2133                          toplevel_surface->resource(), &empty);
2134 
2135   // Send two events - button down and button up.
2136   wl_pointer_send_button(server_.seat()->pointer()->resource(),
2137                          button_press_serial, 1002, BTN_LEFT,
2138                          WL_POINTER_BUTTON_STATE_PRESSED);
2139   wl_pointer_send_button(server_.seat()->pointer()->resource(),
2140                          button_release_serial, 1004, BTN_LEFT,
2141                          WL_POINTER_BUTTON_STATE_RELEASED);
2142   Sync();
2143 
2144   // Create a popup window and verify the client used correct serial.
2145   MockPlatformWindowDelegate delegate;
2146   auto popup = CreateWaylandWindowWithParams(
2147       PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50),
2148       &delegate);
2149   ASSERT_TRUE(popup);
2150 
2151   Sync();
2152 
2153   auto* test_popup = GetPopupByWindow(popup.get());
2154   ASSERT_TRUE(test_popup);
2155   EXPECT_NE(test_popup->grab_serial(), button_release_serial);
2156   EXPECT_EQ(test_popup->grab_serial(), button_press_serial);
2157 }
2158 
2159 // Tests that a popup window is created using the serial of touch down events
2160 // as required by the Wayland protocol spec.
TEST_P(WaylandWindowTest,CreatesPopupOnTouchDownSerial)2161 TEST_P(WaylandWindowTest, CreatesPopupOnTouchDownSerial) {
2162   wl_seat_send_capabilities(
2163       server_.seat()->resource(),
2164       WL_SEAT_CAPABILITY_TOUCH | WL_SEAT_CAPABILITY_KEYBOARD);
2165 
2166   Sync();
2167 
2168   constexpr uint32_t enter_serial = 1;
2169   constexpr uint32_t touch_down_serial = 2;
2170   constexpr uint32_t touch_up_serial = 3;
2171 
2172   wl::MockSurface* toplevel_surface = server_.GetObject<wl::MockSurface>(
2173       window_->root_surface()->GetSurfaceId());
2174   struct wl_array empty;
2175   wl_array_init(&empty);
2176   wl_keyboard_send_enter(server_.seat()->keyboard()->resource(), enter_serial,
2177                          toplevel_surface->resource(), &empty);
2178 
2179   // Send two events - touch down and touch up.
2180   wl_touch_send_down(server_.seat()->touch()->resource(), touch_down_serial, 0,
2181                      surface_->resource(), 0 /* id */, wl_fixed_from_int(50),
2182                      wl_fixed_from_int(100));
2183   wl_touch_send_up(server_.seat()->touch()->resource(), touch_up_serial, 1000,
2184                    0 /* id */);
2185 
2186   Sync();
2187 
2188   // Create a popup window and verify the client used correct serial.
2189   MockPlatformWindowDelegate delegate;
2190   auto popup = CreateWaylandWindowWithParams(
2191       PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50),
2192       &delegate);
2193   ASSERT_TRUE(popup);
2194 
2195   Sync();
2196 
2197   auto* test_popup = GetPopupByWindow(popup.get());
2198   ASSERT_TRUE(test_popup);
2199 
2200   // Touch events are the exception. We can't use the serial that was sent
2201   // before the "up" event. Otherwise, some compositors may dismiss popups.
2202   // Thus, no serial must be used.
2203   EXPECT_EQ(test_popup->grab_serial(), 0U);
2204 
2205   popup->Hide();
2206 
2207   // Send a single down event now.
2208   wl_touch_send_down(server_.seat()->touch()->resource(), touch_down_serial, 0,
2209                      surface_->resource(), 0 /* id */, wl_fixed_from_int(50),
2210                      wl_fixed_from_int(100));
2211 
2212   Sync();
2213 
2214   popup->Show(false);
2215 
2216   Sync();
2217 
2218   test_popup = GetPopupByWindow(popup.get());
2219   ASSERT_TRUE(test_popup);
2220 
2221   EXPECT_EQ(test_popup->grab_serial(), touch_down_serial);
2222 }
2223 
2224 // Tests nested menu windows get the topmost window in the stack of windows
2225 // within the same family/tree.
TEST_P(WaylandWindowTest,NestedPopupWindowsGetCorrectParent)2226 TEST_P(WaylandWindowTest, NestedPopupWindowsGetCorrectParent) {
2227   VerifyAndClearExpectations();
2228 
2229   gfx::Rect menu_window_bounds(gfx::Rect(10, 20, 20, 20));
2230   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
2231       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds,
2232       &delegate_);
2233   EXPECT_TRUE(menu_window);
2234 
2235   EXPECT_TRUE(menu_window->parent_window() == window_.get());
2236 
2237   gfx::Rect menu_window_bounds2(gfx::Rect(20, 40, 30, 20));
2238   std::unique_ptr<WaylandWindow> menu_window2 = CreateWaylandWindowWithParams(
2239       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds2,
2240       &delegate_);
2241   EXPECT_TRUE(menu_window2);
2242 
2243   EXPECT_TRUE(menu_window2->parent_window() == menu_window.get());
2244 
2245   gfx::Rect menu_window_bounds3(gfx::Rect(30, 40, 30, 20));
2246   std::unique_ptr<WaylandWindow> menu_window3 = CreateWaylandWindowWithParams(
2247       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds3,
2248       &delegate_);
2249   EXPECT_TRUE(menu_window3);
2250 
2251   EXPECT_TRUE(menu_window3->parent_window() == menu_window2.get());
2252 
2253   gfx::Rect menu_window_bounds4(gfx::Rect(40, 40, 30, 20));
2254   std::unique_ptr<WaylandWindow> menu_window4 = CreateWaylandWindowWithParams(
2255       PlatformWindowType::kMenu, window_->GetWidget(), menu_window_bounds4,
2256       &delegate_);
2257   EXPECT_TRUE(menu_window4);
2258 
2259   EXPECT_TRUE(menu_window4->parent_window() == menu_window3.get());
2260 }
2261 
TEST_P(WaylandWindowTest,DoesNotGrabPopupIfNoSeat)2262 TEST_P(WaylandWindowTest, DoesNotGrabPopupIfNoSeat) {
2263   // Create a popup window and verify the grab serial is not set.
2264   MockPlatformWindowDelegate delegate;
2265   auto popup = CreateWaylandWindowWithParams(
2266       PlatformWindowType::kMenu, window_->GetWidget(), gfx::Rect(0, 0, 50, 50),
2267       &delegate);
2268   ASSERT_TRUE(popup);
2269 
2270   Sync();
2271 
2272   auto* test_popup = GetPopupByWindow(popup.get());
2273   ASSERT_TRUE(test_popup);
2274   EXPECT_EQ(test_popup->grab_serial(), 0u);
2275 }
2276 
TEST_P(WaylandWindowTest,OneWaylandSubsurface)2277 TEST_P(WaylandWindowTest, OneWaylandSubsurface) {
2278   VerifyAndClearExpectations();
2279 
2280   std::unique_ptr<WaylandWindow> window = CreateWaylandWindowWithParams(
2281       PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
2282       gfx::Rect(0, 0, 640, 480), &delegate_);
2283   EXPECT_TRUE(window);
2284 
2285   gfx::Rect subsurface_bounds(gfx::Point(15, 15), gfx::Size(10, 10));
2286   bool result = window->RequestSubsurface();
2287   EXPECT_TRUE(result);
2288 
2289   WaylandSubsurface* wayland_subsurface =
2290       window->wayland_subsurfaces().begin()->get();
2291 
2292   Sync();
2293 
2294   auto* mock_surface_root_window = server_.GetObject<wl::MockSurface>(
2295       window->root_surface()->GetSurfaceId());
2296   auto* mock_surface_subsurface = server_.GetObject<wl::MockSurface>(
2297       wayland_subsurface->wayland_surface()->GetSurfaceId());
2298   EXPECT_TRUE(mock_surface_subsurface);
2299   wayland_subsurface->ConfigureAndShowSurface(gfx::OVERLAY_TRANSFORM_NONE,
2300                                               gfx::RectF(), subsurface_bounds,
2301                                               true, nullptr, nullptr);
2302   connection_->ScheduleFlush();
2303 
2304   Sync();
2305 
2306   auto* test_subsurface = mock_surface_subsurface->sub_surface();
2307   EXPECT_TRUE(test_subsurface);
2308   auto* parent_resource = mock_surface_root_window->resource();
2309   EXPECT_EQ(parent_resource, test_subsurface->parent_resource());
2310 
2311   EXPECT_EQ(test_subsurface->position(), subsurface_bounds.origin());
2312   EXPECT_TRUE(test_subsurface->sync());
2313 }
2314 
TEST_P(WaylandWindowTest,UsesCorrectParentForChildrenWindows)2315 TEST_P(WaylandWindowTest, UsesCorrectParentForChildrenWindows) {
2316   uint32_t serial = 0;
2317 
2318   MockPlatformWindowDelegate window_delegate;
2319   std::unique_ptr<WaylandWindow> window = CreateWaylandWindowWithParams(
2320       PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
2321       gfx::Rect(10, 10, 100, 100), &window_delegate);
2322   EXPECT_TRUE(window);
2323 
2324   window->Show(false);
2325 
2326   std::unique_ptr<WaylandWindow> another_window = CreateWaylandWindowWithParams(
2327       PlatformWindowType::kWindow, gfx::kNullAcceleratedWidget,
2328       gfx::Rect(10, 10, 300, 400), &window_delegate);
2329   EXPECT_TRUE(another_window);
2330 
2331   another_window->Show(false);
2332 
2333   Sync();
2334 
2335   auto* window1 = window.get();
2336   auto* window2 = window_.get();
2337   auto* window3 = another_window.get();
2338 
2339   // Make sure windows are not "active".
2340   auto empty_state = MakeStateArray({});
2341   SendConfigureEvent(xdg_surface_, 0, 0, ++serial, empty_state.get());
2342   auto* xdg_surface_window =
2343       server_
2344           .GetObject<wl::MockSurface>(window->root_surface()->GetSurfaceId())
2345           ->xdg_surface();
2346   SendConfigureEvent(xdg_surface_window, 0, 0, ++serial, empty_state.get());
2347   auto* xdg_surface_another_window =
2348       server_
2349           .GetObject<wl::MockSurface>(
2350               another_window->root_surface()->GetSurfaceId())
2351           ->xdg_surface();
2352   SendConfigureEvent(xdg_surface_another_window, 0, 0, ++serial,
2353                      empty_state.get());
2354 
2355   Sync();
2356 
2357   // Case 1: provided parent window's widget..
2358   MockPlatformWindowDelegate menu_window_delegate;
2359   std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
2360       PlatformWindowType::kMenu, window1->GetWidget(),
2361       gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
2362 
2363   EXPECT_TRUE(menu_window->parent_window() == window1);
2364 
2365   // Case 2: didn't provide parent window's widget - must use current focused.
2366   //
2367   // Subcase 1: pointer focus.
2368   window2->SetPointerFocus(true);
2369   menu_window = CreateWaylandWindowWithParams(
2370       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
2371       gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
2372 
2373   EXPECT_TRUE(menu_window->parent_window() == window2);
2374   EXPECT_TRUE(wl::IsMenuType(menu_window->type()));
2375 
2376   // Subcase 2: keyboard focus.
2377   window2->SetPointerFocus(false);
2378   window2->set_keyboard_focus(true);
2379   menu_window = CreateWaylandWindowWithParams(
2380       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
2381       gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
2382 
2383   // Mustn't be able to create a menu window, but rather creates a toplevel
2384   // window as we must provide at least something.
2385   EXPECT_TRUE(menu_window);
2386   // Make it create xdg objects.
2387   menu_window->Show(false);
2388 
2389   Sync();
2390 
2391   auto* menu_window_xdg =
2392       server_
2393           .GetObject<wl::MockSurface>(
2394               another_window->root_surface()->GetSurfaceId())
2395           ->xdg_surface();
2396   EXPECT_TRUE(menu_window_xdg);
2397   EXPECT_TRUE(menu_window_xdg->xdg_toplevel());
2398   EXPECT_FALSE(menu_window_xdg->xdg_popup());
2399 
2400   // Subcase 3: touch focus.
2401   window2->set_keyboard_focus(false);
2402   window2->set_touch_focus(true);
2403   menu_window = CreateWaylandWindowWithParams(
2404       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
2405       gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
2406 
2407   EXPECT_TRUE(menu_window->parent_window() == window2);
2408   EXPECT_TRUE(wl::IsMenuType(menu_window->type()));
2409 
2410   // Case 3: neither of the windows are focused. However, there is one that is
2411   // active. Must use that then.
2412   window2->set_touch_focus(false);
2413 
2414   auto active = InitializeWlArrayWithActivatedState();
2415   SendConfigureEvent(xdg_surface_another_window, 0, 0, ++serial, active.get());
2416   Sync();
2417 
2418   menu_window = CreateWaylandWindowWithParams(
2419       PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
2420       gfx::Rect(10, 10, 10, 10), &menu_window_delegate);
2421 
2422   EXPECT_TRUE(menu_window->parent_window() == window3);
2423   EXPECT_TRUE(wl::IsMenuType(menu_window->type()));
2424 }
2425 
2426 INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
2427                          WaylandWindowTest,
2428                          ::testing::Values(kXdgShellStable));
2429 INSTANTIATE_TEST_SUITE_P(XdgVersionV6Test,
2430                          WaylandWindowTest,
2431                          ::testing::Values(kXdgShellV6));
2432 
2433 }  // namespace ui
2434