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