| Index: remoting/host/desktop_shape_tracker_win.cc
|
| diff --git a/remoting/host/desktop_shape_tracker_win.cc b/remoting/host/desktop_shape_tracker_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dbf732c11db37c2269593147a12db0cf2e004743
|
| --- /dev/null
|
| +++ b/remoting/host/desktop_shape_tracker_win.cc
|
| @@ -0,0 +1,141 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "remoting/host/desktop_shape_tracker.h"
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/win/scoped_gdi_object.h"
|
| +#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
|
| +#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
|
| +
|
| +namespace remoting {
|
| +
|
| +namespace {
|
| +
|
| +struct EnumDesktopShapeData {
|
| + EnumDesktopShapeData()
|
| + : window_region(CreateRectRgn(0, 0, 0, 0)),
|
| + desktop_region(CreateRectRgn(0, 0, 0, 0)) {
|
| + }
|
| + base::win::ScopedRegion window_region;
|
| + base::win::ScopedRegion desktop_region;
|
| +};
|
| +
|
| +class DesktopShapeTrackerWin : public DesktopShapeTracker {
|
| + public:
|
| + DesktopShapeTrackerWin();
|
| + virtual ~DesktopShapeTrackerWin();
|
| +
|
| + virtual void RefreshDesktopShape();
|
| + virtual const webrtc::DesktopRegion& desktop_shape();
|
| +
|
| + private:
|
| + // Callback passed to EnumWindows() to enumerate windows.
|
| + static BOOL CALLBACK EnumWindowsCallback(HWND window, LPARAM lparam);
|
| +
|
| + // The most recently calculated desktop region.
|
| + webrtc::DesktopRegion desktop_shape_;
|
| +
|
| + // Stored to compare with newly calculated desktop shapes, to avoid converting
|
| + // to an DesktopRegion unless the shape has actually changed.
|
| + base::win::ScopedRegion old_desktop_region_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DesktopShapeTrackerWin);
|
| +};
|
| +
|
| +DesktopShapeTrackerWin::DesktopShapeTrackerWin()
|
| + : old_desktop_region_(CreateRectRgn(0, 0, 0, 0)) {
|
| +}
|
| +
|
| +DesktopShapeTrackerWin::~DesktopShapeTrackerWin() {
|
| +}
|
| +
|
| +void DesktopShapeTrackerWin::RefreshDesktopShape() {
|
| + // Accumulate a new desktop shape from current window positions.
|
| + scoped_ptr<EnumDesktopShapeData> shape_data(new EnumDesktopShapeData);
|
| + if (!EnumWindows(EnumWindowsCallback, (LPARAM)shape_data.get())) {
|
| + LOG_GETLASTERROR(ERROR) << "Failed to enumerate windows";
|
| + desktop_shape_.Clear();
|
| + return;
|
| + }
|
| +
|
| + // If the shape has changed, refresh |desktop_shape_|.
|
| + if (!EqualRgn(shape_data->desktop_region, old_desktop_region_)) {
|
| + old_desktop_region_.Set(shape_data->desktop_region.release());
|
| +
|
| + // Determine the size of output buffer required to receive the region.
|
| + DWORD bytes_size = GetRegionData(old_desktop_region_, 0, NULL);
|
| + CHECK(bytes_size != 0);
|
| +
|
| + // Fetch the Windows RECTs that comprise the region.
|
| + std::vector<char> buffer(bytes_size);;
|
| + LPRGNDATA region_data = reinterpret_cast<LPRGNDATA>(buffer.data());
|
| + DWORD result = GetRegionData(old_desktop_region_, bytes_size, region_data);
|
| + CHECK(result == bytes_size);
|
| + const LPRECT rects = reinterpret_cast<LPRECT>(®ion_data->Buffer[0]);
|
| +
|
| + // Reset |desktop_shape_| and add new rectangles into it.
|
| + desktop_shape_.Clear();
|
| + for (size_t i = 0; i < region_data->rdh.nCount; ++i) {
|
| + desktop_shape_.AddRect(webrtc::DesktopRect::MakeLTRB(
|
| + rects[i].left, rects[i].top, rects[i].right, rects[i].bottom));
|
| + }
|
| + }
|
| +}
|
| +
|
| +const webrtc::DesktopRegion& DesktopShapeTrackerWin::desktop_shape() {
|
| + return desktop_shape_;
|
| +}
|
| +
|
| +// static
|
| +BOOL DesktopShapeTrackerWin::EnumWindowsCallback(HWND window, LPARAM lparam) {
|
| + EnumDesktopShapeData* data = reinterpret_cast<EnumDesktopShapeData*>(lparam);
|
| + HRGN desktop_region = data->desktop_region.Get();
|
| + HRGN window_region = data->window_region.Get();
|
| +
|
| + // Is the window visible?
|
| + if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window))
|
| + return TRUE;
|
| +
|
| + // Find the desktop position of the window (including non-client-area).
|
| + RECT window_rect;
|
| + if (!GetWindowRect(window, &window_rect))
|
| + return TRUE;
|
| +
|
| + // Find the shape of the window, in window coords.
|
| + // GetWindowRgn will overwrite the current contents of |window_region|.
|
| + if (GetWindowRgn(window, window_region) != ERROR) {
|
| + // Translate the window region into desktop coordinates.
|
| + OffsetRgn(window_region, window_rect.left, window_rect.top);
|
| + } else {
|
| + // Window has no shape, or an error occurred, so assume it's rectangular.
|
| + SetRectRgn(window_region, window_rect.left, window_rect.top,
|
| + window_rect.right, window_rect.bottom);
|
| + }
|
| +
|
| + // TODO(wez): If the window is maximized then we should clip it to the
|
| + // display on which it is maximized.
|
| + // if (IsZoomed(window))
|
| + // CombineRgn(window_region, window_region, screen_region, RGN_AND);
|
| +
|
| + // Merge the window region into the accumulated desktop region. Window
|
| + // regions are combined together before converting the result to
|
| + // DesktopRegion. It assumed that this approach is more efficient than
|
| + // converting each window region individually.
|
| + CombineRgn(desktop_region, desktop_region, window_region, RGN_OR);
|
| +
|
| + return TRUE;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +scoped_ptr<DesktopShapeTracker> DesktopShapeTracker::Create(
|
| + webrtc::DesktopCaptureOptions options) {
|
| + return scoped_ptr<DesktopShapeTracker>(new DesktopShapeTrackerWin());
|
| +}
|
| +
|
| +} // namespace remoting
|
|
|