| 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 |