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