desktop_shape_tracker_win.cc revision f2477e01787aa58f445919b809d89e252beef54f
1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "remoting/host/desktop_shape_tracker.h" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <vector> 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/win/scoped_gdi_object.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_region.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace remoting { 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace { 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)struct EnumDesktopShapeData { 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EnumDesktopShapeData() 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : window_region(CreateRectRgn(0, 0, 0, 0)), 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) desktop_region(CreateRectRgn(0, 0, 0, 0)) { 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::win::ScopedRegion window_region; 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::win::ScopedRegion desktop_region; 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class DesktopShapeTrackerWin : public DesktopShapeTracker { 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DesktopShapeTrackerWin(); 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~DesktopShapeTrackerWin(); 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual void RefreshDesktopShape(); 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual const webrtc::DesktopRegion& desktop_shape(); 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Callback passed to EnumWindows() to enumerate windows. 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static BOOL CALLBACK EnumWindowsCallback(HWND window, LPARAM lparam); 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The most recently calculated desktop region. 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) webrtc::DesktopRegion desktop_shape_; 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Stored to compare with newly calculated desktop shapes, to avoid converting 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // to an DesktopRegion unless the shape has actually changed. 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::win::ScopedRegion old_desktop_region_; 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DesktopShapeTrackerWin); 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)DesktopShapeTrackerWin::DesktopShapeTrackerWin() 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : old_desktop_region_(CreateRectRgn(0, 0, 0, 0)) { 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)DesktopShapeTrackerWin::~DesktopShapeTrackerWin() { 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DesktopShapeTrackerWin::RefreshDesktopShape() { 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Accumulate a new desktop shape from current window positions. 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<EnumDesktopShapeData> shape_data(new EnumDesktopShapeData); 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!EnumWindows(EnumWindowsCallback, (LPARAM)shape_data.get())) { 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG_GETLASTERROR(ERROR) << "Failed to enumerate windows"; 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) desktop_shape_.Clear(); 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If the shape has changed, refresh |desktop_shape_|. 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!EqualRgn(shape_data->desktop_region, old_desktop_region_)) { 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) old_desktop_region_.Set(shape_data->desktop_region.release()); 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Determine the size of output buffer required to receive the region. 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DWORD bytes_size = GetRegionData(old_desktop_region_, 0, NULL); 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(bytes_size != 0); 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Fetch the Windows RECTs that comprise the region. 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::vector<char> buffer(bytes_size);; 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LPRGNDATA region_data = reinterpret_cast<LPRGNDATA>(buffer.data()); 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DWORD result = GetRegionData(old_desktop_region_, bytes_size, region_data); 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CHECK(result == bytes_size); 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const LPRECT rects = reinterpret_cast<LPRECT>(®ion_data->Buffer[0]); 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Reset |desktop_shape_| and add new rectangles into it. 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) desktop_shape_.Clear(); 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (size_t i = 0; i < region_data->rdh.nCount; ++i) { 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) desktop_shape_.AddRect(webrtc::DesktopRect::MakeLTRB( 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) rects[i].left, rects[i].top, rects[i].right, rects[i].bottom)); 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const webrtc::DesktopRegion& DesktopShapeTrackerWin::desktop_shape() { 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return desktop_shape_; 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)BOOL DesktopShapeTrackerWin::EnumWindowsCallback(HWND window, LPARAM lparam) { 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EnumDesktopShapeData* data = reinterpret_cast<EnumDesktopShapeData*>(lparam); 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) HRGN desktop_region = data->desktop_region.Get(); 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) HRGN window_region = data->window_region.Get(); 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Is the window visible? 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window)) 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return TRUE; 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Find the desktop position of the window (including non-client-area). 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RECT window_rect; 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!GetWindowRect(window, &window_rect)) 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return TRUE; 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Find the shape of the window, in window coords. 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // GetWindowRgn will overwrite the current contents of |window_region|. 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (GetWindowRgn(window, window_region) != ERROR) { 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Translate the window region into desktop coordinates. 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) OffsetRgn(window_region, window_rect.left, window_rect.top); 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Window has no shape, or an error occurred, so assume it's rectangular. 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetRectRgn(window_region, window_rect.left, window_rect.top, 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) window_rect.right, window_rect.bottom); 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(wez): If the window is maximized then we should clip it to the 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // display on which it is maximized. 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // if (IsZoomed(window)) 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // CombineRgn(window_region, window_region, screen_region, RGN_AND); 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Merge the window region into the accumulated desktop region. Window 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // regions are combined together before converting the result to 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // DesktopRegion. It assumed that this approach is more efficient than 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // converting each window region individually. 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CombineRgn(desktop_region, desktop_region, window_region, RGN_OR); 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return TRUE; 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_ptr<DesktopShapeTracker> DesktopShapeTracker::Create( 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) webrtc::DesktopCaptureOptions options) { 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return scoped_ptr<DesktopShapeTracker>(new DesktopShapeTrackerWin()); 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace remoting 142