diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/modules/desktop_capture/screen_drawer_win.cc | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/desktop_capture/screen_drawer_win.cc b/third_party/libwebrtc/modules/desktop_capture/screen_drawer_win.cc new file mode 100644 index 0000000000..7cf634fe89 --- /dev/null +++ b/third_party/libwebrtc/modules/desktop_capture/screen_drawer_win.cc @@ -0,0 +1,209 @@ +/* + * 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 |