• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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