OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" | 5 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h" |
6 | 6 |
7 #include <stddef.h> | |
8 #include <X11/extensions/shape.h> | |
9 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
10 #include <X11/Xregion.h> | 8 #include <X11/Xregion.h> |
| 9 #include <X11/extensions/shape.h> |
| 10 #include <stddef.h> |
| 11 |
11 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <memory> |
12 #include <vector> | 14 #include <vector> |
13 | 15 |
14 // Get rid of X11 macros which conflict with gtest. | 16 // Get rid of X11 macros which conflict with gtest. |
15 #undef Bool | 17 #undef Bool |
16 #undef None | 18 #undef None |
17 | 19 |
18 #include "base/macros.h" | 20 #include "base/macros.h" |
19 #include "base/memory/scoped_ptr.h" | |
20 #include "base/path_service.h" | 21 #include "base/path_service.h" |
21 #include "third_party/skia/include/core/SkRect.h" | 22 #include "third_party/skia/include/core/SkRect.h" |
22 #include "third_party/skia/include/core/SkRegion.h" | 23 #include "third_party/skia/include/core/SkRegion.h" |
23 #include "ui/aura/window.h" | 24 #include "ui/aura/window.h" |
24 #include "ui/aura/window_tree_host.h" | 25 #include "ui/aura/window_tree_host.h" |
25 #include "ui/base/resource/resource_bundle.h" | 26 #include "ui/base/resource/resource_bundle.h" |
26 #include "ui/base/ui_base_paths.h" | 27 #include "ui/base/ui_base_paths.h" |
27 #include "ui/events/platform/x11/x11_event_source.h" | 28 #include "ui/events/platform/x11/x11_event_source.h" |
28 #include "ui/gfx/path.h" | 29 #include "ui/gfx/path.h" |
29 #include "ui/gfx/path_x11.h" | 30 #include "ui/gfx/path_x11.h" |
(...skipping 25 matching lines...) Expand all Loading... |
55 bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override { | 56 bool ShouldKeepOnWaiting(const ui::PlatformEvent& event) override { |
56 std::vector<Atom> wm_states; | 57 std::vector<Atom> wm_states; |
57 if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) { | 58 if (ui::GetAtomArrayProperty(xwindow(), "_NET_WM_STATE", &wm_states)) { |
58 auto it = std::find(wm_states.cbegin(), wm_states.cend(), | 59 auto it = std::find(wm_states.cbegin(), wm_states.cend(), |
59 atom_cache_->GetAtom("_NET_WM_STATE_HIDDEN")); | 60 atom_cache_->GetAtom("_NET_WM_STATE_HIDDEN")); |
60 return it == wm_states.cend(); | 61 return it == wm_states.cend(); |
61 } | 62 } |
62 return true; | 63 return true; |
63 } | 64 } |
64 | 65 |
65 scoped_ptr<ui::X11AtomCache> atom_cache_; | 66 std::unique_ptr<ui::X11AtomCache> atom_cache_; |
66 | 67 |
67 DISALLOW_COPY_AND_ASSIGN(MinimizeWaiter); | 68 DISALLOW_COPY_AND_ASSIGN(MinimizeWaiter); |
68 }; | 69 }; |
69 | 70 |
70 // Waits till |_NET_CLIENT_LIST_STACKING| is updated to include | 71 // Waits till |_NET_CLIENT_LIST_STACKING| is updated to include |
71 // |expected_windows|. | 72 // |expected_windows|. |
72 class StackingClientListWaiter : public X11PropertyChangeWaiter { | 73 class StackingClientListWaiter : public X11PropertyChangeWaiter { |
73 public: | 74 public: |
74 StackingClientListWaiter(XID* expected_windows, size_t count) | 75 StackingClientListWaiter(XID* expected_windows, size_t count) |
75 : X11PropertyChangeWaiter(ui::GetX11RootWindow(), | 76 : X11PropertyChangeWaiter(ui::GetX11RootWindow(), |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 | 112 |
112 class X11TopmostWindowFinderTest : public ViewsTestBase { | 113 class X11TopmostWindowFinderTest : public ViewsTestBase { |
113 public: | 114 public: |
114 X11TopmostWindowFinderTest() { | 115 X11TopmostWindowFinderTest() { |
115 } | 116 } |
116 | 117 |
117 ~X11TopmostWindowFinderTest() override {} | 118 ~X11TopmostWindowFinderTest() override {} |
118 | 119 |
119 // Creates and shows a Widget with |bounds|. The caller takes ownership of | 120 // Creates and shows a Widget with |bounds|. The caller takes ownership of |
120 // the returned widget. | 121 // the returned widget. |
121 scoped_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) { | 122 std::unique_ptr<Widget> CreateAndShowWidget(const gfx::Rect& bounds) { |
122 scoped_ptr<Widget> toplevel(new Widget); | 123 std::unique_ptr<Widget> toplevel(new Widget); |
123 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); | 124 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); |
124 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 125 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
125 params.native_widget = new DesktopNativeWidgetAura(toplevel.get()); | 126 params.native_widget = new DesktopNativeWidgetAura(toplevel.get()); |
126 params.bounds = bounds; | 127 params.bounds = bounds; |
127 params.remove_standard_frame = true; | 128 params.remove_standard_frame = true; |
128 toplevel->Init(params); | 129 toplevel->Init(params); |
129 toplevel->Show(); | 130 toplevel->Show(); |
130 return toplevel; | 131 return toplevel; |
131 } | 132 } |
132 | 133 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 } | 220 } |
220 | 221 |
221 private: | 222 private: |
222 DISALLOW_COPY_AND_ASSIGN(X11TopmostWindowFinderTest); | 223 DISALLOW_COPY_AND_ASSIGN(X11TopmostWindowFinderTest); |
223 }; | 224 }; |
224 | 225 |
225 TEST_F(X11TopmostWindowFinderTest, Basic) { | 226 TEST_F(X11TopmostWindowFinderTest, Basic) { |
226 // Avoid positioning test windows at 0x0 because window managers often have a | 227 // Avoid positioning test windows at 0x0 because window managers often have a |
227 // panel/launcher along one of the screen edges and do not allow windows to | 228 // panel/launcher along one of the screen edges and do not allow windows to |
228 // position themselves to overlap the panel/launcher. | 229 // position themselves to overlap the panel/launcher. |
229 scoped_ptr<Widget> widget1( | 230 std::unique_ptr<Widget> widget1( |
230 CreateAndShowWidget(gfx::Rect(100, 100, 200, 100))); | 231 CreateAndShowWidget(gfx::Rect(100, 100, 200, 100))); |
231 aura::Window* window1 = widget1->GetNativeWindow(); | 232 aura::Window* window1 = widget1->GetNativeWindow(); |
232 XID xid1 = window1->GetHost()->GetAcceleratedWidget(); | 233 XID xid1 = window1->GetHost()->GetAcceleratedWidget(); |
233 | 234 |
234 XID xid2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200)); | 235 XID xid2 = CreateAndShowXWindow(gfx::Rect(200, 100, 100, 200)); |
235 | 236 |
236 scoped_ptr<Widget> widget3( | 237 std::unique_ptr<Widget> widget3( |
237 CreateAndShowWidget(gfx::Rect(100, 190, 200, 110))); | 238 CreateAndShowWidget(gfx::Rect(100, 190, 200, 110))); |
238 aura::Window* window3 = widget3->GetNativeWindow(); | 239 aura::Window* window3 = widget3->GetNativeWindow(); |
239 XID xid3 = window3->GetHost()->GetAcceleratedWidget(); | 240 XID xid3 = window3->GetHost()->GetAcceleratedWidget(); |
240 | 241 |
241 XID xids[] = { xid1, xid2, xid3 }; | 242 XID xids[] = { xid1, xid2, xid3 }; |
242 StackingClientListWaiter waiter(xids, arraysize(xids)); | 243 StackingClientListWaiter waiter(xids, arraysize(xids)); |
243 waiter.Wait(); | 244 waiter.Wait(); |
244 ui::X11EventSource::GetInstance()->DispatchXEvents(); | 245 ui::X11EventSource::GetInstance()->DispatchXEvents(); |
245 | 246 |
246 EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150)); | 247 EXPECT_EQ(xid1, FindTopmostXWindowAt(150, 150)); |
(...skipping 23 matching lines...) Expand all Loading... |
270 EXPECT_EQ(NULL, | 271 EXPECT_EQ(NULL, |
271 FindTopmostLocalProcessWindowWithIgnore(150, 250, window3)); | 272 FindTopmostLocalProcessWindowWithIgnore(150, 250, window3)); |
272 EXPECT_EQ(window1, | 273 EXPECT_EQ(window1, |
273 FindTopmostLocalProcessWindowWithIgnore(150, 195, window3)); | 274 FindTopmostLocalProcessWindowWithIgnore(150, 195, window3)); |
274 | 275 |
275 XDestroyWindow(xdisplay(), xid2); | 276 XDestroyWindow(xdisplay(), xid2); |
276 } | 277 } |
277 | 278 |
278 // Test that the minimized state is properly handled. | 279 // Test that the minimized state is properly handled. |
279 TEST_F(X11TopmostWindowFinderTest, Minimized) { | 280 TEST_F(X11TopmostWindowFinderTest, Minimized) { |
280 scoped_ptr<Widget> widget1( | 281 std::unique_ptr<Widget> widget1( |
281 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); | 282 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); |
282 aura::Window* window1 = widget1->GetNativeWindow(); | 283 aura::Window* window1 = widget1->GetNativeWindow(); |
283 XID xid1 = window1->GetHost()->GetAcceleratedWidget(); | 284 XID xid1 = window1->GetHost()->GetAcceleratedWidget(); |
284 XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100)); | 285 XID xid2 = CreateAndShowXWindow(gfx::Rect(300, 100, 100, 100)); |
285 | 286 |
286 XID xids[] = { xid1, xid2 }; | 287 XID xids[] = { xid1, xid2 }; |
287 StackingClientListWaiter stack_waiter(xids, arraysize(xids)); | 288 StackingClientListWaiter stack_waiter(xids, arraysize(xids)); |
288 stack_waiter.Wait(); | 289 stack_waiter.Wait(); |
289 ui::X11EventSource::GetInstance()->DispatchXEvents(); | 290 ui::X11EventSource::GetInstance()->DispatchXEvents(); |
290 | 291 |
(...skipping 18 matching lines...) Expand all Loading... |
309 EXPECT_NE(xid2, FindTopmostXWindowAt(350, 150)); | 310 EXPECT_NE(xid2, FindTopmostXWindowAt(350, 150)); |
310 | 311 |
311 XDestroyWindow(xdisplay(), xid2); | 312 XDestroyWindow(xdisplay(), xid2); |
312 } | 313 } |
313 | 314 |
314 // Test that non-rectangular windows are properly handled. | 315 // Test that non-rectangular windows are properly handled. |
315 TEST_F(X11TopmostWindowFinderTest, NonRectangular) { | 316 TEST_F(X11TopmostWindowFinderTest, NonRectangular) { |
316 if (!ui::IsShapeExtensionAvailable()) | 317 if (!ui::IsShapeExtensionAvailable()) |
317 return; | 318 return; |
318 | 319 |
319 scoped_ptr<Widget> widget1( | 320 std::unique_ptr<Widget> widget1( |
320 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); | 321 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); |
321 XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); | 322 XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); |
322 SkRegion* skregion1 = new SkRegion; | 323 SkRegion* skregion1 = new SkRegion; |
323 skregion1->op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op); | 324 skregion1->op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op); |
324 skregion1->op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op); | 325 skregion1->op(SkIRect::MakeXYWH(10, 0, 90, 100), SkRegion::kUnion_Op); |
325 // Widget takes ownership of |skregion1|. | 326 // Widget takes ownership of |skregion1|. |
326 widget1->SetShape(skregion1); | 327 widget1->SetShape(skregion1); |
327 | 328 |
328 SkRegion skregion2; | 329 SkRegion skregion2; |
329 skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op); | 330 skregion2.op(SkIRect::MakeXYWH(0, 10, 10, 90), SkRegion::kUnion_Op); |
(...skipping 19 matching lines...) Expand all Loading... |
349 EXPECT_NE(xid2, FindTopmostXWindowAt(305, 105)); | 350 EXPECT_NE(xid2, FindTopmostXWindowAt(305, 105)); |
350 | 351 |
351 XDestroyWindow(xdisplay(), xid2); | 352 XDestroyWindow(xdisplay(), xid2); |
352 } | 353 } |
353 | 354 |
354 // Test that a window with an empty shape are properly handled. | 355 // Test that a window with an empty shape are properly handled. |
355 TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) { | 356 TEST_F(X11TopmostWindowFinderTest, NonRectangularEmptyShape) { |
356 if (!ui::IsShapeExtensionAvailable()) | 357 if (!ui::IsShapeExtensionAvailable()) |
357 return; | 358 return; |
358 | 359 |
359 scoped_ptr<Widget> widget1( | 360 std::unique_ptr<Widget> widget1( |
360 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); | 361 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); |
361 XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); | 362 XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); |
362 SkRegion* skregion1 = new SkRegion; | 363 SkRegion* skregion1 = new SkRegion; |
363 skregion1->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op); | 364 skregion1->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op); |
364 // Widget takes ownership of |skregion1|. | 365 // Widget takes ownership of |skregion1|. |
365 widget1->SetShape(skregion1); | 366 widget1->SetShape(skregion1); |
366 | 367 |
367 XID xids[] = { xid1 }; | 368 XID xids[] = { xid1 }; |
368 StackingClientListWaiter stack_waiter(xids, arraysize(xids)); | 369 StackingClientListWaiter stack_waiter(xids, arraysize(xids)); |
369 stack_waiter.Wait(); | 370 stack_waiter.Wait(); |
370 ui::X11EventSource::GetInstance()->DispatchXEvents(); | 371 ui::X11EventSource::GetInstance()->DispatchXEvents(); |
371 | 372 |
372 EXPECT_NE(xid1, FindTopmostXWindowAt(105, 105)); | 373 EXPECT_NE(xid1, FindTopmostXWindowAt(105, 105)); |
373 } | 374 } |
374 | 375 |
375 // Test that setting a Null shape removes the shape. | 376 // Test that setting a Null shape removes the shape. |
376 TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) { | 377 TEST_F(X11TopmostWindowFinderTest, NonRectangularNullShape) { |
377 if (!ui::IsShapeExtensionAvailable()) | 378 if (!ui::IsShapeExtensionAvailable()) |
378 return; | 379 return; |
379 | 380 |
380 scoped_ptr<Widget> widget1( | 381 std::unique_ptr<Widget> widget1( |
381 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); | 382 CreateAndShowWidget(gfx::Rect(100, 100, 100, 100))); |
382 XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); | 383 XID xid1 = widget1->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); |
383 SkRegion* skregion1 = new SkRegion; | 384 SkRegion* skregion1 = new SkRegion; |
384 skregion1->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op); | 385 skregion1->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op); |
385 // Widget takes ownership of |skregion1|. | 386 // Widget takes ownership of |skregion1|. |
386 widget1->SetShape(skregion1); | 387 widget1->SetShape(skregion1); |
387 | 388 |
388 // Remove the shape - this is now just a normal window. | 389 // Remove the shape - this is now just a normal window. |
389 widget1->SetShape(NULL); | 390 widget1->SetShape(NULL); |
390 | 391 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 | 433 |
433 EXPECT_EQ(xid, FindTopmostXWindowAt(110, 110)); | 434 EXPECT_EQ(xid, FindTopmostXWindowAt(110, 110)); |
434 EXPECT_EQ(menu_xid, FindTopmostXWindowAt(150, 120)); | 435 EXPECT_EQ(menu_xid, FindTopmostXWindowAt(150, 120)); |
435 EXPECT_EQ(menu_xid, FindTopmostXWindowAt(210, 120)); | 436 EXPECT_EQ(menu_xid, FindTopmostXWindowAt(210, 120)); |
436 | 437 |
437 XDestroyWindow(xdisplay(), xid); | 438 XDestroyWindow(xdisplay(), xid); |
438 XDestroyWindow(xdisplay(), menu_xid); | 439 XDestroyWindow(xdisplay(), menu_xid); |
439 } | 440 } |
440 | 441 |
441 } // namespace views | 442 } // namespace views |
OLD | NEW |