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