xref: /aosp_15_r20/external/webrtc/modules/desktop_capture/window_finder_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 <stdint.h>
14 
15 #include <memory>
16 
17 #include "api/scoped_refptr.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.
TEST(WindowFinderTest,FindConsoleWindow)43 TEST(WindowFinderTest, FindConsoleWindow) {
44   // Creates a ScreenDrawer to avoid this test from conflicting with
45   // ScreenCapturerIntegrationTest: both tests require its window to be in
46   // foreground.
47   //
48   // In ScreenCapturer related tests, this is controlled by
49   // ScreenDrawer, which has a global lock to ensure only one ScreenDrawer
50   // window is active. So even we do not use ScreenDrawer for Windows test,
51   // creating an instance can block ScreenCapturer related tests until this test
52   // finishes.
53   //
54   // Usually the test framework should take care of this "isolated test"
55   // requirement, but unfortunately WebRTC trybots do not support this.
56   std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create();
57   const int kMaxSize = 10000;
58   // Enlarges current console window.
59   system("mode 1000,1000");
60   const HWND console_window = GetConsoleWindow();
61   // Ensures that current console window is visible.
62   ShowWindow(console_window, SW_MAXIMIZE);
63   // Moves the window to the top-left of the display.
64   MoveWindow(console_window, 0, 0, kMaxSize, kMaxSize, true);
65 
66   bool should_restore_notopmost =
67       (GetWindowLong(console_window, GWL_EXSTYLE) & WS_EX_TOPMOST) == 0;
68 
69   // Brings console window to top.
70   SetWindowPos(console_window, HWND_TOPMOST, 0, 0, 0, 0,
71                SWP_NOMOVE | SWP_NOSIZE);
72   BringWindowToTop(console_window);
73 
74   bool success = false;
75   WindowFinderWin finder;
76   for (int i = 0; i < kMaxSize; i++) {
77     const DesktopVector spot(i, i);
78     const HWND id = reinterpret_cast<HWND>(finder.GetWindowUnderPoint(spot));
79     if (id == console_window) {
80       success = true;
81       break;
82     }
83   }
84   if (should_restore_notopmost)
85     SetWindowPos(console_window, HWND_NOTOPMOST, 0, 0, 0, 0,
86                  SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
87 
88   if (!success)
89     FAIL();
90 }
91 
92 #else
93 TEST(WindowFinderTest, FindDrawerWindow) {
94   WindowFinder::Options options;
95 #if defined(WEBRTC_USE_X11)
96   std::unique_ptr<XAtomCache> cache;
97   const auto shared_x_display = SharedXDisplay::CreateDefault();
98   if (shared_x_display) {
99     cache = std::make_unique<XAtomCache>(shared_x_display->display());
100     options.cache = cache.get();
101   }
102 #endif
103   std::unique_ptr<WindowFinder> finder = WindowFinder::Create(options);
104   if (!finder) {
105     RTC_LOG(LS_WARNING)
106         << "No WindowFinder implementation for current platform.";
107     return;
108   }
109 
110   std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create();
111   if (!drawer) {
112     RTC_LOG(LS_WARNING)
113         << "No ScreenDrawer implementation for current platform.";
114     return;
115   }
116 
117   if (drawer->window_id() == kNullWindowId) {
118     // TODO(zijiehe): WindowFinderTest can use a dedicated window without
119     // relying on ScreenDrawer.
120     RTC_LOG(LS_WARNING)
121         << "ScreenDrawer implementation for current platform does "
122            "create a window.";
123     return;
124   }
125 
126   // ScreenDrawer may not be able to bring the window to the top. So we test
127   // several spots, at least one of them should succeed.
128   const DesktopRect region = drawer->DrawableRegion();
129   if (region.is_empty()) {
130     RTC_LOG(LS_WARNING)
131         << "ScreenDrawer::DrawableRegion() is too small for the "
132            "WindowFinderTest.";
133     return;
134   }
135 
136   for (int i = 0; i < region.width(); i++) {
137     const DesktopVector spot(
138         region.left() + i, region.top() + i * region.height() / region.width());
139     const WindowId id = finder->GetWindowUnderPoint(spot);
140     if (id == drawer->window_id()) {
141       return;
142     }
143   }
144 
145   FAIL();
146 }
147 #endif
148 
TEST(WindowFinderTest,ShouldReturnNullWindowIfSpotIsOutOfScreen)149 TEST(WindowFinderTest, ShouldReturnNullWindowIfSpotIsOutOfScreen) {
150   WindowFinder::Options options;
151 #if defined(WEBRTC_USE_X11)
152   std::unique_ptr<XAtomCache> cache;
153   const auto shared_x_display = SharedXDisplay::CreateDefault();
154   if (shared_x_display) {
155     cache = std::make_unique<XAtomCache>(shared_x_display->display());
156     options.cache = cache.get();
157   }
158 #endif
159   std::unique_ptr<WindowFinder> finder = WindowFinder::Create(options);
160   if (!finder) {
161     RTC_LOG(LS_WARNING)
162         << "No WindowFinder implementation for current platform.";
163     return;
164   }
165 
166   ASSERT_EQ(kNullWindowId,
167             finder->GetWindowUnderPoint(DesktopVector(INT16_MAX, INT16_MAX)));
168   ASSERT_EQ(kNullWindowId,
169             finder->GetWindowUnderPoint(DesktopVector(INT16_MAX, INT16_MIN)));
170   ASSERT_EQ(kNullWindowId,
171             finder->GetWindowUnderPoint(DesktopVector(INT16_MIN, INT16_MAX)));
172   ASSERT_EQ(kNullWindowId,
173             finder->GetWindowUnderPoint(DesktopVector(INT16_MIN, INT16_MIN)));
174 }
175 
176 }  // namespace
177 
178 }  // namespace webrtc
179