window_finder_unittest.cc (6379B)
1 /* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/desktop_capture/window_finder.h" 12 13 #include <cstdint> 14 #include <memory> 15 16 #include "api/scoped_refptr.h" 17 #include "modules/desktop_capture/desktop_capture_types.h" 18 #include "modules/desktop_capture/desktop_geometry.h" 19 #include "modules/desktop_capture/screen_drawer.h" 20 #include "rtc_base/logging.h" 21 #include "test/gtest.h" 22 23 #if defined(WEBRTC_USE_X11) 24 #include "modules/desktop_capture/linux/x11/shared_x_display.h" 25 #include "modules/desktop_capture/linux/x11/x_atom_cache.h" 26 #endif 27 28 #if defined(WEBRTC_WIN) 29 #include <windows.h> 30 31 #include "modules/desktop_capture/win/window_capture_utils.h" 32 #include "modules/desktop_capture/window_finder_win.h" 33 #endif 34 35 namespace webrtc { 36 37 namespace { 38 39 #if defined(WEBRTC_WIN) 40 // ScreenDrawerWin does not have a message loop, so it's unresponsive to user 41 // inputs. WindowFinderWin cannot detect this kind of unresponsive windows. 42 // Instead, console window is used to test WindowFinderWin. 43 // TODO(b/373792116): Reenable once flakiness is fixed. 44 TEST(WindowFinderTest, DISABLED_FindConsoleWindow) { 45 // Creates a ScreenDrawer to avoid this test from conflicting with 46 // ScreenCapturerIntegrationTest: both tests require its window to be in 47 // foreground. 48 // 49 // In ScreenCapturer related tests, this is controlled by 50 // ScreenDrawer, which has a global lock to ensure only one ScreenDrawer 51 // window is active. So even we do not use ScreenDrawer for Windows test, 52 // creating an instance can block ScreenCapturer related tests until this test 53 // finishes. 54 // 55 // Usually the test framework should take care of this "isolated test" 56 // requirement, but unfortunately WebRTC trybots do not support this. 57 std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create(); 58 const int kMaxSize = 10000; 59 // Enlarges current console window. 60 system("mode 1000,1000"); 61 const HWND console_window = GetConsoleWindow(); 62 // Ensures that current console window is visible. 63 ShowWindow(console_window, SW_MAXIMIZE); 64 // Moves the window to the top-left of the display. 65 if (!MoveWindow(console_window, 0, 0, kMaxSize, kMaxSize, true)) { 66 FAIL() << "Failed to move window. Error code: " << GetLastError(); 67 } 68 69 bool should_restore_notopmost = 70 (GetWindowLong(console_window, GWL_EXSTYLE) & WS_EX_TOPMOST) == 0; 71 72 // Brings console window to top. 73 if (!SetWindowPos(console_window, HWND_TOPMOST, 0, 0, 0, 0, 74 SWP_NOMOVE | SWP_NOSIZE)) { 75 FAIL() << "Failed to bring window to top. Error code: " << GetLastError(); 76 } 77 if (!BringWindowToTop(console_window)) { 78 FAIL() << "Failed second attempt to bring window to top. Error code: " 79 << GetLastError(); 80 } 81 82 bool success = false; 83 WindowFinderWin finder; 84 for (int i = 0; i < kMaxSize; i++) { 85 const DesktopVector spot(i, i); 86 const HWND id = reinterpret_cast<HWND>(finder.GetWindowUnderPoint(spot)); 87 88 if (id == console_window) { 89 success = true; 90 break; 91 } 92 RTC_LOG(LS_INFO) << "Expected window " << console_window 93 << ". Found window " << id; 94 } 95 if (should_restore_notopmost) 96 SetWindowPos(console_window, HWND_NOTOPMOST, 0, 0, 0, 0, 97 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); 98 99 if (!success) 100 FAIL(); 101 } 102 103 #else 104 TEST(WindowFinderTest, FindDrawerWindow) { 105 WindowFinder::Options options; 106 #if defined(WEBRTC_USE_X11) 107 std::unique_ptr<XAtomCache> cache; 108 const auto shared_x_display = SharedXDisplay::CreateDefault(); 109 if (shared_x_display) { 110 cache = std::make_unique<XAtomCache>(shared_x_display->display()); 111 options.cache = cache.get(); 112 } 113 #endif 114 std::unique_ptr<WindowFinder> finder = WindowFinder::Create(options); 115 if (!finder) { 116 RTC_LOG(LS_WARNING) 117 << "No WindowFinder implementation for current platform."; 118 return; 119 } 120 121 std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create(); 122 if (!drawer) { 123 RTC_LOG(LS_WARNING) 124 << "No ScreenDrawer implementation for current platform."; 125 return; 126 } 127 128 if (drawer->window_id() == kNullWindowId) { 129 // TODO(zijiehe): WindowFinderTest can use a dedicated window without 130 // relying on ScreenDrawer. 131 RTC_LOG(LS_WARNING) 132 << "ScreenDrawer implementation for current platform does " 133 "create a window."; 134 return; 135 } 136 137 // ScreenDrawer may not be able to bring the window to the top. So we test 138 // several spots, at least one of them should succeed. 139 const DesktopRect region = drawer->DrawableRegion(); 140 if (region.is_empty()) { 141 RTC_LOG(LS_WARNING) 142 << "ScreenDrawer::DrawableRegion() is too small for the " 143 "WindowFinderTest."; 144 return; 145 } 146 147 for (int i = 0; i < region.width(); i++) { 148 const DesktopVector spot( 149 region.left() + i, region.top() + i * region.height() / region.width()); 150 const WindowId id = finder->GetWindowUnderPoint(spot); 151 if (id == drawer->window_id()) { 152 return; 153 } 154 } 155 156 FAIL(); 157 } 158 #endif 159 160 TEST(WindowFinderTest, ShouldReturnNullWindowIfSpotIsOutOfScreen) { 161 WindowFinder::Options options; 162 #if defined(WEBRTC_USE_X11) 163 std::unique_ptr<XAtomCache> cache; 164 const auto shared_x_display = SharedXDisplay::CreateDefault(); 165 if (shared_x_display) { 166 cache = std::make_unique<XAtomCache>(shared_x_display->display()); 167 options.cache = cache.get(); 168 } 169 #endif 170 std::unique_ptr<WindowFinder> finder = WindowFinder::Create(options); 171 if (!finder) { 172 RTC_LOG(LS_WARNING) 173 << "No WindowFinder implementation for current platform."; 174 return; 175 } 176 177 ASSERT_EQ(kNullWindowId, 178 finder->GetWindowUnderPoint(DesktopVector(INT16_MAX, INT16_MAX))); 179 ASSERT_EQ(kNullWindowId, 180 finder->GetWindowUnderPoint(DesktopVector(INT16_MAX, INT16_MIN))); 181 ASSERT_EQ(kNullWindowId, 182 finder->GetWindowUnderPoint(DesktopVector(INT16_MIN, INT16_MAX))); 183 ASSERT_EQ(kNullWindowId, 184 finder->GetWindowUnderPoint(DesktopVector(INT16_MIN, INT16_MIN))); 185 } 186 187 } // namespace 188 189 } // namespace webrtc