OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/desktop_capture/cropping_window_capturer.h" | 11 #include "webrtc/modules/desktop_capture/cropping_window_capturer.h" |
12 | 12 |
13 #include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h" | 13 #include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h" |
14 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" | 14 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" |
15 #include "webrtc/modules/desktop_capture/win/window_capture_utils.h" | 15 #include "webrtc/modules/desktop_capture/win/window_capture_utils.h" |
16 #include "webrtc/rtc_base/logging.h" | 16 #include "webrtc/rtc_base/logging.h" |
17 #include "webrtc/rtc_base/win32.h" | 17 #include "webrtc/rtc_base/win32.h" |
18 | 18 |
19 namespace webrtc { | 19 namespace webrtc { |
20 | 20 |
21 namespace { | 21 namespace { |
22 | 22 |
23 // Used to pass input/output data during the EnumWindow call for verifying if | 23 // Used to pass input/output data during the EnumWindow call for verifying if |
24 // the selected window is on top. | 24 // the selected window is on top. |
25 struct TopWindowVerifierContext { | 25 struct TopWindowVerifierContext { |
26 TopWindowVerifierContext(HWND selected_window, HWND excluded_window) | 26 TopWindowVerifierContext(HWND selected_window, |
| 27 HWND excluded_window, |
| 28 DesktopRect selected_window_rect) |
27 : selected_window(selected_window), | 29 : selected_window(selected_window), |
28 excluded_window(excluded_window), | 30 excluded_window(excluded_window), |
29 is_top_window(false), | 31 selected_window_rect(selected_window_rect), |
30 selected_window_process_id(0) {} | 32 is_top_window(false) { |
| 33 RTC_DCHECK_NE(selected_window, excluded_window); |
| 34 } |
31 | 35 |
32 HWND selected_window; | 36 const HWND selected_window; |
33 HWND excluded_window; | 37 const HWND excluded_window; |
| 38 const DesktopRect selected_window_rect; |
34 bool is_top_window; | 39 bool is_top_window; |
35 DWORD selected_window_process_id; | |
36 DesktopRect selected_window_rect; | |
37 }; | 40 }; |
38 | 41 |
39 // The function is called during EnumWindow for every window enumerated and is | 42 // The function is called during EnumWindow for every window enumerated and is |
40 // responsible for verifying if the selected window is on top. | 43 // responsible for verifying if the selected window is on top. |
41 BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) { | 44 BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) { |
42 TopWindowVerifierContext* context = | 45 TopWindowVerifierContext* context = |
43 reinterpret_cast<TopWindowVerifierContext*>(param); | 46 reinterpret_cast<TopWindowVerifierContext*>(param); |
44 | 47 |
45 if (hwnd == context->selected_window) { | 48 if (hwnd == context->selected_window) { |
46 context->is_top_window = true; | 49 context->is_top_window = true; |
(...skipping 16 matching lines...) Expand all Loading... |
63 if (GetAncestor(hwnd, GA_ROOTOWNER) == context->selected_window) { | 66 if (GetAncestor(hwnd, GA_ROOTOWNER) == context->selected_window) { |
64 return TRUE; | 67 return TRUE; |
65 } | 68 } |
66 | 69 |
67 // If |hwnd| has no title and belongs to the same process, assume it's a | 70 // If |hwnd| has no title and belongs to the same process, assume it's a |
68 // tooltip or context menu from the selected window and ignore it. | 71 // tooltip or context menu from the selected window and ignore it. |
69 const size_t kTitleLength = 32; | 72 const size_t kTitleLength = 32; |
70 WCHAR window_title[kTitleLength]; | 73 WCHAR window_title[kTitleLength]; |
71 GetWindowText(hwnd, window_title, kTitleLength); | 74 GetWindowText(hwnd, window_title, kTitleLength); |
72 if (wcsnlen_s(window_title, kTitleLength) == 0) { | 75 if (wcsnlen_s(window_title, kTitleLength) == 0) { |
73 DWORD enumerated_process; | 76 DWORD enumerated_window_process_id; |
74 GetWindowThreadProcessId(hwnd, &enumerated_process); | 77 DWORD selected_window_process_id; |
75 if (!context->selected_window_process_id) { | 78 GetWindowThreadProcessId(hwnd, &enumerated_window_process_id); |
76 GetWindowThreadProcessId(context->selected_window, | 79 GetWindowThreadProcessId(context->selected_window, |
77 &context->selected_window_process_id); | 80 &selected_window_process_id); |
78 } | 81 if (selected_window_process_id == enumerated_window_process_id) { |
79 if (context->selected_window_process_id == enumerated_process) { | |
80 return TRUE; | 82 return TRUE; |
81 } | 83 } |
82 } | 84 } |
83 | 85 |
84 // Check if the enumerated window intersects with the selected window. | 86 // Check if the enumerated window intersects with the selected window. |
85 RECT enumerated_rect; | 87 RECT enumerated_rect; |
86 if (!GetWindowRect(hwnd, &enumerated_rect)) { | 88 if (!GetWindowRect(hwnd, &enumerated_rect)) { |
87 // Bail out if failed to get the window area. | 89 // Bail out if failed to get the window area. |
88 context->is_top_window = false; | 90 context->is_top_window = false; |
89 return FALSE; | 91 return FALSE; |
(...skipping 30 matching lines...) Expand all Loading... |
120 // rectangular, or the rect from GetWindowRect if the region is not set. | 122 // rectangular, or the rect from GetWindowRect if the region is not set. |
121 DesktopRect window_region_rect_; | 123 DesktopRect window_region_rect_; |
122 | 124 |
123 AeroChecker aero_checker_; | 125 AeroChecker aero_checker_; |
124 }; | 126 }; |
125 | 127 |
126 bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { | 128 bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { |
127 if (!rtc::IsWindows8OrLater() && aero_checker_.IsAeroEnabled()) | 129 if (!rtc::IsWindows8OrLater() && aero_checker_.IsAeroEnabled()) |
128 return false; | 130 return false; |
129 | 131 |
| 132 HWND selected = reinterpret_cast<HWND>(selected_window()); |
| 133 // Check if the window is hidden or minimized. |
| 134 if (IsIconic(selected) || !IsWindowVisible(selected)) { |
| 135 return false; |
| 136 } |
| 137 |
130 // Check if the window is a translucent layered window. | 138 // Check if the window is a translucent layered window. |
131 HWND selected = reinterpret_cast<HWND>(selected_window()); | |
132 LONG window_ex_style = GetWindowLong(selected, GWL_EXSTYLE); | 139 LONG window_ex_style = GetWindowLong(selected, GWL_EXSTYLE); |
133 if (window_ex_style & WS_EX_LAYERED) { | 140 if (window_ex_style & WS_EX_LAYERED) { |
134 COLORREF color_ref_key = 0; | 141 COLORREF color_ref_key = 0; |
135 BYTE alpha = 0; | 142 BYTE alpha = 0; |
136 DWORD flags = 0; | 143 DWORD flags = 0; |
137 | 144 |
138 // GetLayeredWindowAttributes fails if the window was setup with | 145 // GetLayeredWindowAttributes fails if the window was setup with |
139 // UpdateLayeredWindow. We have no way to know the opacity of the window in | 146 // UpdateLayeredWindow. We have no way to know the opacity of the window in |
140 // that case. This happens for Stiky Note (crbug/412726). | 147 // that case. This happens for Stiky Note (crbug/412726). |
141 if (!GetLayeredWindowAttributes(selected, &color_ref_key, &alpha, &flags)) | 148 if (!GetLayeredWindowAttributes(selected, &color_ref_key, &alpha, &flags)) |
142 return false; | 149 return false; |
143 | 150 |
144 // UpdateLayeredWindow is the only way to set per-pixel alpha and will cause | 151 // UpdateLayeredWindow is the only way to set per-pixel alpha and will cause |
145 // the previous GetLayeredWindowAttributes to fail. So we only need to check | 152 // the previous GetLayeredWindowAttributes to fail. So we only need to check |
146 // the window wide color key or alpha. | 153 // the window wide color key or alpha. |
147 if ((flags & LWA_COLORKEY) || ((flags & LWA_ALPHA) && (alpha < 255))) | 154 if ((flags & LWA_COLORKEY) || ((flags & LWA_ALPHA) && (alpha < 255))) |
148 return false; | 155 return false; |
149 } | 156 } |
150 | 157 |
151 TopWindowVerifierContext context( | |
152 selected, reinterpret_cast<HWND>(excluded_window())); | |
153 | |
154 RECT selected_window_rect; | 158 RECT selected_window_rect; |
155 if (!GetWindowRect(selected, &selected_window_rect)) { | 159 if (!GetWindowRect(selected, &selected_window_rect)) { |
156 return false; | 160 return false; |
157 } | 161 } |
158 context.selected_window_rect = DesktopRect::MakeLTRB( | 162 window_region_rect_ = DesktopRect::MakeLTRB( |
159 selected_window_rect.left, | 163 selected_window_rect.left, selected_window_rect.top, |
160 selected_window_rect.top, | 164 selected_window_rect.right, selected_window_rect.bottom); |
161 selected_window_rect.right, | |
162 selected_window_rect.bottom); | |
163 | 165 |
164 // Get the window region and check if it is rectangular. | 166 // Get the window region and check if it is rectangular. |
165 win::ScopedGDIObject<HRGN, win::DeleteObjectTraits<HRGN> > | 167 win::ScopedGDIObject<HRGN, win::DeleteObjectTraits<HRGN> > |
166 scoped_hrgn(CreateRectRgn(0, 0, 0, 0)); | 168 scoped_hrgn(CreateRectRgn(0, 0, 0, 0)); |
167 int region_type = GetWindowRgn(selected, scoped_hrgn.Get()); | 169 int region_type = GetWindowRgn(selected, scoped_hrgn.Get()); |
168 | 170 |
169 // Do not use the screen capturer if the region is empty or not rectangular. | 171 // Do not use the screen capturer if the region is empty or not rectangular. |
170 if (region_type == COMPLEXREGION || region_type == NULLREGION) | 172 if (region_type == COMPLEXREGION || region_type == NULLREGION) |
171 return false; | 173 return false; |
172 | 174 |
173 if (region_type == SIMPLEREGION) { | 175 if (region_type == SIMPLEREGION) { |
174 RECT region_rect; | 176 RECT region_rect; |
175 GetRgnBox(scoped_hrgn.Get(), ®ion_rect); | 177 GetRgnBox(scoped_hrgn.Get(), ®ion_rect); |
176 DesktopRect rgn_rect = | 178 DesktopRect rgn_rect = |
177 DesktopRect::MakeLTRB(region_rect.left, | 179 DesktopRect::MakeLTRB(region_rect.left, |
178 region_rect.top, | 180 region_rect.top, |
179 region_rect.right, | 181 region_rect.right, |
180 region_rect.bottom); | 182 region_rect.bottom); |
181 rgn_rect.Translate(context.selected_window_rect.left(), | 183 rgn_rect.Translate(window_region_rect_.left(), window_region_rect_.top()); |
182 context.selected_window_rect.top()); | 184 window_region_rect_.IntersectWith(rgn_rect); |
183 context.selected_window_rect.IntersectWith(rgn_rect); | |
184 } | 185 } |
185 window_region_rect_ = context.selected_window_rect; | |
186 | 186 |
187 // Check if the window is occluded by any other window, excluding the child | 187 // Check if the window is occluded by any other window, excluding the child |
188 // windows, context menus, and |excluded_window_|. | 188 // windows, context menus, and |excluded_window_|. |
189 // TODO(zijiehe): EnumWindows enumerates root window only, so the window may | 189 // TODO(zijiehe): EnumWindows enumerates root window only, so the window may |
190 // be covered by its own child window. See bug | 190 // be covered by its own child window. See bug |
191 // https://bugs.chromium.org/p/webrtc/issues/detail?id=8062 | 191 // https://bugs.chromium.org/p/webrtc/issues/detail?id=8062 |
| 192 TopWindowVerifierContext context( |
| 193 selected, reinterpret_cast<HWND>(excluded_window()), window_region_rect_); |
192 EnumWindows(&TopWindowVerifier, reinterpret_cast<LPARAM>(&context)); | 194 EnumWindows(&TopWindowVerifier, reinterpret_cast<LPARAM>(&context)); |
193 return context.is_top_window; | 195 return context.is_top_window; |
194 } | 196 } |
195 | 197 |
196 DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() { | 198 DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() { |
197 DesktopRect original_rect; | 199 DesktopRect original_rect; |
198 DesktopRect window_rect; | 200 DesktopRect window_rect; |
199 HWND hwnd = reinterpret_cast<HWND>(selected_window()); | 201 HWND hwnd = reinterpret_cast<HWND>(selected_window()); |
200 if (!GetCroppedWindowRect(hwnd, &window_rect, &original_rect)) { | 202 if (!GetCroppedWindowRect(hwnd, &window_rect, &original_rect)) { |
201 LOG(LS_WARNING) << "Failed to get window info: " << GetLastError(); | 203 LOG(LS_WARNING) << "Failed to get window info: " << GetLastError(); |
(...skipping 11 matching lines...) Expand all Loading... |
213 } // namespace | 215 } // namespace |
214 | 216 |
215 // static | 217 // static |
216 std::unique_ptr<DesktopCapturer> CroppingWindowCapturer::CreateCapturer( | 218 std::unique_ptr<DesktopCapturer> CroppingWindowCapturer::CreateCapturer( |
217 const DesktopCaptureOptions& options) { | 219 const DesktopCaptureOptions& options) { |
218 return std::unique_ptr<DesktopCapturer>( | 220 return std::unique_ptr<DesktopCapturer>( |
219 new CroppingWindowCapturerWin(options)); | 221 new CroppingWindowCapturerWin(options)); |
220 } | 222 } |
221 | 223 |
222 } // namespace webrtc | 224 } // namespace webrtc |
OLD | NEW |