1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <algorithm>
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <vector>
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <X11/extensions/shape.h>
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <X11/Xlib.h>
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <X11/Xregion.h>
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Get rid of X11 macros which conflict with gtest.
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#undef Bool
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#undef None
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "third_party/skia/include/core/SkRect.h"
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "third_party/skia/include/core/SkRegion.h"
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/aura/window.h"
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/aura/window_tree_host.h"
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/events/platform/x11/x11_event_source.h"
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gfx/path.h"
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gfx/path_x11.h"
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gfx/x/x11_atom_cache.h"
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/test/views_test_base.h"
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/test/x11_property_change_waiter.h"
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/views/widget/widget.h"
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace views {
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Waits till |window| is minimized.
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class MinimizeWaiter : public X11PropertyChangeWaiter {
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  explicit MinimizeWaiter(XID window)
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : X11PropertyChangeWaiter(window, "_NET_WM_STATE") {
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const char* kAtomsToCache[] = { "_NET_WM_STATE_HIDDEN", NULL };
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    atom_cache_.reset(new ui::X11AtomCache(gfx::GetXDisplay(), kAtomsToCache));
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~MinimizeWaiter() {
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // X11PropertyChangeWaiter:
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) OVERRIDE {
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<Atom> wm_states;
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) {
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      std::vector<Atom>::iterator it = std::find(
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          wm_states.begin(),
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          wm_states.end(),
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          atom_cache_->GetAtom("_NET_WM_STATE_HIDDEN"));
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return it == wm_states.end();
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<ui::X11AtomCache> atom_cache_;
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MinimizeWaiter);
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Waits till |_NET_CLIENT_LIST_STACKING| is updated to include
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// |expected_windows|.
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class StackingClientListWaiter : public X11PropertyChangeWaiter {
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  StackingClientListWaiter(XID* expected_windows, size_t count)
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      : X11PropertyChangeWaiter(ui::GetX11RootWindow(),
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                "_NET_CLIENT_LIST_STACKING"),
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        expected_windows_(expected_windows, expected_windows + count) {
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~StackingClientListWaiter() {
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // X11PropertyChangeWaiter:
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void Wait() OVERRIDE {
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // StackingClientListWaiter may be created after
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // _NET_CLIENT_LIST_STACKING already contains |expected_windows|.
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (!ShouldKeepOnWaiting(NULL))
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return;
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    X11PropertyChangeWaiter::Wait();
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // X11PropertyChangeWaiter:
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) OVERRIDE {
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<XID> stack;
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::GetXWindowStack(ui::GetX11RootWindow(), &stack);
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for (size_t i = 0; i < expected_windows_.size(); ++i) {
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      std::vector<XID>::iterator it = std::find(
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          stack.begin(), stack.end(), expected_windows_[i]);
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (it == stack.end())
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return true;
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<XID> expected_windows_;
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StackingClientListWaiter);
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class X11TopmostWindowFinderTest : public ViewsTestBase {
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  X11TopmostWindowFinderTest() {
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~X11TopmostWindowFinderTest() {
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Creates and shows a Widget with |bounds|. The caller takes ownership of
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // the returned widget.
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) {
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<Widget> toplevel(new Widget);
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    params.native_widget = new DesktopNativeWidgetAura(toplevel.get());
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    params.bounds = bounds;
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    params.remove_standard_frame = true;
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    toplevel->Init(params);
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    toplevel->Show();
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return toplevel.Pass();
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Creates and shows an X window with |bounds|.
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID CreateAndShowXWindow(const gfx::Rect& bounds) {
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XID root = DefaultRootWindow(xdisplay());
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XID xid = XCreateSimpleWindow(xdisplay(),
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  root,
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  0, 0, 1, 1,
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  0,   // border_width
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  0,   // border
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  0);  // background
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::SetUseOSWindowFrame(xid, false);
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ShowAndSetXWindowBounds(xid, bounds);
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return xid;
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Shows |xid| and sets its bounds.
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void ShowAndSetXWindowBounds(XID xid, const gfx::Rect& bounds) {
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XMapWindow(xdisplay(), xid);
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XWindowChanges changes = {0};
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    changes.x = bounds.x();
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    changes.y = bounds.y();
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    changes.width = bounds.width();
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    changes.height = bounds.height();
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XConfigureWindow(xdisplay(),
158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     xid,
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     CWX | CWY | CWWidth | CWHeight,
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     &changes);
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Display* xdisplay() {
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return gfx::GetXDisplay();
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Returns the topmost X window at the passed in screen position.
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID FindTopmostXWindowAt(int screen_x, int screen_y) {
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    X11TopmostWindowFinder finder;
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return finder.FindWindowAt(gfx::Point(screen_x, screen_y));
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Returns the topmost aura::Window at the passed in screen position. Returns
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // NULL if the topmost window does not have an associated aura::Window.
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  aura::Window* FindTopmostLocalProcessWindowAt(int screen_x, int screen_y) {
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    X11TopmostWindowFinder finder;
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y),
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           std::set<aura::Window*>());
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Returns the topmost aura::Window at the passed in screen position ignoring
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // |ignore_window|. Returns NULL if the topmost window does not have an
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // associated aura::Window.
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  aura::Window* FindTopmostLocalProcessWindowWithIgnore(
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      int screen_x,
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      int screen_y,
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      aura::Window* ignore_window) {
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::set<aura::Window*> ignore;
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ignore.insert(ignore_window);
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    X11TopmostWindowFinder finder;
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return finder.FindLocalProcessWindowAt(gfx::Point(screen_x, screen_y),
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                           ignore);
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // ViewsTestBase:
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ViewsTestBase::SetUp();
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Make X11 synchronous for our display connection. This does not force the
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // window manager to behave synchronously.
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XSynchronize(xdisplay(), True);
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Ensure that the X11DesktopHandler exists. The X11DesktopHandler is
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // necessary to properly track menu windows.
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    X11DesktopHandler::get();
206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void TearDown() OVERRIDE {
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XSynchronize(xdisplay(), False);
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ViewsTestBase::TearDown();
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(X11TopmostWindowFinderTest);
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(X11TopmostWindowFinderTest, Basic) {
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Avoid positioning test windows at 0x0 because window managers often have a
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // panel/launcher along one of the screen edges and do not allow windows to
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // position themselves to overlap the panel/launcher.
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<Widget> widget1(
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateAndShowWidget(gfx::Rect(100, 100, 200, 100)));
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  aura::Window* window1 = widget1->GetNativeWindow();
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid1 = window1->GetHost()->GetAcceleratedWidget();
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200));
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<Widget> widget3(
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateAndShowWidget(gfx::Rect(100, 190, 200, 110)));
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  aura::Window* window3 = widget3->GetNativeWindow();
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid3 = window3->GetHost()->GetAcceleratedWidget();
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xids[] = { xid1, xid2, xid3 };
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  StackingClientListWaiter waiter(xids, arraysize(xids));
235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  waiter.Wait();
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150));
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(window1, FindTopmostLocalProcessWindowAt(150, 150));
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid2, FindTopmostXWindowAt(250, 150));
242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(NULL, FindTopmostLocalProcessWindowAt(250, 150));
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid3, FindTopmostXWindowAt(250, 250));
245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(250, 250));
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid3, FindTopmostXWindowAt(150, 250));
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(150, 250));
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid3, FindTopmostXWindowAt(150, 195));
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(window3, FindTopmostLocalProcessWindowAt(150, 195));
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid1, FindTopmostXWindowAt(1000, 1000));
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid2, FindTopmostXWindowAt(1000, 1000));
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid3, FindTopmostXWindowAt(1000, 1000));
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(NULL, FindTopmostLocalProcessWindowAt(1000, 1000));
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(window1,
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            FindTopmostLocalProcessWindowWithIgnore(150, 150, window3));
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(NULL,
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            FindTopmostLocalProcessWindowWithIgnore(250, 250, window3));
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(NULL,
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            FindTopmostLocalProcessWindowWithIgnore(150, 250, window3));
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(window1,
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            FindTopmostLocalProcessWindowWithIgnore(150, 195, window3));
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XDestroyWindow(xdisplay(), xid2);
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Test that the minimized state is properly handled.
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(X11TopmostWindowFinderTest, Minimized) {
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<Widget> widget1(
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  aura::Window* window1 = widget1->GetNativeWindow();
275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid1 = window1->GetHost()->GetAcceleratedWidget();
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xids[] = { xid1, xid2 };
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  StackingClientListWaiter stack_waiter(xids, arraysize(xids));
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  stack_waiter.Wait();
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150));
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  {
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    MinimizeWaiter minimize_waiter(xid1);
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XIconifyWindow(xdisplay(), xid1, 0);
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    minimize_waiter.Wait();
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid1, FindTopmostXWindowAt(150, 150));
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid2, FindTopmostXWindowAt(150, 150));
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Repeat test for an X window which does not belong to a views::Widget
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // because the code path is different.
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid2, FindTopmostXWindowAt(350, 150));
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  {
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    MinimizeWaiter minimize_waiter(xid2);
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    XIconifyWindow(xdisplay(), xid2, 0);
298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    minimize_waiter.Wait();
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid1, FindTopmostXWindowAt(350, 150));
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid2, FindTopmostXWindowAt(350, 150));
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XDestroyWindow(xdisplay(), xid2);
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Test that non-rectangular windows are properly handled.
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(X11TopmostWindowFinderTest, NonRectangular) {
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!ui::IsShapeExtensionAvailable())
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<Widget> widget1(
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CreateAndShowWidget(gfx::Rect(100, 100, 100, 100)));
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget();
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SkRegion* skregion1 = new SkRegion;
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  skregion1->op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  skregion1->op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Widget takes ownership of |skregion1|.
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  widget1->SetShape(skregion1);
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SkRegion skregion2;
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op);
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  skregion2.op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op);
323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100));
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  REGION* region2 = gfx::CreateRegionFromSkRegion(skregion2);
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XShapeCombineRegion(xdisplay(), xid2, ShapeBounding, 0, 0, region2,
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      false);
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XDestroyRegion(region2);
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xids[] = { xid1, xid2 };
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  StackingClientListWaiter stack_waiter(xids, arraysize(xids));
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  stack_waiter.Wait();
332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid1, FindTopmostXWindowAt(105, 120));
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid1, FindTopmostXWindowAt(105, 105));
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid2, FindTopmostXWindowAt(105, 105));
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Repeat test for an X window which does not belong to a views::Widget
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // because the code path is different.
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid2, FindTopmostXWindowAt(305, 120));
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid1, FindTopmostXWindowAt(305, 105));
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_NE(xid2, FindTopmostXWindowAt(305, 105));
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XDestroyWindow(xdisplay(), xid2);
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Test that the TopmostWindowFinder finds windows which belong to menus
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// (which may or may not belong to Chrome).
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)TEST_F(X11TopmostWindowFinderTest, Menu) {
350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xid = CreateAndShowXWindow(gfx::Rect(100, 100, 100, 100));
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID root = DefaultRootWindow(xdisplay());
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XSetWindowAttributes swa;
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  swa.override_redirect = True;
355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID menu_xid = XCreateWindow(xdisplay(),
356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               root,
357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               0, 0, 1, 1,
358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               0,                  // border width
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               CopyFromParent,     // depth
360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               InputOutput,
361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               CopyFromParent,     // visual
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               CWOverrideRedirect,
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               &swa);
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  {
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const char* kAtomsToCache[] = { "_NET_WM_WINDOW_TYPE_MENU", NULL };
366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::X11AtomCache atom_cache(gfx::GetXDisplay(), kAtomsToCache);
367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::SetAtomProperty(menu_xid,
368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        "_NET_WM_WINDOW_TYPE",
369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        "ATOM",
370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        atom_cache.GetAtom("_NET_WM_WINDOW_TYPE_MENU"));
371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::SetUseOSWindowFrame(menu_xid, false);
373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ShowAndSetXWindowBounds(menu_xid, gfx::Rect(140, 110, 100, 100));
374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ui::X11EventSource::GetInstance()->DispatchXEvents();
375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // |menu_xid| is never added to _NET_CLIENT_LIST_STACKING.
377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XID xids[] = { xid };
378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  StackingClientListWaiter stack_waiter(xids, arraysize(xids));
379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  stack_waiter.Wait();
380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(xid, FindTopmostXWindowAt(110, 110));
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(menu_xid, FindTopmostXWindowAt(150, 120));
383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXPECT_EQ(menu_xid, FindTopmostXWindowAt(210, 120));
384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XDestroyWindow(xdisplay(), xid);
386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  XDestroyWindow(xdisplay(), menu_xid);
387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace views
390