|  | /* | 
|  | *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include <windows.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "modules/desktop_capture/screen_drawer.h" | 
|  | #include "system_wrappers/include/sleep.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | static constexpr TCHAR kMutexName[] = | 
|  | TEXT("Local\\ScreenDrawerWin-da834f82-8044-11e6-ac81-73dcdd1c1869"); | 
|  |  | 
|  | class ScreenDrawerLockWin : public ScreenDrawerLock { | 
|  | public: | 
|  | ScreenDrawerLockWin(); | 
|  | ~ScreenDrawerLockWin() override; | 
|  |  | 
|  | private: | 
|  | HANDLE mutex_; | 
|  | }; | 
|  |  | 
|  | ScreenDrawerLockWin::ScreenDrawerLockWin() { | 
|  | while (true) { | 
|  | mutex_ = CreateMutex(NULL, FALSE, kMutexName); | 
|  | if (GetLastError() != ERROR_ALREADY_EXISTS && mutex_ != NULL) { | 
|  | break; | 
|  | } else { | 
|  | if (mutex_) { | 
|  | CloseHandle(mutex_); | 
|  | } | 
|  | SleepMs(1000); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ScreenDrawerLockWin::~ScreenDrawerLockWin() { | 
|  | CloseHandle(mutex_); | 
|  | } | 
|  |  | 
|  | DesktopRect GetScreenRect() { | 
|  | HDC hdc = GetDC(NULL); | 
|  | DesktopRect rect = DesktopRect::MakeWH(GetDeviceCaps(hdc, HORZRES), | 
|  | GetDeviceCaps(hdc, VERTRES)); | 
|  | ReleaseDC(NULL, hdc); | 
|  | return rect; | 
|  | } | 
|  |  | 
|  | HWND CreateDrawerWindow(DesktopRect rect) { | 
|  | HWND hwnd = CreateWindowA( | 
|  | "STATIC", "DrawerWindow", WS_POPUPWINDOW | WS_VISIBLE, rect.left(), | 
|  | rect.top(), rect.width(), rect.height(), NULL, NULL, NULL, NULL); | 
|  | SetForegroundWindow(hwnd); | 
|  | return hwnd; | 
|  | } | 
|  |  | 
|  | COLORREF ColorToRef(RgbaColor color) { | 
|  | // Windows device context does not support alpha. | 
|  | return RGB(color.red, color.green, color.blue); | 
|  | } | 
|  |  | 
|  | // A ScreenDrawer implementation for Windows. | 
|  | class ScreenDrawerWin : public ScreenDrawer { | 
|  | public: | 
|  | ScreenDrawerWin(); | 
|  | ~ScreenDrawerWin() override; | 
|  |  | 
|  | // ScreenDrawer interface. | 
|  | DesktopRect DrawableRegion() override; | 
|  | void DrawRectangle(DesktopRect rect, RgbaColor color) override; | 
|  | void Clear() override; | 
|  | void WaitForPendingDraws() override; | 
|  | bool MayDrawIncompleteShapes() override; | 
|  | WindowId window_id() const override; | 
|  |  | 
|  | private: | 
|  | // Bring the window to the front, this can help to avoid the impact from other | 
|  | // windows or shadow effects. | 
|  | void BringToFront(); | 
|  |  | 
|  | // Draw a line with |color|. | 
|  | void DrawLine(DesktopVector start, DesktopVector end, RgbaColor color); | 
|  |  | 
|  | // Draw a dot with |color|. | 
|  | void DrawDot(DesktopVector vect, RgbaColor color); | 
|  |  | 
|  | const DesktopRect rect_; | 
|  | HWND window_; | 
|  | HDC hdc_; | 
|  | }; | 
|  |  | 
|  | ScreenDrawerWin::ScreenDrawerWin() | 
|  | : ScreenDrawer(), | 
|  | rect_(GetScreenRect()), | 
|  | window_(CreateDrawerWindow(rect_)), | 
|  | hdc_(GetWindowDC(window_)) { | 
|  | // We do not need to handle any messages for the |window_|, so disable Windows | 
|  | // from processing windows ghosting feature. | 
|  | DisableProcessWindowsGhosting(); | 
|  |  | 
|  | // Always use stock pen (DC_PEN) and brush (DC_BRUSH). | 
|  | SelectObject(hdc_, GetStockObject(DC_PEN)); | 
|  | SelectObject(hdc_, GetStockObject(DC_BRUSH)); | 
|  | BringToFront(); | 
|  | } | 
|  |  | 
|  | ScreenDrawerWin::~ScreenDrawerWin() { | 
|  | ReleaseDC(NULL, hdc_); | 
|  | DestroyWindow(window_); | 
|  | // Unfortunately there is no EnableProcessWindowsGhosting() API. | 
|  | } | 
|  |  | 
|  | DesktopRect ScreenDrawerWin::DrawableRegion() { | 
|  | return rect_; | 
|  | } | 
|  |  | 
|  | void ScreenDrawerWin::DrawRectangle(DesktopRect rect, RgbaColor color) { | 
|  | if (rect.width() == 1 && rect.height() == 1) { | 
|  | // Rectangle function cannot draw a 1 pixel rectangle. | 
|  | DrawDot(rect.top_left(), color); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (rect.width() == 1 || rect.height() == 1) { | 
|  | // Rectangle function cannot draw a 1 pixel rectangle. | 
|  | DrawLine(rect.top_left(), DesktopVector(rect.right(), rect.bottom()), | 
|  | color); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SetDCBrushColor(hdc_, ColorToRef(color)); | 
|  | SetDCPenColor(hdc_, ColorToRef(color)); | 
|  | Rectangle(hdc_, rect.left(), rect.top(), rect.right(), rect.bottom()); | 
|  | } | 
|  |  | 
|  | void ScreenDrawerWin::Clear() { | 
|  | DrawRectangle(rect_, RgbaColor(0, 0, 0)); | 
|  | } | 
|  |  | 
|  | // TODO(zijiehe): Find the right signal to indicate the finish of all pending | 
|  | // paintings. | 
|  | void ScreenDrawerWin::WaitForPendingDraws() { | 
|  | BringToFront(); | 
|  | SleepMs(50); | 
|  | } | 
|  |  | 
|  | bool ScreenDrawerWin::MayDrawIncompleteShapes() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | WindowId ScreenDrawerWin::window_id() const { | 
|  | return reinterpret_cast<WindowId>(window_); | 
|  | } | 
|  |  | 
|  | void ScreenDrawerWin::DrawLine(DesktopVector start, | 
|  | DesktopVector end, | 
|  | RgbaColor color) { | 
|  | POINT points[2]; | 
|  | points[0].x = start.x(); | 
|  | points[0].y = start.y(); | 
|  | points[1].x = end.x(); | 
|  | points[1].y = end.y(); | 
|  | SetDCPenColor(hdc_, ColorToRef(color)); | 
|  | Polyline(hdc_, points, 2); | 
|  | } | 
|  |  | 
|  | void ScreenDrawerWin::DrawDot(DesktopVector vect, RgbaColor color) { | 
|  | SetPixel(hdc_, vect.x(), vect.y(), ColorToRef(color)); | 
|  | } | 
|  |  | 
|  | void ScreenDrawerWin::BringToFront() { | 
|  | if (SetWindowPos(window_, HWND_TOPMOST, 0, 0, 0, 0, | 
|  | SWP_NOMOVE | SWP_NOSIZE) != FALSE) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | long ex_style = GetWindowLong(window_, GWL_EXSTYLE); | 
|  | ex_style |= WS_EX_TOPMOST; | 
|  | if (SetWindowLong(window_, GWL_EXSTYLE, ex_style) != 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | BringWindowToTop(window_); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<ScreenDrawerLock> ScreenDrawerLock::Create() { | 
|  | return std::unique_ptr<ScreenDrawerLock>(new ScreenDrawerLockWin()); | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<ScreenDrawer> ScreenDrawer::Create() { | 
|  | return std::unique_ptr<ScreenDrawer>(new ScreenDrawerWin()); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |