1 /*
2 * Copyright (c) 2016 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 <windows.h>
12
13 #include <memory>
14
15 #include "modules/desktop_capture/screen_drawer.h"
16 #include "system_wrappers/include/sleep.h"
17
18 namespace webrtc {
19
20 namespace {
21
22 static constexpr TCHAR kMutexName[] =
23 TEXT("Local\\ScreenDrawerWin-da834f82-8044-11e6-ac81-73dcdd1c1869");
24
25 class ScreenDrawerLockWin : public ScreenDrawerLock {
26 public:
27 ScreenDrawerLockWin();
28 ~ScreenDrawerLockWin() override;
29
30 private:
31 HANDLE mutex_;
32 };
33
ScreenDrawerLockWin()34 ScreenDrawerLockWin::ScreenDrawerLockWin() {
35 while (true) {
36 mutex_ = CreateMutex(NULL, FALSE, kMutexName);
37 if (GetLastError() != ERROR_ALREADY_EXISTS && mutex_ != NULL) {
38 break;
39 } else {
40 if (mutex_) {
41 CloseHandle(mutex_);
42 }
43 SleepMs(1000);
44 }
45 }
46 }
47
~ScreenDrawerLockWin()48 ScreenDrawerLockWin::~ScreenDrawerLockWin() {
49 CloseHandle(mutex_);
50 }
51
GetScreenRect()52 DesktopRect GetScreenRect() {
53 HDC hdc = GetDC(NULL);
54 DesktopRect rect = DesktopRect::MakeWH(GetDeviceCaps(hdc, HORZRES),
55 GetDeviceCaps(hdc, VERTRES));
56 ReleaseDC(NULL, hdc);
57 return rect;
58 }
59
CreateDrawerWindow(DesktopRect rect)60 HWND CreateDrawerWindow(DesktopRect rect) {
61 HWND hwnd = CreateWindowA(
62 "STATIC", "DrawerWindow", WS_POPUPWINDOW | WS_VISIBLE, rect.left(),
63 rect.top(), rect.width(), rect.height(), NULL, NULL, NULL, NULL);
64 SetForegroundWindow(hwnd);
65 return hwnd;
66 }
67
ColorToRef(RgbaColor color)68 COLORREF ColorToRef(RgbaColor color) {
69 // Windows device context does not support alpha.
70 return RGB(color.red, color.green, color.blue);
71 }
72
73 // A ScreenDrawer implementation for Windows.
74 class ScreenDrawerWin : public ScreenDrawer {
75 public:
76 ScreenDrawerWin();
77 ~ScreenDrawerWin() override;
78
79 // ScreenDrawer interface.
80 DesktopRect DrawableRegion() override;
81 void DrawRectangle(DesktopRect rect, RgbaColor color) override;
82 void Clear() override;
83 void WaitForPendingDraws() override;
84 bool MayDrawIncompleteShapes() override;
85 WindowId window_id() const override;
86
87 private:
88 // Bring the window to the front, this can help to avoid the impact from other
89 // windows or shadow effects.
90 void BringToFront();
91
92 // Draw a line with |color|.
93 void DrawLine(DesktopVector start, DesktopVector end, RgbaColor color);
94
95 // Draw a dot with |color|.
96 void DrawDot(DesktopVector vect, RgbaColor color);
97
98 const DesktopRect rect_;
99 HWND window_;
100 HDC hdc_;
101 };
102
ScreenDrawerWin()103 ScreenDrawerWin::ScreenDrawerWin()
104 : ScreenDrawer(),
105 rect_(GetScreenRect()),
106 window_(CreateDrawerWindow(rect_)),
107 hdc_(GetWindowDC(window_)) {
108 // We do not need to handle any messages for the |window_|, so disable Windows
109 // from processing windows ghosting feature.
110 DisableProcessWindowsGhosting();
111
112 // Always use stock pen (DC_PEN) and brush (DC_BRUSH).
113 SelectObject(hdc_, GetStockObject(DC_PEN));
114 SelectObject(hdc_, GetStockObject(DC_BRUSH));
115 BringToFront();
116 }
117
~ScreenDrawerWin()118 ScreenDrawerWin::~ScreenDrawerWin() {
119 ReleaseDC(NULL, hdc_);
120 DestroyWindow(window_);
121 // Unfortunately there is no EnableProcessWindowsGhosting() API.
122 }
123
DrawableRegion()124 DesktopRect ScreenDrawerWin::DrawableRegion() {
125 return rect_;
126 }
127
DrawRectangle(DesktopRect rect,RgbaColor color)128 void ScreenDrawerWin::DrawRectangle(DesktopRect rect, RgbaColor color) {
129 if (rect.width() == 1 && rect.height() == 1) {
130 // Rectangle function cannot draw a 1 pixel rectangle.
131 DrawDot(rect.top_left(), color);
132 return;
133 }
134
135 if (rect.width() == 1 || rect.height() == 1) {
136 // Rectangle function cannot draw a 1 pixel rectangle.
137 DrawLine(rect.top_left(), DesktopVector(rect.right(), rect.bottom()),
138 color);
139 return;
140 }
141
142 SetDCBrushColor(hdc_, ColorToRef(color));
143 SetDCPenColor(hdc_, ColorToRef(color));
144 Rectangle(hdc_, rect.left(), rect.top(), rect.right(), rect.bottom());
145 }
146
Clear()147 void ScreenDrawerWin::Clear() {
148 DrawRectangle(rect_, RgbaColor(0, 0, 0));
149 }
150
151 // TODO(zijiehe): Find the right signal to indicate the finish of all pending
152 // paintings.
WaitForPendingDraws()153 void ScreenDrawerWin::WaitForPendingDraws() {
154 BringToFront();
155 SleepMs(50);
156 }
157
MayDrawIncompleteShapes()158 bool ScreenDrawerWin::MayDrawIncompleteShapes() {
159 return true;
160 }
161
window_id() const162 WindowId ScreenDrawerWin::window_id() const {
163 return reinterpret_cast<WindowId>(window_);
164 }
165
DrawLine(DesktopVector start,DesktopVector end,RgbaColor color)166 void ScreenDrawerWin::DrawLine(DesktopVector start,
167 DesktopVector end,
168 RgbaColor color) {
169 POINT points[2];
170 points[0].x = start.x();
171 points[0].y = start.y();
172 points[1].x = end.x();
173 points[1].y = end.y();
174 SetDCPenColor(hdc_, ColorToRef(color));
175 Polyline(hdc_, points, 2);
176 }
177
DrawDot(DesktopVector vect,RgbaColor color)178 void ScreenDrawerWin::DrawDot(DesktopVector vect, RgbaColor color) {
179 SetPixel(hdc_, vect.x(), vect.y(), ColorToRef(color));
180 }
181
BringToFront()182 void ScreenDrawerWin::BringToFront() {
183 if (SetWindowPos(window_, HWND_TOPMOST, 0, 0, 0, 0,
184 SWP_NOMOVE | SWP_NOSIZE) != FALSE) {
185 return;
186 }
187
188 long ex_style = GetWindowLong(window_, GWL_EXSTYLE);
189 ex_style |= WS_EX_TOPMOST;
190 if (SetWindowLong(window_, GWL_EXSTYLE, ex_style) != 0) {
191 return;
192 }
193
194 BringWindowToTop(window_);
195 }
196
197 } // namespace
198
199 // static
Create()200 std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() {
201 return std::unique_ptr<ScreenDrawerLock>(new ScreenDrawerLockWin());
202 }
203
204 // static
Create()205 std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() {
206 return std::unique_ptr<ScreenDrawer>(new ScreenDrawerWin());
207 }
208
209 } // namespace webrtc
210