OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "webrtc/system_wrappers/include/logging.h" | 29 #include "webrtc/system_wrappers/include/logging.h" |
30 | 30 |
31 namespace webrtc { | 31 namespace webrtc { |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 // Convenience wrapper for XGetWindowProperty() results. | 35 // Convenience wrapper for XGetWindowProperty() results. |
36 template <class PropertyType> | 36 template <class PropertyType> |
37 class XWindowProperty { | 37 class XWindowProperty { |
38 public: | 38 public: |
39 XWindowProperty(Display* display, Window window, Atom property) { | 39 XWindowProperty(Display* display, Window window, Atom property) |
| 40 : is_valid_(false), |
| 41 size_(0), |
| 42 data_(NULL) { |
40 const int kBitsPerByte = 8; | 43 const int kBitsPerByte = 8; |
41 Atom actual_type; | 44 Atom actual_type; |
42 int actual_format; | 45 int actual_format; |
43 unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty | 46 unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty |
44 int status = XGetWindowProperty(display, window, property, 0L, ~0L, False, | 47 int status = XGetWindowProperty(display, window, property, 0L, ~0L, False, |
45 AnyPropertyType, &actual_type, | 48 AnyPropertyType, &actual_type, |
46 &actual_format, &size_, | 49 &actual_format, &size_, |
47 &bytes_after, &data_); | 50 &bytes_after, &data_); |
48 if (status != Success) { | 51 if (status != Success) { |
49 data_ = nullptr; | 52 data_ = NULL; |
50 return; | 53 return; |
51 } | 54 } |
52 if (sizeof(PropertyType) * kBitsPerByte != actual_format) { | 55 if (sizeof(PropertyType) * kBitsPerByte != actual_format) { |
53 size_ = 0; | 56 size_ = 0; |
54 return; | 57 return; |
55 } | 58 } |
56 | 59 |
57 is_valid_ = true; | 60 is_valid_ = true; |
58 } | 61 } |
59 | 62 |
60 ~XWindowProperty() { | 63 ~XWindowProperty() { |
61 if (data_) | 64 if (data_) |
62 XFree(data_); | 65 XFree(data_); |
63 } | 66 } |
64 | 67 |
65 // True if we got properly value successfully. | 68 // True if we got properly value successfully. |
66 bool is_valid() const { return is_valid_; } | 69 bool is_valid() const { return is_valid_; } |
67 | 70 |
68 // Size and value of the property. | 71 // Size and value of the property. |
69 size_t size() const { return size_; } | 72 size_t size() const { return size_; } |
70 const PropertyType* data() const { | 73 const PropertyType* data() const { |
71 return reinterpret_cast<PropertyType*>(data_); | 74 return reinterpret_cast<PropertyType*>(data_); |
72 } | 75 } |
73 PropertyType* data() { | 76 PropertyType* data() { |
74 return reinterpret_cast<PropertyType*>(data_); | 77 return reinterpret_cast<PropertyType*>(data_); |
75 } | 78 } |
76 | 79 |
77 private: | 80 private: |
78 bool is_valid_ = false; | 81 bool is_valid_; |
79 unsigned long size_ = 0; // NOLINT: type required by XGetWindowProperty | 82 unsigned long size_; // NOLINT: type required by XGetWindowProperty |
80 unsigned char* data_ = nullptr; | 83 unsigned char* data_; |
81 | 84 |
82 RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty); | 85 RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty); |
83 }; | 86 }; |
84 | 87 |
85 class WindowCapturerLinux : public WindowCapturer, | 88 class WindowCapturerLinux : public WindowCapturer, |
86 public SharedXDisplay::XEventHandler { | 89 public SharedXDisplay::XEventHandler { |
87 public: | 90 public: |
88 WindowCapturerLinux(const DesktopCaptureOptions& options); | 91 WindowCapturerLinux(const DesktopCaptureOptions& options); |
89 virtual ~WindowCapturerLinux(); | 92 virtual ~WindowCapturerLinux(); |
90 | 93 |
(...skipping 16 matching lines...) Expand all Loading... |
107 // that has WM_STATE property set to NormalState. | 110 // that has WM_STATE property set to NormalState. |
108 // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 . | 111 // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 . |
109 ::Window GetApplicationWindow(::Window window); | 112 ::Window GetApplicationWindow(::Window window); |
110 | 113 |
111 // Returns true if the |window| is a desktop element. | 114 // Returns true if the |window| is a desktop element. |
112 bool IsDesktopElement(::Window window); | 115 bool IsDesktopElement(::Window window); |
113 | 116 |
114 // Returns window title for the specified X |window|. | 117 // Returns window title for the specified X |window|. |
115 bool GetWindowTitle(::Window window, std::string* title); | 118 bool GetWindowTitle(::Window window, std::string* title); |
116 | 119 |
117 Callback* callback_ = nullptr; | 120 Callback* callback_; |
118 | 121 |
119 rtc::scoped_refptr<SharedXDisplay> x_display_; | 122 rtc::scoped_refptr<SharedXDisplay> x_display_; |
120 | 123 |
121 Atom wm_state_atom_; | 124 Atom wm_state_atom_; |
122 Atom window_type_atom_; | 125 Atom window_type_atom_; |
123 Atom normal_window_type_atom_; | 126 Atom normal_window_type_atom_; |
124 bool has_composite_extension_ = false; | 127 bool has_composite_extension_; |
125 | 128 |
126 ::Window selected_window_ = 0; | 129 ::Window selected_window_; |
127 XServerPixelBuffer x_server_pixel_buffer_; | 130 XServerPixelBuffer x_server_pixel_buffer_; |
128 | 131 |
129 RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux); | 132 RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux); |
130 }; | 133 }; |
131 | 134 |
132 WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options) | 135 WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options) |
133 : x_display_(options.x_display()) { | 136 : callback_(NULL), |
| 137 x_display_(options.x_display()), |
| 138 has_composite_extension_(false), |
| 139 selected_window_(0) { |
134 // Create Atoms so we don't need to do it every time they are used. | 140 // Create Atoms so we don't need to do it every time they are used. |
135 wm_state_atom_ = XInternAtom(display(), "WM_STATE", True); | 141 wm_state_atom_ = XInternAtom(display(), "WM_STATE", True); |
136 window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True); | 142 window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True); |
137 normal_window_type_atom_ = XInternAtom( | 143 normal_window_type_atom_ = XInternAtom( |
138 display(), "_NET_WM_WINDOW_TYPE_NORMAL", True); | 144 display(), "_NET_WM_WINDOW_TYPE_NORMAL", True); |
139 | 145 |
140 int event_base, error_base, major_version, minor_version; | 146 int event_base, error_base, major_version, minor_version; |
141 if (XCompositeQueryExtension(display(), &event_base, &error_base) && | 147 if (XCompositeQueryExtension(display(), &event_base, &error_base) && |
142 XCompositeQueryVersion(display(), &major_version, &minor_version) && | 148 XCompositeQueryVersion(display(), &major_version, &minor_version) && |
143 // XCompositeNameWindowPixmap() requires version 0.2 | 149 // XCompositeNameWindowPixmap() requires version 0.2 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 void WindowCapturerLinux::Start(Callback* callback) { | 273 void WindowCapturerLinux::Start(Callback* callback) { |
268 assert(!callback_); | 274 assert(!callback_); |
269 assert(callback); | 275 assert(callback); |
270 | 276 |
271 callback_ = callback; | 277 callback_ = callback; |
272 } | 278 } |
273 | 279 |
274 void WindowCapturerLinux::Capture(const DesktopRegion& region) { | 280 void WindowCapturerLinux::Capture(const DesktopRegion& region) { |
275 if (!x_server_pixel_buffer_.IsWindowValid()) { | 281 if (!x_server_pixel_buffer_.IsWindowValid()) { |
276 LOG(LS_INFO) << "The window is no longer valid."; | 282 LOG(LS_INFO) << "The window is no longer valid."; |
277 callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr); | 283 callback_->OnCaptureCompleted(NULL); |
278 return; | 284 return; |
279 } | 285 } |
280 | 286 |
281 x_display_->ProcessPendingXEvents(); | 287 x_display_->ProcessPendingXEvents(); |
282 | 288 |
283 if (!has_composite_extension_) { | 289 if (!has_composite_extension_) { |
284 // Without the Xcomposite extension we capture when the whole window is | 290 // Without the Xcomposite extension we capture when the whole window is |
285 // visible on screen and not covered by any other window. This is not | 291 // visible on screen and not covered by any other window. This is not |
286 // something we want so instead, just bail out. | 292 // something we want so instead, just bail out. |
287 LOG(LS_INFO) << "No Xcomposite extension detected."; | 293 LOG(LS_INFO) << "No Xcomposite extension detected."; |
288 callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr); | 294 callback_->OnCaptureCompleted(NULL); |
289 return; | 295 return; |
290 } | 296 } |
291 | 297 |
292 std::unique_ptr<DesktopFrame> frame( | 298 DesktopFrame* frame = |
293 new BasicDesktopFrame(x_server_pixel_buffer_.window_size())); | 299 new BasicDesktopFrame(x_server_pixel_buffer_.window_size()); |
294 | 300 |
295 x_server_pixel_buffer_.Synchronize(); | 301 x_server_pixel_buffer_.Synchronize(); |
296 x_server_pixel_buffer_.CaptureRect(DesktopRect::MakeSize(frame->size()), | 302 x_server_pixel_buffer_.CaptureRect(DesktopRect::MakeSize(frame->size()), |
297 frame.get()); | 303 frame); |
298 | 304 |
299 frame->mutable_updated_region()->SetRect( | 305 frame->mutable_updated_region()->SetRect( |
300 DesktopRect::MakeSize(frame->size())); | 306 DesktopRect::MakeSize(frame->size())); |
301 | 307 |
302 callback_->OnCaptureResult(Result::SUCCESS, std::move(frame)); | 308 callback_->OnCaptureCompleted(frame); |
303 } | 309 } |
304 | 310 |
305 bool WindowCapturerLinux::HandleXEvent(const XEvent& event) { | 311 bool WindowCapturerLinux::HandleXEvent(const XEvent& event) { |
306 if (event.type == ConfigureNotify) { | 312 if (event.type == ConfigureNotify) { |
307 XConfigureEvent xce = event.xconfigure; | 313 XConfigureEvent xce = event.xconfigure; |
308 if (!DesktopSize(xce.width, xce.height).equals( | 314 if (!DesktopSize(xce.width, xce.height).equals( |
309 x_server_pixel_buffer_.window_size())) { | 315 x_server_pixel_buffer_.window_size())) { |
310 if (!x_server_pixel_buffer_.Init(display(), selected_window_)) { | 316 if (!x_server_pixel_buffer_.Init(display(), selected_window_)) { |
311 LOG(LS_ERROR) << "Failed to initialize pixel buffer after resizing."; | 317 LOG(LS_ERROR) << "Failed to initialize pixel buffer after resizing."; |
312 } | 318 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 } | 392 } |
387 XFree(class_hint.res_name); | 393 XFree(class_hint.res_name); |
388 XFree(class_hint.res_class); | 394 XFree(class_hint.res_class); |
389 return result; | 395 return result; |
390 } | 396 } |
391 | 397 |
392 bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) { | 398 bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) { |
393 int status; | 399 int status; |
394 bool result = false; | 400 bool result = false; |
395 XTextProperty window_name; | 401 XTextProperty window_name; |
396 window_name.value = nullptr; | 402 window_name.value = NULL; |
397 if (window) { | 403 if (window) { |
398 status = XGetWMName(display(), window, &window_name); | 404 status = XGetWMName(display(), window, &window_name); |
399 if (status && window_name.value && window_name.nitems) { | 405 if (status && window_name.value && window_name.nitems) { |
400 int cnt; | 406 int cnt; |
401 char** list = nullptr; | 407 char **list = NULL; |
402 status = Xutf8TextPropertyToTextList(display(), &window_name, &list, | 408 status = Xutf8TextPropertyToTextList(display(), &window_name, &list, |
403 &cnt); | 409 &cnt); |
404 if (status >= Success && cnt && *list) { | 410 if (status >= Success && cnt && *list) { |
405 if (cnt > 1) { | 411 if (cnt > 1) { |
406 LOG(LS_INFO) << "Window has " << cnt | 412 LOG(LS_INFO) << "Window has " << cnt |
407 << " text properties, only using the first one."; | 413 << " text properties, only using the first one."; |
408 } | 414 } |
409 *title = *list; | 415 *title = *list; |
410 result = true; | 416 result = true; |
411 } | 417 } |
412 if (list) | 418 if (list) |
413 XFreeStringList(list); | 419 XFreeStringList(list); |
414 } | 420 } |
415 if (window_name.value) | 421 if (window_name.value) |
416 XFree(window_name.value); | 422 XFree(window_name.value); |
417 } | 423 } |
418 return result; | 424 return result; |
419 } | 425 } |
420 | 426 |
421 } // namespace | 427 } // namespace |
422 | 428 |
423 // static | 429 // static |
424 WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { | 430 WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { |
425 if (!options.x_display()) | 431 if (!options.x_display()) |
426 return nullptr; | 432 return NULL; |
427 return new WindowCapturerLinux(options); | 433 return new WindowCapturerLinux(options); |
428 } | 434 } |
429 | 435 |
430 } // namespace webrtc | 436 } // namespace webrtc |
OLD | NEW |