blob: 437a6d3fe7712519fec44d87830501bc16127514 [file] [log] [blame]
zijiehe49c01d72016-08-16 17:33:55 -07001/*
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 "webrtc/modules/desktop_capture/screen_drawer.h"
zijiehe0f49dac2016-09-07 11:52:25 -070016#include "webrtc/system_wrappers/include/sleep.h"
zijiehe49c01d72016-08-16 17:33:55 -070017
18namespace webrtc {
19
20namespace {
21
zijiehe6a4607e2016-10-18 18:22:18 -070022static constexpr TCHAR kMutexName[] =
23 TEXT("Local\\ScreenDrawerWin-da834f82-8044-11e6-ac81-73dcdd1c1869");
24
25class ScreenDrawerLockWin : public ScreenDrawerLock {
26 public:
27 ScreenDrawerLockWin();
zijiehe6be0a652016-10-27 16:50:35 -070028 ~ScreenDrawerLockWin() override;
zijiehe6a4607e2016-10-18 18:22:18 -070029
30 private:
31 HANDLE mutex_;
32};
33
34ScreenDrawerLockWin::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
48ScreenDrawerLockWin::~ScreenDrawerLockWin() {
49 CloseHandle(mutex_);
50}
51
zijiehe49c01d72016-08-16 17:33:55 -070052DesktopRect 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
60HWND 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
zijiehe0f49dac2016-09-07 11:52:25 -070068COLORREF ColorToRef(RgbaColor color) {
69 // Windows device context does not support alpha.
70 return RGB(color.red, color.green, color.blue);
71}
72
zijiehe49c01d72016-08-16 17:33:55 -070073// A ScreenDrawer implementation for Windows.
74class ScreenDrawerWin : public ScreenDrawer {
75 public:
76 ScreenDrawerWin();
77 ~ScreenDrawerWin() override;
78
79 // ScreenDrawer interface.
80 DesktopRect DrawableRegion() override;
zijiehe0f49dac2016-09-07 11:52:25 -070081 void DrawRectangle(DesktopRect rect, RgbaColor color) override;
zijiehe49c01d72016-08-16 17:33:55 -070082 void Clear() override;
zijiehe0f49dac2016-09-07 11:52:25 -070083 void WaitForPendingDraws() override;
zijiehe6a4607e2016-10-18 18:22:18 -070084 bool MayDrawIncompleteShapes() override;
zijiehe49c01d72016-08-16 17:33:55 -070085
86 private:
zijiehe6a4607e2016-10-18 18:22:18 -070087 // Bring the window to the front, this can help to avoid the impact from other
88 // windows or shadow effects.
89 void BringToFront();
90
zijiehe0f49dac2016-09-07 11:52:25 -070091 // Draw a line with |color|.
92 void DrawLine(DesktopVector start, DesktopVector end, RgbaColor color);
93
94 // Draw a dot with |color|.
95 void DrawDot(DesktopVector vect, RgbaColor color);
96
zijiehe49c01d72016-08-16 17:33:55 -070097 const DesktopRect rect_;
98 HWND window_;
99 HDC hdc_;
100};
101
102ScreenDrawerWin::ScreenDrawerWin()
103 : ScreenDrawer(),
104 rect_(GetScreenRect()),
105 window_(CreateDrawerWindow(rect_)),
106 hdc_(GetWindowDC(window_)) {
107 // We do not need to handle any messages for the |window_|, so disable Windows
zijiehe0f49dac2016-09-07 11:52:25 -0700108 // from processing windows ghosting feature.
zijiehe49c01d72016-08-16 17:33:55 -0700109 DisableProcessWindowsGhosting();
zijiehe0f49dac2016-09-07 11:52:25 -0700110
111 // Always use stock pen (DC_PEN) and brush (DC_BRUSH).
112 SelectObject(hdc_, GetStockObject(DC_PEN));
113 SelectObject(hdc_, GetStockObject(DC_BRUSH));
zijiehe6a4607e2016-10-18 18:22:18 -0700114 BringToFront();
zijiehe49c01d72016-08-16 17:33:55 -0700115}
116
117ScreenDrawerWin::~ScreenDrawerWin() {
118 ReleaseDC(NULL, hdc_);
119 DestroyWindow(window_);
120 // Unfortunately there is no EnableProcessWindowsGhosting() API.
121}
122
123DesktopRect ScreenDrawerWin::DrawableRegion() {
124 return rect_;
125}
126
zijiehe0f49dac2016-09-07 11:52:25 -0700127void ScreenDrawerWin::DrawRectangle(DesktopRect rect, RgbaColor color) {
128 if (rect.width() == 1 && rect.height() == 1) {
129 // Rectangle function cannot draw a 1 pixel rectangle.
130 DrawDot(rect.top_left(), color);
131 return;
132 }
133
134 if (rect.width() == 1 || rect.height() == 1) {
135 // Rectangle function cannot draw a 1 pixel rectangle.
136 DrawLine(rect.top_left(), DesktopVector(rect.right(), rect.bottom()),
137 color);
138 return;
139 }
140
141 SetDCBrushColor(hdc_, ColorToRef(color));
142 SetDCPenColor(hdc_, ColorToRef(color));
zijiehe49c01d72016-08-16 17:33:55 -0700143 Rectangle(hdc_, rect.left(), rect.top(), rect.right(), rect.bottom());
144}
145
146void ScreenDrawerWin::Clear() {
zijiehe0f49dac2016-09-07 11:52:25 -0700147 DrawRectangle(rect_, RgbaColor(0, 0, 0));
148}
149
150// TODO(zijiehe): Find the right signal to indicate the finish of all pending
151// paintings.
152void ScreenDrawerWin::WaitForPendingDraws() {
153 SleepMs(50);
154}
155
zijiehe6a4607e2016-10-18 18:22:18 -0700156bool ScreenDrawerWin::MayDrawIncompleteShapes() {
157 return true;
158}
159
zijiehe0f49dac2016-09-07 11:52:25 -0700160void ScreenDrawerWin::DrawLine(DesktopVector start,
161 DesktopVector end,
162 RgbaColor color) {
163 POINT points[2];
164 points[0].x = start.x();
165 points[0].y = start.y();
166 points[1].x = end.x();
167 points[1].y = end.y();
168 SetDCPenColor(hdc_, ColorToRef(color));
169 Polyline(hdc_, points, 2);
170}
171
172void ScreenDrawerWin::DrawDot(DesktopVector vect, RgbaColor color) {
173 SetPixel(hdc_, vect.x(), vect.y(), ColorToRef(color));
zijiehe49c01d72016-08-16 17:33:55 -0700174}
175
zijiehe6a4607e2016-10-18 18:22:18 -0700176void ScreenDrawerWin::BringToFront() {
zijiehe84fbf9e2016-10-20 17:00:37 -0700177 if (SetWindowPos(window_, HWND_TOPMOST, 0, 0, 0, 0,
178 SWP_NOMOVE | SWP_NOSIZE) != FALSE) {
zijiehe6a4607e2016-10-18 18:22:18 -0700179 return;
180 }
181
182 long ex_style = GetWindowLong(window_, GWL_EXSTYLE);
183 ex_style |= WS_EX_TOPMOST;
184 if (SetWindowLong(window_, GWL_EXSTYLE, ex_style) != 0) {
185 return;
186 }
187
188 BringWindowToTop(window_);
189}
190
zijiehe49c01d72016-08-16 17:33:55 -0700191} // namespace
192
193// static
zijiehe6a4607e2016-10-18 18:22:18 -0700194std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() {
195 return std::unique_ptr<ScreenDrawerLock>(new ScreenDrawerLockWin());
196}
197
198// static
zijiehe49c01d72016-08-16 17:33:55 -0700199std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() {
200 return std::unique_ptr<ScreenDrawer>(new ScreenDrawerWin());
201}
202
203} // namespace webrtc