blob: f3a41e93469638361a6a186efaf028d70cfce9c0 [file] [log] [blame]
// Copyright 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 {
: 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 {
~DesktopShapeTrackerWin() override;
void RefreshDesktopShape() override;
const webrtc::DesktopRegion& desktop_shape() override;
// 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_;
: 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())) {
PLOG(ERROR) << "Failed to enumerate windows";
// If the shape has changed, refresh |desktop_shape_|.
if (!EqualRgn(shape_data->desktop_region, old_desktop_region_)) {
// Determine the size of output buffer required to receive the region.
DWORD bytes_size = GetRegionData(old_desktop_region_, 0, nullptr);
CHECK(bytes_size != 0);
// Fetch the Windows RECTs that comprise the region.
std::vector<char> buffer(bytes_size);
LPRGNDATA region_data = reinterpret_cast<LPRGNDATA>(;
DWORD result = GetRegionData(old_desktop_region_, bytes_size, region_data);
CHECK(result == bytes_size);
const LPRECT rects = reinterpret_cast<LPRECT>(&region_data->Buffer[0]);
// Reset |desktop_shape_| and add new rectangles into it.
for (size_t i = 0; i < region_data->rdh.nCount; ++i) {
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,;
} else {
// Window has no shape, or an error occurred, so assume it's rectangular.
SetRectRgn(window_region, window_rect.left,,
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 make_scoped_ptr(new DesktopShapeTrackerWin());
} // namespace remoting