OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/host/desktop_shape_tracker.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <vector> | |
10 | |
11 #include "base/logging.h" | |
12 #include "base/macros.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "base/win/scoped_gdi_object.h" | |
15 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" | |
16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | |
17 | |
18 namespace remoting { | |
19 | |
20 namespace { | |
21 | |
22 struct EnumDesktopShapeData { | |
23 EnumDesktopShapeData() | |
24 : window_region(CreateRectRgn(0, 0, 0, 0)), | |
25 desktop_region(CreateRectRgn(0, 0, 0, 0)) { | |
26 } | |
27 base::win::ScopedRegion window_region; | |
28 base::win::ScopedRegion desktop_region; | |
29 }; | |
30 | |
31 class DesktopShapeTrackerWin : public DesktopShapeTracker { | |
32 public: | |
33 DesktopShapeTrackerWin(); | |
34 ~DesktopShapeTrackerWin() override; | |
35 | |
36 void RefreshDesktopShape() override; | |
37 const webrtc::DesktopRegion& desktop_shape() override; | |
38 | |
39 private: | |
40 // Callback passed to EnumWindows() to enumerate windows. | |
41 static BOOL CALLBACK EnumWindowsCallback(HWND window, LPARAM lparam); | |
42 | |
43 // The most recently calculated desktop region. | |
44 webrtc::DesktopRegion desktop_shape_; | |
45 | |
46 // Stored to compare with newly calculated desktop shapes, to avoid converting | |
47 // to an DesktopRegion unless the shape has actually changed. | |
48 base::win::ScopedRegion old_desktop_region_; | |
49 | |
50 DISALLOW_COPY_AND_ASSIGN(DesktopShapeTrackerWin); | |
51 }; | |
52 | |
53 DesktopShapeTrackerWin::DesktopShapeTrackerWin() | |
54 : old_desktop_region_(CreateRectRgn(0, 0, 0, 0)) { | |
55 } | |
56 | |
57 DesktopShapeTrackerWin::~DesktopShapeTrackerWin() { | |
58 } | |
59 | |
60 void DesktopShapeTrackerWin::RefreshDesktopShape() { | |
61 // Accumulate a new desktop shape from current window positions. | |
62 scoped_ptr<EnumDesktopShapeData> shape_data(new EnumDesktopShapeData); | |
63 if (!EnumWindows(EnumWindowsCallback, (LPARAM)shape_data.get())) { | |
64 PLOG(ERROR) << "Failed to enumerate windows"; | |
65 desktop_shape_.Clear(); | |
66 return; | |
67 } | |
68 | |
69 // If the shape has changed, refresh |desktop_shape_|. | |
70 if (!EqualRgn(shape_data->desktop_region.get(), old_desktop_region_.get())) { | |
71 old_desktop_region_ = std::move(shape_data->desktop_region); | |
72 | |
73 // Determine the size of output buffer required to receive the region. | |
74 DWORD bytes_size = GetRegionData(old_desktop_region_.get(), 0, nullptr); | |
75 CHECK(bytes_size != 0); | |
76 | |
77 // Fetch the Windows RECTs that comprise the region. | |
78 std::vector<char> buffer(bytes_size); | |
79 LPRGNDATA region_data = reinterpret_cast<LPRGNDATA>(buffer.data()); | |
80 DWORD result = | |
81 GetRegionData(old_desktop_region_.get(), bytes_size, region_data); | |
82 CHECK(result == bytes_size); | |
83 const LPRECT rects = reinterpret_cast<LPRECT>(®ion_data->Buffer[0]); | |
84 | |
85 // Reset |desktop_shape_| and add new rectangles into it. | |
86 desktop_shape_.Clear(); | |
87 for (size_t i = 0; i < region_data->rdh.nCount; ++i) { | |
88 desktop_shape_.AddRect(webrtc::DesktopRect::MakeLTRB( | |
89 rects[i].left, rects[i].top, rects[i].right, rects[i].bottom)); | |
90 } | |
91 } | |
92 } | |
93 | |
94 const webrtc::DesktopRegion& DesktopShapeTrackerWin::desktop_shape() { | |
95 return desktop_shape_; | |
96 } | |
97 | |
98 // static | |
99 BOOL DesktopShapeTrackerWin::EnumWindowsCallback(HWND window, LPARAM lparam) { | |
100 EnumDesktopShapeData* data = reinterpret_cast<EnumDesktopShapeData*>(lparam); | |
101 HRGN desktop_region = data->desktop_region.get(); | |
102 HRGN window_region = data->window_region.get(); | |
103 | |
104 // Is the window visible? | |
105 if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window)) | |
106 return TRUE; | |
107 | |
108 // Find the desktop position of the window (including non-client-area). | |
109 RECT window_rect; | |
110 if (!GetWindowRect(window, &window_rect)) | |
111 return TRUE; | |
112 | |
113 // Find the shape of the window, in window coords. | |
114 // GetWindowRgn will overwrite the current contents of |window_region|. | |
115 if (GetWindowRgn(window, window_region) != ERROR) { | |
116 // Translate the window region into desktop coordinates. | |
117 OffsetRgn(window_region, window_rect.left, window_rect.top); | |
118 } else { | |
119 // Window has no shape, or an error occurred, so assume it's rectangular. | |
120 SetRectRgn(window_region, window_rect.left, window_rect.top, | |
121 window_rect.right, window_rect.bottom); | |
122 } | |
123 | |
124 // TODO(wez): If the window is maximized then we should clip it to the | |
125 // display on which it is maximized. | |
126 // if (IsZoomed(window)) | |
127 // CombineRgn(window_region, window_region, screen_region, RGN_AND); | |
128 | |
129 // Merge the window region into the accumulated desktop region. Window | |
130 // regions are combined together before converting the result to | |
131 // DesktopRegion. It assumed that this approach is more efficient than | |
132 // converting each window region individually. | |
133 CombineRgn(desktop_region, desktop_region, window_region, RGN_OR); | |
134 | |
135 return TRUE; | |
136 } | |
137 | |
138 } // namespace | |
139 | |
140 // static | |
141 scoped_ptr<DesktopShapeTracker> DesktopShapeTracker::Create( | |
142 webrtc::DesktopCaptureOptions options) { | |
143 return make_scoped_ptr(new DesktopShapeTrackerWin()); | |
144 } | |
145 | |
146 } // namespace remoting | |
OLD | NEW |